# Traceability Matrix

| Capability | Requirement | Source (provenance) |
|---|---|---|
| artisan-migrate | Admin Authentication Gate | Implemented in `routes/web.php:20,23-29`, `config/admin.php:29` |
| artisan-migrate | Non-Interactive Migration Execution | Implemented in `routes/web.php:32-34` |
| artisan-migrate | Static Completion Response | Implemented in `routes/web.php:36` |
| artisan-migrate | Idempotent Behavior When No Migrations Are Pending | Implemented in `routes/web.php:32-36` |
| artisan-migrate | Exception Propagation on Migration Failure | Implemented in `routes/web.php:32-36` |
| auth | Display Login Form to Anonymous Users | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:23-30` |
| auth | Redirect Authenticated Users Away from Login Form | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:25-27` |
| auth | Validate Credentials Before Login Attempt | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:44-51` |
| auth | Authenticate Valid Credentials and Start a Session | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:39-60, 172-179` |
| auth | Regenerate Session on Successful Login | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:176` |
| auth | Return Generic Error for Bad Credentials | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:57-59, 144-149`, auth.fail |
| auth | Protect Every Application Route from Anonymous Access | Implemented in `routes/web.php:23-27`, `config/admin.php:29` |
| auth | Log Out and Invalidate the Session | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:67-74` |
| auth | Display Self-Service Account Form | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:81-100` |
| auth | Update Own Account Details | Implemented in `vendor/salipropham/laravel55-admin/src/Controllers/AuthController.php:101-139` |
| auth | Enforce CSRF Protection on State-Changing Auth Requests | Implemented in `app/Http/Middleware/VerifyCsrfToken.php` via the `web` middleware group |
| brands | List brands on the management screen | Implemented in `app/Http/Controllers/BrandController.php:19-40,53-64` |
| brands | Create a brand via the inline form | Implemented in `app/Http/Controllers/BrandController.php:75-81` |
| brands | Edit an existing brand | Implemented in `app/Http/Controllers/BrandController.php:42-48,75-81` |
| brands | Lock the default brand from editing | Implemented in `app/Http/Controllers/BrandController.php:65-68` |
| brands | Prevent deletion of all brands | Implemented in `app/Http/Controllers/BrandController.php:69` |
| brands | Require an authenticated admin session | Implemented in `routes/web.php:24-28,86-87` |
| categories | List Categories Screen | Implemented in `app/Http/Controllers/CategoryController.php:20-41` |
| categories | Create Category | Implemented in `app/Http/Controllers/CategoryController.php:77-83` |
| categories | Edit Category Form | Implemented in `app/Http/Controllers/CategoryController.php:43-49` |
| categories | Update Category | Implemented in `app/Http/Controllers/CategoryController.php:77-83` |
| categories | All Rows Are Editable | Implemented in `app/Http/Controllers/CategoryController.php:67-70` |
| categories | Delete Is Disabled for All Rows | Implemented in `app/Http/Controllers/CategoryController.php:70` |
| categories | Child-Only Category Dropdown for Products | Implemented in `app/Http/Controllers/ProductController.php:73,157` |
| categories | Admin Authentication Required | Implemented in `routes/web.php:24-28,86-88` |
| categories | CSRF Protection on Mutating Requests | Implemented in `routes/web.php:86-88` |
| customers-crud | Customer Listing Pagination | Implemented in `app/Http/Controllers/CustomerController.php:27-49`, pages.cust |
| customers-crud | Customer Search | Implemented in `app/Http/Controllers/CustomerController.php:38-42` |
| customers-crud | Birthday Month Filter | Implemented in `app/Http/Controllers/CustomerController.php:41-45` |
| customers-crud | Create Form Display | Implemented in `app/Http/Controllers/CustomerController.php:56-65`, pages.cust |
| customers-crud | Customer Creation via Web Form | Implemented in `app/Http/Controllers/CustomerController.php:73-105`, customers.inde |
| customers-crud | POS Quick-Add JSON Path | Implemented in `app/Http/Controllers/CustomerController.php:93-98` |
| customers-crud | New Customer Tier Default | Implemented in `app/Http/Controllers/CustomerController.php:76-84`, `app/Models/Customer.php:49-51` |
| customers-crud | Birthday Format Parsing on Create | Implemented in `app/Http/Controllers/CustomerController.php:86-90` |
| customers-crud | Live Phone Uniqueness | Implemented in `app/Http/Controllers/CustomerController.php:78`, `app/Http/Controllers/CustomerController.php:150` |
| customers-crud | Edit Form Display | Implemented in `app/Http/Controllers/CustomerController.php:124-137`, pages.cust |
| customers-crud | Customer Update | Implemented in `app/Http/Controllers/CustomerController.php:146-167` |
| customers-crud | Customer Soft-Delete | Implemented in `app/Http/Controllers/CustomerController.php:175-188`, admin.dele |
| customers-crud | Admin Authentication | Implemented in `routes/web.php:24-28` |
| customers-debt-actions | Debt Ledger Page Rendering | Implemented in `app/Http/Controllers/CustomerController.php:263-280` |
| customers-debt-actions | Live Balance Display | Implemented in `app/Http/Controllers/CustomerController.php:272`, `app/Models/Customer.php:15-19` |
| customers-debt-actions | Ledger Pagination | Implemented in `app/Http/Controllers/CustomerController.php:274-277` |
| customers-debt-actions | Manual Debt Recording | Implemented in `app/Http/Controllers/CustomerController.php:379-399` |
| customers-debt-actions | Repayment Recording | Implemented in `app/Http/Controllers/CustomerController.php:401-425` |
| customers-debt-actions | Over-Balance Repayment Rejection | Implemented in `app/Models/CustomerDebt.php:43-47`, `app/Http/Controllers/CustomerController.php:410-421` |
| customers-debt-actions | Amount Validation on Writes | 0.01, Implemented in `app/Http/Controllers/CustomerController.php:381-384,403-406` |
| customers-debt-actions | Customer Resolution | Implemented in `app/Http/Controllers/CustomerController.php:271,386,408` |
| customers-debt-actions | Serialised Concurrent Balance Mutations | Implemented in `app/Models/CustomerDebt.php:38-64` |
| customers-debt-actions | Admin Authentication | Implemented in `routes/web.php:23-28,58-61` |
| customers-debt-actions | CSRF Protection on Write Endpoints | Implemented in `resources/views/pages/customer-debt.blade.php` |
| customers-debt-actions | Admin Provenance on Ledger Entries | Implemented in `app/Http/Controllers/CustomerController.php:394,417` |
| customers-debt-actions | Append-Only Ledger with Per-Entry Balance Snapshot | Implemented in `app/Models/CustomerDebt.php:38-64`, `database/migrations/2026_08_28_000001_create_customer_debts_table.php` |
| customers-loyalty | Admin Authentication Required | Implemented in `routes/web.php:23-28,55,56,59` |
| customers-loyalty | Unknown Customer Rejected | Implemented in `app/Http/Controllers/CustomerController.php:303,348,363` |
| customers-loyalty | Gift Availability Pre-flight Returns JSON Verdict | G.limi, Implemented in `app/Http/Controllers/CustomerController.php:361-377`, customers.chec |
| customers-loyalty | Pre-flight Handles Missing or Inactive Gift Cleanly | Implemented in `app/Http/Controllers/CustomerController.php:361-370` |
| customers-loyalty | Pre-flight Is Advisory Only | Implemented in `app/Http/Controllers/CustomerController.php:361-377` |
| customers-loyalty | Redemption Validates gift_id as Required | Implemented in `app/Http/Controllers/CustomerController.php:298-301`, customers.rede |
| customers-loyalty | Redemption Requires an Active Gift | Implemented in `app/Http/Controllers/CustomerController.php:304-307` |
| customers-loyalty | Redemption Gate Enforces Stock, Limit, and Points | G.limi, Implemented in `app/Models/Customer.php:64-89`, `app/Http/Controllers/CustomerController.php:309-311` |
| customers-loyalty | Zero Limit Means Unlimited Redemptions | Implemented in `app/Models/Customer.php:74` |
| customers-loyalty | Successful Redemption Applies All Three Changes | Implemented in `app/Http/Controllers/CustomerController.php:313-337` |
| customers-loyalty | Concurrent Redemptions Are Serialised | Implemented in `app/Http/Controllers/CustomerController.php:315-326` |
| customers-loyalty | Redemption Snapshots the Point Cost | Implemented in `app/Http/Controllers/CustomerController.php:328` |
| customers-loyalty | Gift History Page Renders Paginated Results | Implemented in `app/Http/Controllers/CustomerController.php:340-359`, `resources/views/pages/customer-gift-received.blade.php`, customers.gift |
| customers-loyalty | Gift History Search Filters by Name | Implemented in `app/Http/Controllers/CustomerController.php:351-355` |
| customers-purchase-history | Authentication Gate | Implemented in `routes/web.php:23-28,54` |
| customers-purchase-history | Customer Resolution | Implemented in `app/Http/Controllers/CustomerController.php:200` |
| customers-purchase-history | Paginated Order List | Implemented in `app/Http/Controllers/CustomerController.php:204,208` |
| customers-purchase-history | All Order Statuses Included | Implemented in `app/Http/Controllers/CustomerController.php:204` |
| customers-purchase-history | Category Filter | Implemented in `app/Http/Controllers/CustomerController.php:205-207` |
| customers-purchase-history | Category Dropdown Scope | Implemented in `app/Http/Controllers/CustomerController.php:202` |
| customers-scan | Authenticated Admin Session Required | Implemented in `routes/web.php:23-28,53` |
| customers-scan | Substring Search Over Phone and Full Name | Implemented in `app/Http/Controllers/CustomerController.php:285-287` |
| customers-scan | Result Set Capped at Ten Records | Implemented in `app/Http/Controllers/CustomerController.php:287` |
| customers-scan | Response Is Always HTTP 200 JSON Array | Implemented in `app/Http/Controllers/CustomerController.php:289-291` |
| customers-scan | Full Customer Record Serialized Including Type Attributes | Implemented in `app/Http/Controllers/CustomerController.php:289-291`, `app/Models/Customer.php:15,25,49-55` |
| customers-scan | Soft-Deleted Customers Excluded From Results | Implemented in `app/Models/Customer.php:9-12`, `app/Http/Controllers/CustomerController.php:287` |
| customers-scan | Missing or Empty q Returns First Ten Live Rows | Implemented in `app/Http/Controllers/CustomerController.php:285-287` |
| customers-statistics | Authenticated Admin Access | Implemented in `routes/web.php:57`, ADR-0009 |
| customers-statistics | Customer Resolution | Implemented in `app/Http/Controllers/CustomerController.php:223` |
| customers-statistics | Precomputed Headline Totals | Implemented in `app/Http/Controllers/CustomerController.php:226-229`, ADR-0005 |
| customers-statistics | Live Debt and Reward-Point Balance | Implemented in `app/Http/Controllers/CustomerController.php:228`, `resources/views/pages/customer-statis.blade.php:50-51`, customer.debt, customer.poin |
| customers-statistics | Category Breakdown Split | Implemented in `app/Http/Controllers/CustomerController.php:233-251`, `app/Models/Order.php:23-25`, ADR-0006 |
| customers-statistics | Graceful Degradation on Missing or Malformed Categories | Implemented in `app/Http/Controllers/CustomerController.php:233-256` |
| customers-statistics | Freshness Timestamp | Implemented in `app/Http/Controllers/CustomerController.php:231`, `resources/views/pages/customer-statis.blade.php:107-111`, summary.upda |
| customers-statistics | Annotated Orders Panel | Implemented in `app/Http/Controllers/CustomerController.php:258` |
| customers-statistics | Read-Only Operation | Implemented in `app/Http/Controllers/CustomerController.php:215-261` |
| dashboard | Authentication gate | Implemented in `routes/web.php:24-28,42`, `config/admin.php:29`, pages.dash |
| dashboard | Range parameter validation | Implemented in `app/Http/Controllers/DashboardController.php:47-50` |
| dashboard | KPI — total products | Implemented in `app/Http/Controllers/DashboardController.php:35`, total.prod |
| dashboard | KPI — total customers | Implemented in `app/Http/Controllers/DashboardController.php:36`, total.cust |
| dashboard | KPI — today's completed orders | Implemented in `app/Http/Controllers/DashboardController.php:37-38`, total.orde |
| dashboard | Day chart bucketing | Implemented in `app/Http/Controllers/DashboardController.php:52-64` |
| dashboard | Week chart bucketing | Implemented in `app/Http/Controllers/DashboardController.php:65-77` |
| dashboard | Month chart bucketing | Implemented in `app/Http/Controllers/DashboardController.php:78-99` |
| dashboard | Empty bucket zero-fill | Implemented in `app/Http/Controllers/DashboardController.php:104-112` |
| dashboard | Chart values count orders not revenue | Implemented in `app/Http/Controllers/DashboardController.php:59,69,84,102` |
| dashboard | Top-10 best-selling products | Implemented in `app/Http/Controllers/DashboardController.php:114-119`, order_product.qty |
| dashboard | View payload completeness | Implemented in `app/Http/Controllers/DashboardController.php:121`, pages.dash |
| dashboard | No write side-effects | Implemented in `app/Http/Controllers/DashboardController.php:28-122` |
| dashboard | Non-dashboard resource verbs are not exposed | Implemented in `routes/web.php:42` |
| dashboard | Dashboard is not the application landing page | Implemented in `routes/web.php:22` |
| debts | Admin Authentication Required | Implemented in `routes/web.php:23-27,67` |
| debts | Only Positive-Balance Customers Are Listed | Implemented in `app/Http/Controllers/DebtController.php:17-18`, `app/Models/Customer.php:6,12` |
| debts | Debtor List Is Ordered by Outstanding Balance Descending | Implemented in `app/Http/Controllers/DebtController.php:18` |
| debts | Debtor List Is Paginated at Thirty Records Per Page | Implemented in `app/Http/Controllers/DebtController.php:26` |
| debts | Optional Search Filters by Phone or Full Name Within the Debtor Scope | Implemented in `app/Http/Controllers/DebtController.php:20-24` |
| debts | Empty Debtor List Renders Without Error | Implemented in `resources/views/pages/debts.blade.php` |
| debts | Each Debtor Row Links to the Customer Debt Ledger | Implemented in `resources/views/pages/debts.blade.php`, customers.debt |
| debts | Outstanding Balance Is Displayed with One Decimal Place in VND | 1200.5, 200.5, Implemented in `resources/views/pages/debts.blade.php` |
| debts | The Controller Performs No Writes | Implemented in `app/Http/Controllers/DebtController.php:10-29` |
| gifts-crud | Authenticated Admin Session Required | Implemented in `routes/web.php:24-28,86-91` |
| gifts-crud | Gift Listing Screen | Implemented in `app/Http/Controllers/GiftController.php:19-41` |
| gifts-crud | Gift Grid Column Set | Implemented in `app/Http/Controllers/GiftController.php:51-74` |
| gifts-crud | Every Gift Row Is Editable and Deletable | Implemented in `app/Http/Controllers/GiftController.php:72` |
| gifts-crud | Gift Name Is Required | Implemented in `app/Http/Controllers/GiftController.php:79` |
| gifts-crud | Blank Numeric Fields Stored as Zero | Implemented in `app/Http/Controllers/GiftController.php:99-102` |
| gifts-crud | New Gift Used Counter Initialised to Zero | Implemented in `app/Http/Controllers/GiftController.php:99-104` |
| gifts-crud | Used Counter Preserved on Edit | Implemented in `app/Http/Controllers/GiftController.php:99-104` |
| gifts-crud | Quantity Cannot Be Lowered Below Used on Edit | Implemented in `app/Http/Controllers/GiftController.php:84-92` |
| gifts-crud | Image Upload Validated for Size and Type | Implemented in `app/Http/Controllers/GiftController.php:80-81` |
| gifts-crud | Uploaded Image Normalised to 300×300 | Implemented in `app/Http/Controllers/GiftController.php:106-111` |
| gifts-crud | Missing Image Falls Back to Placeholder | Implemented in `app/Models/Gift.php:21-23`, images/noimage.png, noimage.png |
| gifts-crud | quantity_available Exposed as Computed Attribute | Implemented in `app/Models/Gift.php:18,25-27` |
| gifts-crud | Gift Deletion Is a Soft Delete | Implemented in `app/Models/Gift.php:10-14` |
| gifts-crud | Unknown Gift ID Returns 404 | Implemented in `app/Http/Controllers/GiftController.php:43-49` |
| gifts-crud | Inline Create Form Defaults active to Enabled | Implemented in `app/Http/Controllers/GiftController.php:36` |
| gifts-scan | Authentication Required | Implemented in `routes/web.php:24-28,86-92` |
| gifts-scan | Name Substring Search | Implemented in `app/Http/Controllers/GiftController.php:117-118` |
| gifts-scan | Optional Active Status Filter | Implemented in `app/Http/Controllers/GiftController.php:119-121` |
| gifts-scan | Result Cap of Ten | Implemented in `app/Http/Controllers/GiftController.php:122` |
| gifts-scan | Soft-Deleted Gifts Excluded | Implemented in `app/Models/Gift.php:10-14` |
| gifts-scan | Full Gift Record Serialization | Implemented in `app/Models/Gift.php:16-27`, noimage.png |
| gifts-scan | JSON Envelope Shape | Implemented in `app/Http/Controllers/GiftController.php:123-125` |
| orders-crud | Authentication Required | Implemented in `routes/web.php:24-28` |
| orders-crud | List Orders Paginated | Implemented in `app/Http/Controllers/OrderController.php:21-47` |
| orders-crud | Filter Orders by Status | Implemented in `app/Http/Controllers/OrderController.php:40-42` |
| orders-crud | Search Orders by Query String | Implemented in `app/Http/Controllers/OrderController.php:31-39` |
| orders-crud | Create Order | Implemented in `app/Http/Controllers/OrderController.php:64-165` |
| orders-crud | Reject Empty Cart | Implemented in `app/Http/Controllers/OrderController.php:66-78` |
| orders-crud | Default Order Status to Draft | Implemented in `app/Http/Controllers/OrderController.php:86` |
| orders-crud | Unknown Product Codes Silently Skipped | Implemented in `app/Http/Controllers/OrderController.php:96,265` |
| orders-crud | Walk-In Orders Allowed | Implemented in `app/Http/Controllers/OrderController.php:134,308` |
| orders-crud | Debt Requires Customer | Implemented in `app/Http/Controllers/OrderController.php:121-131,294-306`, pos.inde |
| orders-crud | Debt Must Not Exceed Total | Implemented in `app/Http/Controllers/OrderController.php:121-131,294-306`, pos.inde |
| orders-crud | Draft Order Redirects to POS | Implemented in `app/Http/Controllers/OrderController.php:153-156,339-344`, pos.inde |
| orders-crud | Done Order Returns Printable Receipt | Implemented in `app/Http/Controllers/OrderController.php:158-162,345-349`, pages.pos |
| orders-crud | Award Loyalty Points Exactly Once | Implemented in `app/Http/Controllers/OrderController.php:136-140,311-315`, customer.poin |
| orders-crud | Post Customer Debt Exactly Once | Implemented in `app/Http/Controllers/OrderController.php:149-151,321-323`; `app/Models/Order.php:65-67` |
| orders-crud | Show Order Detail | Implemented in `app/Http/Controllers/OrderController.php:173-184` |
| orders-crud | Enforce 24-Hour Edit Window | Implemented in `app/Http/Controllers/OrderController.php:242-243`; `app/Models/Order.php:53-55` |
| orders-crud | Customer Immutable After Finalisation | Implemented in `app/Http/Controllers/OrderController.php:245-249` |
| orders-crud | Finalise Draft via create_now_mode | Implemented in `app/Http/Controllers/OrderController.php:223-240` |
| orders-crud | Delete Order with Financial Reversal | Implemented in `app/Http/Controllers/OrderController.php:362-383` |
| orders-crud | Create and Edit Routes Are Empty Stubs | Implemented in `app/Http/Controllers/OrderController.php:53-56,192-195` |
| orders-note | Admin Authentication | Implemented in `routes/web.php:24-28,74` |
| orders-note | CSRF Validation | Implemented in `routes/web.php:74`, `resources/views/pages/customer-statis.blade.php:183` |
| orders-note | Note Update | Implemented in `app/Http/Controllers/OrderController.php:342-356`, orders.note |
| orders-note | Note Clearing | Implemented in `app/Http/Controllers/OrderController.php:344-346`, orders.note |
| orders-note | Non-String Note Rejection | Implemented in `app/Http/Controllers/OrderController.php:344-346`, e.g, orders.note |
| orders-note | Unknown Order Returns 404 | Implemented in `app/Http/Controllers/OrderController.php:348` |
| orders-note | Save Failure Redirect | Implemented in `app/Http/Controllers/OrderController.php:355`, orders.note |
| orders-note | Column Isolation | Implemented in `app/Models/Order.php:11`, `app/Http/Controllers/OrderController.php:349`, orders.note |
| orders-note | No Order Status Guard | Implemented in `app/Http/Controllers/OrderController.php:342-356`, orders.note |
| orders-note | Redirect-Back Contract | Implemented in `app/Http/Controllers/OrderController.php:353,355` |
| orders-print | Admin Authentication Required | Implemented in `routes/web.php:24-28,73` |
| orders-print | Unknown Order Returns 404 | Implemented in `app/Http/Controllers/OrderController.php:396` |
| orders-print | Any Order Status Is Printable | Implemented in `app/Http/Controllers/OrderController.php:394-402`; confirmed intentional 2026-09-25 |
| orders-print | Receipt Displays Order Identity | Implemented in `resources/views/pages/pos-print.blade.php:43` |
| orders-print | Customer Block Is Conditional | Implemented in `resources/views/pages/pos-print.blade.php:45-49` |
| orders-print | Customer Points Reflect Current Balance | Implemented in `resources/views/pages/pos-print.blade.php:48` |
| orders-print | Per-Line Unit Label Resolution | Implemented in `resources/views/pages/pos-print.blade.php:56-60`, pivot.unit |
| orders-print | Line Amounts Display at Zero Decimals | 15000.50, 25000.75, 5000.25, Implemented in `resources/views/pages/pos-print.blade.php:64-81`, pivot.pric |
| orders-print | Discount and Grand Total Are Displayed | Implemented in `resources/views/pages/pos-print.blade.php:73,81` |
| orders-print | Back Navigation Controlled by `ref` Parameter | Implemented in `resources/views/pages/pos-print.blade.php:100-108`, history.back |
| orders-print | Print Is Triggered Client-Side | Implemented in `resources/views/pages/pos-print.blade.php:110-112,177-196`, window.prin |
| orders-print | Receipt Is Read-Only | Implemented in `app/Http/Controllers/OrderController.php:394-402` |
| orders-scan | Admin Authentication Required | Implemented in `routes/web.php:24-28,72` |
| orders-scan | Result Set Capped at Ten, Ordered Newest First | Implemented in `app/Http/Controllers/OrderController.php:430` |
| orders-scan | Response Is Always a 200 JSON Array | Implemented in `app/Http/Controllers/OrderController.php:432-436` |
| orders-scan | Full Order Payload Eager-Loaded | Implemented in `app/Http/Controllers/OrderController.php:430`, `app/Models/Order.php:39-41` |
| orders-scan | Appended Computed Attributes Included Per Order | Implemented in `app/Models/Order.php:14,49-67` |
| orders-scan | Optional Customer Search via `q` Parameter | Implemented in `app/Http/Controllers/OrderController.php:422-426` |
| orders-scan | Optional Status Filter via `status` Parameter | Implemented in `app/Http/Controllers/OrderController.php:427-429` |
| pos-scan | Barcode-First Resolution | Implemented in `app/Http/Controllers/PosController.php:765-774`, products.code |
| pos-scan | Name Substring Fallback | 0..10, Implemented in `app/Http/Controllers/PosController.php:774-783`, products.code |
| pos-scan | Name Results Cap | Implemented in `app/Http/Controllers/PosController.php:774` |
| pos-scan | Normalized Units Payload | Implemented in `app/Http/Controllers/PosController.php:786-810`, Unit.name, products.unit |
| pos-scan | Discriminated Union Response Shape | Implemented in `app/Http/Controllers/PosController.php:764,776` |
| pos-scan | Soft-Deleted Product Exclusion | Implemented in `app/Models/Product.php:10,35-38` |
| pos-scan | Authenticated Admin Access | Implemented in `routes/web.php:24-28,80` |
| pos-scan | Route Priority Over Resource Route | Implemented in `routes/web.php:80-81` |
| pos-scan | Read-Only Stateless Operation | Implemented in `app/Http/Controllers/PosController.php:761-784` |
| pos-terminal | Landing Page Redirect | Implemented in `routes/web.php:22` |
| pos-terminal | Authentication Guard | Implemented in `routes/web.php:24-28` |
| pos-terminal | Terminal Rendering | Implemented in `app/Http/Controllers/PosController.php:18-687` |
| pos-terminal | Collaborator URL Seeding | Implemented in `app/Http/Controllers/PosController.php:25-29` |
| pos-terminal | Draft Preload via Query Parameter | Implemented in `app/Http/Controllers/PosController.php:31-41,610` |
| pos-terminal | Invalid Draft ID Fallback | Implemented in `app/Http/Controllers/PosController.php:31-41` |
| pos-terminal | Units Payload Composition | Implemented in `app/Http/Controllers/PosController.php:786-810` |
| pos-terminal | Cart Line Keying and Deduplication | Implemented in `app/Http/Controllers/PosController.php:96-101,131` |
| pos-terminal | Per-Line Price Refresh | Implemented in `app/Http/Controllers/PosController.php:57-72` |
| pos-terminal | Unit Change with Line Merge | Implemented in `app/Http/Controllers/PosController.php:354-407` |
| pos-terminal | Customer Selection and Full-Cart Re-pricing | Implemented in `app/Http/Controllers/PosController.php:489-511` |
| pos-terminal | Quick-Add Customer | Implemented in `app/Http/Controllers/PosController.php:619-650` |
| pos-terminal | Running Totals Maintenance | Implemented in `app/Http/Controllers/PosController.php:168-189,336-345` |
| pos-terminal | Debt Input Locking | Implemented in `app/Http/Controllers/PosController.php:415-422,549-554` |
| pos-terminal | Debt Validation on Submission | Implemented in `app/Http/Controllers/PosController.php:308-334` |
| pos-terminal | Draft Rehydration and Update Mode | Implemented in `app/Http/Controllers/PosController.php:519-564,610-617` |
| pos-terminal | Status-Driven Form Submission | Implemented in `app/Http/Controllers/PosController.php:308-334,332-333,561-562` |
| pos-terminal | Unsaved-Work Guard and Scanner Hotkey | Implemented in `app/Http/Controllers/PosController.php:652-665` |
| pos-terminal | Restricted HTTP Surface | Implemented in `app/Http/Controllers/PosController.php:694-753`, `routes/web.php:81` |
| products-catalog | Paginated Product Listing | Implemented in `app/Http/Controllers/ProductController.php:23-59` |
| products-catalog | Expiry Filter Modes | Implemented in `app/Http/Controllers/ProductController.php:30-46` |
| products-catalog | Code-and-Name Keyword Search | Implemented in `app/Http/Controllers/ProductController.php:49-54` |
| products-catalog | Admin Authentication Gate | Implemented in `routes/web.php:22-28,48` |
| products-catalog | Create Form Scoped to Child Categories and Wholesale Tiers | Implemented in `app/Http/Controllers/ProductController.php:66-82` |
| products-catalog | Edit Form Pre-loads Existing Product Data | Implemented in `app/Http/Controllers/ProductController.php:139-166` |
| products-catalog | Product Code Auto-Generation When Blank on Create | Implemented in `app/Http/Controllers/ProductController.php:117`, `app/Models/Product.php:83-90` |
| products-catalog | Sale Price Defaults to Price When Blank | Implemented in `app/Http/Controllers/ProductController.php:118,191` |
| products-catalog | Product Code Uniqueness Among Live Rows Only | Implemented in `app/Http/Controllers/ProductController.php:99` |
| products-catalog | Product Code Is Not Modified on Update | Implemented in `app/Http/Controllers/ProductController.php:177-189` |
| products-catalog | Optional Picture Upload on Write | Implemented in `app/Http/Controllers/ProductController.php:120-123,195-207` |
| products-catalog | Product Unit Rows Are Fully Replaced on Save | Implemented in `app/Http/Controllers/ProductController.php:241-283` |
| products-catalog | Invalid Unit Rows Are Discarded | Implemented in `app/Http/Controllers/ProductController.php:250-256` |
| products-catalog | At Most One Default Unit Per Product | Implemented in `app/Http/Controllers/ProductController.php:258-261` |
| products-catalog | Product Soft-Delete Returns JSON Status | Implemented in `app/Http/Controllers/ProductController.php:230-240`, admin.dele |
| products-catalog | Soft-Deleted Product Name Is Prefixed and Hidden | Implemented in `app/Models/Product.php:33-38`, `app/Http/Controllers/ProductController.php:230-240` |
| products-catalog | Successful Write Redirects Back with Notification | Implemented in `app/Http/Controllers/ProductController.php:127-131,209-221` |
| products-catalog | Show Action Produces an Empty Response | Implemented in `app/Http/Controllers/ProductController.php:132-137` |
| products-pricing | Authentication Required | Implemented in `routes/web.php:47-48`, admin group `['web','admin']` |
| products-pricing | product_id Is Mandatory | Implemented in `app/Http/Controllers/ProductController.php:277-280` |
| products-pricing | Unknown Product Returns 404 | Implemented in `app/Http/Controllers/ProductController.php:282-286` |
| products-pricing | Customer Resolution by Id | Implemented in `app/Http/Controllers/ProductController.php:289-290` |
| products-pricing | Customer Resolution by Phone | Implemented in `app/Http/Controllers/ProductController.php:291-292` |
| products-pricing | Phone Overrides Id When Both Are Present | Implemented in `app/Http/Controllers/ProductController.php:289-292` |
| products-pricing | Wholesale Tier Pricing | Implemented in `app/Models/Product.php:96`, wholesale_prices.si_1 |
| products-pricing | Unit Conversion by Division | Implemented in `app/Models/Product.php:98-105` |
| products-pricing | Success Response Is a Bare JSON Number | 1666.6666, Implemented in `app/Http/Controllers/ProductController.php:297` |
| products-pricing | Error Responses Use Distinct Status Codes per Failure Kind | Implemented in `app/Http/Controllers/ProductController.php:277-286` |
| units | List Units Screen | Implemented in `app/Http/Controllers/UnitController.php:20-41,54-64` |
| units | Create Unit Via Inline Form | Implemented in `app/Http/Controllers/UnitController.php:76-82` |
| units | Edit Unit | Implemented in `app/Http/Controllers/UnitController.php:43-49,76-82` |
| units | Default Unit Edit Lock | Implemented in `app/Http/Controllers/UnitController.php:67-69` |
| units | Deletion Disabled for All Units | Implemented in `app/Http/Controllers/UnitController.php:70` |
| units | Admin Authentication Required | Implemented in `routes/web.php:24-28,86-89` |
