Structure: - control-plane/: Registries, SIMCO directives, CI/CD templates - projects/: Gamilit, ERP-Suite, Trading-Platform, Betting-Analytics - shared/: Libs catalog, knowledge-base Key features: - Centralized port, domain, database, and service registries - 23 SIMCO directives + 6 fundamental principles - NEXUS agent profiles with delegation rules - Validation scripts for workspace integrity - Dockerfiles for all services - Path aliases for quick reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
648 lines
20 KiB
Markdown
648 lines
20 KiB
Markdown
# Diagrama de Dependencias: initialize_user_stats()
|
|
|
|
**Última actualización:** 2025-11-24
|
|
**Relacionado con:** ADR-012, GAP-003 Bug Fix
|
|
**Propósito:** Documentar todas las dependencias, FK references y relaciones de la función de inicialización
|
|
|
|
---
|
|
|
|
## 📋 Descripción General
|
|
|
|
La función `gamilit.initialize_user_stats()` tiene dependencias con múltiples tablas y esquemas. Este documento mapea exhaustivamente todas estas relaciones para facilitar el mantenimiento y prevenir errores futuros.
|
|
|
|
---
|
|
|
|
## 🔄 Diagrama de Dependencias Completo
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ DISPARADO POR │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌──────────────────────────────────────┐
|
|
│ auth_management.profiles (INSERT) │
|
|
│ │
|
|
│ Trigger: trg_initialize_user_stats │
|
|
└──────────────────┬───────────────────┘
|
|
│
|
|
▼
|
|
┌──────────────────────────────────────┐
|
|
│ gamilit.initialize_user_stats() │
|
|
│ │
|
|
│ Función de inicialización │
|
|
└──────────────────┬───────────────────┘
|
|
│
|
|
│
|
|
┌──────────────────┴───────────────────┐
|
|
│ │
|
|
│ LEE DE (SELECT): │
|
|
│ │
|
|
│ educational_content.modules │
|
|
│ WHERE is_published = true │
|
|
│ AND status = 'published' │
|
|
│ │
|
|
└──────────────────┬───────────────────┘
|
|
│
|
|
│
|
|
┌──────────────────┴───────────────────┐
|
|
│ │
|
|
│ INSERTA EN (4 tablas): │
|
|
│ │
|
|
├──────────────────────────────────────┤
|
|
│ │
|
|
│ 1. gamification_system.user_stats │
|
|
│ FK: user_id → auth.users.id │
|
|
│ │
|
|
├──────────────────────────────────────┤
|
|
│ │
|
|
│ 2. gamification_system. │
|
|
│ comodines_inventory │
|
|
│ FK: user_id → profiles.id │
|
|
│ │
|
|
├──────────────────────────────────────┤
|
|
│ │
|
|
│ 3. gamification_system.user_ranks │
|
|
│ FK: user_id → auth.users.id │
|
|
│ │
|
|
├──────────────────────────────────────┤
|
|
│ │
|
|
│ 4. progress_tracking.module_progress │
|
|
│ FK1: user_id → profiles.id │
|
|
│ FK2: module_id → modules.id │
|
|
│ │
|
|
└──────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 🗃️ Tablas Involucradas
|
|
|
|
### Tabla 1: auth.users (Supabase)
|
|
|
|
**Rol:** Proveedor de user_id para tablas de gamificación
|
|
|
|
**Schema:** `auth` (Supabase built-in)
|
|
|
|
**Columnas relevantes:**
|
|
- `id` (uuid, PK) - UUID del usuario de Supabase Auth
|
|
|
|
**Usado por:**
|
|
- `gamification_system.user_stats.user_id` (FK)
|
|
- `gamification_system.user_ranks.user_id` (FK)
|
|
- `auth_management.profiles.user_id` (FK)
|
|
|
|
**Relación con initialize_user_stats:**
|
|
- ✅ Referenciado indirectamente vía `NEW.user_id` en trigger
|
|
- ✅ Usado para user_stats y user_ranks
|
|
|
|
---
|
|
|
|
### Tabla 2: auth_management.profiles
|
|
|
|
**Rol:** Tabla que dispara el trigger de inicialización
|
|
|
|
**Schema:** `auth_management`
|
|
|
|
**Archivo DDL:** `apps/database/ddl/schemas/auth_management/tables/03-profiles.sql`
|
|
|
|
**Columnas relevantes:**
|
|
- `id` (uuid, PK) - ID del perfil
|
|
- `user_id` (uuid, FK) → auth.users.id
|
|
- `email` (text, UNIQUE)
|
|
- `role` (gamilit_role)
|
|
|
|
**Trigger configurado:**
|
|
```sql
|
|
CREATE TRIGGER trg_initialize_user_stats
|
|
AFTER INSERT ON auth_management.profiles
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION gamilit.initialize_user_stats();
|
|
```
|
|
|
|
**Variables disponibles en trigger:**
|
|
- `NEW.id` → profiles.id (usado para module_progress, comodines_inventory)
|
|
- `NEW.user_id` → auth.users.id (usado para user_stats, user_ranks)
|
|
|
|
**Relación con initialize_user_stats:**
|
|
- ✅ Dispara el trigger en INSERT
|
|
- ✅ Provee NEW.id y NEW.user_id
|
|
|
|
---
|
|
|
|
### Tabla 3: educational_content.modules
|
|
|
|
**Rol:** Proveedor de módulos disponibles para inicialización
|
|
|
|
**Schema:** `educational_content`
|
|
|
|
**Archivo DDL:** `apps/database/ddl/schemas/educational_content/tables/01-modules.sql`
|
|
|
|
**Columnas relevantes:**
|
|
- `id` (uuid, PK) - ID del módulo
|
|
- `is_published` (boolean)
|
|
- `status` (module_status ENUM)
|
|
|
|
**Query ejecutada por initialize_user_stats:**
|
|
```sql
|
|
SELECT m.id
|
|
FROM educational_content.modules m
|
|
WHERE m.is_published = true
|
|
AND m.status = 'published';
|
|
```
|
|
|
|
**Resultado típico:** 5 módulos (M1-M5)
|
|
|
|
**Relación con initialize_user_stats:**
|
|
- ✅ Se lee para obtener lista de módulos disponibles
|
|
- ✅ No se modifica (solo SELECT)
|
|
|
|
---
|
|
|
|
### Tabla 4: gamification_system.user_stats
|
|
|
|
**Rol:** Almacenar estadísticas de gamificación del usuario
|
|
|
|
**Schema:** `gamification_system`
|
|
|
|
**Archivo DDL:** `apps/database/ddl/schemas/gamification_system/tables/01-user_stats.sql`
|
|
|
|
**Columnas relevantes:**
|
|
- `user_id` (uuid, PK, FK) → auth.users.id
|
|
- `total_xp` (bigint)
|
|
- `level` (integer)
|
|
- `ml_coins` (integer)
|
|
- `current_streak` (integer)
|
|
|
|
**FK Constraint:**
|
|
```sql
|
|
CONSTRAINT user_stats_user_id_fkey
|
|
FOREIGN KEY (user_id)
|
|
REFERENCES auth.users(id)
|
|
ON DELETE CASCADE
|
|
```
|
|
|
|
**Índices:**
|
|
- `user_stats_pkey` (PK en user_id)
|
|
- `idx_user_stats_user_id` (índice en user_id)
|
|
|
|
**INSERT ejecutado:**
|
|
```sql
|
|
INSERT INTO gamification_system.user_stats (
|
|
user_id, total_xp, level, ml_coins, current_streak
|
|
)
|
|
VALUES (NEW.user_id, 0, 1, 100, 0)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
```
|
|
|
|
**Estrategia de conflicto:** ON CONFLICT DO NOTHING (idempotente)
|
|
|
|
**Relación con initialize_user_stats:**
|
|
- ✅ Se inserta un registro
|
|
- ✅ FK apunta a auth.users.id (no profiles.id)
|
|
|
|
---
|
|
|
|
### Tabla 5: gamification_system.comodines_inventory
|
|
|
|
**Rol:** Almacenar inventario de comodines del usuario
|
|
|
|
**Schema:** `gamification_system`
|
|
|
|
**Archivo DDL:** `apps/database/ddl/schemas/gamification_system/tables/07-comodines_inventory.sql`
|
|
|
|
**Columnas relevantes:**
|
|
- `user_id` (uuid, PK, FK) → auth_management.profiles.id
|
|
- `total_comodines_earned` (integer)
|
|
- `total_comodines_used` (integer)
|
|
|
|
**FK Constraint:**
|
|
```sql
|
|
CONSTRAINT comodines_inventory_user_id_fkey
|
|
FOREIGN KEY (user_id)
|
|
REFERENCES auth_management.profiles(id)
|
|
ON DELETE CASCADE
|
|
```
|
|
|
|
**Índices:**
|
|
- `comodines_inventory_pkey` (PK en user_id)
|
|
|
|
**INSERT ejecutado:**
|
|
```sql
|
|
INSERT INTO gamification_system.comodines_inventory (
|
|
user_id, total_comodines_earned, total_comodines_used
|
|
)
|
|
VALUES (NEW.id, 0, 0)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
```
|
|
|
|
**Estrategia de conflicto:** ON CONFLICT DO NOTHING (idempotente)
|
|
|
|
**Relación con initialize_user_stats:**
|
|
- ✅ Se inserta un registro
|
|
- ✅ FK apunta a profiles.id (no auth.users.id)
|
|
|
|
---
|
|
|
|
### Tabla 6: gamification_system.user_ranks
|
|
|
|
**Rol:** Almacenar rango Maya del usuario
|
|
|
|
**Schema:** `gamification_system`
|
|
|
|
**Archivo DDL:** `apps/database/ddl/schemas/gamification_system/tables/02-user_ranks.sql`
|
|
|
|
**Columnas relevantes:**
|
|
- `user_id` (uuid, PK, FK) → auth.users.id
|
|
- `current_rank` (maya_rank ENUM)
|
|
- `rank_progress` (integer)
|
|
|
|
**FK Constraint:**
|
|
```sql
|
|
CONSTRAINT user_ranks_user_id_fkey
|
|
FOREIGN KEY (user_id)
|
|
REFERENCES auth.users(id)
|
|
ON DELETE CASCADE
|
|
```
|
|
|
|
**Índices:**
|
|
- `user_ranks_pkey` (PK en user_id)
|
|
|
|
**⚠️ Nota importante:** Esta tabla NO tiene constraint UNIQUE en user_id, por lo que no se puede usar `ON CONFLICT`. Se usa `WHERE NOT EXISTS` en su lugar.
|
|
|
|
**INSERT ejecutado:**
|
|
```sql
|
|
INSERT INTO gamification_system.user_ranks (
|
|
user_id, current_rank, rank_progress
|
|
)
|
|
SELECT NEW.user_id, 'Ajaw'::gamification_system.maya_rank, 0
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM gamification_system.user_ranks
|
|
WHERE user_id = NEW.user_id
|
|
);
|
|
```
|
|
|
|
**Estrategia de conflicto:** WHERE NOT EXISTS (previene duplicados)
|
|
|
|
**Relación con initialize_user_stats:**
|
|
- ✅ Se inserta un registro
|
|
- ✅ FK apunta a auth.users.id (no profiles.id)
|
|
|
|
---
|
|
|
|
### Tabla 7: progress_tracking.module_progress
|
|
|
|
**Rol:** Almacenar progreso del usuario en cada módulo
|
|
|
|
**Schema:** `progress_tracking`
|
|
|
|
**Archivo DDL:** `apps/database/ddl/schemas/progress_tracking/tables/01-module_progress.sql`
|
|
|
|
**Columnas relevantes:**
|
|
- `user_id` (uuid, FK) → auth_management.profiles.id
|
|
- `module_id` (uuid, FK) → educational_content.modules.id
|
|
- `status` (progress_status ENUM)
|
|
- `progress_percentage` (numeric)
|
|
|
|
**FK Constraints:**
|
|
```sql
|
|
-- FK 1: Usuario
|
|
CONSTRAINT module_progress_user_id_fkey
|
|
FOREIGN KEY (user_id)
|
|
REFERENCES auth_management.profiles(id)
|
|
ON DELETE CASCADE
|
|
|
|
-- FK 2: Módulo
|
|
CONSTRAINT module_progress_module_id_fkey
|
|
FOREIGN KEY (module_id)
|
|
REFERENCES educational_content.modules(id)
|
|
ON DELETE CASCADE
|
|
```
|
|
|
|
**Índices:**
|
|
- `module_progress_pkey` (PK compuesto en user_id, module_id)
|
|
- `idx_module_progress_user_id` (índice en user_id)
|
|
- `idx_module_progress_module_id` (índice en module_id)
|
|
|
|
**INSERT ejecutado:**
|
|
```sql
|
|
INSERT INTO progress_tracking.module_progress (
|
|
user_id, module_id, status, progress_percentage
|
|
)
|
|
SELECT
|
|
NEW.id, -- profiles.id
|
|
m.id, -- modules.id
|
|
'not_started'::progress_tracking.progress_status,
|
|
0
|
|
FROM educational_content.modules m
|
|
WHERE m.is_published = true
|
|
AND m.status = 'published'
|
|
ON CONFLICT (user_id, module_id) DO NOTHING;
|
|
```
|
|
|
|
**Estrategia de conflicto:** ON CONFLICT DO NOTHING (idempotente)
|
|
|
|
**Registros típicos creados:** 5 (uno por cada módulo publicado)
|
|
|
|
**Relación con initialize_user_stats:**
|
|
- ✅ Se insertan múltiples registros (1 por módulo)
|
|
- ✅ FK user_id apunta a profiles.id (no auth.users.id)
|
|
- ✅ FK module_id apunta a modules.id
|
|
|
|
---
|
|
|
|
## 🔑 Mapa de Foreign Keys
|
|
|
|
### Resumen de FK References
|
|
|
|
```
|
|
auth.users.id
|
|
↓ (FK)
|
|
auth_management.profiles.user_id
|
|
↓
|
|
├─ [NEW.user_id en trigger]
|
|
│ ↓ (usado para)
|
|
│ ├─ gamification_system.user_stats.user_id
|
|
│ └─ gamification_system.user_ranks.user_id
|
|
│
|
|
└─ [NEW.id en trigger] (profiles.id)
|
|
↓ (usado para)
|
|
├─ gamification_system.comodines_inventory.user_id
|
|
└─ progress_tracking.module_progress.user_id
|
|
|
|
educational_content.modules.id
|
|
↓ (FK)
|
|
progress_tracking.module_progress.module_id
|
|
```
|
|
|
|
### Regla Mnemotécnica
|
|
|
|
**Para recordar qué usar (NEW.id vs NEW.user_id):**
|
|
|
|
```
|
|
Tablas de GAMIFICACIÓN → NEW.user_id (auth.users.id)
|
|
├─ user_stats
|
|
└─ user_ranks
|
|
|
|
Tablas de PROGRESS/INVENTORY → NEW.id (profiles.id)
|
|
├─ module_progress
|
|
└─ comodines_inventory
|
|
```
|
|
|
|
**Razón histórica:**
|
|
- `gamification_system` fue diseñado primero, referencia auth.users directamente
|
|
- `progress_tracking` fue diseñado después, referencia profiles (más limpio)
|
|
|
|
---
|
|
|
|
## 📊 Matriz de Dependencias
|
|
|
|
| Tabla Destino | Schema | FK Column | Referencia | Valor en Trigger | Constraint |
|
|
|---------------|--------|-----------|------------|------------------|------------|
|
|
| user_stats | gamification_system | user_id | auth.users.id | NEW.user_id | ON CONFLICT |
|
|
| comodines_inventory | gamification_system | user_id | profiles.id | NEW.id | ON CONFLICT |
|
|
| user_ranks | gamification_system | user_id | auth.users.id | NEW.user_id | WHERE NOT EXISTS |
|
|
| module_progress | progress_tracking | user_id | profiles.id | NEW.id | ON CONFLICT |
|
|
| module_progress | progress_tracking | module_id | modules.id | m.id (SELECT) | ON CONFLICT |
|
|
|
|
---
|
|
|
|
## 🔍 Casos Críticos a Considerar
|
|
|
|
### Caso 1: Cambiar FK de module_progress
|
|
|
|
**Escenario hipotético:** Migrar module_progress.user_id de profiles.id a auth.users.id
|
|
|
|
**Impacto:**
|
|
```sql
|
|
-- ANTES (actual):
|
|
INSERT INTO module_progress (user_id, ...)
|
|
VALUES (NEW.id, ...) -- profiles.id
|
|
|
|
-- DESPUÉS (hipotético):
|
|
INSERT INTO module_progress (user_id, ...)
|
|
VALUES (NEW.user_id, ...) -- auth.users.id
|
|
```
|
|
|
|
**Cambios requeridos:**
|
|
1. ✅ Modificar constraint FK en tabla module_progress
|
|
2. ✅ Actualizar función initialize_user_stats (NEW.id → NEW.user_id)
|
|
3. ✅ Migración de datos existentes
|
|
4. ✅ Actualizar queries en backend (JOIN diferentes)
|
|
|
|
**Recomendación:** ❌ NO HACER - Mantener consistencia actual
|
|
|
|
---
|
|
|
|
### Caso 2: Agregar Nueva Tabla de Inicialización
|
|
|
|
**Escenario:** Agregar tabla `user_preferences` que debe inicializarse
|
|
|
|
**Pasos:**
|
|
1. Crear tabla `user_management.user_preferences`
|
|
2. Decidir FK: ¿profiles.id o auth.users.id?
|
|
3. Actualizar `gamilit.initialize_user_stats()`
|
|
4. Agregar INSERT con ON CONFLICT
|
|
5. Actualizar tests de validación
|
|
6. Actualizar esta documentación
|
|
|
|
**Template de INSERT:**
|
|
```sql
|
|
-- Si FK apunta a profiles.id:
|
|
INSERT INTO user_management.user_preferences (user_id, ...)
|
|
VALUES (NEW.id, ...)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
|
|
-- Si FK apunta a auth.users.id:
|
|
INSERT INTO user_management.user_preferences (user_id, ...)
|
|
VALUES (NEW.user_id, ...)
|
|
ON CONFLICT (user_id) DO NOTHING;
|
|
```
|
|
|
|
---
|
|
|
|
### Caso 3: Módulos Dinámicos
|
|
|
|
**Escenario:** Se publica un nuevo módulo M6 después de que usuarios ya están registrados
|
|
|
|
**Problema:**
|
|
- Usuarios existentes no tienen module_progress para M6
|
|
- Trigger solo funciona en nuevos registros
|
|
|
|
**Soluciones:**
|
|
|
|
**Opción A: Migration Manual (Recomendada)**
|
|
```sql
|
|
-- Script: apps/database/migrations/YYYY-MM-DD-add-module-6-progress.sql
|
|
INSERT INTO progress_tracking.module_progress (
|
|
user_id, module_id, status, progress_percentage
|
|
)
|
|
SELECT
|
|
p.id,
|
|
'm6-uuid'::uuid,
|
|
'not_started',
|
|
0
|
|
FROM auth_management.profiles p
|
|
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
|
|
AND p.deleted_at IS NULL
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM progress_tracking.module_progress mp
|
|
WHERE mp.user_id = p.id AND mp.module_id = 'm6-uuid'::uuid
|
|
);
|
|
```
|
|
|
|
**Opción B: Lazy Loading en Backend**
|
|
```typescript
|
|
// En module.service.ts
|
|
async getModuleProgress(userId: string, moduleId: string) {
|
|
let progress = await this.findProgress(userId, moduleId);
|
|
|
|
if (!progress) {
|
|
// Crear module_progress si no existe
|
|
progress = await this.createProgress({
|
|
userId,
|
|
moduleId,
|
|
status: 'not_started',
|
|
progressPercentage: 0,
|
|
});
|
|
}
|
|
|
|
return progress;
|
|
}
|
|
```
|
|
|
|
**Recomendación:** Opción A (migration) para consistencia
|
|
|
|
---
|
|
|
|
## 🧪 Testing de Dependencias
|
|
|
|
### Test 1: Validar Todas las FK
|
|
|
|
```sql
|
|
-- Verificar que todas las FK existen y son correctas
|
|
SELECT
|
|
tc.table_schema,
|
|
tc.table_name,
|
|
kcu.column_name,
|
|
ccu.table_schema AS foreign_table_schema,
|
|
ccu.table_name AS foreign_table_name,
|
|
ccu.column_name AS foreign_column_name
|
|
FROM information_schema.table_constraints AS tc
|
|
JOIN information_schema.key_column_usage AS kcu
|
|
ON tc.constraint_name = kcu.constraint_name
|
|
AND tc.table_schema = kcu.table_schema
|
|
JOIN information_schema.constraint_column_usage AS ccu
|
|
ON ccu.constraint_name = tc.constraint_name
|
|
AND ccu.table_schema = tc.table_schema
|
|
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
AND (
|
|
(tc.table_schema = 'gamification_system' AND tc.table_name IN ('user_stats', 'comodines_inventory', 'user_ranks'))
|
|
OR
|
|
(tc.table_schema = 'progress_tracking' AND tc.table_name = 'module_progress')
|
|
)
|
|
ORDER BY tc.table_schema, tc.table_name;
|
|
```
|
|
|
|
**Resultado esperado:** 5 FK constraints listadas
|
|
|
|
---
|
|
|
|
### Test 2: Validar Idempotencia del Trigger
|
|
|
|
```sql
|
|
-- Test de idempotencia: Ejecutar trigger múltiples veces
|
|
DO $$
|
|
DECLARE
|
|
test_profile_id uuid;
|
|
test_user_id uuid;
|
|
BEGIN
|
|
-- Crear usuario de prueba
|
|
INSERT INTO auth.users (email, encrypted_password)
|
|
VALUES ('test-idempotence@test.com', 'hashed')
|
|
RETURNING id INTO test_user_id;
|
|
|
|
-- Crear perfil (dispara trigger 1ra vez)
|
|
INSERT INTO auth_management.profiles (user_id, email, role)
|
|
VALUES (test_user_id, 'test-idempotence@test.com', 'student')
|
|
RETURNING id INTO test_profile_id;
|
|
|
|
-- Intentar insertar duplicados (simular trigger 2da vez)
|
|
-- Todos deben fallar gracefully con ON CONFLICT
|
|
PERFORM gamilit.initialize_user_stats();
|
|
|
|
-- Verificar conteo
|
|
ASSERT (SELECT COUNT(*) FROM gamification_system.user_stats WHERE user_id = test_user_id) = 1,
|
|
'Debe haber exactamente 1 user_stats';
|
|
|
|
ASSERT (SELECT COUNT(*) FROM gamification_system.user_ranks WHERE user_id = test_user_id) = 1,
|
|
'Debe haber exactamente 1 user_ranks';
|
|
|
|
ASSERT (SELECT COUNT(*) FROM progress_tracking.module_progress WHERE user_id = test_profile_id) = 5,
|
|
'Debe haber exactamente 5 module_progress';
|
|
|
|
RAISE NOTICE 'Test de idempotencia: OK';
|
|
END $$;
|
|
```
|
|
|
|
---
|
|
|
|
### Test 3: Validar Cascade Deletes
|
|
|
|
```sql
|
|
-- Test de cascade: Eliminar usuario debe eliminar todo
|
|
DO $$
|
|
DECLARE
|
|
test_profile_id uuid;
|
|
test_user_id uuid;
|
|
BEGIN
|
|
-- Crear usuario de prueba
|
|
INSERT INTO auth.users (email, encrypted_password)
|
|
VALUES ('test-cascade@test.com', 'hashed')
|
|
RETURNING id INTO test_user_id;
|
|
|
|
INSERT INTO auth_management.profiles (user_id, email, role)
|
|
VALUES (test_user_id, 'test-cascade@test.com', 'student')
|
|
RETURNING id INTO test_profile_id;
|
|
|
|
-- Eliminar usuario (debe hacer CASCADE)
|
|
DELETE FROM auth.users WHERE id = test_user_id;
|
|
|
|
-- Verificar que todo se eliminó
|
|
ASSERT (SELECT COUNT(*) FROM gamification_system.user_stats WHERE user_id = test_user_id) = 0;
|
|
ASSERT (SELECT COUNT(*) FROM auth_management.profiles WHERE user_id = test_user_id) = 0;
|
|
ASSERT (SELECT COUNT(*) FROM progress_tracking.module_progress WHERE user_id = test_profile_id) = 0;
|
|
|
|
RAISE NOTICE 'Test de cascade delete: OK';
|
|
END $$;
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Referencias
|
|
|
|
**Documentación relacionada:**
|
|
- ADR: `docs/97-adr/ADR-012-automatic-user-initialization-trigger.md`
|
|
- Flujo: `docs/90-transversal/FLUJO-INICIALIZACION-USUARIO.md`
|
|
- Función: `docs/90-transversal/FUNCIONES-UTILITARIAS-GAMILIT.md`
|
|
|
|
**Código fuente:**
|
|
- Trigger: `apps/database/ddl/schemas/auth_management/triggers/04-trg_initialize_user_stats.sql`
|
|
- Función: `apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql`
|
|
|
|
**Tablas DDL:**
|
|
- `apps/database/ddl/schemas/auth_management/tables/03-profiles.sql`
|
|
- `apps/database/ddl/schemas/gamification_system/tables/01-user_stats.sql`
|
|
- `apps/database/ddl/schemas/gamification_system/tables/02-user_ranks.sql`
|
|
- `apps/database/ddl/schemas/gamification_system/tables/07-comodines_inventory.sql`
|
|
- `apps/database/ddl/schemas/progress_tracking/tables/01-module_progress.sql`
|
|
- `apps/database/ddl/schemas/educational_content/tables/01-modules.sql`
|
|
|
|
---
|
|
|
|
**FIN DEL DOCUMENTO**
|
|
|
|
**Última actualización:** 2025-11-24
|
|
**Mantenedores:** Architecture-Analyst, Database-Agent
|
|
**Revisión necesaria:** Sí, al agregar nuevas tablas de inicialización o modificar FK
|