# Product Requirements Document

## Validation Checklist

- [x] All required sections are complete
- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Problem statement is specific and measurable
- [x] Problem is validated by evidence (not assumptions)
- [x] Context → Problem → Solution flow makes sense
- [x] Every persona has at least one user journey
- [x] All MoSCoW categories addressed (Must/Should/Could/Won't)
- [x] Every feature has testable acceptance criteria
- [x] Every metric has corresponding tracking events
- [x] No feature redundancy (check for duplicates)
- [x] No contradictions between sections
- [x] No technical implementation details included
- [x] A new team member could understand this PRD

---

## Product Overview

### Vision
Enable backstock managers to perform bulk operations on multiple bins simultaneously, transforming what currently requires tedious one-by-one edits into efficient batch workflows.

### Problem Statement
Today, every backstock bin operation (changing location, emptying, re-categorizing, hiding) must be performed one bin at a time through the individual bin edit modal. When a store reorganizes inventory, moves bins between locations, or does end-of-season clearouts, staff must click into each bin individually — repeating the same action dozens or hundreds of times. A store with 400+ bins performing a seasonal reset can spend 2-3 hours on what should be a 5-minute operation. There is no way to look up multiple specific bins at once (e.g., from a handwritten list), forcing staff to search one by one.

### Value Proposition
Mass edit eliminates the repetitive click-per-bin workflow by letting staff select multiple bins, apply a single action, and move on. The comma-separated search lets staff type a list of bin names from a clipboard or handwritten sheet and instantly pull up exactly those bins. Combined with Select All on filtered results, an entire location move or category reassignment becomes a 30-second operation instead of a 30-minute one.

## User Personas

### Primary Persona: Store Manager
- **Demographics:** Mid-30s, manages day-to-day store operations, moderate technical proficiency, uses backstock daily
- **Goals:** Keep inventory organized efficiently, minimize time spent on administrative tasks, maintain accurate bin metadata for reporting
- **Pain Points:** Repetitive single-bin edits waste significant time during reorganizations; can't quickly find a specific set of bins when working from a physical list; has to individually empty bins during seasonal resets

### Secondary Personas

#### Backstock Associate
- **Demographics:** Early-20s, follows manager instructions for bin organization, basic technical proficiency
- **Goals:** Complete assigned bin tasks quickly and accurately, avoid making mistakes that require manager correction
- **Pain Points:** Given a list of bin names to move, must search and edit one at a time; easy to miss bins or make errors on repetitive tasks

#### Regional Manager
- **Demographics:** 40s, oversees multiple stores, reviews backstock reports, rarely edits bins directly
- **Goals:** Ensure consistent organization across stores, verify that seasonal resets and reorganizations are completed
- **Pain Points:** No visibility into whether bulk operations were performed correctly; relies on store managers' word

## User Journey Maps

### Primary User Journey: Seasonal Location Reorganization
1. **Awareness:** Manager decides to move all bins from Storage Unit 111 to Back Room for holiday season
2. **Consideration:** Currently would need to open each bin individually and change location — estimates 45 minutes for 80 bins
3. **Adoption:** Sees the Location filter dropdown, filters to Storage Unit 111, clicks Select All
4. **Usage:** Floating action bar appears showing "80 bins selected". Clicks "Change Location", selects "Back Room" from dropdown, confirms in modal showing affected bin list. All 80 bins updated in seconds.
5. **Retention:** Next reorganization, goes straight to filter → select all → mass action. Reports time savings to regional.

### Secondary User Journeys

#### Clipboard Bin Lookup
1. Manager receives a handwritten list of 12 bin names from an associate who found issues during an audit
2. Types "BIN-042, BIN-088, BIN-103, BIN-215..." into the search bar
3. Table filters to show only those 12 bins AND auto-selects them
4. Floating action bar shows "12 bins selected"
5. Manager can review, then perform any mass action (add notes: "Needs audit review", change category, etc.)

#### End-of-Season Mass Empty
1. Manager filters the table by category "Summer Seasonal"
2. Clicks Select All (selects all filtered bins across all pages)
3. Clicks "Empty Bins" in the floating action bar
4. Confirmation modal shows: "Empty 34 bins? This will clear categories, tags, age dates, notes, item counts, and estimated values."
5. Confirms. All 34 bins are reset to empty state. Actions logged per bin.

#### Mass Hide Inactive Bins
1. Manager notices 20 bins that haven't been used in 6 months via age filter
2. Selects them all and clicks "Hide Selected"
3. Confirmation shows affected bins. Confirms.
4. Bins disappear from the default view. Hidden bin count badge updates.

#### Mass Unhide
1. Manager enables "Show Hidden Bins" toggle
2. Sees previously hidden bins appear in the table (styled differently)
3. Selects the ones to reactivate, clicks "Unhide Selected"
4. Bins return to active inventory

## Feature Requirements

### Must Have Features

#### Feature 1: Multi-Row Selection
- **User Story:** As a store manager, I want to select multiple bins in the overview table so that I can perform actions on all of them at once.
- **Acceptance Criteria:**
  - [ ] Clicking a row selects/deselects it with a visual highlight
  - [ ] Shift+click selects a range of rows between last selected and clicked row
  - [ ] Ctrl/Cmd+click toggles individual row selection without affecting others
  - [ ] A checkbox column appears as the first column for click-target clarity
  - [ ] Selected row count is displayed in the floating action bar
  - [ ] Selection persists across DataTable pagination (page 1 → page 2 → back to page 1 retains selections)
  - [ ] Selection persists across column sorting changes
  - [ ] Selection is cleared when any filter changes (location dropdown, category dropdown, search bar, hidden toggle)
  - [ ] Selection is cleared when navigating away from the backstock page or refreshing the browser
  - [ ] Comma-search auto-selection is the one exception: it sets both filter AND selection atomically (not treated as a "filter change" that clears selection)

#### Feature 2: Select All (Filtered)
- **User Story:** As a store manager, I want to select all bins matching my current filters so that I can perform mass actions on an entire filtered set without clicking each one.
- **Acceptance Criteria:**
  - [ ] "Select All" checkbox in the header selects all rows matching current filters (not just current page)
  - [ ] Header checkbox shows indeterminate state when some (but not all) filtered rows are selected
  - [ ] Display shows "Selected X of Y bins" (X = selected count, Y = total filtered count)
  - [ ] Deselecting any individual row updates the header checkbox to indeterminate
  - [ ] Clicking Select All when all are selected deselects all
  - [ ] When filters change, selection is cleared (prevents acting on stale selections)

#### Feature 3: Floating Action Bar
- **User Story:** As a store manager, I want a persistent action toolbar so that I can see my selection count and available actions regardless of scroll position.
- **Acceptance Criteria:**
  - [ ] Bar slides up from the bottom of the viewport when 1+ rows are selected
  - [ ] Bar shows selected count: "X bins selected"
  - [ ] Bar contains action buttons: Change Location, Empty Bins, Change Category, Change Tags, Hide/Unhide, Print Labels, Update Age Date, Add Notes
  - [ ] Bar disappears (slides down) when selection is cleared (0 rows)
  - [ ] Bar stays visible while scrolling through the table
  - [ ] "Clear Selection" button is accessible on the bar
  - [ ] When selection contains only hidden bins, "Hide" becomes "Unhide". When mixed, both "Hide X Active" and "Unhide Y Hidden" buttons appear (split action).

#### Feature 4: Mass Change Location
- **User Story:** As a store manager, I want to change the location of multiple bins at once so that I can efficiently reorganize inventory after a physical move.
- **Acceptance Criteria:**
  - [ ] Clicking "Change Location" opens a confirmation modal
  - [ ] Modal shows a dropdown of available locations (same source as single-bin edit)
  - [ ] Modal lists all affected bin names for review
  - [ ] Confirming updates all selected bins to the new location
  - [ ] Each bin gets an individual action log entry with the logged-in user's ID
  - [ ] Table rows update in-place to reflect the new location
  - [ ] Success toast shows: "X bins moved to [Location Name]"
  - [ ] If some bins fail, success toast shows: "X of Y bins updated. Z failed." with list of failed bins

#### Feature 5: Mass Empty Bins
- **User Story:** As a store manager, I want to empty multiple bins at once so that I can quickly reset bins during seasonal changeovers.
- **Acceptance Criteria:**
  - [ ] Clicking "Empty Bins" opens a confirmation modal with warning styling
  - [ ] Modal clearly states what will be cleared: main category, tags, age date (reset to now), notes, item count, estimated value
  - [ ] Modal lists all affected bin names
  - [ ] Confirming performs a full reset on all selected bins
  - [ ] Each bin gets an individual "emptied" action log entry
  - [ ] Table rows update in-place to show "Empty" category and reset age
  - [ ] Bins that are already empty are skipped (not counted as failures)
  - [ ] Success toast shows count of actually emptied bins vs already-empty bins

#### Feature 6: Mass Change Main Category
- **User Story:** As a store manager, I want to change the main category of multiple bins at once so that I can re-categorize inventory after a planogram change.
- **Acceptance Criteria:**
  - [ ] Clicking "Change Category" opens a modal with category dropdown
  - [ ] Dropdown shows same categories as single-bin edit (POS subcategories + custom categories)
  - [ ] Modal lists affected bin names
  - [ ] Confirming updates mainCategory on all selected bins
  - [ ] Each bin gets an individual action log entry
  - [ ] Table rows update in-place with new category name and color
  - [ ] Success/partial-failure reporting same as other mass actions

#### Feature 7: Mass Change Tags
- **User Story:** As a store manager, I want to add or remove tags from multiple bins at once so that I can maintain consistent tagging across related bins.
- **Acceptance Criteria:**
  - [ ] Clicking "Change Tags" opens a modal with two modes: "Add Tags" and "Remove Tags"
  - [ ] Add mode: multi-select of available tags; selected tags are ADDED to each bin's existing tags (not replaced)
  - [ ] Remove mode: multi-select of tags; selected tags are REMOVED from each bin
  - [ ] Modal lists affected bin names
  - [ ] Confirming performs the add/remove operation on bsBin_Cat entries
  - [ ] Each bin gets an individual action log entry
  - [ ] Table rows update in-place with new tag badges

#### Feature 8: Mass Hide / Unhide
- **User Story:** As a store manager, I want to hide or unhide multiple bins at once so that I can clean up inactive bins or restore them when needed.
- **Acceptance Criteria:**
  - [ ] "Hide Selected" deactivates all selected active bins (sets active=0, records hiddenAt)
  - [ ] Hidden bins disappear from table (unless "Show Hidden Bins" is on)
  - [ ] Hidden bin count badge updates immediately
  - [ ] When "Show Hidden Bins" is active and hidden bins are selected, button shows "Unhide Selected"
  - [ ] "Unhide Selected" reactivates bins (sets active=1, clears hiddenAt)
  - [ ] Each bin gets an individual action log entry (hide or unhide)
  - [ ] Confirmation modal shows bin list and action (hide vs unhide)
  - [ ] **Mixed selection (split action):** When selection contains BOTH active and hidden bins, the floating bar shows two separate buttons: "Hide X Active" and "Unhide Y Hidden". Each triggers its own confirmation modal for its respective subset. Already-hidden bins are ignored by Hide, already-active bins are ignored by Unhide.
  - [ ] Button labels dynamically reflect the count of applicable bins (e.g., "Hide 5 Active" / "Unhide 3 Hidden")

#### Feature 9: Comma-Separated Bin Search
- **User Story:** As a store manager, I want to paste a comma-separated list of bin names into the search bar so that I can instantly find and select specific bins from a list.
- **Acceptance Criteria:**
  - [ ] Entering "BIN-001, BIN-002, BIN-003" in the search bar filters to only those bins
  - [ ] Matching is performed via case-insensitive exact match against bin name AND case-insensitive exact match against UUID (barcode)
  - [ ] Matched bins are auto-selected (appear highlighted, counted in floating bar)
  - [ ] Bins not found are reported: "Found 10 of 12 bins. Not found: BIN-099, BIN-200"
  - [ ] Whitespace around commas is trimmed (e.g., "BIN-001 , BIN-002" works)
  - [ ] Single-term search (no commas) continues to work as before (existing behavior preserved)
  - [ ] Clearing the search bar clears both the filter and selection

### Should Have Features

#### Feature 10: Mass Print Labels
- **User Story:** As a store manager, I want to print labels for multiple selected bins so that I can reprint damaged labels after a reorganization.
- **Acceptance Criteria:**
  - [ ] Clicking "Print Labels" opens a modal with quantity-per-bin selector
  - [ ] Modal shows list of bins that will get labels
  - [ ] Confirming sends print job for all selected bins
  - [ ] Uses existing reprint endpoint pattern
  - [ ] Success feedback shows total labels printed

#### Feature 11: Mass Update Age Date
- **User Story:** As a store manager, I want to reset the age date on multiple bins so that I can reflect re-evaluated inventory after an audit.
- **Acceptance Criteria:**
  - [ ] Clicking "Update Age Date" opens a modal with a date picker
  - [ ] Default date is today
  - [ ] Modal lists affected bins
  - [ ] Confirming updates ageDate on all selected bins
  - [ ] Age column updates in-place in the table
  - [ ] Each bin gets an individual action log entry

#### Feature 12: Mass Add Notes
- **User Story:** As a store manager, I want to append a note to multiple bins so that I can leave audit comments or instructions across a set of bins.
- **Acceptance Criteria:**
  - [ ] Clicking "Add Notes" opens a modal with a text input
  - [ ] Note is APPENDED to existing notes (not replaced), prefixed with date
  - [ ] Modal lists affected bins
  - [ ] Confirming updates notes on all selected bins
  - [ ] Each bin gets an individual action log entry

### Could Have Features

#### Saved Selections
- Allow naming and saving a set of bin IDs for quick re-selection later
- Useful for recurring operations on the same set of bins

#### Mass Action Presets
- Save a combination of actions as a preset (e.g., "Season Reset" = empty + move to storage)
- One-click to apply a multi-step mass operation

#### Undo Last Mass Action
- 10-second undo window after any mass action completes
- Reverts all changes from the batch

### Won't Have (This Phase)

- **Scheduled mass actions** — No ability to schedule future mass operations (e.g., "hide these bins on December 1st")
- **Cross-store mass actions** — Operations are always within a single store's backstock
- **Mass delete** — Permanent deletion remains single-bin only for safety
- **Drag-and-drop reordering** — No drag to move bins between columns/categories in the table
- **Mass action history page** — No dedicated page showing past mass operations (individual actions logged per bin in existing action log)
- **Import/Export bin lists** — No CSV upload to create bin selections

## Detailed Feature Specifications

### Feature: Mass Change Location (Most representative of all mass action flows)

**Description:** When bins are selected and "Change Location" is clicked, a confirmation modal opens showing a location dropdown and the list of affected bins. On confirmation, all bins are updated to the new location via a single API call. Results are shown with partial success handling.

**User Flow:**
1. User selects bins via clicking, shift+click, select all, or comma-separated search
2. Floating action bar appears showing "X bins selected"
3. User clicks "Change Location" button on the floating bar
4. Modal opens with:
   - Title: "Change Location for X Bins"
   - Location dropdown (populated from existing locations list)
   - Scrollable list of affected bin names (max height with scroll)
   - Cancel and Confirm buttons
5. User selects target location from dropdown
6. User clicks Confirm
7. Loading spinner appears on the Confirm button
8. System processes all bins, returns results
9. Modal closes. Success toast appears.
10. Table rows update in-place (no full page reload)
11. If partial failure, toast shows details and failed bins remain selected

**Business Rules:**
- Rule 1: All selected bins must belong to the current store (enforced by existing store scoping)
- Rule 2: The target location must be an active location for the current store
- Rule 3: If a selected bin is already at the target location, it is skipped (not counted as success or failure)
- Rule 4: Each bin update creates an individual bsActions entry with the logged-in user's ID
- Rule 5: The batch processes synchronously — user sees a loading state until all bins are processed
- Rule 6: If some bins fail (e.g., deleted by another user mid-operation), successful updates are kept and failures are reported
- Rule 7: Bins that were hidden and included in the selection are still updated (location changes apply regardless of active status)

**Edge Cases:**
- Scenario 1: User selects bins, another user deletes some bins before confirm → Expected: Deleted bins reported as failures, rest succeed
- Scenario 2: User selects bins, another user changes the same bins' location concurrently → Expected: Last write wins, both users' changes are logged
- Scenario 3: Network timeout during mass operation → Expected: Loading spinner shows, timeout error displayed, user advised to check which bins were updated
- Scenario 4: User selects 0 bins and somehow clicks action → Expected: Action buttons are disabled when selection count is 0
- Scenario 5: User selects mix of active and hidden bins → Expected: All are updated regardless of active status
- Scenario 6: User selects all 500 bins in a large store → Expected: Sync processing with spinner, expect 5-15 seconds, partial failure handling
- Scenario 7: User navigates to a different page/tab mid-operation → Expected: Operation continues server-side, result shown when user returns (or lost)
- Scenario 8: Same bin appears in comma-search and is manually selected → Expected: No duplicate processing, bin is included once
- Scenario 9: Location dropdown has no locations (new store, nothing configured) → Expected: Show message "No locations available. Please add locations first."
- Scenario 10: User double-clicks the Confirm button → Expected: Button disables on first click with spinner; second click is ignored. Only one request is sent.
- Scenario 11: User navigates away mid-operation (closes tab, clicks sidebar link) → Expected: Server-side processing completes regardless. Changes are persisted. User sees stale data on return — standard page reload shows current state.

### Feature: Comma-Separated Search

**Description:** The existing search bar is enhanced to detect comma-separated input. When commas are detected, each term is treated as a separate bin name or UUID to search for. Matching bins are filtered into view and auto-selected.

**User Flow:**
1. User clicks into the search bar
2. User types or pastes "BIN-001, BIN-042, BIN-103"
3. System detects commas in the input
4. Each term is trimmed of whitespace
5. Table filters to show ONLY bins whose name or UUID matches any of the terms
6. All matching bins are auto-selected (highlighted)
7. Floating action bar appears showing matched count
8. If some terms didn't match, a small info banner appears below the search: "Found 10 of 12. Not found: BIN-099, BIN-200"
9. User can now perform any mass action on the auto-selected bins

**Business Rules:**
- Rule 1: Comma detection triggers multi-search mode only when 2+ terms are present
- Rule 2: Each term is matched via case-insensitive exact match against bin name, and case-insensitive exact match against UUID
- Rule 3: Empty terms after splitting are ignored (e.g., "BIN-001,,BIN-002" works)
- Rule 4: Leading/trailing whitespace on each term is trimmed
- Rule 5: Single-term input (no commas) preserves existing search behavior exactly
- Rule 6: Multi-search results are additive (bin matches if it matches ANY term)
- Rule 7: Clearing the search bar clears both filter and selection
- Rule 8: Not-found report should be dismissible and not block actions on found bins

**Edge Cases:**
- Scenario 1: User pastes 100 comma-separated bins → Expected: All matched, may take 1-2 seconds for filtering, no performance degradation
- Scenario 2: User types a bin name that contains a comma (unlikely but possible) → Expected: Treated as separator, fragments won't match, user should use single search without comma
- Scenario 3: User types "BIN-001, BIN-001" (duplicates) → Expected: Bin appears once in results, selected once
- Scenario 4: All terms are not found → Expected: Table shows no results, message: "No bins found matching your search"
- Scenario 5: User modifies comma search by adding/removing terms → Expected: Filter and selection update live as they type (debounced)

### Standard Mass Action UX Pattern (Applies to All Mass Actions)

All mass actions (Features 4–12) follow this standardized UX pattern:

**Confirmation Modal:**
- Title format: "[Action] for X Bins"
- Scrollable list of affected bin names (max 300px height)
- Cancel and Confirm buttons
- Confirm button shows loading spinner during processing; button is DISABLED to prevent double-submit

**Success Handling:**
- Toast: "X bins [action description]" (e.g., "80 bins moved to Back Room")
- Modal closes automatically
- Table rows update in-place (no full page reload)
- Selection is cleared after successful completion

**Partial Failure Handling:**
- Toast: "X of Y bins updated. Z failed." with expandable details listing failed bin names
- Successfully updated rows refresh in-place in the table
- Failed bins REMAIN SELECTED so the user can retry or investigate
- Action log entries are written ONLY for bins that succeeded

**Full Failure Handling (network timeout, server error):**
- Toast: "Action failed. Please check which bins were updated and try again."
- Selection is preserved (no changes)
- Confirm button re-enables so user can retry

**Permissions:**
- All mass actions use the same permission gate as single-bin edits (`checkStoreGroup` for store access)
- No separate mass_edit permission — if a user can edit a single bin, they can mass edit

**Double-Submit Protection:**
- Confirm button is disabled immediately on click and shows a spinner
- Server-side: each batch request processes synchronously; no idempotency key needed since button is disabled

---

## Success Metrics

### Key Performance Indicators

| KPI | Baseline | Target | Measurement |
|-----|----------|--------|-------------|
| **Adoption** | 0% (feature doesn't exist) | 60% of stores with 50+ bins use within first month | Count distinct store_typeNum in `mass_action_completed` events |
| **Efficiency** | ~45 min (manual one-by-one, estimated from store feedback) | ~2 min (80% reduction) | `duration_ms` in `mass_action_completed` (server-side, request start → response) |
| **Engagement** | 0 | 3+ mass actions per store per week after adoption | Weekly aggregate of `mass_action_completed` per store_typeNum |
| **Quality** | N/A | Error rate < 1% (failure_count / total bins processed) | `failure_count` / (`success_count` + `failure_count`) from `mass_action_completed` events |
| **Business Impact** | Current backstock support ticket volume | 30% reduction | Support ticket count tagged "backstock" (measured monthly) |

### Tracking Requirements

| Event | Properties | Purpose |
|-------|------------|---------|
| mass_action_initiated | action_type, bin_count, store_typeNum, user_id | Track which actions are used and how often |
| mass_action_completed | action_type, bin_count, success_count, failure_count, duration_ms | Measure reliability and performance |
| mass_action_cancelled | action_type, bin_count, stage (modal/confirm) | Understand abandonment patterns |
| comma_search_used | term_count, found_count, not_found_count | Track comma search adoption and accuracy |
| select_all_used | filtered_count, total_count, had_active_filters | Understand Select All usage patterns |
| floating_bar_action_clicked | action_type, bin_count | Track which floating bar actions are most used |

---

## Constraints and Assumptions

### Dependencies

| Feature | Backend Dependencies | Frontend Dependencies |
|---------|---------------------|----------------------|
| Multi-Row Selection | None (client-side only) | Syncfusion EJ2 Grid native checkbox selection (`persistSelection: true`) |
| Select All (Filtered) | None (client-side only) | Syncfusion EJ2 Grid header checkbox (selects all filtered rows across pages) |
| Floating Action Bar | None | New HTML/CSS component |
| Mass Change Location | `bsLocations` table, `/bin/:id/save-all/` pattern | Location dropdown data (already loaded on page) |
| Mass Empty Bins | `bsBins`, `bsBin_Cat`, `bsActions` tables | None beyond floating bar |
| Mass Change Category | `BackstockFactory::getCategoriesArray()` | Category dropdown data (already loaded) |
| Mass Change Tags | `bsBin_Cat` junction table, tag list endpoint | Tag multi-select (already exists in single-bin edit) |
| Mass Hide/Unhide | `bsBins.active`, `bsBins.hiddenAt` columns | Hidden bin toggle (existing) |
| Comma-Separated Search | None (client-side filtering) | Syncfusion Grid dataSource filtering + `selectRows()` API |
| Mass Print Labels | Existing reprint endpoint pattern, printer/label service | Print dialog (existing) |
| Mass Update Age Date | `bsBins.ageDate` column, `bsActions` table | Syncfusion DatePicker (already available) |
| Mass Add Notes | `bsBins.notes` column, `bsActions` table | Text input |

### Constraints
- ~~Must work within existing DataTables-based table~~ **Updated post-SDD**: Backstock overview table will migrate from DataTables to Syncfusion EJ2 Grid as part of this feature (approved in ADR-7). The Syncfusion Grid provides native checkbox selection, `persistSelection`, and `getSelectedRecords()` which eliminate the need for custom selection tracking code. This follows the proven `TeamMemberGrid.js` pattern already in the codebase.
- Must be backward-compatible with existing single-bin edit workflows (no breaking changes)
- Synchronous processing means very large stores (1000+ bins) may experience longer wait times
- Must respect existing store-scoped permissions (checkStoreGroup) — same permission gate for single and mass actions
- All changes must go through the migration system for any DB schema changes
- New bulk API endpoints needed — current endpoints are single-bin only

### Assumptions
- Most stores have fewer than 500 active bins, making synchronous batch processing acceptable
- Users are familiar with shift+click and ctrl+click selection patterns from other applications
- The existing bsActions table can handle the volume of individual action log entries from mass operations
- Bin names are the most intuitive identifier for comma-separated search (vs IDs or UUIDs)
- The floating action bar pattern is familiar to users from email clients (Gmail, Outlook)

## Risks and Mitigations

| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| Accidental mass operation on wrong bins | High | Medium | Always-confirm modal with full bin list review. Clear selection on filter change. |
| Race condition: bins modified by another user during batch | Medium | Low | Partial success handling: apply what succeeds, report what fails. Individual action logging. |
| Performance degradation on large bin counts (500+) | Medium | Medium | Synchronous with loading spinner. Monitor timing. If needed, add pagination to batch processing. |
| Selection state confusion across pages/filters | Medium | Medium | Clear selection when filters change. Show persistent count in floating bar. |
| Comma-separated search false positives | Low | Low | Case-insensitive exact match on both bin name and UUID eliminates partial-match false positives. Show matched bins for review before action. |
| Browser memory with 1000+ rows in DataTable + selection tracking | Low | Low | DataTable already handles this. Selection is lightweight (array of IDs). |
| Conflicting mass hide + show hidden bins toggle | Medium | Medium | Split action UX: when mixed active + hidden bins are selected, show two separate buttons ("Hide X Active" / "Unhide Y Hidden") with independent confirmation modals. No ambiguity. |

## Open Questions

- [x] What does "mass empty" mean? → Full reset (category, tags, age, notes, itemCount, estimatedValue)
- [x] Toolbar placement? → Floating bottom bar
- [x] Search matching? → Bin name OR UUID
- [x] Confirmation flow? → Always confirm all actions
- [x] Batch failure handling? → Partial success with reporting
- [x] Select All scope? → Filtered rows only (not just current page)
- [x] Category + tags together or separate? → Separate mass actions
- [x] Mass unhide? → Yes, bidirectional
- [x] Audit trail? → Individual entries per bin with logged-in user ID
- [x] Comma search auto-select? → Yes, filter + auto-select
- [x] Additional mass actions? → Print labels, update age date, add notes (all included)

No remaining open questions.

---

## Supporting Research

### Competitive Analysis
Bulk action toolbars are standard in inventory management systems (Shopify, Square, Lightspeed) and email clients (Gmail, Outlook). The floating action bar pattern specifically comes from Google's Material Design guidelines and is used in Gmail for batch email operations. It provides persistent visibility without cluttering the primary toolbar.

### User Research
Store managers have repeatedly requested batch operations during seasonal changeovers and store reorganizations. The current one-by-one workflow is the #1 time complaint for backstock management. Comma-separated search was specifically requested by managers who work from physical audit lists.

### Market Data
Inventory management tools that offer bulk operations see 40-60% higher user engagement versus those without. The ability to perform batch operations is consistently rated as a top-3 feature request in the SMB retail inventory space.
