feat(F-049): completed feature
This commit is contained in:
71
work/artifacts/F-049/architect.md
Normal file
71
work/artifacts/F-049/architect.md
Normal 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.
|
||||
23
work/artifacts/F-049/documenter.md
Normal file
23
work/artifacts/F-049/documenter.md
Normal 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.
|
||||
63
work/artifacts/F-049/implementer.md
Normal file
63
work/artifacts/F-049/implementer.md
Normal 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.
|
||||
20
work/artifacts/F-049/leader-close.json
Normal file
20
work/artifacts/F-049/leader-close.json
Normal 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."
|
||||
}
|
||||
37
work/artifacts/F-049/qa.json
Normal file
37
work/artifacts/F-049/qa.json
Normal 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."
|
||||
}
|
||||
37
work/artifacts/F-049/reviewer.json
Normal file
37
work/artifacts/F-049/reviewer.json
Normal 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."
|
||||
}
|
||||
34
work/artifacts/F-049/security.json
Normal file
34
work/artifacts/F-049/security.json
Normal 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."
|
||||
}
|
||||
Reference in New Issue
Block a user