feat(F-049): completed feature

This commit is contained in:
chattie
2026-08-19 07:34:15 +02:00
parent ae922c09d7
commit e86034a62c
16 changed files with 1097 additions and 80 deletions

View File

@@ -0,0 +1,71 @@
# Architect — F-049
## Goal
Disponer de una operación reproducible del monolito completo en una sola máquina, tanto en desarrollo como en producción local/LAN, sin depender de procesos `nohup` manuales ni PIDs conocidos de antemano.
## Service topology
| Service | Package | Port | LAN binding |
|---|---|---:|---|
| Backend API + Swagger | `project/` | 3000 | `0.0.0.0` |
| Customer frontend | `project/frontend/` | 3003 | `0.0.0.0` |
| Admin backoffice | `project/apps/admin/` | 3004 | `0.0.0.0` |
| SEO storefront/ISR | `project/storefront/` | 3005 | `0.0.0.0` |
| PostgreSQL | Docker | 5432 | infrastructure only |
| Redis | Docker | 6379 | infrastructure only |
## Operational design
Implement `project/scripts/monolith.sh` as the single lifecycle entrypoint:
```text
monolith.sh <dev|prod> <start|restart|status|stop|logs|urls>
```
### Runtime state
- PID files: `project/.runtime/<mode>/<service>.pid`.
- Logs: `project/.runtime/<mode>/<service>.log`.
- Runtime files are ignored by Git.
- A process is considered healthy only when its PID exists and responds on its expected HTTP URL.
- Stale PID files are removed safely; the script only sends signals to PIDs recorded under the selected mode.
### Development
- Install dependencies package by package.
- Start Docker PostgreSQL/Redis and wait for readiness.
- Apply migrations.
- Run backend with a TypeScript watch runner and each Next package with `next dev`, all bound to `0.0.0.0`.
- The backend-facing browser variables must use a LAN/browser-reachable API URL rather than `127.0.0.1` when used from another device.
### Production local/LAN
- Install deterministic dependencies (`npm ci`).
- Apply migrations before process replacement.
- Build backend and all Next packages.
- Stop old managed processes gracefully, then start compiled backend and `next start` packages.
- Validate health/UI HTTP status after startup.
### LAN URL strategy
- Detect the active interface/IP from the default route on macOS, with Linux fallback.
- Allow override via `LAN_IP`.
- Export URLs consistently in status/start output.
- Admin uses its server-side proxy; customer frontends receive `NEXT_PUBLIC_API_URL=http://<LAN_IP>:3000` at build/start.
## Safety
- Do not expose DB/Redis URLs as user-facing links.
- Production refuses insecure cookies unless explicitly configured for LAN HTTP and documented as local-only.
- No secrets are printed.
- Stop/restart must not use broad `pkill`; process ownership comes from PID files.
- Existing unmanaged listeners are reported as port conflicts, not killed blindly.
## Acceptance evidence
1. `prod restart` builds, migrates, starts all four HTTP services and health-checks them.
2. `status` shows PID + HTTP health for each service.
3. LAN URLs respond from the host via the detected LAN address.
4. HOWTO documents dev/prod start/restart/status/logs/stop and firewall/LAN notes.
5. Existing quality suites and `verify.sh` remain green.

View File

@@ -0,0 +1,23 @@
# Documenter — F-049
## User-facing changes
- Nueva guía operativa `docs/HOWTO-monolith.md` con:
- requisitos y direcciones LAN;
- comandos de dev y prod (start, restart, status, stop, logs, urls);
- instrucciones de diagnóstico LAN y firewall;
- pasos de validación y troubleshooting.
## Operational notes
- El monolito queda sujeto al script `project/scripts/monolith.sh` con binding LAN (`0.0.0.0`).
- Cada servicio se identifica por PID file en `project/.runtime/<mode>/`.
- Override de puertos mediante variables `*_PORT`; override de IP mediante `LAN_IP`.
- `NEXT_PUBLIC_API_URL` se inyecta al arrancar cada Next y durante el build se incrusta en el bundle, por lo que cambiar la IP requiere `restart`.
## Documenter evidence
- Smoke LAN documentado: backend, admin, frontend y storefront con HTTP 200.
- Tabla de servicios y URLs.
- Lista de comandos disponibles y overrides.
- Notas de seguridad y troubleshooting.

View File

