feat(F-001): scaffold modular monolith skeleton with boundary checker

- TypeScript + Fastify skeleton under project/ (src/modules, shared, infrastructure, app)
- scripts/check-module-boundaries.mjs enforcing module public-API rules (tested with fixtures)
- GET /health endpoint, error envelope without stack leakage
- specs/F-001-scaffold (SPEC/DESIGN/TASKS/TESTS), spec/tech.md dependency justification
- 30-ticket MercadoDeVida roadmap in backlog/features.json, spec/roadmap.md
- All gates approved: reviewer, security, qa; verify.sh green
This commit is contained in:
rikrdo
2026-08-14 21:46:54 +02:00
commit 1d4eebca54
76 changed files with 9430 additions and 0 deletions

0
work/artifacts/.gitkeep Normal file
View File

View File

@@ -0,0 +1,31 @@
# Architect — F-001 Scaffold modular monolith skeleton
done -> work/artifacts/F-001/architect.md
## Decision summary
- Backend skeleton: Node 22 + TypeScript strict + Fastify 5, ESM, tsc build. No framework magic, no aliases (relative imports only) so runtime resolution stays trivial.
- Composition root: `src/app/build-app.ts` is the only place that wires modules onto the HTTP server.
- Boundary enforcement: explicit script `scripts/check-module-boundaries.mjs` wired into `lint:boundaries`, tested with fixtures. ESLint additionally blocks deep `@module` style imports is NOT needed because we use no aliases; the script is the single source of truth.
- Spec-first artifacts at `specs/F-001-scaffold/` (SPEC, DESIGN, TASKS, TESTS).
## Expected blast radius
```text
EXPECTED BLAST RADIUS
Modules modified: none (greenfield; new project/ skeleton only)
Modules indirectly affected: none
Database changes: none
API changes: adds GET /health
Events added/changed: none
Risk level: low
```
## Stack justification (boring choices)
- Fastify: maintained, typed, small, no magic.
- Vitest: TS-native, same mental model as the test pyramid required by design_prompt.
- ESLint flat config + Prettier: standard.
- No ORM, no Redis client, no config framework yet — each arrives with the ticket that needs it.
## Handoff to implementer
Follow `specs/F-001-scaffold/TASKS.md` in order. Definition of done for build stage: all five commands green and evidence written to `work/artifacts/F-001/implementer.md`.

View File

@@ -0,0 +1,22 @@
# Documenter — F-001 Scaffold modular monolith skeleton
done -> work/artifacts/F-001/documenter.md
## Why documentation applies
F-001 introduces new developer-facing contracts: npm scripts, module boundary rules, and project layout.
## Documents reviewed/produced
- `project/README.md` (created at build stage, verified accurate):
- requirements (Node >= 22, npm)
- all 6 npm scripts match package.json exactly: build, start, lint, lint:boundaries, typecheck, test
- layout diagram matches actual tree
- module rules match scripts/check-module-boundaries.mjs behavior (R1/R2)
- `specs/F-001-scaffold/` SPEC/DESIGN/TASKS/TESTS kept consistent with final implementation (TESTS.md updated at build stage).
- `spec/tech.md` completed with stack and dependency justification table (security policy requirement).
## Verification
- `grep` cross-check: README command list == package.json scripts keys (build, start, lint, lint:boundaries, typecheck, test) -> match.
- No API docs needed yet beyond /health (documented in implementer.md and SPEC.md).
## Pending docs (not this ticket)
- API reference will start being meaningful from F-005 onward.

View File

@@ -0,0 +1,55 @@
# Implementer — F-001 Scaffold modular monolith skeleton
done -> work/artifacts/F-001/implementer.md
## Files created (all under project/)
- package.json, tsconfig.json, tsconfig.build.json, eslint.config.mjs, vitest.config.ts
- .prettierrc.json, .prettierignore, .gitignore, README.md
- scripts/check-module-boundaries.mjs
- scripts/tests/boundary-checker.test.ts
- scripts/tests/fixtures/{ok,cross-module-internal,deep-from-app}/ (boundary test fixtures)
- src/app/build-app.ts (composition root)
- src/app/tests/build-app.test.ts
- src/infrastructure/http/server.ts (listen entrypoint)
- src/modules/health/index.ts, src/modules/health/api/health.routes.ts, src/modules/health/tests/health.test.ts
- src/shared/errors.ts
## Files modified
- specs/F-001-scaffold/TESTS.md (test locations updated to final layout)
## Database migrations
- None.
## API changes
- Adds GET /health -> 200 {"status":"ok"}
- Adds 404 JSON envelope: {"error":{"statusCode":404,"message":"Not Found"}}
- Error handler never leaks stack traces (500 -> generic message).
## Tests added
- health module API test (module-scoped, no cross-module imports)
- composition root tests (health wired, 404 envelope without stack leak)
- boundary checker tests: ok tree, R1 violation fixture, R2 violation fixture, index import allowed
## Tests passed (evidence)
```
npm run lint -> OK (eslint + prettier)
npm run lint:boundaries -> Boundary check OK: 7 file(s) checked
npm run typecheck -> exit 0
npm run build -> exit 0 (dist generated)
npm test -> Test Files 3 passed (3), Tests 7 passed (7)
smoke: PORT=3999 node dist/infrastructure/http/server.js
curl /health -> HTTP 200 {"status":"ok"}
curl /nope -> {"error":{"statusCode":404,"message":"Not Found"}}
```
## Known limitations
- Boundary checker covers static import/export specifiers only (no require(), no runtime reflection). Acceptable for TS ESM codebase.
- No request_id / structured logging yet (F-003 scope).
- No CI pipeline defined (repo-level decision, out of F-001 scope).
## Follow-up work
- F-002 database foundation, F-003 request context, F-004 config/flags (per backlog dependencies).
## Notes
- The boundary checker caught a real violation during build (health test importing src/app). Fixed by moving composition tests to src/app/tests and keeping module tests module-scoped. This is the rule working as designed.
- design_prompt.md added to .prettierignore: it is a project input document, not product code.

