Skip to content

ADRs — Registro de decisiones

Historial curado de decisiones de arquitectura y puntos clave del proyecto. Es la fuente única para recuperar contexto de decisiones — no hace falta consultar tareas archivadas del dueño.

Cómo agregar una: al cerrar una tarea que tomó una decisión no obvia (modelado, regla de negocio, tradeoff técnico), agrega un ADR nuevo aquí con el próximo número y súmalo a la tabla.

#Decisión
0001Multi-tenant por organizationId
0002Tres clientes desacoplados: backend, admin web, mobile
0003Captura única del dato; el reporte semanal se genera, no se llena
0004Polyrepo con rama compartida por tarea
0005Módulos de negocio se implementan backend → admin → mobile
0006Envelope de respuesta uniforme {data, message, statusCode}
0007organizationId siempre se lee del JWT
0008Config tipada y validación fail-fast (Joi)
0009Hashing con argon2, no bcrypt
0010Tabla única verification_tokens para todos los tipos de token
0011Jobs y crons centralizados en src/jobs/
0012Swagger obligatorio en cada endpoint
0013Registro de cuenta en 3 fases (solo admin web) — superseded por 0050
0014Refresh token en cookie httpOnly / Drift; access solo en memoria; nunca localStorage
0015Los permisos no viajan en el JWT
0016backfillDefaultPermissions es conservador
0017Admin: arquitectura feature-based, cada feature es isla
0018Admin: TanStack Query para servidor, Zustand solo para sesión
0019Admin: estado del menú lateral vive en AppLayout, no en NavContent
0020Admin: Shadcn + tokens semánticos, prohibido hardcodear colores
0021Mobile: patrón offline-read + online-write
0022Mobile: derivados y summaries del backend se cachean en Drift
0023Mobile: Drift fijado a >=2.28 <2.31
0024Gates de cierre: qué corre automático y qué queda excluido a propósito
0025CI por repo, lint después de prisma generate
0026Mobile: CI pinnea la versión de Flutter, no usa channel: stable
0027Piscinas: tope lb/ha único por piscina
0028Ciclos: apertura por siembra o transferencia; invariante de una activa por piscina
0029Muestreos: biomasa solo existe si hay Population el mismo día que el Sampling
0030Alimentación: FCR usa la biomasa del último muestreo disponible
0031Parámetros de agua: se registran por PISCINA, no por ciclo
0032Eventos: piscina obligatoria, ciclo opcional; onDelete SetNull
0033Raleos y cosecha final: una sola entidad Harvest con type
0034La documentación se muda a camaroneras_docs (VitePress)
0035El spec OpenAPI cubre solo bodies de request, no responses (superada por 0036)
0036El spec OpenAPI cubre también los responses (DTOs de respuesta en el backend)
0037CI backend: cache de node_modules/Prisma con actions/cache, no job+artifact
0038Capa de plataforma (superadmin) cross-tenant con superficie de auth aislada
0039Panel de plataforma en repo propio + enforcement server-side de mustChangePassword
0039Tests e2e: base aislada y desechable, reset por SQL directo (no migrate reset)
0040Tests e2e: bootstrap compartido y bind explícito en IPv4 loopback
0041Seed de demo: idempotencia por piscina y guard de entorno por nombre de base
0042Guía de alimentación: unidades del factor de la curva (kg = c/m² × ha × factor)
0043Raleos: extender Harvest con estado planificado/ejecutado (no un modelo aparte)
0044Reporte semanal: ventana móvil de 7 días (no pestañas de calendario), sin export en v1
0045Paginación server-side opcional con meta global en el envelope
0046Dashboard de producción: ruta /produccion (no /dashboard) y kpis no filtrables
0047No extraer un componente de tabla compartido para ResumenTable/SectorTable
0048RBAC de plataforma con tablas propias (no reuso del modelo de tenant)
0049Alta delegada de tenants: reusar /auth/onboarding, no reimplementarlo
0050Alta de cuentas solo por invitación: retiro del signup público
0051Gestión cross-tenant de usuarios y roles de tenant desde plataforma
0052Operator pasa de solo-lectura a operador de soporte
0053Hardening del invariante "último administrador" con advisory locks
0054Mobile: sync de catálogos (sectores, piscinas, tipos de equipo) usa hard replace, no upsert
0055Mobile: cola de escrituras offline (outbox) con idempotencia best-effort en backend
0056Mobile: política de reintentos del outbox y preservación entre sesiones
0057Motor de scoring KPI: umbrales configurables en BD, "sin dato" uniforme y recomendación por reglas
0058Cycle gana seasonYear/seasonNumber: temporada por orden cronológico, no por conteo al crear
0059FCA por talla reusa los tramos del criterio FCA; Prioridades es página propia con endpoint dedicado
0060Sobrevivencia estimada: censo por consumo con el factor crudo, no kgSugeridosDia
0061Las fórmulas de valores calculados viven en referencia/, no en los *-flow.md
0062Topología de despliegue: Railway para el runtime, Cloudflare Pages para los estáticos
0063Redis se configura con una connection string (REDIS_URL), no con host y puerto

Actualizado: