workspace/projects/gamilit/docs/90-transversal/arquitectura/ARQUITECTURA-AUTENTICACION.md
rckrdmrd 608e1e2a2e
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions
Multi-project update: gamilit, orchestration, trading-platform
Gamilit:
- Backend: Teacher services, assignments, gamification, exercise submissions
- Frontend: Admin/Teacher/Student portals, module 4-5 mechanics, monitoring
- Database: DDL functions, seeds for dev/prod, auth/gamification schemas
- Docs: Architecture, features, guides cleanup and reorganization

Core/Orchestration:
- New workspace directives index
- Documentation directive

Trading-platform:
- Database seeds and inventory updates
- Tech leader validation report

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 07:17:46 -06:00

11 KiB

Arquitectura de Autenticación - GAMILIT

Fecha: 2025-12-14 Versión: 1.0 Estado: Documentado Auditoría: AUDIT-DB-001


1. Resumen Ejecutivo

Este documento describe la arquitectura de autenticación de GAMILIT, aclarando que el proyecto NO utiliza Supabase como servicio. El esquema auth y sus tablas siguen un patrón estándar de la industria para autenticación con PostgreSQL y Row Level Security (RLS).


2. Arquitectura de Dos Capas

GAMILIT implementa una arquitectura de autenticación de dos capas:

┌─────────────────────────────────────────────────────────────┐
│                    CAPA 1: AUTH BASE                        │
│                    Schema: auth                             │
├─────────────────────────────────────────────────────────────┤
│  auth.users                                                 │
│  ├── id (UUID PK)                                          │
│  ├── email (unique)                                        │
│  ├── encrypted_password                                    │
│  ├── email_confirmed_at                                    │
│  ├── last_sign_in_at                                       │
│  ├── raw_user_meta_data (JSONB)                            │
│  ├── created_at                                            │
│  └── updated_at                                            │
│                                                             │
│  Propósito: Credenciales de autenticación puras            │
│  Acceso: Solo servicios de autenticación                   │
└─────────────────────────────────────────────────────────────┘
                            │
                            │ FK: profile_id → auth.users.id
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                 CAPA 2: AUTH MANAGEMENT                     │
│                 Schema: auth_management                     │
├─────────────────────────────────────────────────────────────┤
│  auth_management.profiles                                   │
│  ├── id (UUID PK, FK → auth.users.id)                      │
│  ├── first_name                                            │
│  ├── last_name                                             │
│  ├── display_name                                          │
│  ├── avatar_url                                            │
│  ├── school_id (FK)                                        │
│  ├── grade_level                                           │
│  ├── date_of_birth                                         │
│  ├── preferences (JSONB)                                   │
│  └── tenant_id (FK)                                        │
│                                                             │
│  Propósito: Datos de perfil de negocio                     │
│  Acceso: Toda la aplicación                                │
└─────────────────────────────────────────────────────────────┘

2.1 Por qué Dos Capas

Aspecto auth.users auth_management.profiles
Datos Credenciales (email, password) Información de negocio (nombre, avatar)
Seguridad Altamente restringido Accesible con RLS
Modificación Solo sistema de auth Usuario y administradores
Referencias Ninguna (aislado) Todas las tablas del sistema

3. Roles RLS (Row Level Security)

GAMILIT usa tres roles estándar para RLS:

-- Definidos en 00-prerequisites.sql
CREATE ROLE authenticated;
CREATE ROLE anon;
CREATE ROLE service_role;

-- Descripciones
COMMENT ON ROLE authenticated IS 'Rol RLS: usuarios autenticados (cualquier rol GAMILIT)';
COMMENT ON ROLE anon IS 'Rol RLS: visitantes no autenticados';
COMMENT ON ROLE service_role IS 'Rol RLS: acceso elevado para operaciones del sistema';

3.1 Mapeo de Roles

Rol RLS Rol GAMILIT Permisos
authenticated student, teacher, admin, super_admin Lectura/escritura según policies
anon (sin login) Solo lectura de datos públicos
service_role Backend interno Bypass de RLS para operaciones del sistema

4. Flujo de Autenticación

┌──────────┐     ┌──────────────┐     ┌─────────────┐     ┌──────────────────┐
│  Cliente │────▶│ POST /login  │────▶│ AuthService │────▶│ auth.users       │
└──────────┘     └──────────────┘     └─────────────┘     │ (validar creds)  │
                                             │            └──────────────────┘
                                             │
                                             ▼
                                      ┌─────────────┐
                                      │ JWT Token   │
                                      │ + user_id   │
                                      │ + role      │
                                      └─────────────┘
                                             │
                                             ▼
                 ┌──────────────────────────────────────────────────────┐
                 │  Headers: Authorization: Bearer <token>              │
                 │  PostgreSQL: SET LOCAL role = 'authenticated';       │
                 │              SET LOCAL request.jwt.sub = '<user_id>';│
                 └──────────────────────────────────────────────────────┘

