# FEATURE GAP MATRIX

**Project**: MercadoDeVida vNext
**Inspected**: 2026-08-17
**Backend**: project/src/ | **Storefront**: project/frontend/src/ | **Admin**: project/apps/admin/src/

---

## FEATURE A — Expiration Tracking

| Aspect | Status | Details |
|--------|--------|---------|
| Product model | ⚠️ PARTIAL | Has `ProductState`, no `expiration_tracking_enabled` |
| Inventory model | ⚠️ PARTIAL | `inventory_stock` at variant level only; no lots |
| Inventory repository | ✅ EXISTS | `PgInventoryRepository` (variant-level) |
| Lot model | ❌ MISSING | `inventory_lots` table does not exist |
| Lot repository | ❌ MISSING | No lot-level persistence |
| LotService | ❌ MISSING | Domain service for FEFO + expiry validation |
| InventoryService extended | ❌ MISSING | Delegates to LotService for expiry products |
| Checkout integration | ✅ EXISTS | Uses `InventoryServicePort` — boundary correct |
| GET /inventory/lots | ❌ MISSING | Need this route |
| POST /inventory/lots | ❌ MISSING | Need this route |
| PATCH /inventory/lots/:id | ❌ MISSING | Need this route |
| DELETE /inventory/lots/:id | ❌ MISSING | Need this route |
| GET /inventory/lots with filter | ❌ MISSING | Need ?filter=expiring\|expired\|all |
| Admin product editor | ⚠️ PARTIAL | Has General/Pricing/Inventory/Images/SEO/Publish tabs; no expiry toggle |
| Admin inventory view | ⚠️ PARTIAL | Shows variant stock; no lots |
| Admin expiry filters | ❌ MISSING | Need filter tabs in /admin/inventory |
| Audit for lot mutations | ⚠️ PARTIAL | `AuditLogger` exists; new operation types needed |
| Feature flag | ✅ EXISTS | `FLAG_EXPIRY_TRACKING` can be used |
| DB migration | ❌ MISSING | inventory_lots table, column on catalog_products |

**Backend blockers**: None — can implement in isolation
**DB blocker**: EXP-DB-001 must run before EXP-BE-005 (InventoryService extension)

---

## FEATURE B — Brand Migration

| Aspect | Status | Details |
|--------|--------|---------|
| Tailwind @theme tokens | ✅ EXISTS | `--color-primary: #2D6A4F`, `--color-accent: #E76F51`, fonts set |
| Google Fonts (Inter + Playfair) | ✅ EXISTS | Loaded in globals.css |
| businessConfig | ❌ MISSING | No single source of truth for company info |
| Official logo | ❌ MISSING | Not downloaded; no file in /public/images |
| Header component | ✅ EXISTS | Has logo slot; needs actual logo + businessConfig |
| Footer component | ✅ EXISTS | Needs businessConfig + social links |
| /about page | ✅ EXISTS | Has placeholder content; needs legacy migration |
| /contact page | ✅ EXISTS | Has placeholder content; needs real contact info |
| /shipping page | ✅ EXISTS | Needs enhancement with real policy |
| /terms page | ✅ EXISTS | Needs legacy migration + legal review |
| /privacy page | ✅ EXISTS | Needs creation from scratch |
| /cookies page | ✅ EXISTS | Needs creation from scratch |
| /legal page | ⚠️ PARTIAL | May not exist |
| Legacy redirect map | ⚠️ PARTIAL | Partially mapped; needs full sitemap extraction |
| next.config.ts redirects | ⚠️ PARTIAL | Some routes exist; needs completion + product slugs |
| sitemap.ts | ✅ EXISTS | Needs updating to include migrated routes |
| robots.ts | ✅ EXISTS | Needs updating for new site structure |
| Admin sidebar logo | ⚠️ PARTIAL | Has inline SVG; needs real logo |
| Admin branding | ✅ EXISTS | Same tokens as storefront |

**Backend blockers**: None
**⚠️ Warning**: Legal pages require human review before publishing

---

## FEATURE C — Bulk Update

| Aspect | Status | Details |
|--------|--------|---------|
| BulkOperationHandler port | ❌ MISSING | Interface for pluggable handlers |
| Price handlers (5 ops) | ❌ MISSING | SET, INCREASE/DECREASE (%, fixed) |
| Category handlers (3 ops) | ❌ MISSING | ADD, REMOVE, REPLACE |
| BulkService orchestrator | ❌ MISSING | preview() + execute() + audit |
| BulkProductRepository | ❌ MISSING | Batch read with pricing join |
| Bulk API routes | ❌ MISSING | POST /admin/bulk/preview, POST /admin/bulk/execute |
| PricingService | ✅ EXISTS | `netUnitAmountCents`, VAT calculation |
| ProductRepository | ✅ EXISTS | Has `update(id, patch)` |
| Category API | ✅ EXISTS | Categories managed via product.categoryIds |
| AuditLogger | ✅ EXISTS | `security_audit_log` table exists |
| RBAC | ✅ EXISTS | `permissions.ts` with `products.bulk_update` can be added |
| Feature flag | ✅ EXISTS | `FLAG_ADMIN_BULK_UPDATE` can be used |
| Admin product list | ✅ EXISTS | Checkbox selection is feasible |
| Admin bulk update page | ❌ MISSING | New /admin/bulk-update route |
| Navigation entry | ⚠️ PARTIAL | Need to add to NAV_ITEMS |

