- Configure workspace Git repository with comprehensive .gitignore - Add Odoo as submodule for ERP reference code - Include documentation: SETUP.md, GIT-STRUCTURE.md - Add gitignore templates for projects (backend, frontend, database) - Structure supports independent repos per project/subproject level Workspace includes: - core/ - Reusable patterns, modules, orchestration system - projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.) - knowledge-base/ - Reference code and patterns (includes Odoo submodule) - devtools/ - Development tools and templates - customers/ - Client implementations template 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
17 KiB
17 KiB
Database Cheatsheet - GAMILIT Platform
Versión: 1.0 Última actualización: 2025-11-07 Database: PostgreSQL 15+ Timezone: America/Mexico_City
Nota: Este es un cheatsheet rápido. Para esquema completo ver docs/03-desarrollo/base-de-datos/ESQUEMA-COMPLETO.md
🔌 Conexión Rápida
Desarrollo Local
# Conectar a database
psql -U gamilit_user -d gamilit_platform -h localhost
# Conectar con password inline (no recomendado en producción)
PGPASSWORD=gamilit_dev_2025 psql -U gamilit_user -d gamilit_platform -h localhost
Variables de Entorno
export PGHOST=localhost
export PGPORT=5432
export PGDATABASE=gamilit_platform
export PGUSER=gamilit_user
export PGPASSWORD=gamilit_dev_2025
# Ahora solo:
psql
📊 Esquema General
Resumen
- Schemas: 9
- Tablas: 44
- Funciones: 50+
- Triggers: 35+
- Índices: 279+
- RLS Policies: 159 (41 activas)
Schemas Principales
| Schema | Tablas | Propósito |
|---|---|---|
| auth_management | 12 | Autenticación, usuarios, sesiones, roles |
| educational_content | 8 | Módulos, ejercicios, contenido educativo |
| gamification_system | 10 | ML Coins, rangos, achievements, power-ups |
| progress_tracking | 6 | Progreso, intentos, sesiones de aprendizaje |
| social_features | 7 | Escuelas, aulas, equipos, amistades |
| content_management | 4 | Media files, Marie Curie content |
| audit_logging | 2 | Logs de auditoría, eventos de seguridad |
| system_configuration | 1 | Configuración del sistema |
| public | 2 | Schema público |
🗂️ Comandos Útiles de psql
Navegación
-- Listar schemas
\dn
-- Listar tablas de un schema
\dt auth_management.*
-- Listar todas las tablas
\dt *.*
-- Describir tabla
\d auth_management.profiles
-- Listar funciones
\df
-- Listar triggers de una tabla
\dy auth_management.profiles
-- Listar índices de una tabla
\di auth_management.profiles
-- Ver tamaño de tablas
\dt+ *.*
-- Ayuda
\?
-- Salir
\q
Configuración
-- Mostrar configuración actual
\set
-- Timing de queries
\timing on
-- Formato expandido (mejor para filas anchas)
\x auto
-- Paginación
\pset pager off
🔍 Queries Comunes por Caso de Uso
1. Autenticación
-- Buscar usuario por email
SELECT id, email, full_name, role, status
FROM auth_management.profiles
WHERE email = 'student@example.com';
-- Verificar sesiones activas de un usuario
SELECT session_token, device_type, ip_address, expires_at, created_at
FROM auth_management.user_sessions
WHERE user_id = 'user-uuid'
AND expires_at > NOW()
ORDER BY created_at DESC;
-- Contar intentos de login fallidos recientes
SELECT COUNT(*)
FROM auth_management.auth_attempts
WHERE user_id = 'user-uuid'
AND success = false
AND created_at > NOW() - INTERVAL '15 minutes';
-- Listar usuarios por rol
SELECT id, email, full_name, role, status, created_at
FROM auth_management.profiles
WHERE role = 'student'
AND status = 'active'
ORDER BY created_at DESC
LIMIT 10;
2. Gamificación
-- Stats generales de un usuario
SELECT user_id, level, total_xp, ml_coins,
current_streak, max_streak,
exercises_completed, average_score,
global_rank_position
FROM gamification_system.user_stats
WHERE user_id = 'user-uuid';
-- Balance de ML Coins actual
SELECT ml_coins
FROM gamification_system.user_stats
WHERE user_id = 'user-uuid';
-- Historial de transacciones ML Coins (últimas 20)
SELECT id, amount, transaction_type, reason,
balance_after, created_at
FROM gamification_system.ml_coins_ledger
WHERE user_id = 'user-uuid'
ORDER BY created_at DESC
LIMIT 20;
-- Top 10 ranking global
SELECT u.user_id, p.display_name, u.total_xp,
u.level, u.ml_coins, u.global_rank_position
FROM gamification_system.user_stats u
JOIN auth_management.profiles p ON u.user_id = p.id
WHERE u.global_rank_position IS NOT NULL
ORDER BY u.global_rank_position ASC
LIMIT 10;
-- Achievements desbloqueados por usuario
SELECT ua.achievement_id, a.name, a.description,
a.category, a.rarity, a.ml_coins_reward,
ua.unlocked_at
FROM gamification_system.user_achievements ua
JOIN gamification_system.achievements a ON ua.achievement_id = a.id
WHERE ua.user_id = 'user-uuid'
AND ua.is_claimed = true
ORDER BY ua.unlocked_at DESC;
-- Rango actual del usuario (Maya ranks)
SELECT r.rank_name, r.min_xp_required, r.benefits
FROM gamification_system.user_ranks ur
JOIN gamification_system.ranks r ON ur.rank_id = r.id
WHERE ur.user_id = 'user-uuid'
AND ur.is_current = true;
3. Progreso Educativo
-- Progreso general del estudiante
SELECT m.title AS module_name,
mp.status,
mp.progress_percentage,
mp.completed_exercises,
mp.total_exercises,
mp.average_score,
mp.time_spent,
mp.last_accessed_at
FROM progress_tracking.module_progress mp
JOIN educational_content.modules m ON mp.module_id = m.id
WHERE mp.user_id = 'user-uuid'
ORDER BY mp.last_accessed_at DESC;
-- Ejercicios completados recientemente
SELECT e.title AS exercise_name,
ea.score,
ea.is_correct,
ea.time_spent,
ea.attempt_number,
ea.created_at
FROM progress_tracking.exercise_attempts ea
JOIN educational_content.exercises e ON ea.exercise_id = e.id
WHERE ea.user_id = 'user-uuid'
AND ea.created_at > NOW() - INTERVAL '7 days'
ORDER BY ea.created_at DESC
LIMIT 20;
-- Estadísticas de un módulo específico
SELECT status,
completed_exercises || '/' || total_exercises AS progress,
progress_percentage || '%' AS percentage,
ROUND(average_score, 2) AS avg_score,
time_spent,
last_accessed_at
FROM progress_tracking.module_progress
WHERE user_id = 'user-uuid'
AND module_id = 'module-uuid';
-- Mecánicas más completadas
SELECT e.mechanic_type, COUNT(*) AS times_completed,
ROUND(AVG(ea.score), 2) AS avg_score
FROM progress_tracking.exercise_attempts ea
JOIN educational_content.exercises e ON ea.exercise_id = e.id
WHERE ea.user_id = 'user-uuid'
AND ea.is_correct = true
GROUP BY e.mechanic_type
ORDER BY times_completed DESC;
4. Teacher Dashboard
-- Aulas del profesor
SELECT c.id, c.name, c.grade_level,
c.current_students_count, c.capacity,
s.name AS school_name
FROM social_features.classrooms c
LEFT JOIN social_features.schools s ON c.school_id = s.id
WHERE c.teacher_id = 'teacher-uuid'
AND c.is_active = true
ORDER BY c.created_at DESC;
-- Estudiantes de un aula
SELECT p.id, p.display_name, p.email,
us.level, us.total_xp, us.ml_coins,
cm.enrolled_at
FROM social_features.classroom_members cm
JOIN auth_management.profiles p ON cm.student_id = p.id
JOIN gamification_system.user_stats us ON p.id = us.user_id
WHERE cm.classroom_id = 'classroom-uuid'
AND cm.status = 'active'
ORDER BY us.total_xp DESC;
-- Progreso de estudiantes en un módulo
SELECT p.display_name,
mp.status,
mp.progress_percentage,
mp.average_score,
mp.time_spent
FROM progress_tracking.module_progress mp
JOIN auth_management.profiles p ON mp.user_id = p.id
JOIN social_features.classroom_members cm
ON cm.student_id = p.id
WHERE cm.classroom_id = 'classroom-uuid'
AND mp.module_id = 'module-uuid'
ORDER BY mp.progress_percentage DESC, mp.average_score DESC;
-- Estudiantes que necesitan atención (bajo rendimiento)
SELECT p.display_name, p.email,
us.exercises_completed,
us.average_score,
us.current_streak,
us.last_active_at
FROM gamification_system.user_stats us
JOIN auth_management.profiles p ON us.user_id = p.id
JOIN social_features.classroom_members cm ON p.id = cm.student_id
WHERE cm.classroom_id = 'classroom-uuid'
AND (us.average_score < 70 OR us.current_streak = 0)
ORDER BY us.average_score ASC;
5. Analytics
-- Actividad diaria de la plataforma (últimos 7 días)
SELECT DATE(created_at) AS date,
COUNT(DISTINCT user_id) AS active_users,
COUNT(*) AS total_exercises
FROM progress_tracking.exercise_attempts
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY DATE(created_at)
ORDER BY date DESC;
-- Sesiones de aprendizaje promedio por usuario
SELECT u.user_id, p.display_name,
COUNT(ls.id) AS total_sessions,
AVG(EXTRACT(EPOCH FROM ls.duration) / 60) AS avg_duration_minutes,
SUM(ls.exercises_completed) AS total_exercises
FROM progress_tracking.learning_sessions ls
JOIN gamification_system.user_stats u ON ls.user_id = u.user_id
JOIN auth_management.profiles p ON u.user_id = p.id
WHERE ls.created_at > NOW() - INTERVAL '30 days'
GROUP BY u.user_id, p.display_name
HAVING COUNT(ls.id) > 5
ORDER BY total_sessions DESC
LIMIT 20;
-- Retención de usuarios (días activos)
SELECT days_active_total AS days_active,
COUNT(*) AS user_count
FROM gamification_system.user_stats
GROUP BY days_active_total
ORDER BY days_active_total DESC;
-- Conversión de intentos a completaciones
SELECT e.title,
COUNT(*) AS total_attempts,
SUM(CASE WHEN ea.is_correct THEN 1 ELSE 0 END) AS successful,
ROUND(100.0 * SUM(CASE WHEN ea.is_correct THEN 1 ELSE 0 END) / COUNT(*), 2) AS success_rate
FROM progress_tracking.exercise_attempts ea
JOIN educational_content.exercises e ON ea.exercise_id = e.id
WHERE ea.created_at > NOW() - INTERVAL '30 days'
GROUP BY e.id, e.title
HAVING COUNT(*) >= 10
ORDER BY success_rate ASC
LIMIT 10;
🔗 Relaciones Principales
User → Stats → Progress
-- Diagrama de relaciones
auth_management.profiles (id)
↓
gamification_system.user_stats (user_id)
↓
progress_tracking.module_progress (user_id)
↓
progress_tracking.exercise_attempts (user_id)
School → Classroom → Students
-- Diagrama de relaciones
social_features.schools (id)
↓
social_features.classrooms (school_id, teacher_id)
↓
social_features.classroom_members (classroom_id, student_id)
↓
auth_management.profiles (id)
Module → Exercise → Attempts
-- Diagrama de relaciones
educational_content.modules (id)
↓
educational_content.exercises (module_id)
↓
progress_tracking.exercise_attempts (exercise_id, user_id)
⚡ Funciones Útiles
Función: gamilit.now_mexico()
Retorna timestamp en zona horaria de México.
-- Uso
SELECT gamilit.now_mexico();
-- Comparar con UTC
SELECT NOW() AS utc_time, gamilit.now_mexico() AS mexico_time;
Función: gamilit.update_updated_at()
Trigger function para actualizar automáticamente updated_at.
-- Ya está aplicado automáticamente a todas las tablas principales
-- No necesitas llamarlo manualmente
Calcular Nivel desde XP
-- Fórmula: level = floor(sqrt(total_xp / 100)) + 1
SELECT FLOOR(SQRT(total_xp / 100)) + 1 AS calculated_level
FROM gamification_system.user_stats
WHERE user_id = 'user-uuid';
📈 Índices y Performance
Ver índices de una tabla
-- Listar índices
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'profiles'
AND schemaname = 'auth_management';
-- Uso de índices (requiere pg_stat_statements)
SELECT schemaname, tablename, indexname,
idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes
WHERE schemaname = 'auth_management'
ORDER BY idx_scan DESC;
Índices más importantes
-- Email lookup (muy frecuente)
CREATE INDEX idx_profiles_email ON auth_management.profiles(email);
-- User stats lookup
CREATE INDEX idx_user_stats_user_id ON gamification_system.user_stats(user_id);
-- Exercise attempts por usuario
CREATE INDEX idx_exercise_attempts_user_id
ON progress_tracking.exercise_attempts(user_id);
-- Sesiones activas
CREATE INDEX idx_sessions_expires
ON auth_management.user_sessions(expires_at)
WHERE expires_at > NOW();
🔐 RLS (Row Level Security)
Verificar políticas RLS
-- Listar políticas de una tabla
SELECT schemaname, tablename, policyname, cmd, qual
FROM pg_policies
WHERE tablename = 'profiles';
-- Verificar si RLS está habilitado
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'auth_management';
Políticas comunes
-- Students can only see their own data
CREATE POLICY students_view_own_data
ON progress_tracking.module_progress
FOR SELECT
USING (user_id = current_setting('app.current_user_id')::UUID);
-- Teachers can see their classroom students
CREATE POLICY teachers_view_classroom_data
ON progress_tracking.module_progress
FOR SELECT
USING (
EXISTS (
SELECT 1
FROM social_features.classroom_members cm
JOIN social_features.classrooms c ON cm.classroom_id = c.id
WHERE cm.student_id = module_progress.user_id
AND c.teacher_id = current_setting('app.current_user_id')::UUID
)
);
🛠️ Mantenimiento
Vacuum y Analyze
-- Vacuum de una tabla
VACUUM ANALYZE auth_management.profiles;
-- Vacuum de todo el schema
VACUUM ANALYZE auth_management.*;
-- Ver última vez que se ejecutó
SELECT schemaname, relname, last_vacuum, last_autovacuum, last_analyze
FROM pg_stat_user_tables
WHERE schemaname = 'auth_management'
ORDER BY last_vacuum DESC NULLS LAST;
Ver tamaño de tablas
-- Tamaño de una tabla
SELECT pg_size_pretty(pg_total_relation_size('auth_management.profiles'));
-- Top 10 tablas más grandes
SELECT schemaname, tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
LIMIT 10;
Ver locks activos
-- Locks actuales
SELECT pid, usename, pg_blocking_pids(pid) AS blocked_by,
query, state
FROM pg_stat_activity
WHERE pg_blocking_pids(pid)::text != '{}';
-- Terminar query lento
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid = 12345;
📊 Backups
Backup completo
# Backup de toda la database
pg_dump -U gamilit_user -d gamilit_platform -h localhost \
-F c -f gamilit_backup_$(date +%Y%m%d).dump
# Backup de un schema específico
pg_dump -U gamilit_user -d gamilit_platform -h localhost \
-n auth_management -F c -f auth_schema_$(date +%Y%m%d).dump
# Backup en SQL text
pg_dump -U gamilit_user -d gamilit_platform -h localhost \
-F p -f gamilit_backup_$(date +%Y%m%d).sql
Restore
# Restore desde custom format
pg_restore -U gamilit_user -d gamilit_platform -h localhost \
-c gamilit_backup_20251107.dump
# Restore desde SQL text
psql -U gamilit_user -d gamilit_platform -h localhost \
-f gamilit_backup_20251107.sql
🧪 Testing Queries
Crear usuario de prueba
-- Insertar perfil
INSERT INTO auth_management.profiles
(id, email, full_name, display_name, role, status)
VALUES
(gen_random_uuid(), 'test@example.com', 'Test User', 'Test', 'student', 'active')
RETURNING id;
-- Stats se crean automáticamente por trigger
Limpiar datos de prueba
-- Eliminar usuario de prueba (cascade eliminará stats, progress, etc.)
DELETE FROM auth_management.profiles
WHERE email LIKE '%@example.com';
-- Resetear sequence (si aplica)
ALTER SEQUENCE some_sequence RESTART WITH 1;
Ver queries lentas (últimas 24h)
-- Requiere pg_stat_statements extension
SELECT calls, total_exec_time, mean_exec_time,
substring(query, 1, 100) AS query_preview
FROM pg_stat_statements
WHERE total_exec_time > 1000 -- más de 1 segundo total
ORDER BY mean_exec_time DESC
LIMIT 10;
💡 Tips y Best Practices
1. Siempre usar tenant_id en queries multi-tenant
-- ❌ MAL (no filtra por tenant)
SELECT * FROM auth_management.profiles WHERE email = 'test@example.com';
-- ✅ BIEN (filtra por tenant)
SELECT * FROM auth_management.profiles
WHERE email = 'test@example.com'
AND tenant_id = 'tenant-uuid';
2. Usar prepared statements
-- Preparar statement
PREPARE get_user_stats (UUID) AS
SELECT level, total_xp, ml_coins, current_streak
FROM gamification_system.user_stats
WHERE user_id = $1;
-- Ejecutar
EXECUTE get_user_stats('user-uuid');
-- Deallocate cuando termines
DEALLOCATE get_user_stats;
3. EXPLAIN para entender queries lentas
-- Ver plan de ejecución
EXPLAIN SELECT * FROM auth_management.profiles WHERE email = 'test@example.com';
-- Ver plan con costos reales
EXPLAIN ANALYZE SELECT * FROM auth_management.profiles WHERE email = 'test@example.com';
4. Transacciones para operaciones atómicas
BEGIN;
-- Restar ML Coins
UPDATE gamification_system.user_stats
SET ml_coins = ml_coins - 50
WHERE user_id = 'user-uuid'
AND ml_coins >= 50;
-- Registrar transacción
INSERT INTO gamification_system.ml_coins_ledger
(user_id, amount, transaction_type, reason, balance_after)
VALUES
('user-uuid', -50, 'powerup_purchase', 'Bought hint', 450);
COMMIT;
📚 Recursos
Documentación completa:
- ESQUEMA-COMPLETO.md - Esquema detallado de 44 tablas
- RLS-POLICIES.md - Políticas de Row Level Security
- MIGRACIONES.md - Sistema de migraciones
DDL Files:
- apps/database/ddl/ - Definiciones de esquema
PostgreSQL Docs:
Última actualización: 2025-11-07 Versión: 1.0 Método: Extracted from ESQUEMA-COMPLETO.md