View File

@@ -0,0 +1,29 @@
{
"feature_id": "F-001",
"agent": "leader",
"verdict": "APPROVED",
"summary": "F-001 closed. Scaffold modular monolith implemented in project/, all gates APPROVED, verify.sh exit 0.",
"gates": {
"reviewer": "APPROVED (reviewer.json)",
"security": "APPROVED (security.json)",
"qa": "APPROVED (qa.json)",
"verify_sh": "exit 0"
},
"deliverables": [
"project/: TypeScript + Fastify modular monolith skeleton (7 source files + toolchain)",
"boundary checker with tested fixtures enforcing module rules",
"specs/F-001-scaffold/ SPEC, DESIGN, TASKS, TESTS",
"spec/tech.md with dependency justification"
],
"next_feature_hint": "F-002 (database foundation) - only depends on F-001",
"evidence": [
"work/artifacts/F-001/architect.md",
"work/artifacts/F-001/implementer.md",
"work/artifacts/F-001/reviewer.json",
"work/artifacts/F-001/security.json",
"work/artifacts/F-001/qa.json",
"work/artifacts/F-001/documenter.md",
"./scripts/verify.sh exit 0 at close"
],
"timestamp": "2026-08-14T19:52:00Z"
}

View File

@@ -0,0 +1,42 @@
{
"feature_id": "F-001",
"agent": "qa",
"verdict": "APPROVED",
"summary": "All 5 acceptance criteria verified with fresh executions against the final tree. No regressions (greenfield baseline).",
"traceability": [
{
"criterion": "AC1: npm install, build, lint, typecheck, test all green in project/",
"test": "fresh run of npm run build && typecheck && lint && lint:boundaries && test",
"result": "PASS (all exit 0; 3 test files / 7 tests passed)"
},
{
"criterion": "AC2: GET /health returns 200 {\"status\":\"ok\"}",
"test": "vitest inject tests (health.test.ts, build-app.test.ts) + live smoke: PORT=3998 node dist/infrastructure/http/server.js; curl /health",
"result": "PASS (HTTP 200 {\"status\":\"ok\"} live)"
},
{
"criterion": "AC3: src/modules, src/shared, src/infrastructure, src/app exist",
"test": "ls -d over project/src",
"result": "PASS (all four directories present)"
},
{
"criterion": "AC4: cross-module internal import fails boundary check",
"test": "node scripts/check-module-boundaries.mjs scripts/tests/fixtures/cross-module-internal + boundary-checker.test.ts fixtures",
"result": "PASS (exit 1, R1 violation reported)"
},
{
"criterion": "AC5: ./scripts/verify.sh green at repo root",
"test": "./scripts/verify.sh",
"result": "PASS (exit 0, 'Orquestra verificado')"
}
],
"regressions": "n/a - greenfield ticket, no prior behavior to regress",
"evidence": [
"project/: npm run build/typecheck/lint/lint:boundaries/test -> all exit 0",
"npm test -> Test Files 3 passed (3), Tests 7 passed (7)",
"live smoke on PORT=3998 -> 200 {\"status\":\"ok\"}",
"boundary checker on violation fixture -> exit 1 with R1 violation message",
"./scripts/verify.sh -> exit 0"
],
"timestamp": "2026-08-14T19:50:00Z"
}

View File