@@ -0,0 +1,63 @@
# Implementer — F-049
## Summary
Se ha creado `project/scripts/monolith.sh` como punto único de operación dev/prod para backend, frontend, admin y storefront. Se ha ejecutado un redeploy productivo y se ha verificado la disponibilidad de los cuatro servicios tanto por localhost como por la IP LAN.
## Implemented
### Scripts and configuration
- `project/scripts/monolith.sh` administra los servicios por PID file con PIDs en `project/.runtime/<mode>/<service>.pid` y logs en `project/.runtime/<mode>/<service>.log` (ambos ignorados por git).
- Comandos soportados: `start`, `restart`, `status`, `stop`, `logs`, `urls`. Modos: `dev` y `prod`.
- En dev: instala con `npm install`, levanta PostgreSQL/Redis, aplica migraciones y arranca cada servicio con `next dev` o `tsx watch` enlazado a `0.0.0.0`.
- En prod: `npm ci`, migraciones, builds completos y arranque con `next start`/`node dist/.../server.js` en `0.0.0.0`.
- El script detecta la IP LAN desde la ruta por defecto y la imprime, con override vía `LAN_IP`.
- El script no utiliza `pkill`; envía señales únicamente a los PIDs registrados y, si un puerto está ocupado por un proceso ajeno, aborta mostrando el PID.
- `project/package.json` añadió `tsx` como devDependency y el script `dev` para `tsx watch`; los builds siguen con `tsc -p tsconfig.build.json`.
- `project/.gitignore` ignora el runtime efímero `.runtime/`.
### Documentación
- `docs/HOWTO-monolith.md` cubre requisitos, dev, prod, acceso LAN, infraestructura, validación, troubleshooting y overrides de puertos.
- Tabla de servicios, URLs LAN, comandos `start/restart/status/stop/logs/urls`, `LAN_IP` para forzar IP y notas de firewall.
### Redespliegue productivo
- Migraciones aplicadas sin cambios pendientes.
- Builds: backend TypeScript, admin Next (24 rutas), frontend principal Next (29 rutas), storefront SEO Next (6 rutas) — todos verdes.
- Servicios reiniciados y escuchando en sus puertos. Health y HTTP 200 desde el host y desde la IP LAN.
## Evidence
### Status y procesos gestionados
```text
SERVICE PID PROCESS HTTP URL
backend 43396 running 200 http://192.168.18.93:3000/health
frontend 43418 running 200 http://192.168.18.93:3003/
admin 43438 running 200 http://192.168.18.93:3004/
storefront 43482 running 200 http://192.168.18.93:3005/
```
### Smoke LAN
```text
http://192.168.18.93:3000/health 200
http://192.168.18.93:3000/docs 200
http://192.168.18.93:3003/ 200
http://192.168.18.93:3004/ 200
http://192.168.18.93:3005/ 200
```
### Quality gates
- `npm run typecheck` (backend): PASS.
- `npm run lint:boundaries`: PASS — 237 files checked.
- `./scripts/verify.sh`: PASS — backlog 117 features y runtime consistente.
- `git diff --check`: PASS.
## Known non-blocking warnings
- El build de `frontend` registra durante SSG que dos `fetch` `no-store` hacen la home dinámica. Es esperado y no falla la compilación.
- El admin inicia en producción con `COOKIE_SECURE=false` para HTTP en LAN de confianza; en producción pública debe usarse HTTPS y `COOKIE_SECURE=true` detrás de un reverse proxy.

View File

@@ -0,0 +1,20 @@
{
"feature_id": "F-049",
"verdict": "APPROVED",
"agent": "leader",
"timestamp": "2026-08-19T05:36:30Z",
"gates_approved": {
"reviewer": true,
"security": true,
"qa": true
},
"verify_sh": "green",
"validation": {
"redeploy": "monolith.sh prod start construyó, migró y levantó los 4 servicios",
"status": "Los 4 servicios reportan HTTP 200 desde localhost y desde la IP LAN",
"scripts": "monolith.sh probado en producción con start, status y stop; URLs detectan LAN IP",
"docs": "docs/HOWTO-monolith.md cubre dev, prod, acceso LAN, troubleshooting"
},
"summary": "Lifecycle operativo único para el monolito, redeploy productivo verificado y guía HOWTO publicada.",
"push": "No origin remote configured; commit will remain local."
}

View File

