Skip to main content
Estado: Propuesto · Fecha: 2026-08-17 · Extiende: DEC-B1 · Refs: DEC-D5, DEC-D6, ADR-009, ADR-010
Traducción. Autoritativo: ../../adr/adr-022-identity-bounded-context.md.

Contexto

DEC-B1 nombró cuatro schemas de Postgres: core, loyalty, messaging, crm. La autenticación y la autorización nunca se asignaron a ninguno, porque hasta ahora se trataban como infraestructura que simplemente existía. No pueden quedar sin asignar. La plataforma necesita usuarios que entran a una consola, roles que agrupan permisos, API keys y clientes OAuth que llevan esos mismos roles como máquinas (DEC-D5), un provider OAuth2 para que los terceros se integren, MFA, gestión de sesiones e impersonación de soporte acotada en el tiempo. Eso es un dominio con sus propias tablas, invariantes y superficie de cumplimiento — no una librería. La pregunta real es dónde va. Había tres opciones. Dentro de core. Tentador, porque core ya tiene el realm de member (ADR-010, FS-CORE-0009): un member es un contacto autenticado, así que la auth de member sí pertenece junto al contacto. Pero los usuarios de consola no son contactos. Son el personal de nuestros clientes, una población totalmente distinta con otro ciclo de vida, otro radio de daño y otra posición regulatoria — para los usuarios de consola Softcrum es el responsable, mientras que para los contactos es el encargado (DEC-J1). Poner ambos en un schema pondría los datos de nuestros propios usuarios y los de los clientes de nuestros clientes bajo el mismo techo, que es exactamente el límite que traza el DPA. Repartido en cada módulo. Cada módulo dueño de sus propios permisos. Rechazado de inmediato: el registro de permisos tiene que ser global para que {module}.{resource}.{action} signifique algo, y un rol que no puede cruzar módulos no es un rol. Su propio contexto. Más superficie de gobierno, un schema más que razonar.

Decisión

Un quinto bounded context, identity (schema identity), es dueño del realm organizacional y del plano de control de acceso de la plataforma. Contiene: organizaciones y usuarios, membresías, invitaciones, el registro de permisos, roles y asignaciones, métodos de autenticación, login social y SSO empresarial, MFA, sesiones y dispositivos, credenciales de máquina (API keys y clientes OAuth), el provider OAuth2, y la impersonación de soporte. El realm de member se queda en core (FS-CORE-0009), sin cambios. Un member es un contacto autenticado y el contacto pertenece a core; mover las sesiones de member a identity crearía una dependencia de identity hacia core sin beneficio, y difuminaría la separación de realms que ADR-010 hace estructural. Reglas de dependencia, agregadas al conjunto existente:
  • identity no depende de nada. Es una fundación, junto a core, ni por encima ni por debajo.
  • core, loyalty, messaging y crm nunca importan las tablas de identity. Reciben un contexto de autorización ya resuelto desde la capa de API.
  • El registro de permisos lo consume cada módulo como constante de build, no como FK de runtime. Una ruta que declara loyalty.redemptions.create se verifica contra un union generado, el mismo mecanismo que los catálogos paramétricos.
  • Existen dos realms de auth y nunca se superponen: identity (organizacional) y core (member). Un token de uno nunca puede satisfacer al otro, por construcción y no por verificación.

Consecuencias

+ Los datos de nuestros propios usuarios quedan en un schema distinto de los datos de los clientes de nuestros clientes, lo que calza con la división responsable/encargado que el DPA ya describe. Eso es una propiedad de cumplimiento, no de prolijidad. + Un registro global de permisos se vuelve posible, que es lo que DEC-D5 necesita y lo que renderiza una pantalla de consentimiento OAuth2. + El realm organizacional se puede endurecer de forma independiente — política de sesión más estricta, MFA obligatorio, auditoría más apretada — sin tocar la experiencia del member. + Better Auth se configura dos veces, en dos lugares, lo que hace visible la separación de realms en el árbol de archivos en vez de dejarla como una convención que alguien tiene que recordar. Un quinto contexto que gobernar, y la frase “cuatro bounded contexts” de la constitución hay que actualizarla. Dos configuraciones de Better Auth que mantener y actualizar en conjunto. El contexto de autorización hay que hilarlo desde la capa de API hacia cada módulo, ya que los módulos no pueden leer identity directamente. Ese es el costo del límite y es deliberado: un módulo que pudiera consultar roles directamente terminaría aplicándolos de forma inconsistente.

Trabajo de seguimiento

  • AGENTS.md §1 y §3: cinco contextos, no cuatro.
  • standards/data.md §1: se agrega identity; la regla de FK entre schemas no cambia (solo hacia coreidentity no tiene ninguna FK entre schemas).
  • standards/api.md: el registro de permisos pasa a ser un artefacto generado con su propio chequeo de CI.
  • Spec de módulo, PRD y nueve feature specs bajo modules/identity/.

Alternativas consideradas

Auth dentro de core — perdió por el límite responsable/encargado. La posición regulatoria de nuestros usuarios y la de los clientes de nuestros clientes es distinta, y un límite de schema es el lugar más barato para hacerlo explícito. Un proveedor de identidad de terceros (Auth0, Clerk, WorkOS) en vez de Better Auth — genuinamente atractivo para MFA, SSO y el provider OAuth2, que son trabajo real. Perdió por tres razones: el pricing por MAU sobre una plataforma cuyo propio pricing es por contacto se apila mal; ser provider OAuth2 para las integraciones de nuestros tenants es una superficie de producto de primera clase que no deberíamos arrendar; y la regla de stack cerrado hace que adoptar uno sea un ADR propio con camino de migración, no un default. Better Auth se mantiene, y esta decisión se revisa si MFA o SSO resultan más caros de construir de lo esperado.