13 tareas con pasos bite-sized para crear el repo, copiar/editar archivos, yarn install y commit inicial. Incluye self-review con tabla de cobertura del spec y verificaciones contra strings prohibidos.
40 KiB
Plan de Implementación — Scaffold base-backend
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Crear ~/code/ref/base-backend como repo git independiente con el esqueleto mínimo de un monorepo TypeScript ESM al estilo sf-sim (Yarn 4 workspaces + DDD/Hexagonal + config de Claude Code), genericizado y listo para arrancar servicios.
Architecture: Repo nuevo, generado por copia selectiva desde sf-sim + ediciones. Sin RabbitMQ, sin Postgres, sin Docker. Solo _template en packages/. Verificación estructural (lint, typecheck, ausencia de strings prohibidos), no TDD — no hay código de aplicación que testear.
Tech Stack: TypeScript ESM, Yarn 4 workspaces, vitest, ESLint, Prettier.
Spec: docs/superpowers/specs/2026-05-06-base-backend-scaffold-design.md (commits 3186b43, 609cd2f).
Convención de paths en este plan: las rutas con prefijo ~/code/ref/base-backend/ o target/ se refieren al repo nuevo. Las rutas con ~/code/ref/sf-sim/ o source/ al actual.
Convención de commits: todo el trabajo se hace sin commitear hasta el final. Un único commit inicial con todo el scaffold (Task 13). Esto es coherente con git init + primer commit; no hay historia previa que preservar en el repo nuevo.
Task 1: Inicializar el repo
Files:
-
Create:
~/code/ref/base-backend/(directorio) -
Create:
~/code/ref/base-backend/.git/(víagit init) -
Step 1.1: Verificar que el directorio destino no existe
ls -d ~/code/ref/base-backend 2>/dev/null && echo "EXISTS — abortar" || echo "OK"
Expected: OK. Si dice EXISTS — abortar, parar y avisar al usuario.
- Step 1.2: Crear el directorio y subdirectorios
mkdir -p ~/code/ref/base-backend/.claude/{rules,commands,skills}
mkdir -p ~/code/ref/base-backend/.agents/skills
mkdir -p ~/code/ref/base-backend/packages/_template/config/env
mkdir -p ~/code/ref/base-backend/docs/superpowers/specs
mkdir -p ~/code/ref/base-backend/docs/superpowers/plans
- Step 1.3: Inicializar repo git
cd ~/code/ref/base-backend && git init -b main
Expected: Initialized empty Git repository in /home/jorge/code/ref/base-backend/.git/.
- Step 1.4: Verificar estructura
ls -a ~/code/ref/base-backend/ && find ~/code/ref/base-backend -type d -not -path '*/.git*'
Expected: ver .git, .claude, .agents, packages, docs y subdirectorios creados.
Task 2: Archivos de configuración raíz simples
Files:
-
Create:
~/code/ref/base-backend/.editorconfig -
Create:
~/code/ref/base-backend/.gitattributes -
Create:
~/code/ref/base-backend/.gitignore -
Create:
~/code/ref/base-backend/.yarnrc.yml -
Step 2.1: Copiar
.editorconfigtal cual
cp ~/code/ref/sf-sim/.editorconfig ~/code/ref/base-backend/.editorconfig
Verificar: diff ~/code/ref/sf-sim/.editorconfig ~/code/ref/base-backend/.editorconfig → sin output.
- Step 2.2: Copiar
.gitattributestal cual
cp ~/code/ref/sf-sim/.gitattributes ~/code/ref/base-backend/.gitattributes
- Step 2.3: Crear
.gitignorelimpio
Contenido (copia de sf-sim, adaptado quitando referencias a understand-anything y skill-creator-workspace específicas):
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Whether you use PnP or not, the node_modules folder is often used to store
# build artifacts that should be gitignored
node_modules
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
# Documentation here: https://yarnpkg.com/features/caching#zero-installs
#!.yarn/cache
.pnp.*
*.pem
dist/*
.env
# Knowledge graph generado localmente por la skill understand-anything
.understand-anything/
# Settings de Claude Code locales por desarrollador
.claude/settings.local.json
# Workspaces de skill-creator (artefactos de iteración, no la skill en sí)
.agents/skills/*-workspace/
Escribir en ~/code/ref/base-backend/.gitignore.
- Step 2.4: Crear
.yarnrc.yml
Contenido (copia de sf-sim, quitando npmScopes.sf-alvar que apunta al registro de SaveFamily):
compressionLevel: mixed
enableGlobalCache: false
nodeLinker: node-modules
npmRegistryServer: "https://registry.npmjs.org/"
Escribir en ~/code/ref/base-backend/.yarnrc.yml.
- Step 2.5: Verificar
ls -la ~/code/ref/base-backend/.editorconfig ~/code/ref/base-backend/.gitattributes ~/code/ref/base-backend/.gitignore ~/code/ref/base-backend/.yarnrc.yml
grep -i 'sf-alvar\|savefamilygps' ~/code/ref/base-backend/.yarnrc.yml ~/code/ref/base-backend/.gitignore && echo "FAIL — sigue habiendo referencias" || echo "OK"
Expected: cuatro ficheros listados, OK.
Task 3: package.json raíz
Files:
-
Create:
~/code/ref/base-backend/package.json -
Step 3.1: Escribir
package.jsongenericizado
Contenido completo (sin migrate, sin @sf-alvar/db-migrate, sin setup:runtime específico, name actualizado):
{
"name": "base-backend",
"version": "0.1.0",
"description": "Monorepo backend TypeScript ESM con DDD/Hexagonal — base para servicios nuevos",
"packageManager": "yarn@4.12.0",
"workspaces": [
"packages/*"
],
"scripts": {
"test": "vitest watch",
"build": "rm -rf ./dist && yarn workspaces foreach -Api run build",
"start": "yarn workspaces foreach -Apiv run start",
"typecheck": "npx tsc --noEmit",
"dev": "yarn workspaces foreach -Apiv run dev",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"dependencies": {
"@tsconfig/node22": "^22.0.5",
"dotenv": "^17.2.3",
"typescript": "^6.0.3",
"vite": "^7.3.1",
"vite-tsconfig-paths": "^6.0.5"
},
"devDependencies": {
"@types/node": "^25.0.3",
"concurrently": "^9.2.1",
"prettier": "^3.7.4",
"tsc-alias": "^1.8.16",
"tsx": "^4.21.0",
"vitest": "^4.0.16"
}
}
Escribir en ~/code/ref/base-backend/package.json.
Diferencias con sf-sim (para tu referencia, no escribir esto en el archivo):
name:sim-eventos→base-backend.version:1.0.0→0.1.0.- Añadido
description. scripts.build: quitado&& yarn setup:runtimey el scriptsetup:runtimeentero.- Quitado script
migrate. - Quitadas dependencias de infra:
@sf-alvar/db-migrate,amqp-connection-manager,amqplib,axios,cors,express,pg,uuidv7. - Quitadas devDependencies de infra:
@types/amqplib,@types/cors,@types/express,@types/pg,@types/supertest,supertest.
Las dependencias de infra se añaden cuando se cree un servicio real que las necesite — no son parte del scaffold.
- Step 3.2: Verificar JSON válido
node -e "JSON.parse(require('fs').readFileSync('/home/jorge/code/ref/base-backend/package.json', 'utf8'))" && echo "JSON OK"
grep -E '"sf-alvar|"sim-|RabbitMQ|migrate' ~/code/ref/base-backend/package.json && echo "FAIL" || echo "OK"
Expected: JSON OK y OK.
Task 4: tsconfig.json raíz + tsconfig.vitest.json + vitest.config.ts
Files:
-
Create:
~/code/ref/base-backend/tsconfig.json -
Create:
~/code/ref/base-backend/tsconfig.vitest.json -
Create:
~/code/ref/base-backend/vitest.config.ts -
Step 4.1: Escribir
tsconfig.jsonraíz
Contenido (copia de sf-sim quitando paths.sim-consumidor-objenious):
{
"extends": "@tsconfig/node22/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "./",
"composite": true,
"esModuleInterop": true,
"sourceMap": true,
"inlineSources": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"module": "nodenext",
"moduleResolution": "nodenext"
},
"include": [
"**/*.ts",
"tsconfig.vitest.json",
"packages/**/*.ts"
],
"exclude": [
"dist"
]
}
Escribir en ~/code/ref/base-backend/tsconfig.json.
- Step 4.2: Copiar
tsconfig.vitest.jsontal cual
cp ~/code/ref/sf-sim/tsconfig.vitest.json ~/code/ref/base-backend/tsconfig.vitest.json
Nota: este fichero extends "./tsconfig.app.json" que no existe — heredamos el bug de sf-sim sin corregirlo (decisión spec § 11). No tocar.
- Step 4.3: Copiar
vitest.config.tstal cual
cp ~/code/ref/sf-sim/vitest.config.ts ~/code/ref/base-backend/vitest.config.ts
- Step 4.4: Verificar
node -e "JSON.parse(require('fs').readFileSync('/home/jorge/code/ref/base-backend/tsconfig.json','utf8'))" && echo "OK"
grep 'sim-consumidor-objenious' ~/code/ref/base-backend/tsconfig.json && echo "FAIL" || echo "OK"
ls ~/code/ref/base-backend/tsconfig.json ~/code/ref/base-backend/tsconfig.vitest.json ~/code/ref/base-backend/vitest.config.ts
Expected: dos OK, tres ficheros listados.
Task 5: CLAUDE.md (genericizado)
Files:
-
Create:
~/code/ref/base-backend/CLAUDE.md -
Step 5.1: Escribir
CLAUDE.md
Contenido completo:
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Comandos
Yarn 4 con workspaces. Desde la raíz:
- `yarn dev` — arranca todos los servicios en watch (tsx).
- `yarn build` — `tsc --build` por workspace.
- `yarn start` — arranca los servicios desde `dist/`.
- `yarn typecheck` — `tsc --noEmit` global.
- `yarn lint` / `yarn lint:fix` — ESLint.
- `yarn format` / `yarn format:check` — Prettier.
- `yarn test` — vitest en watch (todos los packages).
- `yarn vitest run packages/<pkg>/path/file.test.ts` — un único test, single-shot.
ESM puro: los imports llevan `.js` aunque el archivo sea `.ts`. Las rutas usan path aliases por servicio (`#config/*`, `#adapters/*`, `#application/*`, `#domain/*`, `#ports/*`).
## Arquitectura
Monorepo de microservicios TypeScript ESM. Cada servicio sigue capas DDD/Hexagonal.
Packages en `packages/`:
- **`_template/`** — plantilla oficial para servicios nuevos. Cópiala, renómbrala y desarrolla desde ahí.
Capas por servicio:
- `domain/` — entidades, eventos, ports (`*.port.ts`).
- `application/` — usecases (`X.usecases.ts`), controllers, validators.
- `infrastructure/` — adapters (repositorios, clientes HTTP, routers Express `*Routes.http.ts`).
- `config/` — composition root + env.
**Errores**: `Result<E, D>` para fallos esperables (negocio, I/O). `throw` solo para invariantes rotas.
**Inyección de dependencias**: manual, por constructor con objeto `args: { dep1, dep2, ... }` (NO posicional). Cableado en `index.ts` o `config/*.config.ts` — nunca dentro de un usecase, controller o adapter. Los tipos del constructor apuntan al **port**, nunca al adapter concreto.
## Skill experta y referencias
Para cualquier trabajo no trivial de diseño, revisión o auditoría arquitectónica, invoca la skill **`sf-backend-architecture`** (modos: asesor de diseño / auditor de servicios — preguntar al usuario si ambiguo). Su auto-trigger tiene recall bajo, invócala explícitamente. Referencias en `.agents/skills/sf-backend-architecture/references/`:
- `HOUSE-STYLE.md` — carpetas, naming de ficheros, DI, Result, ESM.
- `CODE-STYLE.md` — naming a nivel código, idioma, `interface`/`type`, `any`, async, tests.
- `ANTI-PATTERNS.md` — olores conocidos.
- `AUDIT-CHECKLIST.md` — checklist exhaustivo del modo auditor.
- `EVENTS-RABBITMQ.md` — publish/consume, routing keys, retries, DLX, outbox, idempotencia. Aplica si añades RabbitMQ al proyecto; si no, ignorable.
Lee solo la referencia que necesites; no las cargues todas por defecto.
> **Nota**: la skill y sus referencias están escritas con ejemplos del repo origen sf-sim (dominio SIM, RabbitMQ). Adapta los ejemplos al dominio e infraestructura concretos de este proyecto cuando los uses.
Convenciones de contribución en [`CONTRIBUTING.md`](CONTRIBUTING.md).
@.claude/rules/code-style.md
@.claude/rules/git-conventions.md
Escribir en ~/code/ref/base-backend/CLAUDE.md.
- Step 5.2: Verificar ausencia de strings prohibidos
grep -iE '\b(sim|iccid|objenious|nos|rabbitmq|postgres|sf-alvar|savefamilygps|aplication)\b' ~/code/ref/base-backend/CLAUDE.md
Expected: solo dos resultados — la línea EVENTS-RABBITMQ.md (mención al fichero de referencia, intencional) y la línea con sf-sim en la nota (intencional, advierte el origen). Ningún otro hit. Si hay más, ajustar.
Task 6: CONTRIBUTING.md (genericizado)
Files:
-
Create:
~/code/ref/base-backend/CONTRIBUTING.md -
Step 6.1: Escribir
CONTRIBUTING.md
Contenido completo (copia de sf-sim quitando sección 1.3 Pull Requests con reviewer concreto, y la sección "Excepción para este repo (sf-sim)"):
# Guía de Contribución
¡Gracias por tu interés en contribuir a este proyecto! Este documento establece las pautas para asegurar que nuestro código se mantenga de alta calidad y que nuestra historia de git sea limpia y legible.
## 1. Flujo de Trabajo con Git
### Ramas (Branches)
Utilizamos un modelo de ramas basado en el propósito del cambio.
- **Rama Principal**: `main`. Esta rama siempre debe ser estable y desplegable.
- **Creación de Ramas**: Crea una nueva rama para cada tarea, feature o bugfix. Nunca trabajes directamente sobre `main`.
#### Convención de nombres de ramas
- **Con ticket:** `TICKET-XXX_descripcion-breve` — el ticket actúa como tipo.
- **Sin ticket:** `tipo/descripcion-breve`
Donde `tipo` puede ser:
- `feat`: Nuevas características o funcionalidades.
- `fix`: Corrección de errores.
- `docs`: Cambios solo en documentación.
- `style`: Cambios que no afectan el significado del código (espacios, formato, etc).
- `refactor`: Cambio de código que no arregla un bug ni añade una característica.
- `test`: Añadir tests faltantes o corregir existentes.
- `chore`: Cambios en el proceso de construcción o herramientas auxiliares.
Ejemplos:
- `TICKET-338_descripcion-breve`
- `feat/nuevo-gateway`
- `fix/correlation-id`
### Commits
Seguimos la convención de **Conventional Commits** para nuestros mensajes de commit. Esto ayuda a generar changelogs automáticos y facilita la lectura del historial.
#### Formato
```text
tipo(alcance): descripción breve en imperativo
[Cuerpo opcional: descripción más detallada del cambio]
[Pie opcional: referencias a issues, breaking changes]
```
#### Tipos comunes
- `feat`: Una nueva característica.
- `fix`: Una corrección de un bug.
- `docs`: Cambios en la documentación.
- `style`: Formato, puntos y comas faltantes, etc. (no cambios en la lógica).
- `refactor`: Refactorización de código en producción.
- `perf`: Cambio de código que mejora el rendimiento.
- `test`: Añadir o corregir tests.
- `chore`: Tareas rutinarias, actualizaciones de dependencias, etc.
Ejemplos:
- `feat(auth): implementar login con Google`
- `fix(db): corregir error de conexión en timeout`
- `docs(readme): actualizar instrucciones de instalación`
### Pull Requests
Adapta este apartado al hosting y proceso de revisión de tu proyecto (GitHub, GitLab, Gitea, etc.). Como mínimo:
1. Asegúrate de que tu rama está actualizada con `main`.
2. Abre un Pull Request con descripción clara de los cambios.
3. Enlaza issues relacionados.
4. Asigna revisor(es) y espera aprobación antes de fusionar.
## 2. Estilo de Código
Las convenciones de código (naming, idioma, TypeScript, tests) están en:
- [`.claude/rules/code-style.md`](.claude/rules/code-style.md) — reglas resumidas que aplican a cualquier cambio.
- [`.agents/skills/sf-backend-architecture/references/CODE-STYLE.md`](.agents/skills/sf-backend-architecture/references/CODE-STYLE.md) — detalle completo con ejemplos y justificaciones.
- [`.agents/skills/sf-backend-architecture/references/HOUSE-STYLE.md`](.agents/skills/sf-backend-architecture/references/HOUSE-STYLE.md) — convenciones de arquitectura (capas DDD, ports, Result, ESM).
## 3. Tests
Estrategia detallada en `HOUSE-STYLE.md` § Tests (vitest, tres niveles: domain puro / application con mocks de ports / infrastructure contra BD o testcontainers).
### Política por defecto (TDD)
- **Código nuevo:** se escribe con TDD (test primero) e incluye tests del nivel apropiado (domain puro si aplica; application con mocks; infrastructure si se añade un adapter).
- **Cobertura mínima del repo:** 70%. Cada PR debe mantener o aumentar la cobertura.
- **Bugs corregidos:** requieren al menos un test de regresión que reproduzca el fallo.
- **Antes de abrir un PR:** los tests existentes deben pasar (`yarn vitest run` o `/check`).
---
Equipo de Desarrollo.
Escribir en ~/code/ref/base-backend/CONTRIBUTING.md.
- Step 6.2: Verificar ausencia de referencias específicas
grep -iE 'savefamilygps|alvarsanmartin|alvar san martin|webint|sf-sim' ~/code/ref/base-backend/CONTRIBUTING.md && echo "FAIL" || echo "OK"
Expected: OK.
Task 7: README.md (nuevo)
Files:
-
Create:
~/code/ref/base-backend/README.md -
Step 7.1: Escribir
README.md
Contenido completo:
# base-backend
Monorepo backend TypeScript ESM con DDD/Hexagonal. Punto de partida para servicios nuevos del mismo perfil arquitectónico.
## Stack
- **Yarn 4** workspaces (`packages/*`).
- **TypeScript** ESM puro (imports con extensión `.js` aunque el archivo sea `.ts`).
- **Path aliases** por servicio (`#config/*`, `#adapters/*`, `#application/*`, `#domain/*`, `#ports/*`).
- **vitest** para tests, **ESLint** + **Prettier** para estilo.
## Arrancar
```bash
yarn install
yarn typecheck
yarn lint
```
## Crear un servicio
1. Copia `packages/_template/` a `packages/<nombre-servicio>/`.
2. Renombra `name` en `package.json` y actualiza `outDir` en `tsconfig.json`.
3. Crea las carpetas `domain/`, `application/`, `infrastructure/` según el patrón hexagonal.
4. Cablea dependencias en `index.ts` o `config/*.config.ts`.
## Documentación
- [`CLAUDE.md`](CLAUDE.md) — contexto de arquitectura para Claude Code.
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — flujo de git, commits, código y tests.
- [`.agents/skills/sf-backend-architecture/`](.agents/skills/sf-backend-architecture/) — skill experta con referencias detalladas (HOUSE-STYLE, CODE-STYLE, ANTI-PATTERNS, AUDIT-CHECKLIST, EVENTS-RABBITMQ).
## Origen
Scaffold extraído de [sf-sim](https://git.savefamilygps.net/SaveFamily/sf-sim). Mantiene el estilo arquitectónico (DDD/Hexagonal + EDA), genericizado y sin la infra específica de SIM (RabbitMQ, Postgres, Docker).
Escribir en ~/code/ref/base-backend/README.md.
Task 8: .claude/ — rules, commands, skills, settings
Files:
-
Create:
~/code/ref/base-backend/.claude/rules/code-style.md -
Create:
~/code/ref/base-backend/.claude/rules/git-conventions.md -
Copy:
~/code/ref/base-backend/.claude/commands/audit.md(desde sf-sim) -
Copy:
~/code/ref/base-backend/.claude/commands/check.md(desde sf-sim) -
Copy:
~/code/ref/base-backend/.claude/commands/md-lint.md(desde sf-sim) -
Copy:
~/code/ref/base-backend/.claude/skills/(skills custom + symlinks) -
Copy:
~/code/ref/base-backend/.claude/settings.local.json(desde sf-sim) -
Step 8.1: Escribir
.claude/rules/code-style.md(sin "Excepciones de este repo")
Contenido completo:
# Code style — reglas mínimas
Subset siempre cargado. Para detalle completo (ejemplos, casos borde, justificaciones) ver [`.agents/skills/sf-backend-architecture/references/CODE-STYLE.md`](../../.agents/skills/sf-backend-architecture/references/CODE-STYLE.md) — invoca la skill `sf-backend-architecture` para cargarlo bajo demanda.
## Reglas que aplican siempre
- **Comentarios en español.** Inline, JSDoc, TODO. Sin excepciones.
- **Identificadores:** español para dominio, inglés para infraestructura técnica (`httpClient`, `eventBus`).
- **Funciones y métodos:** `camelCase`, verbo en infinitivo (`getUsuario`, `publishEvent`).
- **Variables locales y parámetros:** `camelCase` (`activationDate`, `msgData`).
- **Constantes literales de módulo:** `UPPER_SNAKE_CASE` (`DEFAULT_LIMIT = 1000`). Instancias configuradas (aunque sean `const`) van en `camelCase` (`const eventBus = new RabbitMQEventBus(...)`).
- **Clases, interfaces y tipos:** `PascalCase`.
- **Sin prefijo `I`** en interfaces (`EventBus`, no `IEventBus`).
- **`type` por defecto, `interface` solo para ports** (contratos implementados por adapters).
- **Sin `enum`** — usar uniones de strings literales (`type X = 'a' | 'b'`).
- **Sin `any` en código nuevo** salvo en boundaries de I/O externo con comentario justificando. Preferencia: `unknown` + type guard.
- **`async/await` siempre.** Nada de `.then().catch()` salvo fire-and-forget consciente con comentario.
- **Tests en español:** `describe` e `it` ambos (`it('debería ...')`).
- **Política de tests (TDD por defecto):** todo código nuevo se escribe con TDD y el repo mantiene ≥70% de cobertura. Tests del nivel apropiado (domain puro / application con mocks de ports / infrastructure cuando añade adapter). Bugs corregidos requieren test de regresión que reproduzca el fallo. Estrategia detallada en `HOUSE-STYLE.md` § Tests.
- **Errores:** `Result<E, D>` para fallos esperables, `throw` solo para invariantes rotas.
- **Aplicación:** estricto en código nuevo, oportunista al tocar código existente. No PRs masivos de retrofit.
Escribir en ~/code/ref/base-backend/.claude/rules/code-style.md.
Nota: la sección "Excepciones de este repo" del fichero de sf-sim queda eliminada por completo — esas excepciones eran específicas de sf-sim (cobertura legacy, sim-objenious-cron, typo aplication).
- Step 8.2: Escribir
.claude/rules/git-conventions.md(sin reviewer específico)
Contenido completo:
# Git conventions
Subset siempre cargado. Para guía completa (PRs, flujo de revisión, propósito) ver [`CONTRIBUTING.md`](../../CONTRIBUTING.md).
## Branches
- **Con ticket:** `TICKET-XXX_descripcion-breve` — el ticket actúa como tipo.
- **Sin ticket:** `tipo/descripcion-breve` con `tipo` ∈ `feat` | `fix` | `docs` | `style` | `refactor` | `test` | `chore`.
Ejemplos: `TICKET-338_descripcion-breve`, `feat/nuevo-gateway`, `fix/correlation-id`.
Nunca trabajar directo sobre `main`.
## Commits — Conventional Commits
Formato:
```text
tipo(alcance): descripción breve en imperativo
[Cuerpo opcional]
[Pie opcional: refs a issues, breaking changes]
```
`tipo` ∈ `feat` | `fix` | `docs` | `style` | `refactor` | `perf` | `test` | `chore`.
Ejemplos:
- `feat(auth): implementar login con Google`
- `fix(db): corregir error de conexión en timeout`
- `docs(readme): actualizar instrucciones de instalación`
Descripción en español, imperativo, sin punto final, minúscula tras los dos puntos.
## Pull Requests
Adapta este apartado al hosting y revisor de tu proyecto (GitHub, GitLab, Gitea, etc.).
Escribir en ~/code/ref/base-backend/.claude/rules/git-conventions.md.
- Step 8.3: Copiar comandos
/audit,/check,/md-linttal cual
cp ~/code/ref/sf-sim/.claude/commands/audit.md ~/code/ref/base-backend/.claude/commands/audit.md
cp ~/code/ref/sf-sim/.claude/commands/check.md ~/code/ref/base-backend/.claude/commands/check.md
cp ~/code/ref/sf-sim/.claude/commands/md-lint.md ~/code/ref/base-backend/.claude/commands/md-lint.md
- Step 8.4: Copiar
.claude/skills/(incluye symlinks)
cp -a ~/code/ref/sf-sim/.claude/skills/. ~/code/ref/base-backend/.claude/skills/
cp -a preserva symlinks. Verificar:
ls -la ~/code/ref/base-backend/.claude/skills/
Expected: ver clean-ddd-hexagonal -> ../../.agents/skills/clean-ddd-hexagonal (el symlink apunta relativo, así que seguirá funcionando una vez .agents/skills/ esté poblado en Task 9).
- Step 8.5: Copiar
settings.local.jsontal cual
cp ~/code/ref/sf-sim/.claude/settings.local.json ~/code/ref/base-backend/.claude/settings.local.json
Nota: este fichero no se commitea (está en .gitignore). Se copia para que el usuario tenga las allow-rules de rtk listas en local.
- Step 8.6: Verificar
ls ~/code/ref/base-backend/.claude/rules/ ~/code/ref/base-backend/.claude/commands/ ~/code/ref/base-backend/.claude/skills/
grep -iE 'savefamilygps|alvarsanmartin|sim-objenious-cron|aplication' ~/code/ref/base-backend/.claude/rules/*.md && echo "FAIL" || echo "OK"
Expected: ficheros listados, OK.
Task 9: .agents/skills/sf-backend-architecture/ con nota inicial
Files:
-
Copy:
~/code/ref/base-backend/.agents/skills/sf-backend-architecture/(entero desde sf-sim) -
Modify:
~/code/ref/base-backend/.agents/skills/sf-backend-architecture/SKILL.md(añadir nota tras frontmatter) -
Step 9.1: Copiar la skill entera (incluye
references/yevals/)
cp -a ~/code/ref/sf-sim/.agents/skills/sf-backend-architecture ~/code/ref/base-backend/.agents/skills/
Verificar:
ls ~/code/ref/base-backend/.agents/skills/sf-backend-architecture/
ls ~/code/ref/base-backend/.agents/skills/sf-backend-architecture/references/
Expected: SKILL.md, references/, evals/ (y los .md dentro de references/).
- Step 9.2: Localizar el final del frontmatter en
SKILL.md
grep -n '^---$' ~/code/ref/base-backend/.agents/skills/sf-backend-architecture/SKILL.md | head -2
Expected: dos líneas. La segunda es el final del frontmatter; la nota se inserta justo después.
- Step 9.3: Insertar nota inicial tras el frontmatter
Edición: localizar la segunda línea --- del fichero (cierre del frontmatter) e insertar inmediatamente debajo un párrafo en blanco + el siguiente bloque:
> **Nota**: esta skill describe el estilo arquitectónico originado en el repo sf-sim (RabbitMQ + Postgres + DDD/Hexagonal + EDA). Los ejemplos están escritos contra ese dominio (SIM/ICCID/Objenious). Cuando la apliques en un repo distinto, **adapta los ejemplos** al dominio e infraestructura concretos — la arquitectura subyacente sigue valiendo.
Si el contenido inmediatamente después del frontmatter es un encabezado (p. ej. # ...), inserta la nota antes del encabezado, separada por una línea en blanco.
- Step 9.4: Verificar nota presente y única
grep -c 'esta skill describe el estilo arquitectónico originado' ~/code/ref/base-backend/.agents/skills/sf-backend-architecture/SKILL.md
Expected: 1.
- Step 9.5: Verificar symlink
.claude/skills/clean-ddd-hexagonalresuelve
readlink -f ~/code/ref/base-backend/.claude/skills/clean-ddd-hexagonal
ls ~/code/ref/base-backend/.agents/skills/clean-ddd-hexagonal/ 2>/dev/null && echo "OK" || echo "FAIL — symlink roto, falta copiar clean-ddd-hexagonal"
Si FAIL: copiar también clean-ddd-hexagonal:
cp -a ~/code/ref/sf-sim/.agents/skills/clean-ddd-hexagonal ~/code/ref/base-backend/.agents/skills/
Y reverificar.
Task 10: packages/_template/ adaptado
Files:
-
Create:
~/code/ref/base-backend/packages/_template/package.json -
Create:
~/code/ref/base-backend/packages/_template/tsconfig.json -
Create:
~/code/ref/base-backend/packages/_template/index.ts -
Create:
~/code/ref/base-backend/packages/_template/.env -
Create:
~/code/ref/base-backend/packages/_template/config/env/index.ts -
Step 10.1: Escribir
_template/package.json
Contenido (name: "template", sin amqplib, imports consolidados con #application/* añadido y #config/* añadido):
{
"name": "template",
"version": "1.0.0",
"description": "Plantilla base para servicios del monorepo",
"main": "index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "tsx index.ts"
},
"author": "",
"license": "ISC",
"packageManager": "yarn@4.12.0",
"imports": {
"#config/*.js": {
"types": "./src/config/*.ts",
"default": "./src/config/*.js"
},
"#config/*": {
"types": "./src/config/*.ts",
"default": "./src/config/*.js"
},
"#adapters/*.js": {
"types": "./src/adapters/*.ts",
"default": "./src/adapters/*.js"
},
"#adapters/*": {
"types": "./src/adapters/*.ts",
"default": "./src/adapters/*.js"
},
"#application/*.js": {
"types": "./src/application/*.ts",
"default": "./src/application/*.js"
},
"#application/*": {
"types": "./src/application/*.ts",
"default": "./src/application/*.js"
},
"#domain/*.js": {
"types": "./src/domain/*.ts",
"default": "./src/domain/*.js"
},
"#domain/*": {
"types": "./src/domain/*.ts",
"default": "./src/domain/*.js"
},
"#ports/*.js": {
"types": "./src/ports/*.ts",
"default": "./src/ports/*.js"
},
"#ports/*": {
"types": "./src/ports/*.ts",
"default": "./src/ports/*.js"
},
"#tests/*.js": {
"types": "./__tests__/*.ts",
"default": "./__tests__/*.js"
},
"#tests/*": {
"types": "./__tests__/*.ts",
"default": "./__tests__/*.js"
}
},
"dependencies": {
"@tsconfig/node22": "*",
"dotenv": "*",
"typescript": "*"
},
"devDependencies": {
"@types/node": "*",
"prettier": "*",
"tsx": "*",
"vitest": "*"
}
}
Escribir en ~/code/ref/base-backend/packages/_template/package.json.
Diferencias con sf-sim:
-
name:sim-template→template. -
Quitado
amqplib,@types/amqplib,cors,@types/cors,express,@types/express,supertest,@types/supertest. -
Añadidos
#config/*y#application/*aimports(consolidación con tsconfig paths). -
Step 10.2: Escribir
_template/tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/template",
"baseUrl": ".",
"paths": {
"#config/*": [
"config/*"
],
"#adapters/*": [
"adapters/*"
],
"#application/*": [
"application/*"
],
"#domain/*": [
"domain/*"
],
"#ports/*": [
"ports/*"
],
"#tests/*": [
"__tests__/*"
]
}
},
"exclude": [
"node_modules"
],
"include": [
"**/*.ts",
"src/**/*.d.ts"
],
"files": [
"index.ts"
]
}
Escribir en ~/code/ref/base-backend/packages/_template/tsconfig.json.
Diferencias con sf-sim: outDir sim-gestor-eventos → template, añadido "#application/*".
- Step 10.3: Copiar
_template/index.tstal cual
cp ~/code/ref/sf-sim/packages/_template/index.ts ~/code/ref/base-backend/packages/_template/index.ts
Verificar:
cat ~/code/ref/base-backend/packages/_template/index.ts
Expected:
console.log(new Date().toISOString())
export default {}
- Step 10.4: Escribir
_template/.envmínimo
ENVIRONMENT=development
Escribir en ~/code/ref/base-backend/packages/_template/.env.
Nota: .env está en .gitignore raíz, así que no se commitea. Se incluye como referencia para quien clone el template.
- Step 10.5: Escribir
_template/config/env/index.tsmínimo
export const env = {
ENVIRONMENT: String(process.env.ENVIRONMENT ?? "development"),
};
Escribir en ~/code/ref/base-backend/packages/_template/config/env/index.ts.
- Step 10.6: Verificar limpieza del _template
grep -riE 'rabbitmq|postgres|amqplib|sim-' ~/code/ref/base-backend/packages/_template/ && echo "FAIL" || echo "OK"
node -e "JSON.parse(require('fs').readFileSync('/home/jorge/code/ref/base-backend/packages/_template/package.json','utf8'))" && echo "JSON OK"
node -e "JSON.parse(require('fs').readFileSync('/home/jorge/code/ref/base-backend/packages/_template/tsconfig.json','utf8'))" && echo "JSON OK"
Expected: tres OK.
Task 11: Sustituir aplication → application en docs y skills
Files:
-
Modify: cualquier fichero del repo nuevo que mencione
aplication(typo de sf-sim). -
Step 11.1: Inventariar ocurrencias
grep -rl 'aplication' ~/code/ref/base-backend/ 2>/dev/null
Expected: lista de ficheros con la palabra. Probablemente:
.agents/skills/sf-backend-architecture/SKILL.mdo referencias.- Posiblemente comandos en
.claude/commands/.
Si la lista está vacía, saltar a Step 11.3.
- Step 11.2: Sustituir
aplication→applicationen cada fichero
Para cada fichero del listado del paso anterior, hacer la sustitución. Usa este comando por fichero (más controlado que un find -exec ciego):
sed -i 's/aplication/application/g' <ruta-fichero>
Importante: revisar si la palabra aparece en algún contexto donde es intencional (ej. una nota explicando "el typo aplication en sf-sim..."). Si la encuentras, conservar esa mención. La sustitución debe ser solo donde el typo se usa como nombre de carpeta/path alias real, no donde se discute como fenómeno histórico.
Caso esperado: en sf-sim hay menciones a la carpeta aplication como path alias / nombre de carpeta que en base-backend ya es application. Esas sí se sustituyen. Si hay un ADR / referencia que cite el typo histórico, se conserva.
- Step 11.3: Verificar limpieza
grep -rn 'aplication' ~/code/ref/base-backend/ 2>/dev/null
Expected: vacío, o solo menciones intencionales documentadas (poco probable).
Task 12: yarn install y verificación estructural
Files:
-
Genera:
~/code/ref/base-backend/yarn.lock -
Genera:
~/code/ref/base-backend/node_modules/ -
Step 12.1:
yarn installdesde la raíz
cd ~/code/ref/base-backend && yarn install
Expected: instalación sin errores. Crea yarn.lock y node_modules/.
Si falla: leer el error y corregir el package.json (raíz o _template). No avanzar hasta que yarn install pase limpio.
- Step 12.2:
yarn typecheck
cd ~/code/ref/base-backend && yarn typecheck
Expected: pasa sin errores. El único .ts en el repo es _template/index.ts, _template/config/env/index.ts y vitest.config.ts — los tres deberían compilar limpios.
Si falla: revisar tsconfig.json (raíz o _template) y arreglar.
- Step 12.3:
yarn lint
cd ~/code/ref/base-backend && yarn lint
Expected: pasa, posiblemente con avisos pero sin errores.
Nota: sf-sim no tiene eslint.config.js ni .eslintrc.* que hayamos copiado. Si yarn lint falla por config faltante, no es bloqueante para esta tarea — anótalo en el resumen final como deuda conocida del scaffold (resolver creando una eslint.config.js mínima en una iteración futura, fuera del alcance de este plan).
- Step 12.4:
yarn format:check
cd ~/code/ref/base-backend && yarn format:check
Expected: pasa o reporta diferencias menores. Si reporta diferencias, ejecutar yarn format para normalizar y volver a ejecutar format:check.
Task 13: Verificación final + commit inicial
Files:
-
Modify:
~/code/ref/base-backend/.git/(commit) -
Step 13.1: Verificación de aceptación — strings prohibidos en docs raíz
grep -iEn '\b(iccid|objenious|nos|sim-eventos|sim-shared|sim-entrada|sim-consumidor|sim-objenious|sim-gestor)\b' \
~/code/ref/base-backend/CLAUDE.md \
~/code/ref/base-backend/CONTRIBUTING.md \
~/code/ref/base-backend/README.md \
~/code/ref/base-backend/.claude/rules/*.md \
2>/dev/null && echo "FAIL" || echo "OK"
Expected: OK.
- Step 13.2: Verificación — referencias a hosting/reviewer concretos
grep -iEn 'savefamilygps|alvarsanmartin|webint-' \
~/code/ref/base-backend/CLAUDE.md \
~/code/ref/base-backend/CONTRIBUTING.md \
~/code/ref/base-backend/README.md \
~/code/ref/base-backend/.claude/rules/*.md \
2>/dev/null
Expected: solo el README.md menciona savefamilygps en la sección "Origen" (intencional, link al repo origen). Cualquier otra mención = FAIL → revisar y limpiar.
- Step 13.3: Verificación — sin typo
aplication
grep -rn 'aplication' ~/code/ref/base-backend/ 2>/dev/null
Expected: vacío (o solo menciones intencionales históricas marcadas).
- Step 13.4: Verificación — estructura completa
find ~/code/ref/base-backend -maxdepth 3 -not -path '*/node_modules*' -not -path '*/.git*' -not -path '*/.yarn*' | sort
Expected: ver al menos:
-
.editorconfig,.gitattributes,.gitignore,.yarnrc.yml -
CLAUDE.md,CONTRIBUTING.md,README.md -
package.json,tsconfig.json,tsconfig.vitest.json,vitest.config.ts,yarn.lock -
.claude/rules/code-style.md,.claude/rules/git-conventions.md -
.claude/commands/audit.md,.claude/commands/check.md,.claude/commands/md-lint.md -
.claude/skills/clean-ddd-hexagonal(symlink) -
.agents/skills/sf-backend-architecture/SKILL.md -
.agents/skills/sf-backend-architecture/references/ -
packages/_template/package.json,tsconfig.json,index.ts -
packages/_template/config/env/index.ts -
docs/superpowers/specs/,docs/superpowers/plans/ -
Step 13.5: Verificación — no se ha colado infra del stack completo
ls ~/code/ref/base-backend/{deployment,imgs,rabbitmq_plugins,build.local.sh,run.local.sh,stop.local.sh} 2>/dev/null && echo "FAIL" || echo "OK"
Expected: OK.
- Step 13.6: Stage de todos los archivos
cd ~/code/ref/base-backend && git add -A && git status --short
Expected: lista de ficheros nuevos. Verificar manualmente que .claude/settings.local.json y .env NO aparecen (deberían estar ignorados por .gitignore):
cd ~/code/ref/base-backend && git check-ignore -v .claude/settings.local.json packages/_template/.env
Expected: ambos reportados como ignorados.
- Step 13.7: Commit inicial
cd ~/code/ref/base-backend && git commit -m "$(cat <<'EOF'
chore: scaffold base-backend monorepo
Esqueleto mínimo de monorepo TypeScript ESM con DDD/Hexagonal extraído
de sf-sim. Genericizado: sin RabbitMQ, sin Postgres, sin Docker. Solo
_template en packages/. Incluye config de Claude Code (CLAUDE.md, rules,
comandos /audit /check /md-lint, skill sf-backend-architecture).
Spec: docs/superpowers/specs/2026-05-06-base-backend-scaffold-design.md
(en repo origen sf-sim).
EOF
)"
Expected: commit creado. Verificar:
cd ~/code/ref/base-backend && git log --oneline
Expected: una línea con el hash del commit inicial.
- Step 13.8: Resumen final al usuario
Generar mensaje resumen para el usuario con:
- Path del repo creado:
~/code/ref/base-backend - Commit inicial: hash + asunto
- Resultados de las verificaciones (12.2 typecheck, 12.3 lint, 12.4 format, 13.1-13.5 estructura).
- Cualquier deuda conocida (ej. si lint falló por config faltante en Step 12.3).
- Siguientes pasos sugeridos: añadir remote y
git push -u, o empezar a clonar_template/para el primer servicio.
Self-Review
Spec coverage (cada sección del spec → task que la cubre):
| Sección spec | Task |
|---|---|
| Lo que incluye / estructura de directorios | Task 1 (mkdir) + Tasks 2-10 (contenido) |
| Lo que NO se copia | Task 1 no crea esos dirs; Step 13.5 lo verifica |
§ 1 package.json raíz |
Task 3 |
§ 2 CLAUDE.md |
Task 5 |
§ 3 .claude/rules/code-style.md |
Task 8 step 8.1 |
§ 4 .claude/rules/git-conventions.md |
Task 8 step 8.2 |
§ 5 CONTRIBUTING.md |
Task 6 |
§ 6 README.md |
Task 7 |
§ 7 _template/ (package.json, tsconfig, .env, env/index.ts) |
Task 10 |
§ 8 sf-backend-architecture/SKILL.md nota |
Task 9 |
§ 9 .gitignore |
Task 2 step 2.3 |
§ 10 tsconfig.json raíz |
Task 4 step 4.1 |
§ 11 tsconfig.vitest.json y vitest.config.ts |
Task 4 steps 4.2-4.3 |
§ 12 aplication → application |
Task 11 + verificación 13.3 |
| Verificación de aceptación | Task 12 + Task 13 steps 13.1-13.5 |
Placeholder scan: revisado. Todos los pasos contienen comandos concretos o contenido completo. No hay TBD, TODO, "implement later", "similar to task N", ni descripciones sin código.
Type consistency: el plan no introduce tipos TypeScript propios (es un scaffold). Los nombres de path aliases son consistentes en package.json#imports y tsconfig.json#paths del template (Task 10): #config/*, #adapters/*, #application/*, #domain/*, #ports/*, #tests/*.
Casos edge cubiertos:
- Symlink
.claude/skills/clean-ddd-hexagonal: Task 9 step 9.5 verifica que resuelve y, si no, copia el destino. .gitignorecubre.envy.claude/settings.local.json: Task 13 step 13.6 verifica explícitamente.yarn lintpuede fallar por falta de eslint config: Task 12 step 12.3 lo trata como deuda no bloqueante (sf-sim tampoco traeeslint.config.jsen lo que copiamos).
Plan listo para ejecutar.