@@ -0,0 +1,37 @@
{
"feature_id": "F-049",
"verdict": "APPROVED",
"agent": "qa",
"timestamp": "2026-08-19T05:36:00Z",
"checks": {
"acceptance_redeploy": {
"pass": true,
"evidence": "prod start construyó, migró y levantó los cuatro servicios; status reporta HTTP 200 y PID válido para cada uno."
},
"acceptance_lan_urls": {
"pass": true,
"evidence": "curl a 192.168.18.93:3000/health, /docs, :3003, :3004, :3005 retornan 200."
},
"acceptance_howto_dev": {
"pass": true,
"evidence": "docs/HOWTO-monolith.md documenta start/restart/status/stop/logs/url en dev con docker compose, sin seña de pkill global."
},
"acceptance_howto_prod": {
"pass": true,
"evidence": "docs/HOWTO-monolith.md documenta npm ci, build, start, restart, status, stop, logs, urls y firewall/HTTPS para producción."
},
"acceptance_state_sync": {
"pass": true,
"evidence": "work/current.md describe F-049; runtime y backlog son coherentes; F-049 es la única in_progress."
},
"acceptance_verify": {
"pass": true,
"evidence": "./scripts/verify.sh verde con 117 features y runtime consistente."
},
"regression_suites": {
"pass": true,
"evidence": "Backend typecheck/lint:boundaries/build verdes; build de los tres frontends verdes; no se añadieron regresiones en las suites."
}
},
"notes": "QA gate aprobado. F-049 está lista para documentación breve y close_feature.py."
}

View File

@@ -0,0 +1,37 @@
{
"feature_id": "F-049",
"verdict": "APPROVED",
"agent": "reviewer",
"timestamp": "2026-08-19T05:34:00Z",
"checks": {
"scope_control": {
"pass": true,
"notes": "Sólo se añadieron scripts/devdeps y docs; ningún cambio de dominio en módulos del producto."
},
"lifecycle_script": {
"pass": true,
"notes": "monolith.sh implementa start/restart/status/stop/logs/urls, usa PID files, aborta ante unmanaged listeners y nunca hace pkill global."
},
"lan_binding": {
"pass": true,
"notes": "Backend, admin, frontend y storefront se lanzan con binding 0.0.0.0 y sus health/UI responden 200 desde localhost y desde 192.168.18.93."
},
"migration_apply": {
"pass": true,
"notes": "Migraciones se ejecutan como paso previo al start en dev y prod, y son idempotentes."
},
"documentation": {
"pass": true,
"notes": "docs/HOWTO-monolith.md cubre dev, prod, URLs LAN, troubleshooting y overrides."
},
"quality": {
"pass": true,
"notes": "Typecheck y boundaries verdes, build de los cuatro paquetes verdes, verify.sh verde."
},
"hygiene": {
"pass": true,
"notes": "git diff --check verde, runtime efímero ignorado por git, secrets no se imprimen."
}
},
"notes": "Aprobado para security gate. Los warnings legacy de frontend y admin siguen sin bloquear."
}

View File

@@ -0,0 +1,34 @@
{
"feature_id": "F-049",
"verdict": "APPROVED",
"agent": "security",
"timestamp": "2026-08-19T05:35:00Z",
"checks": {
"dependency_audit": {
"pass": true,
"notes": "npm audit --omit=dev --audit-level=high sin vulnerabilidades en backend, admin, frontend y storefront."
},
"secret_scan": {
"pass": true,
"notes": "No se detectan claves privadas, AWS access keys ni Stripe live keys en árbol de proyecto ni en el diff."
},
"shell_safety": {
"pass": true,
"notes": "monolith.sh usa set -euo pipefail, no hace pkill global, no imprime variables de entorno, aborta ante conflictos de puerto y maneja SIGTERM con KILL como último recurso."
},
"auth_state": {
"pass": true,
"notes": "El backend actual no expone endpoints sensibles sin auth; el admin corre con COOKIE_SECURE=false sólo porque la deployment actual es HTTP en LAN de confianza (documentado)."
},
"lan_exposure": {
"pass": true,
"notes": "Bindings 0.0.0.0 documentados como acceso LAN de confianza; el HOWTO recomienda habilitar HTTPS y COOKIE_SECURE=true en producción pública con reverse proxy."
},
"hygiene": {
"pass": true,
"notes": "git diff --check verde y runtime efímero ignorado."
}
},
"residual_risk": "Exposición LAN sin TLS y con cookies no-secure. Aceptable para HTTP interno; en producción pública se debe añadir reverse proxy HTTPS y COOKIE_SECURE=true.",
"notes": "Security gate aprobado."
}