cavioca

Stack y decisiones

5 min

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

PiezaElegimosAlternativa(s) descartada(s)Por qué
Hosting frontCloudflare PagesVercel, NetlifyMismo 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 APICloudflare WorkersFly.io, Render, AWS LambdaCold-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 APIHonoExpress, Fastify, Itty RouterHecho 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.
ORMDrizzlePrisma, Kysely, SQL rawFunciona 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 datosD1 (SQLite)Neon (Postgres), Supabase, PlanetScaleVive 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 storageR2S3, Cloudflare ImagesAPI 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.
AuthPasswordless por email (custom)Auth.js, Clerk, Supabase AuthSesiones 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 frameworkNext 14 (App Router)Remix, SvelteKit, AstroServer 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).
EstilosTailwind + tokens CSSCSS Modules, styled-components, shadcn copy-pasteTailwind para utilidades; variables CSS (--color-*) en globals.css para el sistema. Permite cambiar tema sin tocar componentes.
Coordinación de trabajoMeshKore (.meshkore/)Linear, GitHub ProjectsEl 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 / monoreponpm workspaces (planos)pnpm, Turborepo, NxEl 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 pg es 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.