Files
mercadodevida/spec/tech.md
2026-08-22 12:40:23 +02:00

3.0 KiB

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_centsstore_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).