SaaS Starter

AI-ready

Cómo este boilerplate está optimizado para que un agente de IA escriba código que funcione.

Última actualización 3 may 2026

Filosofía

Los LLMs no leen tu mente — leen tu código. Un boilerplate AI-friendly minimiza la ambigüedad: tipos exactos, patrones repetidos, ADRs explícitos.

Tipos como contrato

@app/contracts exporta schemas Zod y tipos inferidos. Un agente que mira el contract sabe exactamente qué payload mandar y qué esperar de vuelta. Sin documentación que se desactualiza.

import { CreateUserInput } from '@app/contracts';
// El tipo es la doc.

Branded IDs

UserId ≠ OrganizationId ≠ string. Si un agente confunde uno con otro, el TS server lo detecta antes del commit. Menos bugs sutiles.

Result en lugar de throws

Los LLMs propagan errores mejor cuando son valores. Result<T, E> se mapea naturalmente a JSON, a tests, a docs.

ADRs versionados

docs/adr/ documenta decisiones arquitectónicas (por qué BetterAuth, por qué billing agnóstico al proveedor). Un agente lee la ADR antes de proponer un cambio que la contradiga.

Generadores

bun run gen:domain <name> genera el scaffold de un agregado completo (entity, VOs, repo, use cases, controller, tests). El agente sigue el patrón existente sin inventar uno nuevo.

MCP-friendly

Schemas de Prisma + OpenAPI generado en apps/server/openapi.json. Cualquier agente con tools de OpenAPI explora el API sin adivinar.

Patrones repetidos

Cada agregado tiene la misma estructura (domain/, application/, infrastructure/, interface/). Un LLM aprende el patrón en un dominio y lo replica en el siguiente sin fricción.

Guardrails del endpoint de chat

POST /api/v1/ai/chat cuesta plata real, así que está blindado:

  • El cliente solo puede enviar mensajes user y assistant. El rol system lo rechaza el schema de @app/contracts.
  • model debe ser AI_MODEL o estar en AI_ALLOWED_MODELS; cualquier otro da 422 antes de llamar al upstream.
  • La salida está limitada por AI_MAX_OUTPUT_TOKENS.
  • Si el cliente se desconecta, el stream upstream se aborta para que una pestaña cerrada deje de gastar tokens.

[!NOTE] En Bun 1.3.x un POST cuyo body ya fue consumido no emite evento de desconexión, así que el abort por desconexión puede no dispararse. Dos límites duros lo cubren: AI_MAX_OUTPUT_TOKENS y AI_STREAM_TIMEOUT_MS (default 120000), un tope de tiempo que aborta la llamada upstream. El stream también se aborta si una escritura a la respuesta falla o la respuesta se destruye.

En esta página