4.1 JWT Claims

interface JWTPayload {
  sub: string;        // auth.users.id (UUID)
  email: string;      // auth.users.email
  role: string;       // GAMILIT role (student, teacher, etc.)
  tenant_id?: string; // Multi-tenant support
  iat: number;        // Issued at
  exp: number;        // Expiration
}

5. Tablas de Autenticación

5.1 Schema auth

Tabla Descripción Columnas Clave
users Credenciales de usuario id, email, encrypted_password, email_confirmed_at

5.2 Schema auth_management

Tabla Descripción FK Principal
profiles Datos de perfil extendido id → auth.users.id
tenants Organizaciones multi-tenant -
memberships Relación usuario-tenant user_id → profiles.id
roles Definición de roles -
user_roles Asignación usuario-rol profile_id → profiles.id
user_sessions Sesiones activas user_id → profiles.id
auth_providers Proveedores externos (Google, etc.) user_id → profiles.id
auth_attempts Log de intentos de login user_id → profiles.id
email_verification_tokens Tokens de verificación user_id → profiles.id
password_reset_tokens Tokens de reset user_id → profiles.id
security_events Eventos de seguridad user_id → profiles.id

6. Decisiones Arquitectónicas

ADR-001: No Supabase

Contexto: El diseño inicial consideraba Supabase como opción de BaaS.

Decisión: Implementar autenticación personalizada con NestJS + PostgreSQL.

Razones:

  1. Mayor control sobre lógica de autenticación
  2. Sin dependencia de servicios externos
  3. Flexibilidad para multi-tenant personalizado
  4. RLS implementado directamente en PostgreSQL

Consecuencias:

  • Mayor código de autenticación a mantener
  • Mayor flexibilidad en personalización
  • Sin costos de servicio externo

ADR-002: Patrón de Dos Capas

Contexto: Necesidad de separar credenciales de datos de perfil.

Decisión: Usar auth.users para credenciales y auth_management.profiles para datos de negocio.

Razones:

  1. Principio de responsabilidad única
  2. Seguridad mejorada (aislamiento de credenciales)
  3. Facilidad de extensión del perfil
  4. Compatibilidad con patrones estándar de la industria

7. Constantes de Backend

// apps/backend/src/shared/constants/database.constants.ts

export const DB_SCHEMAS = {
  AUTH: 'auth_management',        // Gestión de autenticación
  AUTH_BASE: 'auth',              // Credenciales base
  // ... otros schemas
};

export const DB_TABLES = {
  AUTH: {
    USERS: 'users',
    PROFILES: 'profiles',
    USER_ROLES: 'user_roles',
    ROLES: 'roles',
    // ... resto de tablas
  },
  AUTH_BASE: {
    USERS: 'users',
  },
};

8. Ejemplo de Policies RLS

-- Solo el usuario puede ver su propio perfil
CREATE POLICY "Users can view own profile"
ON auth_management.profiles
FOR SELECT
TO authenticated
USING (id = current_setting('request.jwt.sub')::uuid);

-- Solo admins pueden ver todos los perfiles
CREATE POLICY "Admins can view all profiles"
ON auth_management.profiles
FOR SELECT
TO authenticated
USING (
  EXISTS (
    SELECT 1 FROM auth_management.user_roles ur
    JOIN auth_management.roles r ON ur.role_id = r.id
    WHERE ur.profile_id = current_setting('request.jwt.sub')::uuid
    AND r.name IN ('admin', 'super_admin')
  )
);

9. Referencias

  • apps/database/ddl/schemas/auth/ - DDL del schema auth
  • apps/database/ddl/schemas/auth_management/ - DDL del schema auth_management
  • apps/backend/src/modules/auth/ - Código de autenticación
  • orchestration/inventarios/DATABASE_INVENTORY.yml - Inventario de BD
  • orchestration/agentes/database-auditor/audit-2025-12-14/07-REPORTE-CORRECCIONES-P0.md - Auditoría P0

10. Historial de Cambios

Fecha Cambio Autor
2025-12-14 Documento inicial, clarificación de no-Supabase AUDIT-DB-001

Estado: Este documento es la fuente de verdad para la arquitectura de autenticación de GAMILIT.