Este documento define las entidades, relaciones y reglas de integridad del sistema. Es la fuente de verdad para el schema de Prisma (prisma/schema.prisma) y para toda decisión de persistencia.
Cuatro principios que gobiernan todo el modelo:
tenantId. No hay tabla global de empleados; hay empleados de un tenant.source, confidence y primaryOwner.Tenant — cada empresa clienteCampos:
id, name, enrollmentCode (código de empresa; ADR-006)logoUrl, primaryColor, secondaryColor (co-branding; ADR-003)aggregationMinSegmentSize (umbral mínimo para dashboards; ADR-001; default 5)defaultLanguage (ADR-005; solo es en MVP)status (active, pilot, suspended)methodologyVersionId, questionBankVersionId, scoringVersionId, interventionCatalogVersionIdcorporateEmailDomain (para advertir al empleado que use email personal)createdAt, activatedAtSegment — subdivisiones dentro de una empresaDepartamentos, sedes, roles. Permite jerarquía.
Campos: id, tenantId, name, type (department, location, role, custom), parentSegmentId, createdAt
Employee — el usuario final del beneficioVisibilidad: la empresa nunca ve esta entidad individual; solo agregados que la deriven.
Campos:
id, tenantIdpersonalEmail (email personal; ADR-006; ADR-008)enrollmentCodeUsedauthMethod (magic_link, google_oauth)demographicData (JSON: edad, dependientes, etc. — data mínima autodeclarada)status (registered, active, opted_out)createdAt, lastActiveAtEmployeeSegment — relación N:M empleado-segmentoUn empleado puede pertenecer a más de un segmento.
Campos: employeeId, segmentId, assignedAt
TenantAdmin — usuarios del portal de RRHHCampos: id, tenantId, email, role (viewer, admin), createdAt, lastActiveAt
PlatformUser — usuarios del admin interno de CaudallRoles (spec §53): platform_owner, methodologist, product_admin, analyst, viewer.
Campos: id, email, role, createdAt, lastActiveAt
Methodology (versionada)Campos: id, version, status (draft, active, deprecated), publishedAt, publishedById, createdAt
DimensionLas 5 dimensiones del CFHI.
Campos:
id, code (CONTROL, RESILIENCE, DEBT, SAVING, PLANNING)nameI18nKey, descriptionI18nKeyweight (parametrizable; default 20% cada una)methodologyIdConstructConstructos dentro de dimensiones (spec §5).
Campos:
id, dimensionId, code (ej. CTRL_MARGIN)nameI18nKeyweightWithinDimensionVariableVariables maestras (spec §10-14, 17).
Campos:
id, code (ej. CTRL_CASHFLOW)variableType (score, context, behavioral, readiness, derived)dimensionId (nullable — context y behavioral no pertenecen a dimensión)possibleStates (JSON: array de los valores enumerados de la spec)primaryOwnerConstructId (spec §6: cada variable de scoring tiene UN dueño)QuestionBank (versionada)Campos: id, version, status, createdAt
QuestionPreguntas del banco adaptativo (spec §22, §43).
Campos:
id, bankId, code (ej. CTRL-01)textI18nKeydimensionId, variableTargetId, constructTargetIdaskIfRule (expresión JSON sobre variables ya conocidas)skipIfRule, doNotAskIfRulebasePriority, informationValue, safetyValue, scoringValue, routingValueuncertaintyReduction, burdeninferenceSubstitutionAllowed (boolean)minConfidenceToSkip (default 80)status (draft, active, deprecated)AnswerOptionOpciones de respuesta con la evidencia que producen.
Campos: id, questionId, textI18nKey, evidenceProduced (JSON: qué Evidence genera)
ScoringConfig (versionada)Configuración de pesos y reglas de N/A (spec §45).
Campos: id, version, status, dimensionWeights (JSON), constructWeights (JSON), naRedistributionRule (JSON)
ForbiddenInferenceInferencias explícitamente prohibidas (spec §9).
Campos: id, sourceVariableCode, sourceValue, targetVariableCode, targetValue, reason
Evidence — cada dato que llega al sistemaEl corazón de la spec. Nunca se borra; los cambios generan nueva Evidence, no sobreescriben.
Campos:
id, tenantId, employeeIdsource (question, inference, integration)questionId (nullable), answerOptionId (nullable)variableId, value (JSON)reliability (direct, strong_inference, weak_inference)confidence (0–100)primaryOwnerConstructIdtimestamp, period (nullable — a qué momento se refiere)methodologyVersionId (con qué versión se capturó)VariableState — valor computado actual de cada variable para un empleadoCampos:
employeeId, variableIdvalue (JSON), confidence, statederivedFromEvidenceIds (array — trazabilidad)updatedAtConstructScoreCampos: employeeId, constructId, score (0–100), confidence, computedAt
DimensionScoreCampos:
employeeId, dimensionIdscore, state (MET, PARTIAL, UNMET, CRITICAL, NA), confidencedriverVariableId (variable identificada como principal driver)FinancialState — snapshot vivo por empleado (spec §15)Campos:
employeeIdcfhiScore, cfhiConfidenceuserGoal (JSON), systemPriority, rootCauseeligibility (JSON), finReadiness, behReadinesslastDiagnosticCompletedAtSafetyFlagIndependiente del score (spec §19).
Campos: id, employeeId, flagCode (ej. CRITICAL_DEBT, DEBT_PAYMENT_STRESS), raisedAt, evidenceIds (array), resolvedAt (nullable)
InterventionCatalog (maestro, versionado — ADR-004)Campos: id, version, status, createdAt
InterventionParte del catálogo maestro.
Campos:
id, catalogIdtype (educational_content, behavioral_action, commitment, reminder)dimensionId, appliesToStates (array), appliesToStages (array)financialReadinessRequired, behavioralReadinessRequiredbehavioralTechniqueCode (ej. IMPLEMENTATION_INTENTION, COMMITMENT_DEVICE) — spec §28titleI18nKey, descriptionI18nKey, actionTextI18nKeywhyThisStepI18nKey (spec §56)TenantInterventionOverride (ADR-004)Campos: tenantId, interventionId, status (enabled, disabled)
En MVP solo activar/desactivar; contenido propio de tenant es fase posterior.
EmployeeIntervention — instancia asignadaCampos:
id, employeeId, interventionId, assignedAtstatus (suggested, committed, in_progress, completed, dismissed)commitmentData (JSON: monto, frecuencia, trigger, fecha — spec §30)completedAt, outcome (achieved, partial, not_achieved), feedback (JSON)Version — tabla genérica para versionablesCampos: id, entityType (methodology, question_bank, scoring, intervention_catalog), entityId, versionNumber, status (draft, in_review, active, rollback), createdById, publishedById, publishedAt
AuditLog — cambios estructurales (spec §52)Campos: id, whoId, who (JSON con nombre y rol), what, when, previousValue (JSON), newValue (JSON), entityType, entityId
LearningEvent — señales para el motor de aprendizaje (Fase 8 spec)Campos: id, eventType (question_shown, question_abandoned, intervention_completed, outcome_reported), employeeId (nullable para anonimizar), tenantId, context (JSON), timestamp
Estas son las que la spec repite y que el modelo debe blindar:
DEBT_APPLICABILITY = NONE, la dimensión Debt se excluye del denominador del CFHI y se redistribuyen pesos entre las aplicables. No se pone score = 100.source, reliability, confidence. Constraint a nivel de aplicación y validación en zod.methodologyVersionId y questionBankVersionId específicos. Los cambios de versión no reescriben respuestas históricas.ForbiddenInference antes de propagar inferencias.TenantAdmin pasa por un helper que verifica que el segmento consultado tenga al menos tenant.aggregationMinSegmentSize empleados. Si no, devuelve INSUFFICIENT_ANONYMITY.La barrera empresa-empleado (ADR-001) no puede depender solo de la lógica de aplicación. Se enforce a nivel de base de datos:
tenantId tiene policy RLS que filtra automáticamente por el tenant del usuario autenticado.TenantAdmin no puede leer Evidence, VariableState, ConstructScore, DimensionScore, FinancialState, SafetyFlag, ni EmployeeIntervention individual. Solo puede leer vistas agregadas que aplican el umbral.Employee solo puede leer sus propias entidades.PlatformUser con rol correspondiente puede leer todo, pero cada acceso queda en AuditLog.Las políticas de RLS se definen en migraciones de Prisma con SQL raw cuando Prisma no las soporta nativamente.
Estos son fases posteriores. No agregar tablas para ellos ahora.