feat(F-151): completed feature

This commit is contained in:
chattie
2026-08-21 22:14:29 +02:00
parent c4d0206d5d
commit ef79c54006
9 changed files with 270 additions and 12 deletions

View File

@@ -0,0 +1,87 @@
# F-151 — Implementer evidence
## Problema observado
Los servicios estaban levantados y respondían HTTP 200, pero la base activa estaba vacía:
- `catalog_products`: 0
- `catalog_product_variants`: 0
- `pricing_variant_prices`: 0
- `inventory_stock`: 0
- `categories_categories`: 0
- `brands_brands`: 0
- `backoffice_users`: 0
Por eso:
- frontend no mostraba productos;
- admin no aceptaba credenciales porque no existía ningún usuario backoffice.
Además, al ejecutar `node scripts/seed.cjs`, fallaba desde POS-002:
```text
there is no unique or exclusion constraint matching the ON CONFLICT specification
```
Causa: `inventory_stock` ya no es único por `variant_id`; ahora es único por `(variant_id, store_id)`.
Tras crear usuario backoffice, había otro problema: login devolvía 200, pero la cookie `backoffice_session` se emitía con `Secure` en HTTP local, por lo que el navegador/curl no la reenviaba.
## Cambios
### `project/scripts/seed.cjs`
- Limpia también `inventory_movements` para evitar movimientos obsoletos tras reseed.
- Inserta stock con `store_id = DEFAULT_STORE_ID`.
- Usa `ON CONFLICT (variant_id, store_id)`.
- Crea/actualiza un usuario backoffice admin:
- email por defecto: `admin@mdv.local`
- password por defecto en seed dev: `Admin123456!`
- configurable con `SEED_ADMIN_EMAIL` y `SEED_ADMIN_PASSWORD`.
- si `NODE_ENV=production`, exige `SEED_ADMIN_PASSWORD` explícito.
### `project/src/modules/backoffice/api/backoffice.routes.ts`
- Cookie `backoffice_session` ahora usa `secure` solo si la request es HTTPS o `x-forwarded-proto=https`.
- En HTTP local/LAN la cookie se emite sin `Secure`, permitiendo que el admin mantenga sesión.
## Acciones aplicadas al entorno
- Ejecutado `node scripts/seed.cjs` sobre la DB activa.
- Reiniciado solo backend para cargar el cambio de cookie.
## Estado verificado
Counts actuales:
```text
products: 12
variants: 12
prices: 12
stock: 12
categories: 11
brands: 6
backoffice_users: admin@mdv.local / admin
```
Pruebas:
```text
GET /health backend/admin/frontend/storefront ✅
POST /backoffice/auth/login ✅ 200
Set-Cookie backoffice_session sin Secure en HTTP ✅
GET /backoffice/auth/me vía admin proxy ✅
GET /catalog/products?limit=2 vía admin proxy ✅ productos
GET /products/search?limit=1 público ✅ productos
GET frontend /products contiene productos ✅
npm run build ✅
npm test ✅ 191 passed, 56 skipped
eslint/prettier archivos tocados ✅
./scripts/verify.sh ✅
git diff --check ✅
```
Nota: `npm run lint` global sigue fallando por errores preexistentes no tocados:
- `scripts/generate-thumbnails.mjs`: unused import y empty block.
- `src/infrastructure/logging/log-broadcaster.ts`: `no-this-alias`.

View File

@@ -0,0 +1,25 @@
{
"feature_id": "F-151",
"agent": "leader",
"verdict": "APPROVED",
"summary": "F-151 cerrado: seed compatible con inventario multi-tienda, admin backoffice bootstrap creado y cookie de sesión corregida para HTTP local/LAN. Productos y login restaurados en el entorno activo.",
"checks": [
"reviewer.json APPROVED",
"security.json APPROVED",
"qa.json APPROVED",
"node scripts/seed.cjs OK",
"backend restarted and health 200",
"admin login via proxy 200",
"admin /me via proxy OK",
"admin catalog products via proxy OK",
"frontend /products contains products",
"npm run build OK",
"npm test 191 passed / 56 skipped",
"touched-file eslint/prettier OK",
"verify.sh OK",
"git diff --check OK"
],
"commit_message": "fix(F-151): restore seeded products and admin login",
"next_step": "Continue with selected pending feature, likely F-143 or F-138 depending operator priority",
"closed_at": "2026-08-21T20:15:30Z"
}

View File

@@ -0,0 +1,20 @@
{
"feature_id": "F-151",
"agent": "qa",
"stage": "qa_gate",
"verdict": "APPROVED",
"reviewed_at": "2026-08-21T20:15:00Z",
"summary": "El entorno vuelve a estar utilizable: servicios arriba, productos restaurados y login admin mantiene sesión en HTTP LAN.",
"acceptance_traceability": [
{"criterion":"Servicios levantados","ok":true,"evidence":"monolith prod status: backend/admin/frontend/storefront running HTTP 200"},
{"criterion":"Productos disponibles","ok":true,"evidence":"DB: 12 products/variants/prices/stock; /products/search devuelve items; frontend /products contiene Almendras/Aceite"},
{"criterion":"Admin acepta credenciales","ok":true,"evidence":"POST /api/backoffice/auth/login vía admin proxy 200 con admin@mdv.local"},
{"criterion":"Sesión admin persistente","ok":true,"evidence":"Cookie guardada sin Secure en HTTP; GET /api/backoffice/auth/me devuelve admin"},
{"criterion":"Admin puede listar productos","ok":true,"evidence":"GET /api/catalog/products?limit=2 con cookie devuelve items"},
{"criterion":"Seed corregido","ok":true,"evidence":"node scripts/seed.cjs completa y es compatible con inventory_stock (variant_id, store_id)"},
{"criterion":"Regression checks","ok":true,"evidence":"npm run build; npm test 191 passed/56 skipped; touched-file lint/prettier; verify.sh; git diff --check"}
],
"checks": [],
"issues": [],
"notes":"npm run lint global no se usa como bloqueo de esta feature porque falla por errores preexistentes en archivos no tocados, documentados en implementer.md."
}