**Backend blockers**: None — all components can be built in isolation
**⚠️ Critical**: No bulk update should be exposed without confirmation UI

---

## API Changes Required

### New Endpoints (Backend)

| Endpoint | Method | Auth | Purpose |
|----------|--------|------|---------|
| `/inventory/lots` | GET | admin | List lots with filter |
| `/inventory/lots` | POST | admin | Create lot |
| `/inventory/lots/:id` | PATCH | admin | Update lot |
| `/inventory/lots/:id` | DELETE | admin | Delete lot |
| `/admin/bulk/preview` | POST | admin | Dry-run bulk operation |
| `/admin/bulk/execute` | POST | admin | Execute bulk operation |

### Modified Endpoints

| Endpoint | Change | Reason |
|---------|--------|--------|
| `GET /products/:id` | + `expiration_tracking_enabled` field | Product expiry policy |
| `PATCH /products/:id` | + accepts `expiration_tracking_enabled` | Set product expiry policy |
| `PUT /inventory/:variantId/stock` | Consider deprecating in favor of lots | For expiry products |

### No Changes Required

- `POST /cart`, `POST /checkout` — use InventoryServicePort unchanged
- `GET /products/search` — unchanged
- `GET /categories/tree` — unchanged
- `GET /brands` — unchanged

---

## Database Changes Required

### New Tables

| Table | Purpose |
|-------|---------|
| `inventory_lots` | Per-arrival stock with expiration date |
| `inventory_lot_movements` | Optional: movement tracking per lot |

### Modified Tables

| Table | Change | Default |
|-------|--------|---------|
| `catalog_products` | + `expiration_tracking_enabled boolean` | `false` |
| `inventory_movements` | + `lot_id uuid` (nullable) | `NULL` |
| `inventory_movements` | + new operation types | — |

### Indexes

| Index | Table | Columns |
|-------|-------|---------|
| `inventory_lots_variant_id_idx` | `inventory_lots` | `variant_id` |
| `inventory_lots_expiration_idx` | `inventory_lots` | `expiration_date` (partial) |

---

## STOREFRONT Changes

### Expected: NONE

**Expiration**: Checkout uses `InventoryServicePort` unchanged. No lot querying from frontend. No expiration display requirement from product team.

**Branding**: Storefront touches every visual component (Header, Footer, pages). Changes scoped to: tokens, logo, static pages, redirects.

**Bulk Update**: ZERO storefront changes. Bulk update is an Admin-only feature. Storefront automatically reflects updated prices/categories because it reads from the same backend.

---

## Cross-Feature Impact

```
FEATURE A (Expiration)
  ┌─ EXP-BE-005 (InventoryService extension)
  │   └─ Checkout uses InventoryServicePort → NO CHANGE to checkout code
  │       └─ Unit test regression required
  │
  └─ EXP-ADM-002/003/004 (Admin lot UI)
      └─ Uses new lot API routes

FEATURE B (Branding)
  ┌─ Token updates may touch frontend + admin globals.css
  │   └─ Build verification required on both apps
  │
  └─ Redirects in next.config.ts
      └─ May conflict with existing routes → verify no overlap

FEATURE C (Bulk Update)
  ┌─ Bulk write to catalog_products (prices, categories)
  │   └─ Storefront reads same DB → no code change needed
  │
  └─ New admin route /admin/bulk-update
      └─ No conflict with existing routes
```

---

## Implementation Order

```
1. EXPIRATION
   ├─ BE: EXP-BE-001 (product column) ──┐
   ├─ BE: EXP-BE-002 (lot model) ──────────┼── parallel
   └─ DB: EXP-DB-001 (run migrations) ────┘
           │
2. EXPIRATION
   ├─ BE: EXP-BE-003 (LotService) ────────▶ EXP-BE-004 (lot routes)
   │                                          │
   └─ BE: EXP-BE-005 (InventoryService) ◀──────┘
           │
3. BRAND + BULK (parallel)
   ├─ BRAND: BRAND-FE-001..003 (assets, config) ──▶ BRAND-FE-004..009 (pages, redirects)
   └─ BULK: BULK-BE-001..008 (all backend) ──────────────────▶ BULK-ADM-001..005
           │
4. ALL FEATURES
   ├─ QA: EXP-QA-001 + BULK-QA-001 (E2E regression)
   ├─ BRAND: Legal pages human review
   └─ FLAGS: Flip feature flags when ready
```

---

## Feature Flags Needed

| Flag | Feature | Default |
|------|---------|---------|
| `expiration_tracking` | Expiration tracking (lot model + FEFO) | `false` |
| `admin_bulk_update` | Bulk update module in admin | `false` |

Branding has no feature flag — purely additive changes that cannot break existing functionality.
