12 KiB
EXPIRATION TRACKING — TASKS.md
Backend
EXP-BE-001
ID: EXP-BE-001 Title: Product expiration_tracking_enabled column Goal: Add boolean column to catalog_products Why: Products need to declare whether they require expiration tracking Dependencies: None Applications: Backend Modules: catalog_products table, Product domain, ProductRepository Database impact: ALTER TABLE catalog_products ADD COLUMN expiration_tracking_enabled boolean NOT NULL DEFAULT false API contracts: GET /products/:id returns field; PATCH /products/:id accepts field Permissions: admin Implementation: Add to NewProduct interface, ProductPatch type, pg-product-repository Tests: Unit — default false; Integration — column exists with correct default Migration: See MIGRATION.md Phase 1 Expected blast radius: Low — only affects new product queries Definition of Done: Column exists, defaults to false, persists on create/update
EXP-BE-002
ID: EXP-BE-002 Title: InventoryLot domain and repository Goal: New InventoryLot entity and InventoryLotRepository port + PgInventoryLotRepository Why: Core data model for lot-level stock Dependencies: EXP-BE-001 Applications: Backend Modules: inventory/domain, inventory/infrastructure Database impact: CREATE TABLE inventory_lots (see DESIGN.md) API contracts: None yet (repository only) Permissions: N/A Implementation: InventoryLot interface, CreateLotCommand, InventoryLotRepository port, PgInventoryLotRepository Tests: Unit — CRUD operations; Integration — table constraints, FK Expected blast radius: Low — new table, no existing data touched Definition of Done: Lot CRUD works, FK to catalog_variants enforced, CHECK constraint on expiration_date
EXP-BE-003
ID: EXP-BE-003 Title: LotService — create, update, delete, FEFO allocation Goal: Domain service handling lot business rules Why: Encapsulates expiration validation and FEFO logic Dependencies: EXP-BE-002 Applications: Backend Modules: inventory/application API contracts: None (domain service) Permissions: N/A Implementation: LotService class with createLot (validates expiry required), allocateLots (FEFO), adjustQuantity Tests: Unit — missing expiry rejected; past expiry rejected; FEFO order; partial lot allocation Expected blast radius: Low Definition of Done: LotService methods have correct business rules; FEFO allocates from earliest expiry first
EXP-BE-004
ID: EXP-BE-004 Title: InventoryLots API routes Goal: CRUD endpoints for lots + availability query with filter Why: Admin needs to manage lots; frontend needs to display them Dependencies: EXP-BE-003 Applications: Backend Modules: inventory/api API contracts: GET /inventory/lots, POST /inventory/lots, PATCH /inventory/lots/:id, DELETE /inventory/lots/:id (all admin) Permissions: admin role required Implementation: New route registrations in inventory module; serialize LotService results Tests: Integration — CRUD round-trip; filter=expiring|expired|all Expected blast radius: Low — new routes Definition of Done: All 5 routes respond correctly; filter parameters work; auth enforced
EXP-BE-005
ID: EXP-BE-005 Title: InventoryService — integrate LotService for expiration products Goal: Extend existing InventoryService to delegate to LotService when expiry is enabled Why: Preserve existing InventoryServicePort contract while adding expiration support Dependencies: EXP-BE-001, EXP-BE-003 Applications: Backend, Checkout Modules: inventory/application, checkout API contracts: Existing InventoryServicePort contract unchanged Permissions: N/A Implementation: In InventoryService, check product.expiration_tracking_enabled; if true, use LotService.getAvailableStock and LotService.allocateLots; feature flag gates behavior Tests: Unit — delegation to LotService for expiry products; existing path for non-expiry products Expected blast radius: Checkout uses InventoryServicePort — must not break Definition of Done: Checkout reserve/confirm still works for both expiry and non-expiry products; FEFO used for expiry products
EXP-BE-006
ID: EXP-BE-006 Title: Extend inventory_movements with lot operation types Goal: Track lot_create, lot_adjust, lot_delete in movement audit log Why: Full auditability of lot changes Dependencies: EXP-BE-002 Applications: Backend Modules: inventory/infrastructure, security Database impact: ALTER TABLE inventory_movements — new operation types + optional lot_id FK API contracts: Movement audit reflects lot operations Permissions: N/A Implementation: Add operation types in pg-inventory-repository insertMovement calls Tests: Integration — movements logged with correct operation type Expected blast radius: Low Definition of Done: Lot mutations produce audit entries
Database
EXP-DB-001
ID: EXP-DB-001 Title: Run expiration tracking migrations Goal: Apply all DB changes from MIGRATION.md Phase 1 Why: Infrastructure for lot model Dependencies: EXP-BE-001 (column on catalog_products), EXP-BE-002 (lots table) Applications: Database Modules: N/A Database impact: See MIGRATION.md Phase 1 API contracts: N/A Permissions: DBA Implementation: Add migration file or run raw SQL against dev DB; apply via docker-compose migration pipeline Tests: Verify schema after migration Expected blast radius: Low — additive changes Definition of Done: Migration runs without error; new columns/tables exist with correct constraints
Admin
EXP-ADM-001
ID: EXP-ADM-001 Title: Product Editor — expiration tracking toggle Goal: Add checkbox to General tab: "Track expiration dates" Why: Admin configures per-product policy Dependencies: EXP-BE-001 Applications: Admin Modules: ProductEditor, GeneralSection Database impact: None (uses EXP-BE-001) API contracts: PATCH /catalog/products/:id Permissions: products.write Implementation: Add toggle to GeneralSection; saves { expiration_tracking_enabled: boolean } on save Tests: Toggle saves correctly; shows/hides expiration UI based on state Expected blast radius: Low Definition of Done: Admin can enable/disable expiry tracking per product; toggle persists
EXP-ADM-002
ID: EXP-ADM-002 Title: Inventory — lot-level stock view Goal: Show lots table for expiry-tracking products in inventory page Why: Operational visibility into expiration state Dependencies: EXP-BE-004 Applications: Admin Modules: InventorySection, inventory page Database impact: None API contracts: GET /inventory/lots?variant_id=X Permissions: inventory.read Implementation: Extend InventorySection to show lots when product has expiry enabled; compute status (VALID/NEAR_EXPIRY/EXPIRED) client-side from FLAG_EXPIRY_WARNING_DAYS Tests: Lot table renders correctly; status computed from dates Expected blast radius: Low Definition of Done: Lots displayed with correct quantity, date, and status badge
EXP-ADM-003
ID: EXP-ADM-003 Title: Inventory — lot create/edit/delete Goal: Inline lot management in inventory section Why: Admin must be able to add/update/remove lots Dependencies: EXP-BE-004 Applications: Admin Modules: InventorySection Database impact: None API contracts: POST/PATCH/DELETE /inventory/lots/:id Permissions: inventory.write Implementation: Add lot form (quantity, expiration date); inline edit on lot row; delete confirmation Tests: Create lot with required expiry date; edit quantity; delete lot; 422 shown for missing expiry Expected blast radius: Low Definition of Done: Admin can fully manage lots; validation errors shown correctly
EXP-ADM-004
ID: EXP-ADM-004 Title: Inventory filters — expiring, expired, all, no-expiry Goal: Filter inventory page by expiration status Why: Operational efficiency for stock management Dependencies: EXP-BE-004 Applications: Admin Modules: inventory page Database impact: None API contracts: GET /inventory/lots?filter=expiring|expired|all|no-expiry Permissions: inventory.read Implementation: Add filter tabs/dropdown to inventory page; calls API with filter param Tests: Each filter returns correct lot subset Expected blast radius: Low Definition of Done: Filters work; filter state reflected in URL or UI
QA
EXP-QA-001
ID: EXP-QA-001 Title: Expiration tracking regression tests Goal: Ensure existing checkout flow is unbroken Why: No regressions on existing products Dependencies: EXP-BE-005, EXP-DB-001 Applications: QA Modules: E2E tests Tests:
- Normal product (non-expiry) still checks out correctly
- Expiry product with no lots: unavailable
- Expiry product with valid lot: available and reservable
- FEFO: earliest expiry lot consumed first
- Expired lot: contributes zero sellable units Expected blast radius: N/A Definition of Done: All regression tests pass
EXP-QA-002
ID: EXP-QA-002 Title: Expiration tracking unit/integration tests Goal: Comprehensive test coverage for all new domain code Why: Business rules must be correct Dependencies: EXP-BE-003, EXP-BE-004, EXP-BE-005 Applications: QA Modules: Backend test suite Tests: See TESTS.md Expected blast radius: N/A Definition of Done: 100% pass rate on expiration-specific tests
Task Summary Table
| Task | Layer | Feature | Depends On | Risk | Parallel |
|---|---|---|---|---|---|
| EXP-BE-001 | Backend | Product expiry column | — | Low | * |
| EXP-BE-002 | Backend | Lot model + repository | — | Low | * |
| EXP-BE-003 | Backend | LotService domain | EXP-BE-002 | Low | * |
| EXP-BE-004 | Backend | Lot API routes | EXP-BE-003 | Low | * |
| EXP-BE-005 | Backend | InventoryService + LotService | EXP-BE-001, EXP-BE-003 | Medium | * |
| EXP-BE-006 | Backend | Movement audit for lots | EXP-BE-002 | Low | EXP-BE-004 |
| EXP-DB-001 | DB | Run migrations | EXP-BE-001, EXP-BE-002 | Low | * |
| EXP-ADM-001 | Admin | Product expiry toggle | EXP-BE-001 | Low | * |
| EXP-ADM-002 | Admin | Lot stock view | EXP-BE-004 | Low | * |
| EXP-ADM-003 | Admin | Lot CRUD | EXP-BE-004 | Low | * |
| EXP-ADM-004 | Admin | Expiry filters | EXP-BE-004 | Low | * |
| EXP-QA-001 | QA | Checkout regression | EXP-BE-005, EXP-DB-001 | Medium | After backend |
| EXP-QA-002 | QA | Domain unit tests | All BE tasks | Low | With backend |
Parallel group: EXP-BE-001 and EXP-BE-002 can run in parallel. BE-003 depends on BE-002. BE-004 and BE-006 depend on BE-003. BE-005 depends on BE-001 + BE-003.
Recommended order:
- EXP-BE-001 + EXP-BE-002 (parallel, no dependencies)
- EXP-BE-003 (depends on BE-002)
- EXP-BE-004 + EXP-BE-006 (depend on BE-003, parallel)
- EXP-DB-001 (run after BE-001 + BE-002 code is deployed)
- EXP-BE-005 (depends on BE-001 + BE-003)
- EXP-ADM-001 (depends on BE-001)
- EXP-ADM-002 + EXP-ADM-003 + EXP-ADM-004 (depend on BE-004, parallel)
- EXP-QA-001 + EXP-QA-002 (after all backend + admin)
High-risk tasks: EXP-BE-005 (changes InventoryService contract internal behavior, affects checkout — thorough regression testing required).
MVP boundary: EXP-BE-001 through EXP-BE-005 + EXP-DB-001 + EXP-ADM-001 through EXP-ADM-004. EXP-BE-006 (audit) is low priority for MVP. EXP-QA-002 is bundled with implementation. EXP-QA-001 is blocking go-live.