El móduloDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/DevCarlosRodriguez/Documentacion-Arccnova-2.0/llms.txt
Use this file to discover all available pages before exploring further.
Identity de ArccNova v2 no delega la autenticación a un proveedor externo: ArccNova actúa como su propio IdP con JWT HS256. Sobre esa base de identidad, ADR-015 extiende el modelo de autorización con un RBAC granular y dinámico —roles personalizables por empresa, matriz de permisos por submodulo y acción, y permisos individuales por usuario— que entra en vigor desde la fase inicial del proyecto. ADR-019 cierra el ciclo de tiempo real: los cambios de estado de pagos se notifican al navegador mediante Server-Sent Events.
ADR-003 — Identity Propio con JWT HS256
Fecha: 2026-06-05 | Estado: Aceptado (actualizado 2026-06-10)Contexto
ArccNova necesita autenticación multi-tenant con claims personalizados (tenant_id, branch_id, user_pk, role). Se evaluaron las alternativas de mercado frente a implementar el propio issuer.
Opciones evaluadas
| Opción | Descripción |
|---|---|
| Identity propio JWT HS256 ✅ | ArccNova implementa su propio issuer con BCrypt + JWT |
| Auth0 | SaaS de identidad gestionado |
| Keycloak | IdP open source self-hosted |
| AWS Cognito | IdP gestionado de AWS |
Decisión
Identity propio. El móduloIdentity de ArccNova implementa login, registro, refresh token rotativo y emisión de JWT HS256 con claims personalizados. ArccNova actúa como IdP del ecosistema: los sistemas futuros validarán el JWT contra los endpoints de ArccNova sin requerir un IdP externo separado.
Estructura de claims del JWT
El claim
imp (impersonación) indica si el token fue emitido por un SysAdmin actuando en nombre de otro usuario. El branch_id cambia cuando el usuario selecciona un proyecto diferente en el WebClient; el backend siempre lee estos valores del JWT y nunca del body de la petición.Consecuencias
- Sin costo recurrente de IdP externo.
- Control total del schema de claims y del ciclo de vida del token.
- El equipo es responsable de la seguridad del issuer (almacenamiento seguro de la clave HS256).
- Se debe documentar el contrato OIDC-compatible para integraciones futuras.
Actualización 2026-06-10
La decisión se mantiene. Dos ajustes de contexto: (1) RH/Nómina ya no es un sistema externo que valide tokens — vive dentro del monolito (ADR-009); el rol de IdP del ecosistema queda reservado para sistemas futuros reales. (2) El modelo de autorización sobre este Identity se extiende a RBAC granular y dinámico — ver ADR-015.ADR-015 — RBAC Granular y Dinámico en Identity
Fecha: 2026-06-10 | Estado: Aceptado (actualizado 2026-06-11)Contexto
El módulo Identity implementado opera con 4 roles fijos (SysAdmin, Admin, Agent, Auditor). Los requerimientos del núcleo piden roles personalizados por empresa, una matriz de permisos por área y acción, y permisos individuales por usuario. Congelar los 4 roles y refactorizar después invalidaría buena parte de las historias de usuario ya escritas.
Opciones evaluadas
| Opción | Descripción |
|---|---|
| RBAC granular desde la base ✅ | Tablas de Roles, Permisos y Membresías; matriz área × acción; overrides por usuario |
| Congelar los 4 roles fijos | Posponer el RBAC como épica posterior; refactor crítico después |
| Autorización por políticas en código | Policies estáticas de ASP.NET sin administración por el usuario |
Decisión
El modelo de datos de Identity se extiende desde la fase inicial con cinco componentes:Roles personalizados por tenant
Tabla
Roles con TenantId. El rol CEO es protegido (IsProtected = true): no editable ni eliminable por ningún usuario del tenant.Catálogo de permisos: matriz submodulo × acción
Tabla
Permissions con Code único, ModuleGroup, Submodule y Action (Ver / Escribir / Actualizar / Eliminar / Descargar). Arranca con los 18 permisos confirmados en 5 áreas (conceptos de mora, cobros, ventas, contratos, usuarios) y es extensible.Permisos individuales por usuario
Tabla
UserPermissions que otorga permisos adicionales por encima del rol del usuario, con registro del usuario que los concedió (GrantedByUserId).Membresías usuario-branch con rol propio
Tabla
UserBranches con campo RoleId, dejando la estructura lista para que el CRM asocie roles a proyectos sin refactor. Un usuario puede tener roles y permisos distintos en proyectos distintos (confirmado en C12).Permisos protegidos (C33/C34)
La lista de 18 permisos protegidos es exhaustiva y cubre exactamente 5 áreas:| Área | Acciones protegidas |
|---|---|
| Conceptos de mora | Editar, Eliminar |
| Cobros | Ver, Escribir, Actualizar, Eliminar |
| Ventas | Ver, Escribir, Actualizar, Eliminar |
| Contratos | Ver, Escribir, Actualizar, Eliminar |
| Usuarios | Ver, Escribir, Actualizar, Eliminar |
TenantProtectedActions y pueden desactivarse (la acción deja de pedir verificación adicional). El rol CEO y Admin están exentos.
Política de contraseñas (decisión interna 22)
La política aplica a todo el sistema —login, alta de usuarios y restablecimiento— y corrige la inconsistencia detectada en los documentos fuente (C06 decía “8 dígitos”):- Mínimo 8 caracteres
- Al menos una mayúscula
- Al menos una minúscula
- Al menos un carácter especial
Consecuencias
- Es la épica más grande sobre un módulo ya implementado; precede a casi todo el control de acceso fino.
- Los guards del WebClient pasan de rol fijo a permiso granular — el contrato del JWT/bootstrap debe exponer los permisos efectivos del usuario.
- La auditoría permanente implica crecimiento de datos: tabla particionable a futuro.
ADR-019 — Tiempo Real con Server-Sent Events (SSE)
Fecha: 2026-06-10 | Estado: AceptadoContexto
El módulo Collections requiere tiempo real para el contador de cobros no identificados y los cambios de estado de pagos en línea. El v1 usa SignalR (WebSockets). El despliegue v2 es distroless detrás de nginx (ADR-011) y se busca mantener el stack sobre HTTP puro.Opciones evaluadas
| Opción | Descripción |
|---|---|
| SSE nativo de .NET 10 ✅ | TypedResults.ServerSentEvents; unidireccional servidor→navegador |
| SignalR (WebSockets) | Bidireccional; requiere upgrade de protocolo a través del proxy |
| Polling | Simple pero ineficiente y con latencia percibida |
Decisión
Tiempo real con SSE usando el soporte nativo de .NET 10 (TypedResults.ServerSentEvents). No se usa SignalR ni WebSockets.
Qué usa SSE
- ✅ Usa SSE
- ❌ No usa SSE
- Cobros no identificados: contador en tiempo real en la pantalla de cobranza cuando llega un pago cuyo
SaleId/ContactIdes null. - Confirmación de pagos en línea: Stripe notifica por webhook (HTTP POST) al backend → el backend transmite el cambio de estado por SSE al navegador del usuario.
Flujo de pago en línea con SSE
Configuración obligatoria de nginx
Consecuencias
- Stack HTTP puro: sin negociación de upgrade ni configuración de WebSockets en el proxy.
- SSE es unidireccional — suficiente para notificar estado; las acciones del usuario siguen siendo requests normales.
- Cada conexión SSE mantiene un request abierto: dimensionar keep-alives y límites de conexiones de nginx y Kestrel.
- El patrón webhook + SSE queda sentado con Stripe y se reutiliza cuando el CRM incorpore sus canales de tiempo real.