57 lines
3.0 KiB
Markdown
57 lines
3.0 KiB
Markdown
# F-144 — Diseño técnico
|
|
|
|
## Enfoque
|
|
Una única migrations `048_reporting_store_shipping_snapshots.js` (node-pg-migrate,
|
|
estilo `043_pos_basics`/`047_*`) idempotente y reversible. **No hay migración de
|
|
datos costosa**: `store_id` usa column `DEFAULT` del default store (sembrado por
|
|
043), por lo que filas existentes e inserts sin store_id heredan el default sin
|
|
table rewrite ni toque en el app-layer.
|
|
|
|
## Columnas nuevas
|
|
|
|
| Tabla | Columna | Tipo | Nullable | Default | Restricción |
|
|
|---|---|---|---|---|---|
|
|
| orders_orders | store_id | uuid | NOT NULL | `'00000000-0000-0000-0000-000000000001'::uuid` | FK → pos_stores(id) |
|
|
| orders_orders | shipping_cents | integer | NOT NULL | 0 | CHECK (>=0) |
|
|
| orders_items | cost_at_sale_cents | bigint | YES (snapshot) | — | — |
|
|
| orders_items | vat_rate | text | YES (snapshot) | — | — |
|
|
|
|
Índice: `orders_orders_store_id_created_at_idx ON orders_orders(store_id, created_at)`
|
|
(por el patrón de reporting §7: consultas por tienda + rango de fechas).
|
|
|
|
## Idempotencia + reversibilidad
|
|
- Toda la DDL: `ADD COLUMN IF NOT EXISTS` / `DO $$ IF NOT EXISTS` sobre
|
|
`pg_constraint`. Re-ejecutar es no-op.
|
|
- `down()`: `DROP INDEX`, `DROP CONSTRAINT`, `DROP COLUMN` por cada nueva
|
|
columna (orden inverso de dependencias).
|
|
|
|
## Por qué DEFAULT (no NOT NULL sin default + UPDATE)
|
|
- `store_id` es una columna nueva: no hay histórico que "reescribir". Un
|
|
`DEFAULT` constante backfilla silenciosamente y evita un `UPDATE` table-scan
|
|
sobre tabla potencialmente grande — alineado con §11 "no añadir índices
|
|
duplicados indiscriminadamente" y con no-rewrite-history.
|
|
- El app **inserta pedidos** vía `PgOrderRepository` (raw SQL `INSERT INTO
|
|
orders_orders (...)`). Con column `DEFAULT`, ese INSERT sigue funcionando
|
|
(la column no aparece en la lista) → cero regresión en checkout/orders.itest.
|
|
La resolución explícita de tienda (writes app-layered) se deja a F-146.
|
|
|
|
## Test
|
|
- itest `reporting-snapshots.itest.ts` (mirror `inventory.itest.ts`):
|
|
`recreateDatabase(url)` + `runMigrations(url,'up')` (aplica 048 contra
|
|
`mercadodevida_test`) + `createPool`, con `describe.skipIf(!hasDb)`.
|
|
- Asocia columnas/nullabilidad/default/FK/índice vía `information_schema` /
|
|
`pg_constraint` / `pg_indexes`, e inserta `INSERT INTO orders_orders DEFAULT
|
|
VALUES RETURNING store_id, shipping_cents` → `store_id = DEFAULT_STORE_ID`,
|
|
`shipping_cents = 0`.
|
|
- Harness: `TEST_DATABASE_URL=postgres://mdv:mdv_dev_only@localhost:5432/mercadodevida_test`
|
|
(verificado: `orders.itest.ts` recrea+migra+tests en ~450ms con el
|
|
`mdv` superuser).
|
|
|
|
## Verificación esperada
|
|
- `npx tsc --noEmit` → 0 errores.
|
|
- `TEST_DATABASE_URL=... npx vitest run src/app/tests/reporting-snapshots.itest.ts` → 3/3.
|
|
- `TEST_DATABASE_URL=... npx vitest run` → 1 archivo itest nuevo + regresión
|
|
(orders/catalog/checkout/sales itests) verde, 0 fallos.
|
|
- `node scripts/check-module-boundaries.mjs src` → 0 violaciones nuevas
|
|
(F-144 añade 1 migration .js + 1 .ts en tests; sin imports inter-módulo).
|