View File

@@ -0,0 +1,18 @@
{
"feature_id": "F-151",
"agent": "reviewer",
"stage": "review_gate",
"verdict": "APPROVED",
"reviewed_at": "2026-08-21T20:14:00Z",
"summary": "El diagnóstico identifica correctamente que los servicios estaban levantados pero la DB estaba vacía, el seed estaba roto por el nuevo constraint multi-tienda y la cookie backoffice Secure impedía sesión sobre HTTP local. El fix restaura productos y login sin cambiar contratos de negocio.",
"checks": [
{"item":"Seed compatible con POS-002","ok":true,"evidence":"inventory_stock inserta store_id y usa ON CONFLICT (variant_id, store_id)"},
{"item":"Backoffice admin bootstrap","ok":true,"evidence":"seed crea/actualiza backoffice_users admin con hash argon2 configurable"},
{"item":"Cookie de admin funciona en HTTP y HTTPS","ok":true,"evidence":"secure deriva de request.protocol/x-forwarded-proto; curl HTTP guarda y reenvía cookie"},
{"item":"Datos restaurados","ok":true,"evidence":"12 productos, 12 variantes, 12 precios, 12 stock, 11 categorías, 6 marcas, 1 admin"},
{"item":"APIs verificadas","ok":true,"evidence":"login 200, /me vía proxy OK, /catalog/products vía proxy devuelve productos, /products/search público devuelve productos"},
{"item":"Regression checks","ok":true,"evidence":"backend build/tests pass; touched-file eslint/prettier pass; verify.sh pass"}
],
"issues": [],
"notes":"El seed queda pensado para entorno dev/local. En NODE_ENV=production requiere SEED_ADMIN_PASSWORD explícito."
}

View File

@@ -0,0 +1,18 @@
{
"feature_id": "F-151",
"agent": "security",
"stage": "security_gate",
"verdict": "APPROVED",
"reviewed_at": "2026-08-21T20:14:30Z",
"summary": "Aprobado con alcance dev/local. La cookie no-Secure solo se permite para HTTP; bajo HTTPS o proxy x-forwarded-proto=https conserva Secure. El seed exige password explícita si NODE_ENV=production.",
"checks": [
{"item":"Cookie security preserved for HTTPS","ok":true,"evidence":"isSecureRequest returns true for request.protocol=https or x-forwarded-proto=https"},
{"item":"HTTP local login usable","ok":true,"evidence":"Secure=false en HTTP permite sesión admin en LAN sin TLS"},
{"item":"HttpOnly and SameSite preserved","ok":true,"evidence":"setCookie mantiene httpOnly y sameSite=lax"},
{"item":"Admin password hashed","ok":true,"evidence":"seed usa argon2.hash antes de insertar backoffice_users"},
{"item":"Production seed guard","ok":true,"evidence":"NODE_ENV=production sin SEED_ADMIN_PASSWORD lanza error"},
{"item":"No card/PII changes","ok":true,"evidence":"Solo seed dev catalog/backoffice and cookie flag derivation"}
],
"issues": [],
"notes":"La contraseña por defecto del seed debe considerarse solo dev/local. Para despliegue real usar SEED_ADMIN_PASSWORD y cambiar credenciales tras el primer login."
}

View File

@@ -1,11 +1,54 @@
{
"feature_id": null,
"stage": "idle",
"feature_id": "F-151",
"stage": "close",
"agent": "leader",
"action": "Sin ejecución activa",
"state": "waiting",
"action": "Close: admin login and product catalog restored",
"state": "running",
"next_agent": "leader",
"waiting_for": "Seleccionar una feature pending y actualizar este estado",
"updated_at": "2026-08-21T20:07:08Z",
"timeline": []
"waiting_for": "commit",
"updated_at": "2026-08-21T20:14:18Z",
"timeline": [
{
"ts": "2026-08-21T20:10:01Z",
"agent": "leader",
"stage": "intake",
"state": "running",
"message": "Intake: admin login fails and products unavailable after restart"
},
{
"ts": "2026-08-21T20:11:19Z",
"agent": "implementer",
"stage": "build",
"state": "running",
"message": "Implement: fix dev seed for store-scoped inventory and bootstrap backoffice admin"
},
{
"ts": "2026-08-21T20:13:35Z",
"agent": "reviewer",
"stage": "review_gate",
"state": "running",
"message": "Review: seed fixed for store-scoped inventory and HTTP admin cookie"
},
{
"ts": "2026-08-21T20:13:48Z",
"agent": "security",
"stage": "security_gate",
"state": "running",
"message": "Security: admin bootstrap password controls and cookie Secure policy reviewed"
},
{
"ts": "2026-08-21T20:14:04Z",
"agent": "qa",
"stage": "qa_gate",
"state": "running",
"message": "QA: services, seed counts, login session, product APIs and builds verified"
},
{
"ts": "2026-08-21T20:14:18Z",
"agent": "leader",
"stage": "close",
"state": "running",
"message": "Close: admin login and product catalog restored"
}
]
}