Stack de la vertical y cumplimiento de los estándares
Qué prescriben SV Backend §1 y SV Frontend §1, qué adopta de verdad el monorepo, y qué adopta
muebles. Medido contra los 17 workspaces el 2026-08-29.
El hallazgo
Los estándares prescriben un stack de ~30 tecnologías por capa. Medido contra el código real, se parte en tres niveles muy distintos, y tratarlos igual es cómo se acaba adoptando un broker de mensajes para servir un catálogo.
Nivel A — Universal. Innegociable, se adopta entero
Adoptado por las tres verticales de producción. No hay discusión ni ADR posible.
| Capa | Tecnología | Adopción |
|---|---|---|
| Lenguaje | Python 3.13+ | 3/3 |
| Gestor de paquetes | uv + uv.lock |
10 lockfiles en el repo |
| Framework | FastAPI | 3/3 |
| ORM | SQLAlchemy 2.0 async, sintaxis select() |
3/3 · cero db.query() legacy |
| Driver | asyncpg | 3/3 |
| Migraciones | Alembic + migration-cycle en CI |
3/3 |
| Validación | Pydantic v2 + pydantic-settings | 3/3 |
| Caché / rate limit | Redis 7 (redis-py async) + slowapi |
3/3 |
| Logging | structlog JSON | 3/3 |
| Linter | Ruff | 3/3 |
| Tipado | mypy --strict en CI |
3/3 |
| SAST | Bandit + pip-audit | 3/3 |
| Testing | pytest + pytest-asyncio + httpx | 3/3 · 1.497 pruebas |
| Contenedor | Docker multistage | 3/3 |
| Proxy | Traefik | 3/3 |
| CI | GitHub Actions | 20 workflows |
Muebles adopta los 16.
Nivel B — Adoptado por los buenos, no por todos
Aquí es donde se separa una vertical seria de una que solo funciona.
| Tecnología | Adopción | ¿Muebles? |
|---|---|---|
| OpenTelemetry + Sentry | 8 de 9 backends — falta en Events | ✅ desde el primer commit |
| Testcontainers | 5 pyproject | ✅ pruebas contra Postgres real |
| respx (mocks HTTP) | 4 pyproject | ✅ la pasarela de crédito se prueba sin red |
| react-hook-form + Zod | 13 package.json — el más adoptado | ✅ |
| Vitest | 11 | ✅ |
| Playwright (E2E) | 8 | ✅ |
| nuqs (estado en URL) | 7 | ✅ el filtro del catálogo vive en la URL o no se comparte |
| MSW | 5 | ✅ |
| Storybook | 5 | ✅ el catálogo es un design system |
| Radix UI | 4 | ✅ el selector de variantes necesita teclado resuelto |
| XState | 4 | ⚠️ solo si el separado supera 3 estados |
| openapi-ts | 2 | ✅ — ver abajo |
La regla más incumplida y más valiosa
El estándar dice: «HTTP client generado desde OpenAPI. Cero código manual de fetching.» Solo 2 de 8 frontends lo hacen.
Para muebles no es opcional. El contrato del catálogo —producto, variantes,
tipos de opción, medidas, materiales, financiación— es el payload más grande del
monorepo. Escribirlo a mano en TypeScript garantiza que se desincronice del
backend. Y el gate de deriva de OpenAPI ya existe en CI: se genera el cliente
desde el mismo openapi.json que CI verifica con git diff --exit-code.
Nivel C — Prescrito y adoptado por nadie
Cero adopción en 17 workspaces. No es descuido: es que el monorepo no ha necesitado ninguna.
| Tecnología | Adopción | Veredicto para muebles |
|---|---|---|
| NATS / RabbitMQ | 0 | No. Un catálogo no tiene eventos de dominio entre servicios. Adoptarlo sería sobreingeniería con nombre de estándar |
| Celery | 0 · ARQ 1 | No. El patrón de la casa es background_tasks.py de Travel, con referencia fuerte para que el GC no mate la task a medias |
| Temporal | 0 | No. No hay sagas |
| Granian | 0 | No. Uvicorn, como todos |
| Vault / Infisical / Doppler | 0 | ⚠️ Brecha real de todo el monorepo. Todo secreto vive en .env. Muebles no lo resuelve sola, pero tampoco lo empeora: pydantic-settings con SecretStr, listo para migrar |
Regla que dejo escrita: una tecnología de Nivel C solo entra con ADR que demuestre la necesidad. Estar en la tabla del estándar no es justificación.
El apéndice del estándar está vencido
SV_Standard_Frontend Apéndice A se titula «Q2 2026» y el repo ya lo superó:
| Paquete | Dice el apéndice | Corre el repo |
|---|---|---|
| Vite | ^6.0.0 |
8.x |
| Next.js | 15 | 16.3 |
| Zod | ^3.24.0 |
4.x |
| TypeScript | ^5.7.0 |
6.0 |
| Storybook | ^8.5.0 |
9.x |
Muebles sigue las versiones del repo, no las del apéndice. Nacer con Vite 6
sería nacer con dos majors de retraso para cumplir un documento vencido. Queda
anotado en TECH_DEBT.md del monorepo que el apéndice necesita refresco
trimestral, que es lo que él mismo exige.
Stack final de muebles
Backend: Python 3.13 · FastAPI · SQLAlchemy 2.0 async · asyncpg · Alembic ·
Pydantic v2 · Redis + slowapi · structlog · OTEL + Sentry · aioboto3 (R2) ·
Pillow · uv con pyproject.toml como fuente única (sin requirements.txt) ·
ruff · mypy strict · bandit · pip-audit · pytest + asyncio + httpx +
Testcontainers + respx + schemathesis.
Frontend admin: Vite 8 · React 19 · TS 6 · Tailwind 4 · TanStack Query 5 · Zustand · RHF + Zod 4 · Radix · nuqs · Vitest + MSW + Playwright · Storybook.
Frontend showroom: Next.js 16 App Router · el mismo núcleo · cliente HTTP generado desde OpenAPI.
Toda desviación exige ADR. Y lo que no está aquí no se instala «porque el estándar lo menciona».