Stack y decisiones
Una lectura honesta de por qué cavioca usa lo que usa. Cada decisión tiene un coste; documentarlas evita que se cuestionen otra vez en seis meses sin contexto.
Tabla de decisiones
| Pieza | Elegimos | Alternativa(s) descartada(s) | Por qué |
|---|---|---|---|
| Hosting front | Cloudflare Pages | Vercel, Netlify | Mismo edge que la API; un único proveedor y una factura. Pages soporta Next 14 vía @cloudflare/next-on-pages con limitaciones aceptadas (sin ISR, sin image optimization nativa). |
| Hosting API | Cloudflare Workers | Fly.io, Render, AWS Lambda | Cold-start ~0 ms, escala a cero, mismo plano de control que Pages/D1/R2. Limita el runtime a Web APIs (no fs, no child_process) — para cavioca eso es un feature, no un bug. |
| Framework API | Hono | Express, Fastify, Itty Router | Hecho para runtimes edge desde el día uno (Workers, Deno, Bun). API tipo Express sin el peso de Express. Compatibilidad zero con APIs Node-only que no necesitamos. |
| ORM | Drizzle | Prisma, Kysely, SQL raw | Funciona en Workers sin engine binario (Prisma no, sin el motor de queries fuera). Schemas en TypeScript, migraciones SQL planas (no opaco). Trade-off: ergonomía algo más cruda que Prisma. |
| Base de datos | D1 (SQLite) | Neon (Postgres), Supabase, PlanetScale | Vive en el mismo edge que el Worker; sin egress entre proveedores. SQLite cubre todo lo que necesitamos hoy (sin tipos JSON complejos, sin búsqueda full-text avanzada). Si alguna vez hay que migrar, el mirror Postgres en apps/api/db/migrations/pg/ da una pista de cómo. |
| Object storage | R2 | S3, Cloudflare Images | API S3-compatible sin coste de egress. Cloudflare Images se evaluó para avatares pero R2 + un transformador en Worker es más flexible y predecible en coste. |
| Auth | Passwordless por email (custom) | Auth.js, Clerk, Supabase Auth | Sesiones cookie firmadas + magic link bastan para el alcance actual. Clerk añade un proveedor más en la ruta de login y dependencia externa para reset / sesiones. Auth.js es pesado para Workers. |
| UI framework | Next 14 (App Router) | Remix, SvelteKit, Astro | Server Components encajan con el modelo "todo edge"; el ecosistema React minimiza la fricción para contribuyentes nuevos. Trade-off: Next sobre Pages tiene más aristas que Next sobre Vercel (ver Arquitectura). |
| Estilos | Tailwind + tokens CSS | CSS Modules, styled-components, shadcn copy-paste | Tailwind para utilidades; variables CSS (--color-*) en globals.css para el sistema. Permite cambiar tema sin tocar componentes. |
| Coordinación de trabajo | MeshKore (.meshkore/) | Linear, GitHub Projects | El cluster vive dentro del repo, junto al código. Permite que agentes y operadores trabajen contra el mismo source of truth sin cambiar de contexto. |
| Empaquetado / monorepo | npm workspaces (planos) | pnpm, Turborepo, Nx | El repo es pequeño y los builds rápidos no justifican el cache distribuido todavía. Migrar a pnpm más adelante es barato. open |
Decisiones explícitas que no vamos a tomar pronto
Más útil que la tabla anterior, a veces: lo que sabemos que no vamos a cambiar en el próximo trimestre, para que no se gaste energía debatiéndolo.
- No vamos a salir de Cloudflare. El acoplamiento es deliberado: una factura, un plano de control, un edge. Si algún día se rompe, sabremos qué refactor toca; hoy es un acelerador.
- No vamos a meter Postgres en producción. El mirror
pges para dev local. Si D1 se queda corto, antes evaluamos sharding o caches específicos que un cambio de motor. - No vamos a montar un panel de admin custom. Consultas directas a D1
(
wrangler d1 execute) cubren las operaciones manuales que necesitamos. - No vamos a añadir un sistema de jobs / colas hasta que haya un caso de uso real con dos workloads compitiendo. deferred Cuando llegue, el candidato natural es Cloudflare Queues.
Lo que sí está abierto
open Image optimization — Pages no la sirve nativa. Hoy las imágenes se sirven tal cual o pasan por una transformación manual en Worker. Decidir entre Cloudflare Images o un transformer propio sigue pendiente.
open Observabilidad — Workers tiene logs y tail, pero no hay panel de métricas custom. Cuando el tráfico justifique el coste, toca evaluar Workers Analytics Engine vs. un colector externo.
open Self-hosting del cluster MeshKore en infra ajena a Cloudflare no está soportado. El estándar es portable, pero los bindings de D1/R2 atan la API al edge de Cloudflare. Documentar un perfil "self-host on Postgres" es trabajo futuro.
Cómo evolucionar este documento
Si añades una decisión nueva al stack o cambias una existente, edita esta página en la PR donde toca el código. Una decisión sin par "qué + por qué" escrito en alguna parte es deuda técnica disfrazada de productividad.