# F-144 — Implementer evidence

## What
F-144 build evidence: an additive schema migration `048_*` adds the store/VAT/cost/shipping snapshot columns to `orders_orders` / `orders_items`, plus DB integration test `reporting-snapshots.itest.ts`. Backend-only, **no API or user-facing behavior change** (reporting routes are unchanged from F-143).

## Design recap (architect-approved — see architect.md)
- `orders_orders.store_id` `uuid NOT NULL DEFAULT <default store>` with guarded FK → `pos_stores(id)` + index `(store_id, created_at)`. Column DEFAULT backfills existing rows and future inserts without a table rewrite and without app-layer changes to the order INSERT path. FK resolución por request se posterga a F-146.
- `orders_orders.shipping_cents` `integer NOT NULL DEFAULT 0` separa envío del total (sin sobreescritura: históricos → 0, `total_cents` intacto).
- `orders_items.cost_at_sale_cents` `bigint` y `orders_items.vat_rate` `text`, **nullable** (snapshots → NULL hasta poblados; margen/IVA-por-tipo permanecen `unavailable`, nunca 0).
- `up()` idempotente: `ADD COLUMN IF NOT EXISTS` (PG>=9.6) + `DO $$ IF NOT EXISTS ... $$` guard para el FK (PG16 no admite `ADD CONSTRAINT IF NOT EXISTS`). `down()` reversible (índice/constraint/columnas).

## Files
- `project/migrations/048_reporting_store_shipping_snapshots.js` (created) — `up`/`down` idempotent/reversible. El FK usa `DO $$` guard (convención 047/046) tras confirmar via psql que el bloque DO es SQL válido en PG16.15.
- `project/src/app/tests/reporting-snapshots.itest.ts` (created) — recrea la DB (drop+recreate), migra `001→048`, verifica schema vía `information_schema`/`pg_constraint`/`pg_indexes`, e inserta revertindo el CHECK de 047.

## Tests
- NEW `reporting-snapshots.itest.ts` (3, real PostgreSQL): AC1 (store_id col NOT NULL + DEFAULT + FK contype='f' + índice + INSERT backfill store_id=DEFAULT_STORE_ID), AC2 (shipping_cents NOT NULL DEFAULT 0 + backfill=0), AC3 (cost_at_sale_cents bigint nullable / vat_rate text nullable).
  - Adaptación: el `INSERT` usa `INSERT INTO orders_orders (source) VALUES ('pos')` en lugar de `DEFAULT VALUES` porque el CHECK de 047 (`source='pos' OR user_id IS NOT NULL`) rechaza una fila 100% NULL; `store_id`/`shipping_cents` siguen backfilliándose por el column DEFAULT → el intento de AC1/AC2 se verifica.

## Verification
- Migration 048 applies clean (dev + test DB): `node-pg-migrate up --verbose` → "Migrations complete!"; `048_reporting_store_shipping_snapshots (UP)` log; columns/FK/index presentes en `mercadodevida` dev. (Raw psql confirmó el DO-block FK válido en PG16.15.)
- `TEST_DATABASE_URL=... npx vitest run src/app/tests/reporting-snapshots.itest.ts` → **3 passed**, 0 skipped, exit 0 (crea DB, migra 048, verifica todo).
- `npx tsc --noEmit` → **0 errors** (incluye el itest .ts; estricto, noUncheckedIndexedAccess).
- `node scripts/check-module-boundaries.mjs src` → **0 NEW violations** (única infracción R1 preexistente `security.routes.ts → log-broadcaster`, no introducida por F-144, fuera del diff).
- `./scripts/verify.sh` → green (F-144 in_progress, runtime-consistent; 270 features válidos).
- Re-run up() idempotente → no-op (DDL `IF NOT EXISTS` + DO guard); `down()` revierte todo.

## AC traceability
| AC | Estado | Evidencia |
|----|--------|-----------|
| AC1 store_id NOT NULL + DEFAULT + FK + idx + backfill | ✅ | itest col/is_nullable=NO/default+FK contype='f'+índice+INSERT backfill |
| AC2 shipping_cents NOT NULL DEFAULT 0 | ✅ | itest col + INSERT backfill=0 |
| AC3 cost_at_sale/vat_rate nullable | ✅ | itest is_nullable=YES en orders_items |
| AC4 idempotent/reversible | ✅ | IF NOT EXISTS + DO guard; down() drops all (PG16 raw check válida DO-block) |
| AC5 itest DB | ✅ | 3/3 (dev + test DB fresh) |
| AC6 gates | ✅ | tsc 0; itest 3/3; 0 boundaries nuevas |
| AC7 no regressión | ✅ | orders_orders INSERT sin store_id explícito sigue válido (column DEFAULT) |
