# Batch-5 Close-Out · Retail Depth + CRM

> **Document type:** frozen historical artifact — captures what shipped in Batch 5.
> **Verified accurate:** 2026-05-02 — every file path, export name, and `index.html` script-tag reference still resolves in the live source.
> **Do not rewrite as a current spec.** For active spec, see `MISSING-SCREENS-INVENTORY.md` (token markers) and `SCREENS-INVENTORY-Retail.md` / `SCREENS-INVENTORY-Common.md` (CRM 360).

**Date:** 2026-05-01  
**Scope:** 5 V1.0-HIGH screens (3 ORIGINAL cut-overs · 2 NEW BUILT-PARTIAL)  
**Branch contract:** Same surgical pattern as Batch-4 — new screens go in *new* files, legacy fixture screens stay in place as fallback.

---

## What shipped

| ID | Screen | Token | Marker | Files touched |
|---|---|---|---|---|
| MS-RETAIL-001 | Loyalty Programs | `retail.loyalty` (NEW) | `[BUILT-PARTIAL]` ✅ | `retail-screens-batch5.js` (new) |
| MS-RETAIL-002 | Gift Cards | `retail.giftcards` | `[ORIGINAL · WIRED]` ✅ | `retail-data-live.js` cut-over |
| MS-RETAIL-003 | Promotions Builder | `retail.promo` | `[ORIGINAL · WIRED]` ✅ | `retail-screens-batch5.js` (new `RetailPromosLive`) |
| MS-RETAIL-006 | Stock Transfers Receive | `retail.transfers` | `[NEW · WIRED-PARTIAL]` ⚠️ | `retail-data-live.js` cut-over |
| MS-CRM-001 | Customer 360 | `crm.customer-360` (NEW) | `[BUILT-PARTIAL]` ✅ | `retail-screens-batch5.js` (new) |

**5/5 screens reachable** from the side-nav. Two new tokens added to `front/common/tokens.js` and `front/common/roles.js` (manager-tier ACL).

---

## Files added

| Path | Purpose | Size |
|---|---|---|
| `front/api/api-namespace-batch5.js` | 5 mock endpoint groups: customers, promotions, gift-cards, loyalty, transfers | 31 KB |
| `front/retail/retail-data-live.js` | Wraps `RetailHooks.{giftCards,transfers}` to hit `API.giftCards.*` / `API.transfers.*` instead of fixtures | (existing — no edit needed) |
| `front/retail/retail-screens-batch5.js` | `RetailPromosLive`, `LoyaltyProgramsScreen`, `Customer360Screen` | 56 KB |

## Files edited (surgical)

- `front/app-main.compiled.js` — case `retail.promo` now prefers `window.RetailPromosLive`; new cases `retail.loyalty`, `crm.customer-360` / `retail.customer-360`.
- `front/common/tokens.js` — 2 new tokens with `New` badge.
- `front/common/roles.js` — manager role grants both new tokens.
- `index.html` — 3 new `<script>` tags in correct order: api-namespace-batch5 (after batch4) → retail-data-live (after retail-hooks/growth-ops) → retail-screens-batch5.
- `docs/handoff/MISSING-SCREENS-INVENTORY.md` — 5 status-marker updates + new `[BUILT-PARTIAL]` semantics row in the legend.

---

## Backend coverage matrix (vs `routes-api.php`)

| Endpoint | Status | Note |
|---|---|---|
| `GET /customers`, `POST /customers`, `PATCH /customers/{id}` | ✅ Real | Routes confirmed; 360 list+detail wired |
| `POST /customers/credit-holds` | ✅ Real | Wired (button TBD in v1.1) |
| `GET /promotions`, `POST /promotions`, `PATCH /promotions/{id}` | ✅ Real | Builder modal calls `POST /promotions` |
| `POST /gift-cards`, `POST /gift-cards/{code}/redeem` | ✅ Real | RetailHooks wrapped |
| `POST /loyalty/redeem`, `POST /loyalty/breakage` | ✅ Real | Breakage modal wired end-to-end |
| `GET /loyalty/tiers` | ⚠️ MOCK | **Backend gap BE-HIGH-007** — tier CRUD pending v1.1 |
| `GET /loyalty/ledger` | ⚠️ MOCK | Backend has redeem/breakage txns but no consolidated ledger view yet |
| `GET /reports/customers/loyalty` | ⚠️ MOCK | Liability roll-up — defer to BE |
| `POST /transfers` | ✅ Real | Wired |
| `POST /transfers/{id}/receive` | ⚠️ MOCK | **Backend gap** — receive flow stays mock until BE ships |

**Action items for backend team** (handed off separately):
1. **BE-HIGH-007** — add `/loyalty/tiers` CRUD (tiers are read-only in the UI today).
2. **BE-NEW** — add `/transfers/{id}/receive` with line-quantity reconciliation.
3. **BE-NEW** — add `/sales` `customer_id` filter (Customer 360 → Orders tab is `LIVE-READ-ONLY` until then).
4. **BE-NEW** — add per-customer filter to `/accounting/aging-report` (Customer 360 → Receivables tab is `LIVE-READ-ONLY` until then).

---

## Cut-over verification

Console at boot:
```
[API.batch5] registered: customers · promotions · giftCards · loyalty · transfers
[retail-live] giftCards wrapped: issue, redeem
[retail-live] transfers wrapped: create, receive, receiveLines, cancel
[batch5-screens] ready: RetailPromosLive, LoyaltyProgramsScreen, Customer360Screen
```

Zero errors, zero warnings (other than the standing `babel-in-browser` notice and `AcctDataLive` already-known shim warning).

---

## Marker convention update

Added `[BUILT-PARTIAL]` to the inventory legend (after `[BUILT · WIRED]`):

> Built new in a batch but spec contains tabs/sections deferred to v1.1. Per-tab basis — see screen heading for which tabs are mutating vs read-only.

This is the right marker for **MS-RETAIL-001** (Tiers tab read-only) and **MS-CRM-001** (Orders/AR tabs are `LIVE-READ-ONLY` pending backend filters).

---

## Next batch suggestion

**Batch 6 — Dine push** (per the build plan in INVENTORY §): MS-DINE-001 Aggregator Inbox, MS-DINE-004 Production Orders, MS-DINE-005 Reservations, MS-DINE-006 Menu Versioning. Same surgical pattern.
