DDL schemas for Trading Platform: - User management - Authentication - Payments - Education - ML predictions - Trading data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13 KiB
Documentación Técnica - Schema Education
Proyecto: Trading Platform (Trading Platform) Schema: education PostgreSQL: 15+ Versión: 1.0.0
Estadísticas del Schema
- ENUMs: 6 tipos
- Tablas: 14 tablas
- Funciones: 8 funciones
- Triggers: 15+ triggers
- Vistas: 7 vistas
- Índices: 60+ índices
- Total líneas SQL: ~1,350 líneas
Índices por Tabla
categories
idx_categories_parent- parent_ididx_categories_slug- slugidx_categories_active- is_active (WHERE is_active = true)
courses
idx_courses_category- category_ididx_courses_slug- slugidx_courses_status- statusidx_courses_difficulty- difficulty_levelidx_courses_instructor- instructor_ididx_courses_published- published_at (WHERE status = 'published')
modules
idx_modules_course- course_ididx_modules_order- course_id, display_order
lessons
idx_lessons_module- module_ididx_lessons_order- module_id, display_orderidx_lessons_type- content_typeidx_lessons_preview- is_preview (WHERE is_preview = true)
enrollments
idx_enrollments_user- user_ididx_enrollments_course- course_ididx_enrollments_status- statusidx_enrollments_user_active- user_id, status (WHERE status = 'active')
progress
idx_progress_user- user_ididx_progress_lesson- lesson_ididx_progress_enrollment- enrollment_ididx_progress_completed- is_completed (WHERE is_completed = true)idx_progress_user_enrollment- user_id, enrollment_id
quizzes
idx_quizzes_module- module_ididx_quizzes_lesson- lesson_ididx_quizzes_active- is_active (WHERE is_active = true)
quiz_questions
idx_quiz_questions_quiz- quiz_ididx_quiz_questions_order- quiz_id, display_order
quiz_attempts
idx_quiz_attempts_user- user_ididx_quiz_attempts_quiz- quiz_ididx_quiz_attempts_enrollment- enrollment_ididx_quiz_attempts_user_quiz- user_id, quiz_ididx_quiz_attempts_completed- is_completed, completed_at
certificates
idx_certificates_user- user_ididx_certificates_course- course_ididx_certificates_number- certificate_numberidx_certificates_verification- verification_code
user_achievements
idx_user_achievements_user- user_ididx_user_achievements_type- achievement_typeidx_user_achievements_earned- earned_at DESCidx_user_achievements_course- course_id
user_gamification_profile
idx_gamification_user- user_ididx_gamification_level- current_level DESCidx_gamification_xp- total_xp DESCidx_gamification_weekly- weekly_xp DESCidx_gamification_monthly- monthly_xp DESC
user_activity_log
idx_activity_user- user_ididx_activity_type- activity_typeidx_activity_created- created_at DESCidx_activity_user_date- user_id, created_at DESCidx_activity_course- course_id (WHERE course_id IS NOT NULL)
course_reviews
idx_reviews_course- course_ididx_reviews_user- user_ididx_reviews_rating- ratingidx_reviews_approved- is_approved (WHERE is_approved = true)idx_reviews_featured- is_featured (WHERE is_featured = true)idx_reviews_helpful- helpful_votes DESC
Constraints
CHECK Constraints
categories:
valid_color_format- Color debe ser formato #RRGGBB
courses:
valid_rating- avg_rating >= 0 AND <= 5valid_price- price_usd >= 0
lessons:
video_fields_required- Si content_type='video', video_url y video_duration_seconds requeridos
enrollments:
valid_progress- progress_percentage >= 0 AND <= 100valid_completion- Si status='completed', completed_at y progress=100 requeridos
progress:
valid_watch_percentage- watch_percentage >= 0 AND <= 100completion_requires_date- Si is_completed=true, completed_at requerido
quizzes:
valid_passing_score- passing_score_percentage > 0 AND <= 100quiz_association- Debe tener module_id O lesson_id (no ambos)
quiz_questions:
valid_options- Si question_type requiere options, options no puede ser NULL
quiz_attempts:
valid_score_percentage- score_percentage >= 0 AND <= 100
user_gamification_profile:
valid_level- current_level >= 1valid_xp- total_xp >= 0valid_streak- current_streak_days >= 0 AND longest_streak_days >= 0valid_avg_score- average_quiz_score >= 0 AND <= 100
course_reviews:
rating- rating >= 1 AND <= 5
UNIQUE Constraints
categories.slug- UNIQUEcourses.slug- UNIQUEmodules.unique_course_order- UNIQUE(course_id, display_order)lessons.unique_module_order- UNIQUE(module_id, display_order)enrollments.unique_user_course- UNIQUE(user_id, course_id)progress.unique_user_lesson- UNIQUE(user_id, lesson_id)certificates.certificate_number- UNIQUEcertificates.verification_code- UNIQUEcertificates.unique_user_course_cert- UNIQUE(user_id, course_id)user_gamification_profile.unique_user_gamification- UNIQUE(user_id)course_reviews.unique_user_course_review- UNIQUE(user_id, course_id)
Foreign Keys
Relaciones con auth.users
courses.instructor_id→auth.users(id)ON DELETE RESTRICTenrollments.user_id→auth.users(id)ON DELETE CASCADEprogress.user_id→auth.users(id)ON DELETE CASCADEquiz_attempts.user_id→auth.users(id)ON DELETE CASCADEcertificates.user_id→auth.users(id)ON DELETE CASCADEuser_achievements.user_id→auth.users(id)ON DELETE CASCADEuser_gamification_profile.user_id→auth.users(id)ON DELETE CASCADEuser_activity_log.user_id→auth.users(id)ON DELETE CASCADEcourse_reviews.user_id→auth.users(id)ON DELETE CASCADEcourse_reviews.approved_by→auth.users(id)
Relaciones internas
categories.parent_id→categories(id)ON DELETE SET NULLcourses.category_id→categories(id)ON DELETE RESTRICTmodules.course_id→courses(id)ON DELETE CASCADEmodules.unlock_after_module_id→modules(id)ON DELETE SET NULLlessons.module_id→modules(id)ON DELETE CASCADEenrollments.course_id→courses(id)ON DELETE RESTRICTprogress.lesson_id→lessons(id)ON DELETE CASCADEprogress.enrollment_id→enrollments(id)ON DELETE CASCADEquizzes.module_id→modules(id)ON DELETE CASCADEquizzes.lesson_id→lessons(id)ON DELETE CASCADEquiz_questions.quiz_id→quizzes(id)ON DELETE CASCADEquiz_attempts.quiz_id→quizzes(id)ON DELETE RESTRICTquiz_attempts.enrollment_id→enrollments(id)ON DELETE SET NULLcertificates.course_id→courses(id)ON DELETE RESTRICTcertificates.enrollment_id→enrollments(id)ON DELETE RESTRICTuser_achievements.course_id→courses(id)ON DELETE SET NULLuser_achievements.quiz_id→quizzes(id)ON DELETE SET NULLuser_activity_log.course_id→courses(id)ON DELETE SET NULLuser_activity_log.lesson_id→lessons(id)ON DELETE SET NULLuser_activity_log.quiz_id→quizzes(id)ON DELETE SET NULLcourse_reviews.course_id→courses(id)ON DELETE CASCADEcourse_reviews.enrollment_id→enrollments(id)ON DELETE CASCADE
Triggers
Triggers de updated_at
Aplica a: categories, courses, modules, lessons, enrollments, progress, quizzes, quiz_questions, user_gamification_profile, course_reviews
Función: education.update_updated_at_column()
Trigger: update_{table}_updated_at
Evento: BEFORE UPDATE
Acción: Actualiza updated_at = NOW()
Triggers de lógica de negocio
update_enrollment_on_progress
- Tabla: progress
- Función:
education.update_enrollment_progress() - Evento: AFTER INSERT OR UPDATE
- Condición: WHEN (NEW.is_completed = true)
- Acción: Recalcula progreso del enrollment
auto_complete_enrollment_trigger
- Tabla: enrollments
- Función:
education.auto_complete_enrollment() - Evento: BEFORE UPDATE
- Acción: Completa enrollment si progress >= 100%
generate_certificate_number_trigger
- Tabla: certificates
- Función:
education.generate_certificate_number() - Evento: BEFORE INSERT
- Acción: Genera certificate_number y verification_code
update_course_rating_on_review_insert
- Tabla: course_reviews
- Función:
education.update_course_rating_stats() - Evento: AFTER INSERT
- Acción: Actualiza avg_rating del curso
update_course_rating_on_review_update
- Tabla: course_reviews
- Función:
education.update_course_rating_stats() - Evento: AFTER UPDATE
- Condición: rating o is_approved cambió
- Acción: Actualiza avg_rating del curso
update_course_rating_on_review_delete
- Tabla: course_reviews
- Función:
education.update_course_rating_stats() - Evento: AFTER DELETE
- Acción: Actualiza avg_rating del curso
update_enrollment_count_on_insert
- Tabla: enrollments
- Función:
education.update_enrollment_count() - Evento: AFTER INSERT
- Acción: Incrementa contador en courses
update_enrollment_count_on_delete
- Tabla: enrollments
- Función:
education.update_enrollment_count() - Evento: AFTER DELETE
- Acción: Decrementa contador en courses
update_streak_on_activity
- Tabla: user_activity_log
- Función:
education.trigger_update_streak() - Evento: AFTER INSERT
- Acción: Actualiza streak del usuario
Funciones Públicas
education.update_user_xp(user_id UUID, xp_to_add INTEGER)
Actualiza XP del usuario y recalcula nivel.
Parámetros:
user_id: UUID del usuarioxp_to_add: Cantidad de XP a agregar
Lógica:
- Suma XP al total
- Calcula nuevo nivel basado en fórmula cuadrática
- Actualiza weekly_xp y monthly_xp
- Crea achievement si subió de nivel
Ejemplo:
SELECT education.update_user_xp(
'00000000-0000-0000-0000-000000000001',
100
);
education.update_user_streak(user_id UUID)
Actualiza streak del usuario basado en actividad diaria.
Parámetros:
user_id: UUID del usuario
Lógica:
- Verifica última actividad
- Incrementa streak si es día consecutivo
- Resetea streak si se rompió
- Crea achievement en milestones (7, 30, 100 días)
Ejemplo:
SELECT education.update_user_streak(
'00000000-0000-0000-0000-000000000001'
);
Vistas Materializadas Recomendadas
Para mejorar performance en queries frecuentes:
-- Top cursos por enrollments (actualizar diariamente)
CREATE MATERIALIZED VIEW education.mv_top_courses AS
SELECT * FROM education.v_popular_courses;
CREATE UNIQUE INDEX ON education.mv_top_courses(id);
-- Leaderboards (actualizar cada hora)
CREATE MATERIALIZED VIEW education.mv_leaderboard_weekly AS
SELECT * FROM education.v_leaderboard_weekly;
CREATE UNIQUE INDEX ON education.mv_leaderboard_weekly(user_id);
Optimizaciones Recomendadas
1. Particionamiento de user_activity_log
Para logs con alto volumen:
-- Particionar por mes
CREATE TABLE education.user_activity_log_2025_12
PARTITION OF education.user_activity_log
FOR VALUES FROM ('2025-12-01') TO ('2026-01-01');
2. Índices adicionales según uso
-- Si hay muchas búsquedas por título de curso
CREATE INDEX idx_courses_title_trgm ON education.courses
USING gin(title gin_trgm_ops);
-- Requiere extension pg_trgm
CREATE EXTENSION IF NOT EXISTS pg_trgm;
3. Vacuum y Analyze automático
-- Configurar autovacuum para tablas con alta escritura
ALTER TABLE education.user_activity_log
SET (autovacuum_vacuum_scale_factor = 0.01);
ALTER TABLE education.progress
SET (autovacuum_vacuum_scale_factor = 0.02);
Monitoreo
Queries útiles para monitoreo
Tamaño de tablas:
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE schemaname = 'education'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
Índices no usados:
SELECT
schemaname,
tablename,
indexname,
idx_scan
FROM pg_stat_user_indexes
WHERE schemaname = 'education' AND idx_scan = 0;
Actividad de enrollments hoy:
SELECT COUNT(*)
FROM education.enrollments
WHERE enrolled_at::date = CURRENT_DATE;
Cursos más populares (últimos 7 días):
SELECT
c.title,
COUNT(e.id) as new_enrollments
FROM education.courses c
LEFT JOIN education.enrollments e ON c.id = e.course_id
AND e.enrolled_at >= NOW() - INTERVAL '7 days'
GROUP BY c.id, c.title
ORDER BY new_enrollments DESC
LIMIT 10;
Backup y Restore
Backup solo del schema education
pg_dump -h localhost -U postgres -n education trading_platform > education_backup.sql
Restore
psql -h localhost -U postgres trading_platform < education_backup.sql
Versión y Changelog
v1.0.0 (2025-12-06)
- Implementación inicial completa
- 14 tablas
- 8 funciones
- 7 vistas
- Sistema de gamificación completo
- Reviews de cursos
- Activity logging
Documentación generada: 2025-12-06 Última revisión: 2025-12-06