ADR-XXX: Título Descriptivo
Estado
Section titled “Estado”[Propuesta | Aceptada | Rechazada | Deprecada] - [Fecha: YYYY-MM-DD]
Contexto
Section titled “Contexto”Problema o necesidad que motiva la decisión.
[Explicar la situación que requiere tomar una decisión arquitectónica. Incluir:
- ¿Qué problema estamos resolviendo?
- ¿Qué limitaciones o restricciones existen?
- ¿Qué requisitos funcionales o no funcionales influyen?
- ¿Qué factores de negocio o técnicos son relevantes?]
Ejemplo:
El sistema necesita soportar múltiples clientes (multi-tenancy) con datos completamente aislados. Actualmente, no existe infraestructura para esto y debemos decidir cómo implementar el aislamiento de datos sin comprometer rendimiento ni escalabilidad.
Decisión
Section titled “Decisión”Qué se decidió hacer.
[Describir la decisión tomada de forma clara y concisa. Incluir:
- Enfoque seleccionado
- Tecnologías o herramientas involucradas
- Patrón de diseño aplicado
- Principios arquitectónicos seguidos]
Ejemplo:
Implementaremos multi-tenancy usando schema-per-tenant en PostgreSQL. Cada cliente tendrá su propio schema dentro de una única base de datos. Usaremos Foreign Data Wrappers (FDW) para acceso cruzado cuando sea necesario.
Consecuencias
Section titled “Consecuencias”Positivas (Beneficios)
Section titled “Positivas (Beneficios)”- [Beneficio 1: Por qué esta decisión mejora el sistema]
- [Beneficio 2: Ventaja técnica o de negocio]
- [Beneficio 3: Impacto positivo en operaciones o desarrollo]
Ejemplo:
- ✅ Aislamiento completo de datos: Cada tenant tiene su propio schema, eliminando riesgo de data leakage
- ✅ Escalabilidad horizontal: Podemos mover schemas a servidores diferentes usando FDW
- ✅ Migrations independientes: Cada tenant puede tener versiones diferentes de schema si es necesario
Negativas (Trade-offs)
Section titled “Negativas (Trade-offs)”- [Trade-off 1: Qué compromiso o desventaja implica]
- [Trade-off 2: Complejidad adicional introducida]
- [Trade-off 3: Limitación técnica o de recursos]
Ejemplo:
- ❌ Complejidad de pooling: Necesitamos gestionar conexiones por schema, no solo por database
- ❌ Migrations complejas: Aplicar cambios de schema a N tenants requiere scripting robusto
- ❌ PostgreSQL dependency: Fuertemente acoplados a PostgreSQL (no es fácil migrar a otra DB)
Alternativas Consideradas
Section titled “Alternativas Consideradas”Opción A: [Nombre de alternativa]
Section titled “Opción A: [Nombre de alternativa]”Descripción: [Qué proponía esta alternativa]
Rechazada porque: [Razón específica de rechazo]
Ejemplo:
Database-per-tenant: Cada cliente con su propia base de datos PostgreSQL.
Rechazada porque: Gestión operacional compleja con cientos de DBs. Costos de infraestructura elevados (cada DB consume recursos mínimos). Backups y migrations serían un pesadilla operacional.
Opción B: [Nombre de alternativa]
Section titled “Opción B: [Nombre de alternativa]”Descripción: [Qué proponía esta alternativa]
Rechazada porque: [Razón específica de rechazo]
Ejemplo:
Single-schema con tenant_id: Todas las tablas tienen columna
tenant_idpara filtrar datos.Rechazada porque: Riesgo alto de data leakage (un
WHERE tenant_id = ?olvidado expone datos de todos los clientes). Queries complejas con JOINs requieren vigilancia constante. No hay aislamiento real a nivel de DB.
Referencias
Section titled “Referencias”Implementación:
ruta/al/codigo/relevante.ts- Donde se implementó esta decisión- Documentación técnica - Detalles de implementación
Discusión original (si aplica):
- GitHub Issue #123
- [Slack thread] - Enlace a discusión interna
Referencias externas:
- PostgreSQL Schemas - Documentación oficial
- Multi-tenancy Patterns - Artículo de referencia
Notas Adicionales
Section titled “Notas Adicionales”[Cualquier información adicional relevante:
- Lecciones aprendidas durante la implementación
- Métricas de rendimiento observadas
- Feedback del equipo
- Consideraciones para futuras revisiones]
Ejemplo:
La implementación inicial tomó 2 sprints. Observamos que el pooling por schema añadió ~15% de overhead en tiempo de respuesta, pero el aislamiento de datos lo justifica. Consideraremos optimizar pooling en futuro si el overhead crece.