@@ -0,0 +1,32 @@
{
"feature_id": "F-001",
"agent": "reviewer",
"verdict": "APPROVED",
"summary": "Scaffold matches specs/F-001-scaffold DESIGN.md. Layout, composition root, boundary rules, error envelope and toolchain all verified by re-running commands against the tree. No blockers.",
"checks": {
"layout_matches_design": "PASS: src/{app,infrastructure,modules,shared} present; health exemplar exposes public API only via index.ts",
"boundary_rules": "PASS: R1 (module escape) and R2 (deep import from outside) enforced by scripts/check-module-boundaries.mjs, demonstrated by fixture tests (7 file(s) checked clean)",
"composition_root": "PASS: only src/app/build-app.ts wires modules; server.ts is a thin entrypoint",
"error_handling": "PASS: single error envelope, 404 handler, 500 message generic (no stack leak)",
"toolchain_green": "PASS: lint, lint:boundaries, typecheck, build, test all exit 0; 3 test files / 7 tests passed"
},
"findings": [
{
"severity": "info",
"note": "Boundary checker is regex-based over static import/export specifiers; documented limitation acceptable for TS ESM, revisit only if dynamic imports appear."
},
{
"severity": "info",
"note": "Implementer evidence shows the checker caught a real violation during build (test escaping module) and fixed it architecturally - rule is effective, not decorative."
}
],
"evidence": [
"npm run lint -> exit 0 (eslint + prettier)",
"npm run lint:boundaries -> Boundary check OK: 7 file(s) checked",
"npm run typecheck -> exit 0",
"npm test -> Test Files 3 passed (3), Tests 7 passed (7)",
"files reviewed: project/src/**, project/scripts/**, project/*.json, project/eslint.config.mjs",
"specs compared: specs/F-001-scaffold/SPEC.md, DESIGN.md, TASKS.md, TESTS.md"
],
"timestamp": "2026-08-14T19:46:00Z"
}

View File

@@ -0,0 +1,27 @@
{
"feature_id": "F-001",
"agent": "security",
"verdict": "APPROVED",
"summary": "Security gate passed. Zero audit vulnerabilities, no hardcoded secrets, no dangerous patterns in src/, error envelope prevents stack leakage, new dependencies justified in spec/tech.md per policy.",
"checks": {
"secrets": "PASS: grep for api_key/secret/password/token patterns in project code found none",
"dependencies": "PASS: npm audit --omit=dev -> 0 vulnerabilities; npm audit (full) -> 0 vulnerabilities; dependency table with justification added to spec/tech.md",
"sast_basic": "PASS: no eval, no new Function, no child_process in src/ (execFile used only in test harness with fixed, non-user-controlled arguments)",
"input_validation": "PASS (n/a scope): no user input surfaces yet beyond GET /health; Fastify default JSON body limits apply; error handler returns generic message for 5xx",
"repo_hygiene": "PASS: project/.gitignore excludes node_modules, dist, coverage, logs"
},
"findings": [
{
"severity": "info",
"note": "No auth, rate limiting or CSRF surface exists yet; tracked in F-005/F-028. Nothing to mitigate in F-001."
}
],
"evidence": [
"npm audit --omit=dev -> found 0 vulnerabilities",
"npm audit -> found 0 vulnerabilities",
"grep secret scan over project/src, project/scripts, configs -> no hardcoded secrets",
"grep eval|new Function|child_process over project/src -> none",
"dependency justification added to spec/tech.md (fastify, typescript, vitest, eslint stack, prettier)"
],
"timestamp": "2026-08-14T19:48:00Z"
}

14
work/current.md Normal file
View File

@@ -0,0 +1,14 @@
# Sesión actual
- Feature en curso: _ninguna_ (F-001 cerrada DONE el 2026-08-14)
- Inicio: —
- Orquestador: —
## Plan
- Próxima feature según dependencias: F-002 (Database foundation) o F-003 (HTTP foundation) o F-004 (config/flags) — todas dependen solo de F-001.
## Bitácora
- 2026-08-14: F-001 completada con todos los gates APPROVED y verify.sh verde.
## Próximo paso
- intake de la siguiente feature (sugerida: F-002).

9
work/history.md Normal file
View File

@@ -0,0 +1,9 @@
# Historial (append-only)
> Añadir entradas al final. No reescribir historial previo.
## 2026-08-14 — F-001 Scaffold modular monolith skeleton — DONE
- Gates: reviewer APPROVED, security APPROVED, qa APPROVED, verify.sh exit 0
- Entregable: skeleton TypeScript + Fastify en project/ con boundary checker testeado; specs/F-001-scaffold completos; spec/tech.md con justificación de dependencias
- Artefactos: work/artifacts/F-001/ (architect.md, implementer.md, reviewer.json, security.json, qa.json, documenter.md, leader-close.json)
- Nota: el boundary checker detectó una violación real durante build (test escapando del módulo) y se corrigió moviendo los tests de composición a src/app

11
work/runtime-status.json Normal file
View File

@@ -0,0 +1,11 @@
{
"feature_id": null,
"stage": "idle",
"agent": "leader",
"action": "Sin ejecución activa",
"state": "waiting",
"next_agent": "leader",
"waiting_for": "Seleccionar una feature pending y actualizar este estado",
"updated_at": "2026-08-14T19:46:48Z",
"timeline": []
}