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:
identityno depende de nada. Es una fundación, junto acore, ni por encima ni por debajo.core,loyalty,messagingycrmnunca importan las tablas deidentity. 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.createse 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) ycore(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 leeridentity 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 agregaidentity; la regla de FK entre schemas no cambia (solo haciacore—identityno 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 decore — 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.