From 5a0a29412c96e87327f68587d6f63daadf5aeafb Mon Sep 17 00:00:00 2001 From: rckrdmrd Date: Fri, 19 Dec 2025 01:37:45 -0600 Subject: [PATCH] Gamilit: Teacher portal fixes, database initialization improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend: - Fix exercise-responses DTO and service for teacher portal Database: - Update prerequisites and initialize_user_stats function - Fix init-database script - Update tenants seeds (dev/prod) - Add production users and profiles seeds Orchestration: - Document critical gap in responses page πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../teacher/dto/exercise-responses.dto.ts | 43 + .../services/exercise-responses.service.ts | 395 +++++--- .../apps/database/ddl/00-prerequisites.sql | 45 +- .../functions/04-initialize_user_stats.sql | 16 +- .../apps/database/scripts/init-database.sh | 43 +- .../seeds/dev/auth/02-production-users.sql | 863 ++++++++++++++++++ .../seeds/dev/auth_management/01-tenants.sql | 31 + .../07-profiles-production-additional.sql | 646 +++++++++++++ .../seeds/prod/auth_management/01-tenants.sql | 31 + .../07-profiles-production-additional.sql | 646 +++++++++++++ .../50-GAP-CRITICO-RESPONSES-PAGE.md | 489 +++++----- 11 files changed, 2827 insertions(+), 421 deletions(-) create mode 100644 projects/gamilit/apps/database/seeds/dev/auth/02-production-users.sql create mode 100644 projects/gamilit/apps/database/seeds/dev/auth_management/07-profiles-production-additional.sql create mode 100644 projects/gamilit/apps/database/seeds/prod/auth_management/07-profiles-production-additional.sql diff --git a/projects/gamilit/apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts b/projects/gamilit/apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts index 3ac7725..c56cc6e 100644 --- a/projects/gamilit/apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts +++ b/projects/gamilit/apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts @@ -35,6 +35,24 @@ export enum SortOrder { DESC = 'desc', } +/** + * G20 FIX: Source of the response (which table it comes from) + */ +export enum ResponseSource { + ATTEMPT = 'attempt', + SUBMISSION = 'submission', +} + +/** + * G20 FIX: Status for exercise submissions (only for source='submission') + */ +export enum ExerciseSubmissionStatus { + DRAFT = 'draft', + SUBMITTED = 'submitted', + GRADED = 'graded', + REVIEWED = 'reviewed', +} + /** * Query DTO for filtering exercise attempts */ @@ -247,6 +265,31 @@ export class AttemptResponseDto { example: '2024-11-24T10:30:00Z', }) submitted_at!: string; + + // G20 FIX: New fields to support exercise_submissions table + @ApiPropertyOptional({ + description: 'Source of the response (attempt=auto-graded, submission=manual review)', + enum: ResponseSource, + example: 'attempt', + }) + source?: ResponseSource; + + @ApiPropertyOptional({ + description: 'Status (only for submissions - draft, submitted, graded, reviewed)', + enum: ExerciseSubmissionStatus, + example: 'submitted', + }) + status?: ExerciseSubmissionStatus; + + @ApiPropertyOptional({ + description: 'Feedback from teacher (only for submissions)', + }) + feedback?: string; + + @ApiPropertyOptional({ + description: 'Whether the exercise requires manual grading', + }) + requires_manual_grading?: boolean; } /** diff --git a/projects/gamilit/apps/backend/src/modules/teacher/services/exercise-responses.service.ts b/projects/gamilit/apps/backend/src/modules/teacher/services/exercise-responses.service.ts index f4b53de..dc72580 100644 --- a/projects/gamilit/apps/backend/src/modules/teacher/services/exercise-responses.service.ts +++ b/projects/gamilit/apps/backend/src/modules/teacher/services/exercise-responses.service.ts @@ -15,6 +15,8 @@ import { AttemptResponseDto, AttemptDetailDto, AttemptsListResponseDto, + ResponseSource, + ExerciseSubmissionStatus, } from '../dto/exercise-responses.dto'; /** @@ -74,6 +76,13 @@ export class ExerciseResponsesService { * is_correct: true, * }); */ + /** + * G20 FIX: Get paginated list of exercise responses from BOTH tables + * - exercise_attempts: Auto-graded exercises (modules 1-3) + * - exercise_submissions: Manual review exercises (modules 4-5) + * + * Uses UNION query to combine both sources. + */ async getAttempts( userId: string, query: GetAttemptsQueryDto, @@ -89,107 +98,175 @@ export class ExerciseResponsesService { const limit = query.limit || 20; const offset = (page - 1) * limit; - // Sorting + // Sorting - use alias for UNION compatibility const sortField = query.sort_by === 'score' - ? 'attempt.score' + ? 'score' : query.sort_by === 'time' - ? 'attempt.time_spent_seconds' - : 'attempt.submitted_at'; + ? 'time_spent_seconds' + : 'submitted_at'; const sortOrder = query.sort_order?.toUpperCase() === 'ASC' ? 'ASC' : 'DESC'; - // Build WHERE conditions dynamically - const conditions: string[] = [ - '(c.teacher_id = $1 OR EXISTS (SELECT 1 FROM social_features.teacher_classrooms tc WHERE tc.teacher_id = $1 AND tc.classroom_id = c.id))', - 'profile.tenant_id = $2', - ]; + // Build base params const params: any[] = [teacherId, tenantId]; let paramIndex = 3; + // Build dynamic conditions for attempts + // Note: teacher access is validated via classrooms.teacher_id + const buildConditions = () => { + const conditions: string[] = [ + 'c.teacher_id = $1', + 'profile.tenant_id = $2', + ]; + return conditions; + }; + + let attemptsConditions = buildConditions(); + let submissionsConditions = buildConditions(); + + // Add dynamic filters + const dynamicParams: any[] = []; + if (query.student_id) { - conditions.push(`profile.id = $${paramIndex}`); - params.push(query.student_id); + attemptsConditions.push(`profile.id = $${paramIndex}`); + submissionsConditions.push(`profile.id = $${paramIndex}`); + dynamicParams.push(query.student_id); paramIndex++; } if (query.exercise_id) { - conditions.push(`attempt.exercise_id = $${paramIndex}`); - params.push(query.exercise_id); + attemptsConditions.push(`attempt.exercise_id = $${paramIndex}`); + submissionsConditions.push(`sub.exercise_id = $${paramIndex}`); + dynamicParams.push(query.exercise_id); paramIndex++; } if (query.module_id) { - conditions.push(`exercise.module_id = $${paramIndex}`); - params.push(query.module_id); + attemptsConditions.push(`exercise.module_id = $${paramIndex}`); + submissionsConditions.push(`exercise.module_id = $${paramIndex}`); + dynamicParams.push(query.module_id); paramIndex++; } if (query.classroom_id) { - conditions.push(`c.id = $${paramIndex}`); - params.push(query.classroom_id); + attemptsConditions.push(`c.id = $${paramIndex}`); + submissionsConditions.push(`c.id = $${paramIndex}`); + dynamicParams.push(query.classroom_id); paramIndex++; } if (query.from_date) { - conditions.push(`attempt.submitted_at >= $${paramIndex}`); - params.push(query.from_date); + attemptsConditions.push(`attempt.submitted_at >= $${paramIndex}`); + submissionsConditions.push(`sub.submitted_at >= $${paramIndex}`); + dynamicParams.push(query.from_date); paramIndex++; } if (query.to_date) { - conditions.push(`attempt.submitted_at <= $${paramIndex}`); - params.push(query.to_date); + attemptsConditions.push(`attempt.submitted_at <= $${paramIndex}`); + submissionsConditions.push(`sub.submitted_at <= $${paramIndex}`); + dynamicParams.push(query.to_date); paramIndex++; } if (query.is_correct !== undefined) { - conditions.push(`attempt.is_correct = $${paramIndex}`); - params.push(query.is_correct); + attemptsConditions.push(`attempt.is_correct = $${paramIndex}`); + submissionsConditions.push(`sub.is_correct = $${paramIndex}`); + dynamicParams.push(query.is_correct); paramIndex++; } if (query.student_search) { const searchPattern = `%${query.student_search}%`; - conditions.push(`( + const searchCondition = `( profile.first_name ILIKE $${paramIndex} OR profile.last_name ILIKE $${paramIndex} OR CONCAT(profile.first_name, ' ', profile.last_name) ILIKE $${paramIndex} - )`); - params.push(searchPattern); + )`; + attemptsConditions.push(searchCondition); + submissionsConditions.push(searchCondition); + dynamicParams.push(searchPattern); paramIndex++; } - const whereClause = conditions.join(' AND '); + // Submissions: exclude drafts + submissionsConditions.push("sub.status != 'draft'"); - // Main query using raw SQL for cross-schema JOINs + const attemptsWhere = attemptsConditions.join(' AND '); + const submissionsWhere = submissionsConditions.join(' AND '); + + // Merge dynamic params + params.push(...dynamicParams); + + // G20 FIX: UNION query combining both tables + // Note: to_jsonb(sub.comodines_used) converts text[] to jsonb for UNION compatibility const sql = ` - SELECT - attempt.id AS attempt_id, - attempt.user_id AS attempt_user_id, - attempt.exercise_id AS attempt_exercise_id, - attempt.attempt_number AS attempt_attempt_number, - attempt.submitted_answers AS attempt_submitted_answers, - attempt.is_correct AS attempt_is_correct, - attempt.score AS attempt_score, - attempt.time_spent_seconds AS attempt_time_spent_seconds, - attempt.hints_used AS attempt_hints_used, - attempt.comodines_used AS attempt_comodines_used, - attempt.xp_earned AS attempt_xp_earned, - attempt.ml_coins_earned AS attempt_ml_coins_earned, - attempt.submitted_at AS attempt_submitted_at, - profile.id AS profile_id, - profile.first_name AS profile_first_name, - profile.last_name AS profile_last_name, - exercise.id AS exercise_id, - exercise.title AS exercise_title, - module.id AS module_id, - module.title AS module_name - FROM progress_tracking.exercise_attempts attempt - LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id - LEFT JOIN educational_content.exercises exercise ON exercise.id = attempt.exercise_id - LEFT JOIN educational_content.modules module ON module.id = exercise.module_id - LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id - LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id - WHERE ${whereClause} + SELECT * FROM ( + -- Ejercicios autocorregibles (exercise_attempts) + SELECT + 'attempt' AS source, + attempt.id AS id, + attempt.user_id AS user_id, + attempt.exercise_id AS exercise_id, + attempt.attempt_number AS attempt_number, + attempt.submitted_answers AS submitted_answers, + attempt.is_correct AS is_correct, + attempt.score AS score, + attempt.time_spent_seconds AS time_spent_seconds, + attempt.hints_used AS hints_used, + attempt.comodines_used AS comodines_used, + attempt.xp_earned AS xp_earned, + attempt.ml_coins_earned AS ml_coins_earned, + attempt.submitted_at AS submitted_at, + NULL::text AS status, + NULL::text AS feedback, + false AS requires_manual_grading, + profile.id AS profile_id, + profile.first_name AS first_name, + profile.last_name AS last_name, + exercise.title AS exercise_title, + module.title AS module_name + FROM progress_tracking.exercise_attempts attempt + LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id + LEFT JOIN educational_content.exercises exercise ON exercise.id = attempt.exercise_id + LEFT JOIN educational_content.modules module ON module.id = exercise.module_id + LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id + LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id + WHERE ${attemptsWhere} + + UNION ALL + + -- Ejercicios de revision manual (exercise_submissions) + SELECT + 'submission' AS source, + sub.id AS id, + sub.user_id AS user_id, + sub.exercise_id AS exercise_id, + sub.attempt_number AS attempt_number, + sub.answer_data AS submitted_answers, + sub.is_correct AS is_correct, + sub.score AS score, + sub.time_spent_seconds AS time_spent_seconds, + sub.hints_count AS hints_used, + to_jsonb(sub.comodines_used) AS comodines_used, + sub.xp_earned AS xp_earned, + sub.ml_coins_earned AS ml_coins_earned, + sub.submitted_at AS submitted_at, + sub.status AS status, + sub.feedback AS feedback, + true AS requires_manual_grading, + profile.id AS profile_id, + profile.first_name AS first_name, + profile.last_name AS last_name, + exercise.title AS exercise_title, + module.title AS module_name + FROM progress_tracking.exercise_submissions sub + LEFT JOIN auth_management.profiles profile ON profile.user_id = sub.user_id + LEFT JOIN educational_content.exercises exercise ON exercise.id = sub.exercise_id + LEFT JOIN educational_content.modules module ON module.id = exercise.module_id + LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id + LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id + WHERE ${submissionsWhere} + ) AS combined ORDER BY ${sortField} ${sortOrder} LIMIT $${paramIndex} OFFSET $${paramIndex + 1} `; @@ -199,15 +276,25 @@ export class ExerciseResponsesService { // Execute main query const rawResults = await this.dataSource.query(sql, params); - // Count query (separate for efficiency) + // Count query for both tables const countSql = ` - SELECT COUNT(DISTINCT attempt.id) as total - FROM progress_tracking.exercise_attempts attempt - LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id - LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id - LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id - LEFT JOIN educational_content.exercises exercise ON exercise.id = attempt.exercise_id - WHERE ${whereClause} + SELECT ( + (SELECT COUNT(DISTINCT attempt.id) + FROM progress_tracking.exercise_attempts attempt + LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id + LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id + LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id + LEFT JOIN educational_content.exercises exercise ON exercise.id = attempt.exercise_id + WHERE ${attemptsWhere}) + + + (SELECT COUNT(DISTINCT sub.id) + FROM progress_tracking.exercise_submissions sub + LEFT JOIN auth_management.profiles profile ON profile.user_id = sub.user_id + LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id + LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id + LEFT JOIN educational_content.exercises exercise ON exercise.id = sub.exercise_id + WHERE ${submissionsWhere}) + ) AS total `; // Remove LIMIT/OFFSET params for count query @@ -215,24 +302,29 @@ export class ExerciseResponsesService { const countResult = await this.dataSource.query(countSql, countParams); const total = parseInt(countResult[0]?.total || '0', 10); - // Transform raw results to DTOs + // Transform raw results to DTOs with new G20 fields const data: AttemptResponseDto[] = rawResults.map((row: any) => ({ - id: row.attempt_id, - student_id: row.attempt_user_id, - student_name: `${row.profile_first_name || ''} ${row.profile_last_name || ''}`.trim() || 'Unknown', - exercise_id: row.attempt_exercise_id, + id: row.id, + student_id: row.user_id, + student_name: `${row.first_name || ''} ${row.last_name || ''}`.trim() || 'Unknown', + exercise_id: row.exercise_id, exercise_title: row.exercise_title || 'Unknown Exercise', module_name: row.module_name || 'Unknown Module', - attempt_number: row.attempt_attempt_number, - submitted_answers: row.attempt_submitted_answers, - is_correct: row.attempt_is_correct ?? false, - score: row.attempt_score ?? 0, - time_spent_seconds: row.attempt_time_spent_seconds ?? 0, - hints_used: row.attempt_hints_used, - comodines_used: row.attempt_comodines_used, - xp_earned: row.attempt_xp_earned, - ml_coins_earned: row.attempt_ml_coins_earned, - submitted_at: row.attempt_submitted_at ? new Date(row.attempt_submitted_at).toISOString() : new Date().toISOString(), + attempt_number: row.attempt_number, + submitted_answers: row.submitted_answers, + is_correct: row.is_correct ?? false, + score: row.score ?? 0, + time_spent_seconds: row.time_spent_seconds ?? 0, + hints_used: row.hints_used ?? 0, + comodines_used: Array.isArray(row.comodines_used) ? row.comodines_used : (row.comodines_used || []), + xp_earned: row.xp_earned ?? 0, + ml_coins_earned: row.ml_coins_earned ?? 0, + submitted_at: row.submitted_at ? new Date(row.submitted_at).toISOString() : new Date().toISOString(), + // G20 FIX: New fields + source: row.source === 'submission' ? ResponseSource.SUBMISSION : ResponseSource.ATTEMPT, + status: row.status as ExerciseSubmissionStatus | undefined, + feedback: row.feedback || undefined, + requires_manual_grading: row.requires_manual_grading ?? false, })); return { @@ -297,13 +389,17 @@ export class ExerciseResponsesService { } /** - * Get detailed information for a specific attempt + * Get detailed information for a specific attempt or submission + * + * G20 FIX: Now searches BOTH tables: + * - exercise_attempts: Auto-graded exercises (modules 1-3) + * - exercise_submissions: Manual review exercises (modules 4-5) * * @param userId - Teacher's user ID (from auth.users) - * @param attemptId - Attempt ID + * @param attemptId - Attempt or Submission ID * @returns Detailed attempt information including correct answers * - * @throws NotFoundException if attempt not found + * @throws NotFoundException if attempt/submission not found * @throws ForbiddenException if teacher doesn't have access */ async getAttemptDetail( @@ -315,30 +411,34 @@ export class ExerciseResponsesService { const teacherId = teacherProfile.id; const tenantId = teacherProfile.tenant_id; - // Raw SQL query for cross-schema JOINs - const sql = ` + // G20 FIX: First try exercise_attempts table + const attemptSql = ` SELECT - attempt.id AS attempt_id, - attempt.user_id AS attempt_user_id, - attempt.exercise_id AS attempt_exercise_id, - attempt.attempt_number AS attempt_attempt_number, - attempt.submitted_answers AS attempt_submitted_answers, - attempt.is_correct AS attempt_is_correct, - attempt.score AS attempt_score, - attempt.time_spent_seconds AS attempt_time_spent_seconds, - attempt.hints_used AS attempt_hints_used, - attempt.comodines_used AS attempt_comodines_used, - attempt.xp_earned AS attempt_xp_earned, - attempt.ml_coins_earned AS attempt_ml_coins_earned, - attempt.submitted_at AS attempt_submitted_at, + 'attempt' AS source, + attempt.id AS record_id, + attempt.user_id AS user_id, + attempt.exercise_id AS exercise_id, + attempt.attempt_number AS attempt_number, + attempt.submitted_answers AS submitted_answers, + attempt.is_correct AS is_correct, + attempt.score AS score, + attempt.time_spent_seconds AS time_spent_seconds, + attempt.hints_used AS hints_used, + attempt.comodines_used AS comodines_used, + attempt.xp_earned AS xp_earned, + attempt.ml_coins_earned AS ml_coins_earned, + attempt.submitted_at AS submitted_at, + NULL::text AS status, + NULL::text AS feedback, + false AS requires_manual_grading, profile.id AS profile_id, - profile.first_name AS profile_first_name, - profile.last_name AS profile_last_name, - exercise.id AS exercise_id, + profile.first_name AS first_name, + profile.last_name AS last_name, + exercise.id AS ex_id, exercise.title AS exercise_title, exercise.exercise_type AS exercise_type, exercise.content AS exercise_content, - exercise.max_points AS exercise_max_points, + exercise.max_points AS max_points, module.id AS module_id, module.title AS module_name FROM progress_tracking.exercise_attempts attempt @@ -349,15 +449,62 @@ export class ExerciseResponsesService { LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id WHERE attempt.id = $1 AND profile.tenant_id = $2 - AND (c.teacher_id = $3 OR EXISTS (SELECT 1 FROM social_features.teacher_classrooms tc WHERE tc.teacher_id = $3 AND tc.classroom_id = c.id)) + AND c.teacher_id = $3 LIMIT 1 `; - const results = await this.dataSource.query(sql, [attemptId, tenantId, teacherId]); - const row = results[0]; + let results = await this.dataSource.query(attemptSql, [attemptId, tenantId, teacherId]); + let row = results[0]; + + // G20 FIX: If not found in attempts, try exercise_submissions + if (!row) { + const submissionSql = ` + SELECT + 'submission' AS source, + sub.id AS record_id, + sub.user_id AS user_id, + sub.exercise_id AS exercise_id, + sub.attempt_number AS attempt_number, + sub.answer_data AS submitted_answers, + sub.is_correct AS is_correct, + sub.score AS score, + sub.time_spent_seconds AS time_spent_seconds, + sub.hints_count AS hints_used, + to_jsonb(sub.comodines_used) AS comodines_used, + sub.xp_earned AS xp_earned, + sub.ml_coins_earned AS ml_coins_earned, + sub.submitted_at AS submitted_at, + sub.status AS status, + sub.feedback AS feedback, + true AS requires_manual_grading, + profile.id AS profile_id, + profile.first_name AS first_name, + profile.last_name AS last_name, + exercise.id AS ex_id, + exercise.title AS exercise_title, + exercise.exercise_type AS exercise_type, + exercise.content AS exercise_content, + exercise.max_points AS max_points, + module.id AS module_id, + module.title AS module_name + FROM progress_tracking.exercise_submissions sub + LEFT JOIN auth_management.profiles profile ON profile.user_id = sub.user_id + LEFT JOIN educational_content.exercises exercise ON exercise.id = sub.exercise_id + LEFT JOIN educational_content.modules module ON module.id = exercise.module_id + LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id + LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id + WHERE sub.id = $1 + AND profile.tenant_id = $2 + AND c.teacher_id = $3 + LIMIT 1 + `; + + results = await this.dataSource.query(submissionSql, [attemptId, tenantId, teacherId]); + row = results[0]; + } if (!row) { - throw new NotFoundException(`Attempt ${attemptId} not found or access denied`); + throw new NotFoundException(`Attempt/Submission ${attemptId} not found or access denied`); } // Parse exercise content if it's a string @@ -377,26 +524,31 @@ export class ExerciseResponsesService { const correctAnswer = this.extractCorrectAnswers(exerciseContent, row.exercise_type); return { - id: row.attempt_id, - student_id: row.attempt_user_id, - student_name: `${row.profile_first_name || ''} ${row.profile_last_name || ''}`.trim() || 'Unknown', - exercise_id: row.attempt_exercise_id, + id: row.record_id, + student_id: row.user_id, + student_name: `${row.first_name || ''} ${row.last_name || ''}`.trim() || 'Unknown', + exercise_id: row.exercise_id, exercise_title: row.exercise_title || 'Unknown Exercise', module_name: row.module_name || 'Unknown Module', - attempt_number: row.attempt_attempt_number, - submitted_answers: row.attempt_submitted_answers, - is_correct: row.attempt_is_correct ?? false, - score: row.attempt_score ?? 0, - time_spent_seconds: row.attempt_time_spent_seconds ?? 0, - hints_used: row.attempt_hints_used, - comodines_used: row.attempt_comodines_used, - xp_earned: row.attempt_xp_earned, - ml_coins_earned: row.attempt_ml_coins_earned, - submitted_at: row.attempt_submitted_at ? new Date(row.attempt_submitted_at).toISOString() : new Date().toISOString(), + attempt_number: row.attempt_number, + submitted_answers: row.submitted_answers, + is_correct: row.is_correct ?? false, + score: row.score ?? 0, + time_spent_seconds: row.time_spent_seconds ?? 0, + hints_used: row.hints_used ?? 0, + comodines_used: Array.isArray(row.comodines_used) ? row.comodines_used : (row.comodines_used || []), + xp_earned: row.xp_earned ?? 0, + ml_coins_earned: row.ml_coins_earned ?? 0, + submitted_at: row.submitted_at ? new Date(row.submitted_at).toISOString() : new Date().toISOString(), + // G20 FIX: New fields + source: row.source === 'submission' ? ResponseSource.SUBMISSION : ResponseSource.ATTEMPT, + status: row.status as ExerciseSubmissionStatus | undefined, + feedback: row.feedback || undefined, + requires_manual_grading: row.requires_manual_grading ?? false, // Additional detail fields correct_answer: correctAnswer, exercise_type: row.exercise_type || 'unknown', - max_score: row.exercise_max_points || 100, + max_score: row.max_points || 100, }; } @@ -522,6 +674,7 @@ export class ExerciseResponsesService { const tenantId = teacherProfile.tenant_id; // Raw SQL for cross-schema verification + // G20 FIX: Simplified to use only c.teacher_id (removed non-existent teacher_classrooms reference) const sql = ` SELECT 1 FROM auth_management.profiles profile @@ -529,7 +682,7 @@ export class ExerciseResponsesService { LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id WHERE profile.id = $1 AND profile.tenant_id = $2 - AND (c.teacher_id = $3 OR EXISTS (SELECT 1 FROM social_features.teacher_classrooms tc WHERE tc.teacher_id = $3 AND tc.classroom_id = c.id)) + AND c.teacher_id = $3 LIMIT 1 `; diff --git a/projects/gamilit/apps/database/ddl/00-prerequisites.sql b/projects/gamilit/apps/database/ddl/00-prerequisites.sql index 7dcb814..8531c21 100644 --- a/projects/gamilit/apps/database/ddl/00-prerequisites.sql +++ b/projects/gamilit/apps/database/ddl/00-prerequisites.sql @@ -210,9 +210,20 @@ DO $$ BEGIN EXCEPTION WHEN duplicate_object THEN null; END $$; -- πŸ“š DocumentaciΓ³n: educational_content.difficulty_level --- REMOVIDO (2025-11-11): Migrado a ddl/schemas/educational_content/enums/difficulty_level.sql --- RazΓ³n: Evitar duplicaciΓ³n (PolΓ­tica de Carga Limpia) --- El ENUM se define en el schema especΓ­fico con documentaciΓ³n completa (8 niveles CEFR) +-- RESTAURADO (2025-12-19): Necesario en prerequisites para que tablas puedan crearse +-- 8 niveles CEFR: beginner (A1) β†’ native (C2+) +DO $$ BEGIN + CREATE TYPE educational_content.difficulty_level AS ENUM ( + 'beginner', -- A1: Nivel bΓ‘sico de supervivencia + 'elementary', -- A2: Nivel elemental + 'pre_intermediate', -- B1: Pre-intermedio + 'intermediate', -- B2: Intermedio + 'upper_intermediate', -- C1: Intermedio avanzado + 'advanced', -- C2: Avanzado + 'proficient', -- C2+: Competente + 'native' -- Nativo: Dominio total + ); +EXCEPTION WHEN duplicate_object THEN null; END $$; -- πŸ“š DocumentaciΓ³n: educational_content.module_status -- VERSIΓ“N: 1.2 (2025-11-23) - Agregado 'backlog' para mΓ³dulos fuera de alcance de entrega @@ -228,9 +239,16 @@ DO $$ BEGIN EXCEPTION WHEN duplicate_object THEN null; END $$; -- πŸ“š DocumentaciΓ³n: content_management.content_status --- REMOVIDO (2025-11-11): Migrado a ddl/schemas/content_management/enums/content_status.sql --- RazΓ³n: Evitar duplicaciΓ³n (PolΓ­tica de Carga Limpia) --- El ENUM se define en el schema especΓ­fico con documentaciΓ³n completa +-- RESTAURADO (2025-12-19): Necesario en prerequisites para que tablas puedan crearse +-- Estados del ciclo de vida del contenido educativo +DO $$ BEGIN + CREATE TYPE content_management.content_status AS ENUM ( + 'draft', -- Borrador + 'published', -- Publicado + 'archived', -- Archivado + 'under_review' -- En revisiΓ³n + ); +EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN CREATE TYPE educational_content.cognitive_level AS ENUM ('recordar', 'comprender', 'aplicar', 'analizar', 'evaluar', 'crear'); @@ -256,9 +274,18 @@ EXCEPTION WHEN duplicate_object THEN null; END $$; -- 4. ENUMs de Progreso -- πŸ“š DocumentaciΓ³n: progress_tracking.progress_status --- REMOVIDO (2025-11-11): Migrado a ddl/schemas/progress_tracking/enums/progress_status.sql --- RazΓ³n: Evitar duplicaciΓ³n (PolΓ­tica de Carga Limpia) --- El ENUM se define en el schema especΓ­fico con documentaciΓ³n exhaustiva (112 lΓ­neas) +-- RESTAURADO (2025-12-19): Necesario en prerequisites para que tablas puedan crearse +-- Estados de progreso para mΓ³dulos y ejercicios +DO $$ BEGIN + CREATE TYPE progress_tracking.progress_status AS ENUM ( + 'not_started', -- El usuario no ha comenzado el contenido + 'in_progress', -- El usuario estΓ‘ trabajando en el contenido + 'completed', -- El usuario completΓ³ el contenido exitosamente + 'needs_review', -- El contenido fue completado pero requiere revisiΓ³n + 'mastered', -- El usuario dominΓ³ el contenido (nivel de excelencia) + 'abandoned' -- El usuario abandonΓ³ el contenido sin completar + ); +EXCEPTION WHEN duplicate_object THEN null; END $$; -- πŸ“š DocumentaciΓ³n: progress_tracking.attempt_status -- Requerimiento: docs/01-requerimientos/04-progreso-seguimiento/RF-PRG-001-estados-progreso.md diff --git a/projects/gamilit/apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql b/projects/gamilit/apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql index 19d7c39..69d40c7 100644 --- a/projects/gamilit/apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql +++ b/projects/gamilit/apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql @@ -9,6 +9,8 @@ -- #1: Added module_progress initialization (CRITICAL) -- #2: Added ON CONFLICT to user_ranks (prevents duplicate key errors) -- #3: Kept initialize_user_missions commented (function not implemented yet) +-- Updated: 2025-12-19 - BUG FIX CRÍTICO: +-- #4: Todas las tablas tienen FK a profiles.id, usar NEW.id en todos los inserts -- ===================================================== CREATE OR REPLACE FUNCTION gamilit.initialize_user_stats() @@ -19,14 +21,16 @@ BEGIN -- Initialize gamification for students, teachers, and admins -- Only these roles have gamification enabled IF NEW.role IN ('student', 'admin_teacher', 'super_admin') THEN - -- Use NEW.user_id which points to auth.users.id (correct foreign key reference) + -- IMPORTANTE: Todas las tablas (user_stats, user_ranks, comodines_inventory, module_progress) + -- tienen FK user_id que referencia profiles.id, NO auth.users.id + -- Por lo tanto, debemos usar NEW.id (profiles.id) en todos los inserts INSERT INTO gamification_system.user_stats ( user_id, tenant_id, ml_coins, ml_coins_earned_total ) VALUES ( - NEW.user_id, -- Fixed: usar user_id en lugar de id + NEW.id, -- FIXED 2025-12-19: usar NEW.id (profiles.id), FK apunta a profiles(id) NEW.tenant_id, 100, -- Welcome bonus 100 @@ -34,27 +38,25 @@ BEGIN ON CONFLICT (user_id) DO NOTHING; -- Prevent duplicates -- Create comodines inventory - -- IMPORTANT: comodines_inventory.user_id references profiles.id (NOT auth.users.id) INSERT INTO gamification_system.comodines_inventory ( user_id ) VALUES ( - NEW.id -- CORRECTED: usar NEW.id (profiles.id) porque FK apunta a profiles(id) + NEW.id -- profiles.id - FK apunta a profiles(id) ) ON CONFLICT (user_id) DO NOTHING; -- Create initial user rank (starting with Ajaw - lowest rank) - -- BUG FIX #2: Use WHERE NOT EXISTS instead of ON CONFLICT (no unique constraint on user_id) INSERT INTO gamification_system.user_ranks ( user_id, tenant_id, current_rank ) SELECT - NEW.user_id, + NEW.id, -- FIXED 2025-12-19: usar NEW.id (profiles.id), FK apunta a profiles(id) NEW.tenant_id, 'Ajaw'::gamification_system.maya_rank WHERE NOT EXISTS ( - SELECT 1 FROM gamification_system.user_ranks WHERE user_id = NEW.user_id + SELECT 1 FROM gamification_system.user_ranks WHERE user_id = NEW.id ); -- BUG FIX #1: Initialize module progress for all active modules diff --git a/projects/gamilit/apps/database/scripts/init-database.sh b/projects/gamilit/apps/database/scripts/init-database.sh index cbff9f4..688d0d1 100755 --- a/projects/gamilit/apps/database/scripts/init-database.sh +++ b/projects/gamilit/apps/database/scripts/init-database.sh @@ -821,27 +821,24 @@ load_seeds() { local failed=0 # Array con orden especΓ­fico respetando dependencias + # IMPORTANTE: Los mΓ³dulos deben cargarse ANTES de los profiles + # porque el trigger trg_initialize_user_stats crea module_progress + # y necesita que los mΓ³dulos ya existan local seed_files=( + # === FASE 1: INFRAESTRUCTURA BASE === "$SEEDS_DIR/auth_management/01-tenants.sql" "$SEEDS_DIR/auth_management/02-auth_providers.sql" - "$SEEDS_DIR/auth/01-demo-users.sql" - "$SEEDS_DIR/auth/02-production-users.sql" # βœ… PROD: Usuarios reales (13) - "$SEEDS_DIR/auth/02-test-users.sql" # βœ… DEV: Usuarios de prueba (3) - "$SEEDS_DIR/auth_management/03-profiles.sql" - "$SEEDS_DIR/auth_management/04-profiles-testing.sql" # βœ… PROD: Profiles @gamilit.com (3) - "$SEEDS_DIR/auth_management/05-profiles-demo.sql" # βœ… PROD: Profiles demo (20) - "$SEEDS_DIR/auth_management/06-profiles-production.sql" # βœ… PROD: Profiles reales (13) - "$SEEDS_DIR/auth_management/04-user_roles.sql" - "$SEEDS_DIR/auth_management/05-user_preferences.sql" - "$SEEDS_DIR/auth_management/06-auth_attempts.sql" - "$SEEDS_DIR/auth_management/07-security_events.sql" "$SEEDS_DIR/system_configuration/01-system_settings.sql" "$SEEDS_DIR/system_configuration/02-feature_flags.sql" + + # === FASE 2: GAMIFICATION BASE (antes de profiles) === "$SEEDS_DIR/gamification_system/01-achievement_categories.sql" "$SEEDS_DIR/gamification_system/02-leaderboard_metadata.sql" "$SEEDS_DIR/gamification_system/03-maya_ranks.sql" "$SEEDS_DIR/gamification_system/04-achievements.sql" - "$SEEDS_DIR/gamification_system/04-initialize_user_gamification.sql" + + # === FASE 3: MΓ“DULOS Y EJERCICIOS (ANTES de profiles - CRÍTICO) === + # El trigger trg_initialize_user_stats necesita mΓ³dulos publicados "$SEEDS_DIR/educational_content/01-modules.sql" "$SEEDS_DIR/educational_content/02-exercises-module1.sql" "$SEEDS_DIR/educational_content/03-exercises-module2.sql" @@ -849,6 +846,28 @@ load_seeds() { "$SEEDS_DIR/educational_content/05-exercises-module4.sql" "$SEEDS_DIR/educational_content/06-exercises-module5.sql" "$SEEDS_DIR/educational_content/07-assessment-rubrics.sql" + + # === FASE 4: USUARIOS (auth.users) === + "$SEEDS_DIR/auth/01-demo-users.sql" + "$SEEDS_DIR/auth/02-production-users.sql" + "$SEEDS_DIR/auth/02-test-users.sql" + + # === FASE 5: PROFILES (activa trigger que crea module_progress) === + "$SEEDS_DIR/auth_management/03-profiles.sql" + "$SEEDS_DIR/auth_management/04-profiles-complete.sql" + "$SEEDS_DIR/auth_management/04-profiles-testing.sql" + "$SEEDS_DIR/auth_management/05-profiles-demo.sql" + "$SEEDS_DIR/auth_management/06-profiles-production.sql" + "$SEEDS_DIR/auth_management/07-profiles-production-additional.sql" + "$SEEDS_DIR/auth_management/04-user_roles.sql" + "$SEEDS_DIR/auth_management/05-user_preferences.sql" + "$SEEDS_DIR/auth_management/06-auth_attempts.sql" + "$SEEDS_DIR/auth_management/07-security_events.sql" + + # === FASE 6: GAMIFICATION USUARIOS (post-profiles) === + "$SEEDS_DIR/gamification_system/04-initialize_user_gamification.sql" + + # === FASE 7: CONTENIDO ADICIONAL === "$SEEDS_DIR/content_management/01-marie-curie-bio.sql" "$SEEDS_DIR/content_management/02-media-files.sql" "$SEEDS_DIR/content_management/03-tags.sql" diff --git a/projects/gamilit/apps/database/seeds/dev/auth/02-production-users.sql b/projects/gamilit/apps/database/seeds/dev/auth/02-production-users.sql new file mode 100644 index 0000000..5a7f4a0 --- /dev/null +++ b/projects/gamilit/apps/database/seeds/dev/auth/02-production-users.sql @@ -0,0 +1,863 @@ +-- ===================================================== +-- Seed: auth.users - Production Registered Users +-- Description: Usuarios reales registrados en producciΓ³n +-- Environment: PRODUCTION +-- Dependencies: 01-demo-users.sql +-- Order: 02 +-- Created: 2025-11-19 +-- Updated: 2025-12-18 +-- Version: 2.0 (Actualizado con backup producciΓ³n 2025-12-18) +-- ===================================================== +-- +-- USUARIOS REALES REGISTRADOS: +-- - Lote 1 (2025-11-18): 13 usuarios con nombres completos +-- - Lote 2 (2025-11-24/25): 29 usuarios (algunos sin nombres) +-- - Lote 3 (2025-12-08 y 2025-12-17): 2 usuarios +-- +-- TOTAL: 44 usuarios estudiantes +-- +-- POLÍTICA DE CARGA LIMPIA: +-- βœ… UUIDs originales del servidor preservados +-- βœ… Passwords hasheados originales preservados +-- βœ… instance_id corregido a UUID vΓ‘lido +-- βœ… Metadata mΓ­nima agregada para compatibilidad +-- βœ… Triggers crearΓ‘n profiles, user_stats, user_ranks automΓ‘ticamente +-- +-- IMPORTANTE: Estos son usuarios reales de producciΓ³n. +-- No modificar sus UUIDs ni passwords hasheados. +-- ===================================================== + +SET search_path TO auth, public; + +-- ===================================================== +-- INSERT: Production Registered Users (44 usuarios) +-- ===================================================== + +INSERT INTO auth.users ( + id, + instance_id, + aud, + role, + email, + encrypted_password, + email_confirmed_at, + invited_at, + confirmation_token, + confirmation_sent_at, + recovery_token, + recovery_sent_at, + email_change_token_new, + email_change, + email_change_sent_at, + last_sign_in_at, + raw_app_meta_data, + raw_user_meta_data, + is_super_admin, + created_at, + updated_at, + phone, + phone_confirmed_at, + phone_change, + phone_change_token, + phone_change_sent_at, + confirmed_at, + email_change_token_current, + email_change_confirm_status, + banned_until, + reauthentication_token, + reauthentication_sent_at, + is_sso_user, + deleted_at, + gamilit_role, + status +) VALUES + +-- ===================================================== +-- LOTE 1: USUARIOS 2025-11-18 (13 usuarios) +-- ===================================================== + +-- USUARIO 1: Jose Aguirre +( + 'b017b792-b327-40dd-aefb-a80312776952'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'joseal.guirre34@gmail.com', + '$2b$10$kb9yCB4Y2WBr2.Gth.wC9e8q8bnkZJ6O2X6kFSn.O4VK8d76Cr/xO', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Jose", "last_name": "Aguirre"}'::jsonb, + false, '2025-11-18 07:29:05.226874+00'::timestamptz, '2025-11-18 07:29:05.226874+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 2: Sergio Jimenez +( + '06a24962-e83d-4e94-aad7-ff69f20a9119'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'sergiojimenezesteban63@gmail.com', + '$2b$10$8oPdKN15ndCqCOIt12SEO.2yx4D29kQEQGPCC5rtUYWu8Qp5L7/zW', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Sergio", "last_name": "Jimenez"}'::jsonb, + false, '2025-11-18 08:17:40.925857+00'::timestamptz, '2025-11-18 08:17:40.925857+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 3: Hugo Gomez +( + '24e8c563-8854-43d1-b3c9-2f83e91f5a1e'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'Gomezfornite92@gmail.com', + '$2b$10$FuEfoSA0jxvBI2f6odMJqux9Gpgvt7Zjk.plRhRatvK0ykkIXxbI.', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Hugo", "last_name": "Gomez"}'::jsonb, + false, '2025-11-18 08:18:04.240276+00'::timestamptz, '2025-11-18 08:18:04.240276+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 4: Hugo AragΓ³n +( + 'bf0d3e34-e077-43d1-9626-292f7fae2bd6'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'Aragon494gt54@icloud.com', + '$2b$10$lE8M8qWUIsgYLwcHyRGvTOjxdykLVchRVifsMVqCRCZq3bEeXR.xG', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Hugo", "last_name": "AragΓ³n"}'::jsonb, + false, '2025-11-18 08:20:17.228812+00'::timestamptz, '2025-11-18 08:20:17.228812+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 5: Azul Valentina +( + '2f5a9846-3393-40b2-9e87-0f29238c383f'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'blu3wt7@gmail.com', + '$2b$10$gKRXQ.rmOePqsNKWdxABQuyIZike2oSsYpdfWpQdi5HHDWDUk.3u2', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Azul", "last_name": "Valentina"}'::jsonb, + false, '2025-11-18 08:32:17.314233+00'::timestamptz, '2025-11-18 08:32:17.314233+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 6: Ricardo Lugo +( + '5e738038-1743-4aa9-b222-30171300ea9d'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'ricardolugo786@icloud.com', + '$2b$10$YV1StKIdCPPED/Ft84zR2ONxj/VzzV7zOxjgwMSbDpd2hzvYOGtby', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Ricardo", "last_name": "Lugo"}'::jsonb, + false, '2025-11-18 10:15:06.479774+00'::timestamptz, '2025-11-18 10:15:06.479774+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 7: Carlos Marban +( + '00c742d9-e5f7-4666-9597-5a8ca54d5478'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'marbancarlos916@gmail.com', + '$2b$10$PfsKOsEEXpGA6YB6eXNBPePo6OV6Am1glUN6Mkunl64bK/ji6uttW', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Carlos", "last_name": "Marban"}'::jsonb, + false, '2025-11-18 10:29:05.23842+00'::timestamptz, '2025-11-18 10:29:05.23842+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 8: Diego Colores +( + '33306a65-a3b1-41d5-a49d-47989957b822'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'diego.colores09@gmail.com', + '$2b$10$rFlH9alBbgPGVEZMYIV8p.AkeZ30yRCVd5acasFjIt7fpCZhE6RuO', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Diego", "last_name": "Colores"}'::jsonb, + false, '2025-11-18 10:29:20.530359+00'::timestamptz, '2025-11-18 10:29:20.530359+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 9: Benjamin Hernandez +( + '7a6a973e-83f7-4374-a9fc-54258138115f'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'hernandezfonsecabenjamin7@gmail.com', + '$2b$10$1E6gLqfMojNLYrSKIbatqOh0pHblZ3jWZwbcxTY/DCx7MGADToCVm', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Benjamin", "last_name": "Hernandez"}'::jsonb, + false, '2025-11-18 10:37:06.919813+00'::timestamptz, '2025-11-18 10:37:06.919813+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 10: Josue Reyes +( + 'ccd7135c-0fea-4488-9094-9da52df1c98c'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'jr7794315@gmail.com', + '$2b$10$Ej/Gwx8mGCWg4TnQSjh1r.QZLw/GkUANqXmz4bEfVaNF9E527L02C', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Josue", "last_name": "Reyes"}'::jsonb, + false, '2025-11-18 17:53:39.67958+00'::timestamptz, '2025-11-18 17:53:39.67958+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 11: Fernando Barragan +( + '9951ad75-e9cb-47b3-b478-6bb860ee2530'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'barraganfer03@gmail.com', + '$2b$10$VJ8bS.ksyKpa7oG575r5YOWQYcq8vwmwTa8jMBkCv0dwskF04SHn2', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Fernando", "last_name": "Barragan"}'::jsonb, + false, '2025-11-18 20:39:27.408624+00'::timestamptz, '2025-11-18 20:39:27.408624+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 12: Marco Antonio Roman +( + '735235f5-260a-4c9b-913c-14a1efd083ea'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'roman.rebollar.marcoantonio1008@gmail.com', + '$2b$10$l4eF8UoOB7D8LKDEzTigXOUO7EABhVdYCqknJ/lD6R4p8uF1R4I.W', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Marco Antonio", "last_name": "Roman"}'::jsonb, + false, '2025-11-18 21:03:17.326679+00'::timestamptz, '2025-11-18 21:03:17.326679+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 13: Rodrigo Guerrero +( + 'ebe48628-5e44-4562-97b7-b4950b216247'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'rodrigoguerrero0914@gmail.com', + '$2b$10$ihoy7HbOdlqU38zAddpTOuDO7Nqa8.Cr1dEQjCgMpdb30UwCIMhGW', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Rodrigo", "last_name": "Guerrero"}'::jsonb, + false, '2025-11-18 21:20:52.303128+00'::timestamptz, '2025-11-18 21:20:52.303128+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- ===================================================== +-- LOTE 2: USUARIOS 2025-11-24 (23 usuarios) +-- ===================================================== + +-- USUARIO 14: santiagoferrara78 +( + 'd089b1af-462f-4d2c-b0f5-d2528cec8506'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'santiagoferrara78@gmail.com', + '$2b$10$Wjo3EENjiuddS9BwPMAW1OORZrZpU8ECP9zEXmd4Gvn7orwgjo8O2', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 09:21:04.898591+00'::timestamptz, '2025-11-24 09:21:04.898591+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 15: alexanserrv917 +( + 'b1cadf36-1f07-46b2-b63d-da72d9b54dc6'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'alexanserrv917@gmail.com', + '$2b$10$8sT/ObLZUNmiu6CpbceHhenfc7E8zZml8AvB1HUiyOddSLqchggZ2', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:26:51.934739+00'::timestamptz, '2025-11-24 10:26:51.934739+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 16: aarizmendi434 +( + 'af4d8788-f8a8-4971-bb0d-2f48c150dfc2'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'aarizmendi434@gmail.com', + '$2b$10$2BAG4EskBG0feGOIva6XyOCBtBJbKJE9h27GU6DmuBH3f.2iK6FoS', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:30:54.728262+00'::timestamptz, '2025-11-24 10:30:54.728262+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 17: ashernarcisobenitezpalomino +( + '26fbc469-10af-4fa3-bd65-e5498188cc4f'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'ashernarcisobenitezpalomino@gmail.com', + '$2b$10$Bv5vo0GDeseWUWTt.5xV0O9nN93TRVN.vHRigs4vF/ww7Hbnjylam', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:37:35.325342+00'::timestamptz, '2025-11-24 10:37:35.325342+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 18: ra.alejandrobm +( + '74ed8c97-ec36-43aa-a1cc-b0c99e4be4e8'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'ra.alejandrobm@gmail.com', + '$2b$10$QZId3lZBIzBulD7AZCeEKOiL0LBJRekGlQTGiacC70IDwDo2wx7py', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:42:33.424367+00'::timestamptz, '2025-11-24 10:42:33.424367+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 19: abdallahxelhaneriavega +( + 'f4c46f46-3fb9-40bf-a52b-a8ad2e6a92e1'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'abdallahxelhaneriavega@gmail.com', + '$2b$10$jQ4SquNUxIO70e7IBYqqLeUw1d.gSCleJ/cwinuWMVlW25a8.pRGG', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:45:19.984994+00'::timestamptz, '2025-11-24 10:45:19.984994+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 20: 09enriquecampos +( + '012adac4-8ffd-47bd-9248-f0c5851e981f'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + '09enriquecampos@gmail.com', + '$2b$10$95c9hOplonbo/46O5UlPqummq.AIaGVIZ7YgBstSuOWPbgGersKxy', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:51:54.731982+00'::timestamptz, '2025-11-24 10:51:54.731982+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 21: johhkk22 +( + '126b9257-7b0a-4bd6-9ab3-c505ee00e10a'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'johhkk22@gmail.com', + '$2b$10$Bt6IZ19zuBkly.6QmmPWBeF0kfyVN/O/c3/9bqyUGup3gPZu14DGa', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:53:47.029991+00'::timestamptz, '2025-11-24 10:53:47.029991+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 22: edangiel4532 +( + '9ac1746e-94a6-4efc-a961-951c015d416e'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'edangiel4532@gmail.com', + '$2b$10$eZap9LmAws7VtY9sHnS17.RJkhIte5SUobIWaWpuTxTPKjbKgzK.6', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 10:58:12.790316+00'::timestamptz, '2025-11-24 10:58:12.790316+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 23: erickfranco462 +( + '2d9f05d4-44dd-42cd-97aa-d57bd06fecd0'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'erickfranco462@gmail.com', + '$2b$10$lNzkSO7zbBHQcJJui0O76.a2artcsZHari4Mgkjo4btGww.Wy9/iC', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:00:11.800551+00'::timestamptz, '2025-11-24 11:00:11.800551+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 24: gallinainsana +( + 'aff5dcc6-32de-4769-9aaf-eda751fa0866'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'gallinainsana@gmail.com', + '$2b$10$6y/FVa4LqyliI4PXuBxKpepTRwIIRWybFN0NhcAqRM.Kl/cnvXDMq', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:03:17.536383+00'::timestamptz, '2025-11-24 11:03:17.536383+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 25: leile5257 +( + '0cda1645-83c5-445b-80b7-d0e4d436c00c'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'leile5257@gmail.com', + '$2b$10$ZZX0.z30VPm7BsLF8bNVweQpRZ2ca/1EPlxdIZy0xNaCFugoKL0ci', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:05:17.75852+00'::timestamptz, '2025-11-24 11:05:17.75852+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 26: maximiliano.mejia367 +( + '1364c463-88de-479b-a883-c0b7b362bcf8'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'maximiliano.mejia367@gmail.com', + '$2b$10$iTfIWKh2ISvPys2bkK2LOOPI24ua7I47oT8dFxHHYW7AuztoZreQa', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:08:58.232003+00'::timestamptz, '2025-11-24 11:08:58.232003+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 27: fl432025 +( + '547eb778-4782-4681-b198-c731bba36147'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'fl432025@gmail.com', + '$2b$10$aGKv6yhAWwHb07m3N2DxJOXIn5omkP3t2QeSYblhcDo52pB2ZiFQi', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:12:13.692614+00'::timestamptz, '2025-11-24 11:12:13.692614+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 28: 7341023901m +( + '5fc06693-e408-4eab-a9a3-fcd5f4e01296'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + '7341023901m@gmail.com', + '$2b$10$Z/HUBov20g..LZ6RDYax4.NcDuiFD/gn9Nrt7/OPCPBqCoTJUgr3C', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:15:18.276345+00'::timestamptz, '2025-11-24 11:15:18.276345+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 29: segurauriel235 +( + '5d1839f6-b03f-4e12-b236-eca43f4674f2'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'segurauriel235@gmail.com', + '$2b$10$IfdhPuUOModgrJT7bMfYkODZkXeTcaAReuCQf9BGpK1cT6GiP9UGu', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:17:46.846963+00'::timestamptz, '2025-11-24 11:17:46.846963+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 30: angelrabano11 +( + '1b310708-6f24-4c6a-88c9-a11f7a7f9763'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'angelrabano11@gmail.com', + '$2b$10$Sg6q4kErMvxRlZgWM9lCj.PfRg5sCQrwm763d7sfc3iaAUID7y436', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:47:53.790673+00'::timestamptz, '2025-11-24 11:47:53.790673+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 31: daliaayalareyes35 +( + '3c613b0e-66f9-4640-a599-c9426d8edffb'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'daliaayalareyes35@gmail.com', + '$2b$10$dd2SQeBqNIZpZWCGMIDu1O8U6MLpWnKF05w641MNOMzHDZ/U5glCe', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:55:08.708961+00'::timestamptz, '2025-11-24 11:55:08.708961+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 32: alexeimongam +( + '7ded133e-9b13-4467-9803-edb813f6a9a1'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'alexeimongam@gmail.com', + '$2b$10$jyQrHAIj6SsnReQ45FrFlOnDgpZtabskpxPuOYgB/h.YPLyZhuld.', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 11:55:11.906996+00'::timestamptz, '2025-11-24 11:55:11.906996+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 33: davidocampovenegas +( + '4cc04f54-7771-462d-98aa-a94448bb6ff5'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'davidocampovenegas@gmail.com', + '$2b$10$8COk10WE5.bXFJnAucEA0efcGQKU6KUXKV9N7n32ZX6aNKORs4McW', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 14:52:46.468737+00'::timestamptz, '2025-11-24 14:52:46.468737+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 34: zaid080809 +( + 'fbbe7d19-048c-45e4-8a9c-cf86d2098c35'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'zaid080809@gmail.com', + '$2b$10$kdaUWR1BUqPRY7H8YkR.xuuDbqtLcvP5yKW.B0ooPlb.I6b/UU192', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 16:25:03.689847+00'::timestamptz, '2025-11-24 16:25:03.689847+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 35: ruizcruzabrahamfrancisco +( + '5b3d74e8-fd1a-4c80-96d2-24c54bfe90c4'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'ruizcruzabrahamfrancisco@gmail.com', + '$2b$10$DXHr682C4/VpesiHa7fRrOjKceiWSDUSx.1LZTbsvuxpqCdMNh/Ii', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 19:46:06.311558+00'::timestamptz, '2025-11-24 19:46:06.311558+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 36: vituschinchilla +( + '615adf6e-dbf3-480f-a907-3cfb3a64c6d2'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'vituschinchilla@gmail.com', + '$2b$10$dA8adTYlfhgqhZfACcQkFOCYjXdsmggXnIUluNDoh1zRFgQ6pq5O2', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-24 21:07:26.037867+00'::timestamptz, '2025-11-24 21:07:26.037867+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- ===================================================== +-- LOTE 3: USUARIOS 2025-11-25 (6 usuarios) +-- ===================================================== + +-- USUARIO 37: bryan@betanzos.com +( + 'bf445960-4c1f-4e29-8fb7-31667b183d7e'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'bryan@betanzos.com', + '$2b$10$Xdfuf4Tfog9QKd1FRLL.7eAaD6tr2cXgPx1/L8xqT1kLLzNHzSM26', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-25 06:13:30.263795+00'::timestamptz, '2025-11-25 06:13:30.263795+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 38: loganalexander816 +( + 'd5fa4905-a78a-4040-8ad8-23220881c6a6'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'loganalexander816@gmail.com', + '$2b$10$8zLduh/9L/priag.nujz5utuloO9RnNFFDGdKgI2UniFCOwocEPLq', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-25 07:37:04.953164+00'::timestamptz, '2025-11-25 07:37:04.953164+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 39: carlois1974 +( + '71734c15-cdaa-431b-90f5-97a57e0316a8'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'carlois1974@gmail.com', + '$2b$10$IfLfJ.q59DZgicR07ckSVOcrkkBJe42m1FECXxaoaodKYSo6uj5wW', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-25 07:41:38.025764+00'::timestamptz, '2025-11-25 07:41:38.025764+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 40: enriquecuevascbtis136 +( + '1efe491d-98ef-4c02-acd1-3135f7289072'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'enriquecuevascbtis136@gmail.com', + '$2b$10$9BX3OQMZmHruffBtN.3WPOFoyea6zgPd8i72DvhJ7vRAdqWKax6GS', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-25 08:16:33.977647+00'::timestamptz, '2025-11-25 08:16:33.977647+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 41: omarcitogonzalezzavaleta +( + '5ae21325-7450-4c37-82f1-3f9bcd7b6f45'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'omarcitogonzalezzavaleta@gmail.com', + '$2b$10$RRk3DAgQdiikxVImFIMqquqB.TNpKs3E.RNFtt1rwwTzO24uShri.', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-25 08:17:07.610076+00'::timestamptz, '2025-11-25 08:17:07.610076+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 42: gustavobm2024cbtis +( + 'a4d27774-8a51-4660-ad2f-81d0dfd3a5a7'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'gustavobm2024cbtis@gmail.com', + '$2b$10$lg7KRUTPofcx4Rtyey8J7.XO0gmdBLCFIfK5uP08mqT0qUIl1aTJq', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-25 08:20:49.649184+00'::timestamptz, '2025-11-25 08:20:49.649184+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 43: marianaxsotoxt22 +( + '6e30164a-78b0-49b0-bd21-23d7c6c03349'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'marianaxsotoxt22@gmail.com', + '$2b$10$GQC9yTWiP2vP9GUp0gnhUeLjmw70EI4JQhfJBZbMOlCNXGXb/bt5O', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "", "last_name": ""}'::jsonb, + false, '2025-11-25 08:33:18.150784+00'::timestamptz, '2025-11-25 08:33:18.150784+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- ===================================================== +-- LOTE 4: USUARIOS RECIENTES (2 usuarios) +-- ===================================================== + +-- USUARIO 44: javiermar06 (2025-12-08) +( + '69681b09-5077-4f77-84cc-67606abd9755'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'javiermar06@hotmail.com', + '$2b$10$3RHyXnR4BG3NaxP8Ez82FuiGDMNCG7GhNaOsMFigy3BpIVOzCqHMW', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-14 03:51:04.122+00'::timestamptz, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Javier", "last_name": "Mar"}'::jsonb, + false, '2025-12-08 19:24:06.266895+00'::timestamptz, '2025-12-14 03:51:04.123886+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +), + +-- USUARIO 45: ju188an (2025-12-17) +( + 'f929d6df-8c29-461f-88f5-264facd879e9'::uuid, + '00000000-0000-0000-0000-000000000000'::uuid, + 'authenticated', NULL, + 'ju188an@gmail.com', + '$2b$10$9vUERFnXApdfXuAI7DFve.aa8uDjI5bfm4CI75/EZ2cUre83RytKe', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-17 23:51:43.553+00'::timestamptz, + '{"provider": "email", "providers": ["email"]}'::jsonb, + '{"first_name": "Juan", "last_name": "pa"}'::jsonb, + false, '2025-12-17 17:51:43.530434+00'::timestamptz, '2025-12-17 23:51:43.55475+00'::timestamptz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, + 'student'::auth_management.gamilit_role, 'active'::auth_management.user_status +) + +ON CONFLICT (id) DO UPDATE SET + encrypted_password = EXCLUDED.encrypted_password, + raw_user_meta_data = EXCLUDED.raw_user_meta_data, + last_sign_in_at = EXCLUDED.last_sign_in_at, + updated_at = EXCLUDED.updated_at; + +-- ===================================================== +-- Verification Query +-- ===================================================== + +DO $$ +DECLARE + production_user_count INTEGER; + total_user_count INTEGER; + lote1_count INTEGER; + lote2_count INTEGER; + lote3_count INTEGER; + lote4_count INTEGER; +BEGIN + -- Contar usuarios de producciΓ³n (excluyendo @gamilit.com) + SELECT COUNT(*) INTO production_user_count + FROM auth.users + WHERE email NOT LIKE '%@gamilit.com'; + + -- Contar todos los usuarios + SELECT COUNT(*) INTO total_user_count + FROM auth.users; + + -- Contar por lotes + SELECT COUNT(*) INTO lote1_count + FROM auth.users + WHERE created_at::date = '2025-11-18' + AND email NOT LIKE '%@gamilit.com'; + + SELECT COUNT(*) INTO lote2_count + FROM auth.users + WHERE created_at::date = '2025-11-24' + AND email NOT LIKE '%@gamilit.com'; + + SELECT COUNT(*) INTO lote3_count + FROM auth.users + WHERE created_at::date = '2025-11-25' + AND email NOT LIKE '%@gamilit.com'; + + SELECT COUNT(*) INTO lote4_count + FROM auth.users + WHERE created_at::date >= '2025-12-01' + AND email NOT LIKE '%@gamilit.com'; + + RAISE NOTICE '========================================'; + RAISE NOTICE 'USUARIOS DE PRODUCCIΓ“N REGISTRADOS'; + RAISE NOTICE '========================================'; + RAISE NOTICE 'Total usuarios producciΓ³n: %', production_user_count; + RAISE NOTICE 'Total usuarios (con testing): %', total_user_count; + RAISE NOTICE '----------------------------------------'; + RAISE NOTICE 'Por lotes:'; + RAISE NOTICE ' - Lote 1 (2025-11-18): %', lote1_count; + RAISE NOTICE ' - Lote 2 (2025-11-24): %', lote2_count; + RAISE NOTICE ' - Lote 3 (2025-11-25): %', lote3_count; + RAISE NOTICE ' - Lote 4 (2025-12+): %', lote4_count; + RAISE NOTICE '========================================'; + + IF production_user_count >= 44 THEN + RAISE NOTICE 'βœ“ Los usuarios de producciΓ³n fueron creados correctamente'; + ELSE + RAISE WARNING '⚠ Se esperaban 44+ usuarios de producciΓ³n, se crearon %', production_user_count; + END IF; + + RAISE NOTICE '========================================'; +END $$; + +-- ===================================================== +-- IMPORTANTE: Profiles, Stats y Ranks +-- ===================================================== +-- Los profiles, user_stats y user_ranks se crean +-- automΓ‘ticamente mediante triggers cuando se crea +-- un usuario en auth.users. +-- +-- Ver: +-- - auth_management.trg_after_user_insert_create_profile +-- - gamification_system.trg_after_profile_insert_create_stats +-- - gamification_system.trg_after_profile_insert_create_rank +-- ===================================================== + +-- ===================================================== +-- CHANGELOG +-- ===================================================== +-- v2.0 (2025-12-18): ActualizaciΓ³n completa desde backup producciΓ³n +-- - 44 usuarios totales +-- - Lote 1: 13 usuarios (2025-11-18) +-- - Lote 2: 23 usuarios (2025-11-24) +-- - Lote 3: 6 usuarios (2025-11-25) +-- - Lote 4: 2 usuarios (2025-12-08, 2025-12-17) +-- - UUIDs y passwords originales preservados +-- +-- v1.0 (2025-11-19): Primera versiΓ³n +-- - 13 usuarios del lote inicial +-- ===================================================== diff --git a/projects/gamilit/apps/database/seeds/dev/auth_management/01-tenants.sql b/projects/gamilit/apps/database/seeds/dev/auth_management/01-tenants.sql index 5135a2b..05a3f43 100644 --- a/projects/gamilit/apps/database/seeds/dev/auth_management/01-tenants.sql +++ b/projects/gamilit/apps/database/seeds/dev/auth_management/01-tenants.sql @@ -119,6 +119,37 @@ INSERT INTO auth_management.tenants ( }'::jsonb, gamilit.now_mexico(), gamilit.now_mexico() +), +-- Tenant 4: Gamilit Production (para usuarios de producciΓ³n) +-- AGREGADO 2025-12-19: Necesario para profiles de producciΓ³n +( + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'Gamilit Production', + 'gamilit-prod', + 'gamilit.com', + NULL, + 'enterprise', + 10000, + 1000, + true, + NULL, + '{ + "theme": "detective", + "language": "es", + "timezone": "America/Mexico_City", + "features": { + "analytics_enabled": true, + "gamification_enabled": true, + "social_features_enabled": true + } + }'::jsonb, + '{ + "description": "Tenant principal de producciΓ³n", + "environment": "production", + "created_by": "seed_script" + }'::jsonb, + gamilit.now_mexico(), + gamilit.now_mexico() ) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, diff --git a/projects/gamilit/apps/database/seeds/dev/auth_management/07-profiles-production-additional.sql b/projects/gamilit/apps/database/seeds/dev/auth_management/07-profiles-production-additional.sql new file mode 100644 index 0000000..4e24951 --- /dev/null +++ b/projects/gamilit/apps/database/seeds/dev/auth_management/07-profiles-production-additional.sql @@ -0,0 +1,646 @@ +-- ===================================================== +-- Seed: auth_management.profiles - Additional Production Users +-- Description: Perfiles adicionales para usuarios registrados sin nombre completo +-- Environment: PRODUCTION / DEV +-- Dependencies: auth/02-production-users.sql, auth_management/01-tenants.sql +-- Order: 07 (despues de 06-profiles-production.sql) +-- Created: 2025-12-19 +-- Version: 1.0 +-- ===================================================== +-- +-- USUARIOS ADICIONALES: 32 perfiles +-- Estos usuarios se registraron despues del lote inicial y no tienen +-- first_name/last_name en su metadata. Se crean con datos minimos. +-- +-- POLITICA: +-- - profiles.id = auth.users.id (consistente con el resto del sistema) +-- - tenant_id = Tenant principal (GAMILIT Platform) +-- - Nombres vacios permitidos (el usuario puede completarlos despues) +-- +-- EXCLUIDO: rckrdmrd@gmail.com (por solicitud explicita) +-- ===================================================== + +SET search_path TO auth_management, public; + +-- ===================================================== +-- INSERT: Additional Production User Profiles (32 perfiles) +-- ===================================================== + +INSERT INTO auth_management.profiles ( + id, + tenant_id, + user_id, + email, + display_name, + full_name, + first_name, + last_name, + avatar_url, + bio, + phone, + date_of_birth, + grade_level, + student_id, + school_id, + role, + status, + email_verified, + phone_verified, + preferences, + metadata, + created_at, + updated_at +) VALUES + +-- Perfil 1: santiagoferrara78@gmail.com +( + 'd089b1af-462f-4d2c-b0f5-d2528cec8506'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'd089b1af-462f-4d2c-b0f5-d2528cec8506'::uuid, + 'santiagoferrara78@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 09:21:04.898591+00'::timestamptz, + '2025-11-24 09:21:04.898591+00'::timestamptz +), + +-- Perfil 2: alexanserrv917@gmail.com +( + 'b1cadf36-1f07-46b2-b63d-da72d9b54dc6'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'b1cadf36-1f07-46b2-b63d-da72d9b54dc6'::uuid, + 'alexanserrv917@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:26:51.934739+00'::timestamptz, + '2025-11-24 10:26:51.934739+00'::timestamptz +), + +-- Perfil 3: aarizmendi434@gmail.com +( + 'af4d8788-f8a8-4971-bb0d-2f48c150dfc2'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'af4d8788-f8a8-4971-bb0d-2f48c150dfc2'::uuid, + 'aarizmendi434@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:30:54.728262+00'::timestamptz, + '2025-11-24 10:30:54.728262+00'::timestamptz +), + +-- Perfil 4: ashernarcisobenitezpalomino@gmail.com +( + '26fbc469-10af-4fa3-bd65-e5498188cc4f'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '26fbc469-10af-4fa3-bd65-e5498188cc4f'::uuid, + 'ashernarcisobenitezpalomino@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:37:35.325342+00'::timestamptz, + '2025-11-24 10:37:35.325342+00'::timestamptz +), + +-- Perfil 5: ra.alejandrobm@gmail.com +( + '74ed8c97-ec36-43aa-a1cc-b0c99e4be4e8'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '74ed8c97-ec36-43aa-a1cc-b0c99e4be4e8'::uuid, + 'ra.alejandrobm@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:42:33.424367+00'::timestamptz, + '2025-11-24 10:42:33.424367+00'::timestamptz +), + +-- Perfil 6: abdallahxelhaneriavega@gmail.com +( + 'f4c46f46-3fb9-40bf-a52b-a8ad2e6a92e1'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'f4c46f46-3fb9-40bf-a52b-a8ad2e6a92e1'::uuid, + 'abdallahxelhaneriavega@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:45:19.984994+00'::timestamptz, + '2025-11-24 10:45:19.984994+00'::timestamptz +), + +-- Perfil 7: 09enriquecampos@gmail.com +( + '012adac4-8ffd-47bd-9248-f0c5851e981f'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '012adac4-8ffd-47bd-9248-f0c5851e981f'::uuid, + '09enriquecampos@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:51:54.731982+00'::timestamptz, + '2025-11-24 10:51:54.731982+00'::timestamptz +), + +-- Perfil 8: johhkk22@gmail.com +( + '126b9257-7b0a-4bd6-9ab3-c505ee00e10a'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '126b9257-7b0a-4bd6-9ab3-c505ee00e10a'::uuid, + 'johhkk22@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:53:47.029991+00'::timestamptz, + '2025-11-24 10:53:47.029991+00'::timestamptz +), + +-- Perfil 9: edangiel4532@gmail.com +( + '9ac1746e-94a6-4efc-a961-951c015d416e'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '9ac1746e-94a6-4efc-a961-951c015d416e'::uuid, + 'edangiel4532@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:58:12.790316+00'::timestamptz, + '2025-11-24 10:58:12.790316+00'::timestamptz +), + +-- Perfil 10: erickfranco462@gmail.com +( + '2d9f05d4-44dd-42cd-97aa-d57bd06fecd0'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '2d9f05d4-44dd-42cd-97aa-d57bd06fecd0'::uuid, + 'erickfranco462@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:00:11.800551+00'::timestamptz, + '2025-11-24 11:00:11.800551+00'::timestamptz +), + +-- Perfil 11: gallinainsana@gmail.com +( + 'aff5dcc6-32de-4769-9aaf-eda751fa0866'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'aff5dcc6-32de-4769-9aaf-eda751fa0866'::uuid, + 'gallinainsana@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:03:17.536383+00'::timestamptz, + '2025-11-24 11:03:17.536383+00'::timestamptz +), + +-- Perfil 12: leile5257@gmail.com +( + '0cda1645-83c5-445b-80b7-d0e4d436c00c'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '0cda1645-83c5-445b-80b7-d0e4d436c00c'::uuid, + 'leile5257@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:05:17.75852+00'::timestamptz, + '2025-11-24 11:05:17.75852+00'::timestamptz +), + +-- Perfil 13: maximiliano.mejia367@gmail.com +( + '1364c463-88de-479b-a883-c0b7b362bcf8'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '1364c463-88de-479b-a883-c0b7b362bcf8'::uuid, + 'maximiliano.mejia367@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:08:58.232003+00'::timestamptz, + '2025-11-24 11:08:58.232003+00'::timestamptz +), + +-- Perfil 14: fl432025@gmail.com +( + '547eb778-4782-4681-b198-c731bba36147'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '547eb778-4782-4681-b198-c731bba36147'::uuid, + 'fl432025@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:12:13.692614+00'::timestamptz, + '2025-11-24 11:12:13.692614+00'::timestamptz +), + +-- Perfil 15: 7341023901m@gmail.com +( + '5fc06693-e408-4eab-a9a3-fcd5f4e01296'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5fc06693-e408-4eab-a9a3-fcd5f4e01296'::uuid, + '7341023901m@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:15:18.276345+00'::timestamptz, + '2025-11-24 11:15:18.276345+00'::timestamptz +), + +-- Perfil 16: segurauriel235@gmail.com +( + '5d1839f6-b03f-4e12-b236-eca43f4674f2'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5d1839f6-b03f-4e12-b236-eca43f4674f2'::uuid, + 'segurauriel235@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:17:46.846963+00'::timestamptz, + '2025-11-24 11:17:46.846963+00'::timestamptz +), + +-- Perfil 17: angelrabano11@gmail.com +( + '1b310708-6f24-4c6a-88c9-a11f7a7f9763'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '1b310708-6f24-4c6a-88c9-a11f7a7f9763'::uuid, + 'angelrabano11@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:47:53.790673+00'::timestamptz, + '2025-11-24 11:47:53.790673+00'::timestamptz +), + +-- Perfil 18: daliaayalareyes35@gmail.com +( + '3c613b0e-66f9-4640-a599-c9426d8edffb'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '3c613b0e-66f9-4640-a599-c9426d8edffb'::uuid, + 'daliaayalareyes35@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:55:08.708961+00'::timestamptz, + '2025-11-24 11:55:08.708961+00'::timestamptz +), + +-- Perfil 19: alexeimongam@gmail.com +( + '7ded133e-9b13-4467-9803-edb813f6a9a1'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '7ded133e-9b13-4467-9803-edb813f6a9a1'::uuid, + 'alexeimongam@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:55:11.906996+00'::timestamptz, + '2025-11-24 11:55:11.906996+00'::timestamptz +), + +-- Perfil 20: davidocampovenegas@gmail.com +( + '4cc04f54-7771-462d-98aa-a94448bb6ff5'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '4cc04f54-7771-462d-98aa-a94448bb6ff5'::uuid, + 'davidocampovenegas@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 14:52:46.468737+00'::timestamptz, + '2025-11-24 14:52:46.468737+00'::timestamptz +), + +-- Perfil 21: zaid080809@gmail.com +( + 'fbbe7d19-048c-45e4-8a9c-cf86d2098c35'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'fbbe7d19-048c-45e4-8a9c-cf86d2098c35'::uuid, + 'zaid080809@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 16:25:03.689847+00'::timestamptz, + '2025-11-24 16:25:03.689847+00'::timestamptz +), + +-- Perfil 22: ruizcruzabrahamfrancisco@gmail.com +( + '5b3d74e8-fd1a-4c80-96d2-24c54bfe90c4'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5b3d74e8-fd1a-4c80-96d2-24c54bfe90c4'::uuid, + 'ruizcruzabrahamfrancisco@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 19:46:06.311558+00'::timestamptz, + '2025-11-24 19:46:06.311558+00'::timestamptz +), + +-- Perfil 23: vituschinchilla@gmail.com +( + '615adf6e-dbf3-480f-a907-3cfb3a64c6d2'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '615adf6e-dbf3-480f-a907-3cfb3a64c6d2'::uuid, + 'vituschinchilla@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 21:07:26.037867+00'::timestamptz, + '2025-11-24 21:07:26.037867+00'::timestamptz +), + +-- Perfil 24: bryan@betanzos.com +( + 'bf445960-4c1f-4e29-8fb7-31667b183d7e'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'bf445960-4c1f-4e29-8fb7-31667b183d7e'::uuid, + 'bryan@betanzos.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 06:13:30.263795+00'::timestamptz, + '2025-11-25 06:13:30.263795+00'::timestamptz +), + +-- Perfil 25: loganalexander816@gmail.com +( + 'd5fa4905-a78a-4040-8ad8-23220881c6a6'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'd5fa4905-a78a-4040-8ad8-23220881c6a6'::uuid, + 'loganalexander816@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 07:37:04.953164+00'::timestamptz, + '2025-11-25 07:37:04.953164+00'::timestamptz +), + +-- Perfil 26: carlois1974@gmail.com +( + '71734c15-cdaa-431b-90f5-97a57e0316a8'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '71734c15-cdaa-431b-90f5-97a57e0316a8'::uuid, + 'carlois1974@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 07:41:38.025764+00'::timestamptz, + '2025-11-25 07:41:38.025764+00'::timestamptz +), + +-- Perfil 27: enriquecuevascbtis136@gmail.com +( + '1efe491d-98ef-4c02-acd1-3135f7289072'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '1efe491d-98ef-4c02-acd1-3135f7289072'::uuid, + 'enriquecuevascbtis136@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:16:33.977647+00'::timestamptz, + '2025-11-25 08:16:33.977647+00'::timestamptz +), + +-- Perfil 28: omarcitogonzalezzavaleta@gmail.com +( + '5ae21325-7450-4c37-82f1-3f9bcd7b6f45'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5ae21325-7450-4c37-82f1-3f9bcd7b6f45'::uuid, + 'omarcitogonzalezzavaleta@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:17:07.610076+00'::timestamptz, + '2025-11-25 08:17:07.610076+00'::timestamptz +), + +-- Perfil 29: gustavobm2024cbtis@gmail.com +( + 'a4d27774-8a51-4660-ad2f-81d0dfd3a5a7'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'a4d27774-8a51-4660-ad2f-81d0dfd3a5a7'::uuid, + 'gustavobm2024cbtis@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:20:49.649184+00'::timestamptz, + '2025-11-25 08:20:49.649184+00'::timestamptz +), + +-- Perfil 30: marianaxsotoxt22@gmail.com +( + '6e30164a-78b0-49b0-bd21-23d7c6c03349'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '6e30164a-78b0-49b0-bd21-23d7c6c03349'::uuid, + 'marianaxsotoxt22@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:33:18.150784+00'::timestamptz, + '2025-11-25 08:33:18.150784+00'::timestamptz +), + +-- Perfil 31: javiermar06@hotmail.com +( + '69681b09-5077-4f77-84cc-67606abd9755'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '69681b09-5077-4f77-84cc-67606abd9755'::uuid, + 'javiermar06@hotmail.com', + 'Javier Mar', 'Javier Mar', 'Javier', 'Mar', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-12-08 19:24:06.272257+00'::timestamptz, + '2025-12-08 19:24:06.272257+00'::timestamptz +), + +-- Perfil 32: ju188an@gmail.com +( + 'f929d6df-8c29-461f-88f5-264facd879e9'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'f929d6df-8c29-461f-88f5-264facd879e9'::uuid, + 'ju188an@gmail.com', + 'Juan pa', 'Juan pa', 'Juan', 'pa', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-12-17 17:51:43.536295+00'::timestamptz, + '2025-12-17 17:51:43.536295+00'::timestamptz +) + +ON CONFLICT (id) DO UPDATE SET + tenant_id = EXCLUDED.tenant_id, + email = EXCLUDED.email, + updated_at = NOW(); + +-- ===================================================== +-- Verification Query +-- ===================================================== + +DO $$ +DECLARE + additional_count INTEGER; +BEGIN + SELECT COUNT(*) INTO additional_count + FROM auth_management.profiles + WHERE email NOT LIKE '%@gamilit.com' + AND email NOT IN ( + 'joseal.guirre34@gmail.com', + 'sergiojimenezesteban63@gmail.com', + 'Gomezfornite92@gmail.com', + 'Aragon494gt54@icloud.com', + 'blu3wt7@gmail.com', + 'ricardolugo786@icloud.com', + 'marbancarlos916@gmail.com', + 'diego.colores09@gmail.com', + 'hernandezfonsecabenjamin7@gmail.com', + 'jr7794315@gmail.com', + 'barraganfer03@gmail.com', + 'roman.rebollar.marcoantonio1008@gmail.com', + 'rodrigoguerrero0914@gmail.com' + ); + + RAISE NOTICE '========================================'; + RAISE NOTICE 'PERFILES ADICIONALES DE PRODUCCION'; + RAISE NOTICE '========================================'; + RAISE NOTICE 'Perfiles adicionales creados: %', additional_count; + RAISE NOTICE '========================================'; + + IF additional_count >= 30 THEN + RAISE NOTICE 'OK: Se crearon los 32 perfiles adicionales'; + ELSE + RAISE WARNING 'ATENCION: Se esperaban 32 perfiles adicionales'; + END IF; +END $$; + +-- ===================================================== +-- NOTA: rckrdmrd@gmail.com fue EXCLUIDO intencionalmente +-- ===================================================== diff --git a/projects/gamilit/apps/database/seeds/prod/auth_management/01-tenants.sql b/projects/gamilit/apps/database/seeds/prod/auth_management/01-tenants.sql index 5135a2b..05a3f43 100644 --- a/projects/gamilit/apps/database/seeds/prod/auth_management/01-tenants.sql +++ b/projects/gamilit/apps/database/seeds/prod/auth_management/01-tenants.sql @@ -119,6 +119,37 @@ INSERT INTO auth_management.tenants ( }'::jsonb, gamilit.now_mexico(), gamilit.now_mexico() +), +-- Tenant 4: Gamilit Production (para usuarios de producciΓ³n) +-- AGREGADO 2025-12-19: Necesario para profiles de producciΓ³n +( + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'Gamilit Production', + 'gamilit-prod', + 'gamilit.com', + NULL, + 'enterprise', + 10000, + 1000, + true, + NULL, + '{ + "theme": "detective", + "language": "es", + "timezone": "America/Mexico_City", + "features": { + "analytics_enabled": true, + "gamification_enabled": true, + "social_features_enabled": true + } + }'::jsonb, + '{ + "description": "Tenant principal de producciΓ³n", + "environment": "production", + "created_by": "seed_script" + }'::jsonb, + gamilit.now_mexico(), + gamilit.now_mexico() ) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, diff --git a/projects/gamilit/apps/database/seeds/prod/auth_management/07-profiles-production-additional.sql b/projects/gamilit/apps/database/seeds/prod/auth_management/07-profiles-production-additional.sql new file mode 100644 index 0000000..4e24951 --- /dev/null +++ b/projects/gamilit/apps/database/seeds/prod/auth_management/07-profiles-production-additional.sql @@ -0,0 +1,646 @@ +-- ===================================================== +-- Seed: auth_management.profiles - Additional Production Users +-- Description: Perfiles adicionales para usuarios registrados sin nombre completo +-- Environment: PRODUCTION / DEV +-- Dependencies: auth/02-production-users.sql, auth_management/01-tenants.sql +-- Order: 07 (despues de 06-profiles-production.sql) +-- Created: 2025-12-19 +-- Version: 1.0 +-- ===================================================== +-- +-- USUARIOS ADICIONALES: 32 perfiles +-- Estos usuarios se registraron despues del lote inicial y no tienen +-- first_name/last_name en su metadata. Se crean con datos minimos. +-- +-- POLITICA: +-- - profiles.id = auth.users.id (consistente con el resto del sistema) +-- - tenant_id = Tenant principal (GAMILIT Platform) +-- - Nombres vacios permitidos (el usuario puede completarlos despues) +-- +-- EXCLUIDO: rckrdmrd@gmail.com (por solicitud explicita) +-- ===================================================== + +SET search_path TO auth_management, public; + +-- ===================================================== +-- INSERT: Additional Production User Profiles (32 perfiles) +-- ===================================================== + +INSERT INTO auth_management.profiles ( + id, + tenant_id, + user_id, + email, + display_name, + full_name, + first_name, + last_name, + avatar_url, + bio, + phone, + date_of_birth, + grade_level, + student_id, + school_id, + role, + status, + email_verified, + phone_verified, + preferences, + metadata, + created_at, + updated_at +) VALUES + +-- Perfil 1: santiagoferrara78@gmail.com +( + 'd089b1af-462f-4d2c-b0f5-d2528cec8506'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'd089b1af-462f-4d2c-b0f5-d2528cec8506'::uuid, + 'santiagoferrara78@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 09:21:04.898591+00'::timestamptz, + '2025-11-24 09:21:04.898591+00'::timestamptz +), + +-- Perfil 2: alexanserrv917@gmail.com +( + 'b1cadf36-1f07-46b2-b63d-da72d9b54dc6'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'b1cadf36-1f07-46b2-b63d-da72d9b54dc6'::uuid, + 'alexanserrv917@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:26:51.934739+00'::timestamptz, + '2025-11-24 10:26:51.934739+00'::timestamptz +), + +-- Perfil 3: aarizmendi434@gmail.com +( + 'af4d8788-f8a8-4971-bb0d-2f48c150dfc2'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'af4d8788-f8a8-4971-bb0d-2f48c150dfc2'::uuid, + 'aarizmendi434@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:30:54.728262+00'::timestamptz, + '2025-11-24 10:30:54.728262+00'::timestamptz +), + +-- Perfil 4: ashernarcisobenitezpalomino@gmail.com +( + '26fbc469-10af-4fa3-bd65-e5498188cc4f'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '26fbc469-10af-4fa3-bd65-e5498188cc4f'::uuid, + 'ashernarcisobenitezpalomino@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:37:35.325342+00'::timestamptz, + '2025-11-24 10:37:35.325342+00'::timestamptz +), + +-- Perfil 5: ra.alejandrobm@gmail.com +( + '74ed8c97-ec36-43aa-a1cc-b0c99e4be4e8'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '74ed8c97-ec36-43aa-a1cc-b0c99e4be4e8'::uuid, + 'ra.alejandrobm@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:42:33.424367+00'::timestamptz, + '2025-11-24 10:42:33.424367+00'::timestamptz +), + +-- Perfil 6: abdallahxelhaneriavega@gmail.com +( + 'f4c46f46-3fb9-40bf-a52b-a8ad2e6a92e1'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'f4c46f46-3fb9-40bf-a52b-a8ad2e6a92e1'::uuid, + 'abdallahxelhaneriavega@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:45:19.984994+00'::timestamptz, + '2025-11-24 10:45:19.984994+00'::timestamptz +), + +-- Perfil 7: 09enriquecampos@gmail.com +( + '012adac4-8ffd-47bd-9248-f0c5851e981f'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '012adac4-8ffd-47bd-9248-f0c5851e981f'::uuid, + '09enriquecampos@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:51:54.731982+00'::timestamptz, + '2025-11-24 10:51:54.731982+00'::timestamptz +), + +-- Perfil 8: johhkk22@gmail.com +( + '126b9257-7b0a-4bd6-9ab3-c505ee00e10a'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '126b9257-7b0a-4bd6-9ab3-c505ee00e10a'::uuid, + 'johhkk22@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:53:47.029991+00'::timestamptz, + '2025-11-24 10:53:47.029991+00'::timestamptz +), + +-- Perfil 9: edangiel4532@gmail.com +( + '9ac1746e-94a6-4efc-a961-951c015d416e'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '9ac1746e-94a6-4efc-a961-951c015d416e'::uuid, + 'edangiel4532@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 10:58:12.790316+00'::timestamptz, + '2025-11-24 10:58:12.790316+00'::timestamptz +), + +-- Perfil 10: erickfranco462@gmail.com +( + '2d9f05d4-44dd-42cd-97aa-d57bd06fecd0'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '2d9f05d4-44dd-42cd-97aa-d57bd06fecd0'::uuid, + 'erickfranco462@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:00:11.800551+00'::timestamptz, + '2025-11-24 11:00:11.800551+00'::timestamptz +), + +-- Perfil 11: gallinainsana@gmail.com +( + 'aff5dcc6-32de-4769-9aaf-eda751fa0866'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'aff5dcc6-32de-4769-9aaf-eda751fa0866'::uuid, + 'gallinainsana@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:03:17.536383+00'::timestamptz, + '2025-11-24 11:03:17.536383+00'::timestamptz +), + +-- Perfil 12: leile5257@gmail.com +( + '0cda1645-83c5-445b-80b7-d0e4d436c00c'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '0cda1645-83c5-445b-80b7-d0e4d436c00c'::uuid, + 'leile5257@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:05:17.75852+00'::timestamptz, + '2025-11-24 11:05:17.75852+00'::timestamptz +), + +-- Perfil 13: maximiliano.mejia367@gmail.com +( + '1364c463-88de-479b-a883-c0b7b362bcf8'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '1364c463-88de-479b-a883-c0b7b362bcf8'::uuid, + 'maximiliano.mejia367@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:08:58.232003+00'::timestamptz, + '2025-11-24 11:08:58.232003+00'::timestamptz +), + +-- Perfil 14: fl432025@gmail.com +( + '547eb778-4782-4681-b198-c731bba36147'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '547eb778-4782-4681-b198-c731bba36147'::uuid, + 'fl432025@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:12:13.692614+00'::timestamptz, + '2025-11-24 11:12:13.692614+00'::timestamptz +), + +-- Perfil 15: 7341023901m@gmail.com +( + '5fc06693-e408-4eab-a9a3-fcd5f4e01296'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5fc06693-e408-4eab-a9a3-fcd5f4e01296'::uuid, + '7341023901m@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:15:18.276345+00'::timestamptz, + '2025-11-24 11:15:18.276345+00'::timestamptz +), + +-- Perfil 16: segurauriel235@gmail.com +( + '5d1839f6-b03f-4e12-b236-eca43f4674f2'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5d1839f6-b03f-4e12-b236-eca43f4674f2'::uuid, + 'segurauriel235@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:17:46.846963+00'::timestamptz, + '2025-11-24 11:17:46.846963+00'::timestamptz +), + +-- Perfil 17: angelrabano11@gmail.com +( + '1b310708-6f24-4c6a-88c9-a11f7a7f9763'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '1b310708-6f24-4c6a-88c9-a11f7a7f9763'::uuid, + 'angelrabano11@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:47:53.790673+00'::timestamptz, + '2025-11-24 11:47:53.790673+00'::timestamptz +), + +-- Perfil 18: daliaayalareyes35@gmail.com +( + '3c613b0e-66f9-4640-a599-c9426d8edffb'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '3c613b0e-66f9-4640-a599-c9426d8edffb'::uuid, + 'daliaayalareyes35@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:55:08.708961+00'::timestamptz, + '2025-11-24 11:55:08.708961+00'::timestamptz +), + +-- Perfil 19: alexeimongam@gmail.com +( + '7ded133e-9b13-4467-9803-edb813f6a9a1'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '7ded133e-9b13-4467-9803-edb813f6a9a1'::uuid, + 'alexeimongam@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 11:55:11.906996+00'::timestamptz, + '2025-11-24 11:55:11.906996+00'::timestamptz +), + +-- Perfil 20: davidocampovenegas@gmail.com +( + '4cc04f54-7771-462d-98aa-a94448bb6ff5'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '4cc04f54-7771-462d-98aa-a94448bb6ff5'::uuid, + 'davidocampovenegas@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 14:52:46.468737+00'::timestamptz, + '2025-11-24 14:52:46.468737+00'::timestamptz +), + +-- Perfil 21: zaid080809@gmail.com +( + 'fbbe7d19-048c-45e4-8a9c-cf86d2098c35'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'fbbe7d19-048c-45e4-8a9c-cf86d2098c35'::uuid, + 'zaid080809@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 16:25:03.689847+00'::timestamptz, + '2025-11-24 16:25:03.689847+00'::timestamptz +), + +-- Perfil 22: ruizcruzabrahamfrancisco@gmail.com +( + '5b3d74e8-fd1a-4c80-96d2-24c54bfe90c4'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5b3d74e8-fd1a-4c80-96d2-24c54bfe90c4'::uuid, + 'ruizcruzabrahamfrancisco@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 19:46:06.311558+00'::timestamptz, + '2025-11-24 19:46:06.311558+00'::timestamptz +), + +-- Perfil 23: vituschinchilla@gmail.com +( + '615adf6e-dbf3-480f-a907-3cfb3a64c6d2'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '615adf6e-dbf3-480f-a907-3cfb3a64c6d2'::uuid, + 'vituschinchilla@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-24 21:07:26.037867+00'::timestamptz, + '2025-11-24 21:07:26.037867+00'::timestamptz +), + +-- Perfil 24: bryan@betanzos.com +( + 'bf445960-4c1f-4e29-8fb7-31667b183d7e'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'bf445960-4c1f-4e29-8fb7-31667b183d7e'::uuid, + 'bryan@betanzos.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 06:13:30.263795+00'::timestamptz, + '2025-11-25 06:13:30.263795+00'::timestamptz +), + +-- Perfil 25: loganalexander816@gmail.com +( + 'd5fa4905-a78a-4040-8ad8-23220881c6a6'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'd5fa4905-a78a-4040-8ad8-23220881c6a6'::uuid, + 'loganalexander816@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 07:37:04.953164+00'::timestamptz, + '2025-11-25 07:37:04.953164+00'::timestamptz +), + +-- Perfil 26: carlois1974@gmail.com +( + '71734c15-cdaa-431b-90f5-97a57e0316a8'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '71734c15-cdaa-431b-90f5-97a57e0316a8'::uuid, + 'carlois1974@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 07:41:38.025764+00'::timestamptz, + '2025-11-25 07:41:38.025764+00'::timestamptz +), + +-- Perfil 27: enriquecuevascbtis136@gmail.com +( + '1efe491d-98ef-4c02-acd1-3135f7289072'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '1efe491d-98ef-4c02-acd1-3135f7289072'::uuid, + 'enriquecuevascbtis136@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:16:33.977647+00'::timestamptz, + '2025-11-25 08:16:33.977647+00'::timestamptz +), + +-- Perfil 28: omarcitogonzalezzavaleta@gmail.com +( + '5ae21325-7450-4c37-82f1-3f9bcd7b6f45'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '5ae21325-7450-4c37-82f1-3f9bcd7b6f45'::uuid, + 'omarcitogonzalezzavaleta@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:17:07.610076+00'::timestamptz, + '2025-11-25 08:17:07.610076+00'::timestamptz +), + +-- Perfil 29: gustavobm2024cbtis@gmail.com +( + 'a4d27774-8a51-4660-ad2f-81d0dfd3a5a7'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'a4d27774-8a51-4660-ad2f-81d0dfd3a5a7'::uuid, + 'gustavobm2024cbtis@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:20:49.649184+00'::timestamptz, + '2025-11-25 08:20:49.649184+00'::timestamptz +), + +-- Perfil 30: marianaxsotoxt22@gmail.com +( + '6e30164a-78b0-49b0-bd21-23d7c6c03349'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '6e30164a-78b0-49b0-bd21-23d7c6c03349'::uuid, + 'marianaxsotoxt22@gmail.com', + NULL, NULL, '', '', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-11-25 08:33:18.150784+00'::timestamptz, + '2025-11-25 08:33:18.150784+00'::timestamptz +), + +-- Perfil 31: javiermar06@hotmail.com +( + '69681b09-5077-4f77-84cc-67606abd9755'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + '69681b09-5077-4f77-84cc-67606abd9755'::uuid, + 'javiermar06@hotmail.com', + 'Javier Mar', 'Javier Mar', 'Javier', 'Mar', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-12-08 19:24:06.272257+00'::timestamptz, + '2025-12-08 19:24:06.272257+00'::timestamptz +), + +-- Perfil 32: ju188an@gmail.com +( + 'f929d6df-8c29-461f-88f5-264facd879e9'::uuid, + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, + 'f929d6df-8c29-461f-88f5-264facd879e9'::uuid, + 'ju188an@gmail.com', + 'Juan pa', 'Juan pa', 'Juan', 'pa', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'student'::auth_management.gamilit_role, + 'active'::auth_management.user_status, + false, false, + '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}'::jsonb, + '{}'::jsonb, + '2025-12-17 17:51:43.536295+00'::timestamptz, + '2025-12-17 17:51:43.536295+00'::timestamptz +) + +ON CONFLICT (id) DO UPDATE SET + tenant_id = EXCLUDED.tenant_id, + email = EXCLUDED.email, + updated_at = NOW(); + +-- ===================================================== +-- Verification Query +-- ===================================================== + +DO $$ +DECLARE + additional_count INTEGER; +BEGIN + SELECT COUNT(*) INTO additional_count + FROM auth_management.profiles + WHERE email NOT LIKE '%@gamilit.com' + AND email NOT IN ( + 'joseal.guirre34@gmail.com', + 'sergiojimenezesteban63@gmail.com', + 'Gomezfornite92@gmail.com', + 'Aragon494gt54@icloud.com', + 'blu3wt7@gmail.com', + 'ricardolugo786@icloud.com', + 'marbancarlos916@gmail.com', + 'diego.colores09@gmail.com', + 'hernandezfonsecabenjamin7@gmail.com', + 'jr7794315@gmail.com', + 'barraganfer03@gmail.com', + 'roman.rebollar.marcoantonio1008@gmail.com', + 'rodrigoguerrero0914@gmail.com' + ); + + RAISE NOTICE '========================================'; + RAISE NOTICE 'PERFILES ADICIONALES DE PRODUCCION'; + RAISE NOTICE '========================================'; + RAISE NOTICE 'Perfiles adicionales creados: %', additional_count; + RAISE NOTICE '========================================'; + + IF additional_count >= 30 THEN + RAISE NOTICE 'OK: Se crearon los 32 perfiles adicionales'; + ELSE + RAISE WARNING 'ATENCION: Se esperaban 32 perfiles adicionales'; + END IF; +END $$; + +-- ===================================================== +-- NOTA: rckrdmrd@gmail.com fue EXCLUIDO intencionalmente +-- ===================================================== diff --git a/projects/gamilit/orchestration/analisis-teacher-portal-2025-12-18/50-GAP-CRITICO-RESPONSES-PAGE.md b/projects/gamilit/orchestration/analisis-teacher-portal-2025-12-18/50-GAP-CRITICO-RESPONSES-PAGE.md index a5dcc59..3f4e2ac 100644 --- a/projects/gamilit/orchestration/analisis-teacher-portal-2025-12-18/50-GAP-CRITICO-RESPONSES-PAGE.md +++ b/projects/gamilit/orchestration/analisis-teacher-portal-2025-12-18/50-GAP-CRITICO-RESPONSES-PAGE.md @@ -1,275 +1,18 @@ -# GAP CRITICO: Responses Page No Muestra Datos Reales +# Arquitectura: Teacher Responses Page - Consulta Dual de Tablas -**Fecha**: 18 Diciembre 2025 -**Analista**: Requirements-Analyst -**Prioridad**: P0 - CRITICO (Bloquea funcionalidad core) -**Estado**: βœ… CORREGIDO - ImplementaciΓ³n completada +**Fecha**: 19 Diciembre 2025 +**Autor**: Requirements-Analyst +**Modulo**: Teacher Portal - Responses --- -## CORRECCION APLICADA +## ARQUITECTURA ACTUAL -**Fecha de correcciΓ³n**: 19 Diciembre 2025 - -### Archivos Modificados - -| Archivo | Cambio | -|---------|--------| -| `apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts` | Agregados enums `ResponseSource`, `SubmissionStatus` y campos `source`, `status`, `feedback`, `requires_manual_grading` | -| `apps/backend/src/modules/teacher/services/exercise-responses.service.ts` | MΓ©todo `getAttempts()` ahora usa UNION de ambas tablas; `getAttemptDetail()` busca en ambas tablas | - -### Cambios Clave - -1. **UNION Query**: El mΓ©todo `getAttempts()` ahora consulta: - - `progress_tracking.exercise_attempts` (ejercicios autocorregibles) - - `progress_tracking.exercise_submissions` (ejercicios de revisiΓ³n manual) - -2. **Nuevo campo `source`**: Indica de quΓ© tabla proviene cada registro (`attempt` o `submission`) - -3. **Filtro por status**: Excluye automΓ‘ticamente submissions con status `draft` - -4. **getAttemptDetail mejorado**: Busca primero en `exercise_attempts`, si no encuentra busca en `exercise_submissions` - ---- - -## RESUMEN EJECUTIVO - -El Teacher Portal tiene un gap critico: la pagina de Responses (`/teacher/responses`) **NO muestra las respuestas de los estudiantes** porque consulta la tabla incorrecta. - -| Aspecto | Estado Actual | Estado Esperado | -|---------|---------------|-----------------| -| Tabla consultada | `exercise_attempts` | `exercise_submissions` + `exercise_attempts` | -| Datos visibles | 0 o datos antiguos | Todas las respuestas | -| Funcionalidad | ROTA | FUNCIONAL | - ---- - -## ANALISIS DEL PROBLEMA - -### Arquitectura Dual de Tablas - -El sistema GAMILIT tiene **dos tablas** para almacenar respuestas de ejercicios: - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ FLUJO ACTUAL (ROTO) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ ESTUDIANTE TEACHER PORTAL β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Completa β”‚ β”‚ Responses Page β”‚ β”‚ -β”‚ β”‚ Ejercicio β”‚ β”‚ /teacher/ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ responses β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β–Ό β–Ό β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ POST /progress/ β”‚ β”‚ GET /teacher/ β”‚ β”‚ -β”‚ β”‚ submissions/ β”‚ β”‚ attempts β”‚ β”‚ -β”‚ β”‚ submit β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β–Ό β–Ό β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ exercise_ β”‚ β•³ β”‚ exercise_ β”‚ β”‚ -β”‚ β”‚ submissions │─────╳─────────│ attempts β”‚ β”‚ -β”‚ β”‚ (AQUI ESTAN β”‚ β•³ β”‚ (AQUI BUSCA) β”‚ β”‚ -β”‚ β”‚ LOS DATOS!) β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ ❌ NO HAY CONEXION - EL TEACHER NO VE LAS RESPUESTAS β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Tabla 1: `exercise_submissions` - -**Proposito**: Ejercicios que requieren revision manual (Modulos 4 y 5) - -- Archivo DDL: `apps/database/ddl/schemas/progress_tracking/tables/04-exercise_submissions.sql` -- Campo de respuestas: `answer_data` (JSONB) -- Estados: draft, submitted, graded, reviewed -- Tiene: `feedback`, `graded_at`, columnas de revision manual - -**Servicio que escribe**: `ExerciseSubmissionService.submitExercise()` -- Endpoint: `POST /progress/submissions/submit` -- Usado por: Frontend de estudiantes (`progressAPI.ts`) - -### Tabla 2: `exercise_attempts` - -**Proposito**: Ejercicios autocorregibles (multiples intentos) - -- Archivo DDL: `apps/database/ddl/schemas/progress_tracking/tables/03-exercise_attempts.sql` -- Campo de respuestas: `submitted_answers` (JSONB) -- Sin estados de workflow - solo registro de intentos - -**Servicio que lee**: `ExerciseResponsesService.getAttempts()` -- Endpoint: `GET /teacher/attempts` -- Usado por: Teacher Portal Responses Page - ---- - -## EVIDENCIA DEL GAP - -### 1. Frontend de Estudiantes (progressAPI.ts:384-385) - -```typescript -// Backend endpoint: POST /api/progress/submissions/submit -const backendPayload = { - userId, - exerciseId, - answers, -}; - -const { data } = await apiClient.post>( - '/progress/submissions/submit', // <-- ESCRIBE EN exercise_submissions - backendPayload, -); -``` - -### 2. Backend de Teacher Portal (exercise-responses.service.ts:186) - -```sql -FROM progress_tracking.exercise_attempts attempt -- <-- LEE DE exercise_attempts -LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id -... -``` - -### 3. Validacion en ExerciseSubmissionService (linea 227) - -```typescript -// Este servicio es SOLO para ejercicios que requieren revisiΓ³n manual -// Los ejercicios autocorregibles deben usar ExerciseAttemptService -if (!exercise.requires_manual_grading) { - throw new BadRequestException( - 'This exercise is auto-graded and allows multiple attempts...' - ); -} -``` - -Esto confirma la arquitectura dual, pero el Teacher Portal solo lee de una tabla. - ---- - -## IMPACTO - -| Impacto | Descripcion | -|---------|-------------| -| **Funcionalidad** | Teacher no puede ver respuestas de estudiantes | -| **Calificacion** | No puede calificar ejercicios de Modulos 4-5 | -| **Monitoreo** | No puede monitorear progreso real de estudiantes | -| **Datos** | Los datos existen en BD pero son invisibles al teacher | - ---- - -## SOLUCION PROPUESTA - -### Opcion A: Modificar ExerciseResponsesService para consultar AMBAS tablas (RECOMENDADO) - -**Complejidad**: Media -**Riesgo**: Bajo -**Tiempo estimado**: 4-6 horas - -```typescript -// exercise-responses.service.ts - -async getAttempts(userId: string, query: GetAttemptsQueryDto): Promise { - // Query UNION de ambas tablas - const sql = ` - -- Ejercicios autocorregibles (exercise_attempts) - SELECT - 'attempt' as source, - attempt.id AS id, - attempt.user_id AS student_id, - attempt.submitted_answers AS answers, - attempt.score, - attempt.is_correct, - attempt.submitted_at, - ... - FROM progress_tracking.exercise_attempts attempt - ... - - UNION ALL - - -- Ejercicios de revision manual (exercise_submissions) - SELECT - 'submission' as source, - sub.id AS id, - sub.user_id AS student_id, - sub.answer_data AS answers, - sub.score, - sub.is_correct, - sub.submitted_at, - ... - FROM progress_tracking.exercise_submissions sub - ... - WHERE sub.status != 'draft' - - ORDER BY submitted_at DESC - LIMIT $X OFFSET $Y - `; -} -``` - -### Opcion B: Crear endpoint separado para submissions - -**Complejidad**: Baja -**Riesgo**: Bajo -**Tiempo estimado**: 2-3 horas - -Crear un nuevo endpoint `/teacher/submissions` que consulte `exercise_submissions` y agregar una tab en el frontend para mostrar ambos tipos. - -### Opcion C: Migrar datos a una sola tabla (NO RECOMENDADO) - -**Complejidad**: Alta -**Riesgo**: Alto (podria romper otras partes del sistema) -**Tiempo estimado**: 2-3 dias - ---- - -## ARCHIVOS A MODIFICAR - -### Opcion A (Recomendada) - -| Archivo | Cambio | -|---------|--------| -| `apps/backend/src/modules/teacher/services/exercise-responses.service.ts` | Modificar query para UNION de ambas tablas | -| `apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts` | Agregar campo `source: 'attempt' \| 'submission'` | -| `apps/frontend/src/apps/teacher/components/responses/ResponsesTable.tsx` | (Opcional) Mostrar indicador de tipo | - ---- - -## VALIDACION POST-IMPLEMENTACION - -### Pasos de VerificaciΓ³n - -1. **Compilar backend**: - ```bash - cd apps/backend && npm run build - ``` - -2. **Test manual**: Como estudiante, completar un ejercicio de Modulo 4 o 5 - -3. **Verificar BD**: - ```sql - SELECT * FROM progress_tracking.exercise_submissions - WHERE status != 'draft' - ORDER BY submitted_at DESC LIMIT 5; - ``` - -4. **Verificar Teacher Portal**: Navegar a `/teacher/responses` y confirmar que aparece el ejercicio - -5. **Test de detalle**: Click en "Ver" y confirmar que muestra las respuestas correctamente - -6. **Test de filtros**: - - Filtrar por `source=submission` para ver solo ejercicios de revisiΓ³n manual - - Filtrar por `status=submitted` para ver ejercicios pendientes de calificaciΓ³n - -### Nuevo Flujo Corregido +El endpoint `GET /api/v1/teacher/attempts` consulta **dos tablas** mediante UNION query para mostrar todas las respuestas de estudiantes: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ FLUJO CORREGIDO βœ… β”‚ +β”‚ FLUJO DE DATOS β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ ESTUDIANTE TEACHER PORTAL β”‚ @@ -292,26 +35,228 @@ Crear un nuevo endpoint `/teacher/submissions` que consulte `exercise_submission β”‚ β”‚ (M1-M3) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ βœ… CONEXION COMPLETA - Teacher VE todas las respuestas β”‚ +β”‚ βœ… UNION Query combina ambas tablas β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- -## DEPENDENCIAS +## TABLAS DE ORIGEN -- RLS policies ya existen para `exercise_submissions` (linea 168 del DDL) -- El frontend ya maneja el formato de respuesta (no requiere cambios mayores) +### Tabla 1: `progress_tracking.exercise_attempts` + +**Proposito**: Ejercicios autocorregibles (Modulos 1-3) + +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| `id` | UUID | ID del intento | +| `user_id` | UUID | ID del estudiante | +| `exercise_id` | UUID | ID del ejercicio | +| `submitted_answers` | JSONB | Respuestas enviadas | +| `is_correct` | BOOLEAN | Si fue correcto | +| `score` | INTEGER | Puntaje obtenido | +| `comodines_used` | JSONB | Comodines usados | +| `submitted_at` | TIMESTAMP | Fecha de envio | + +**DDL**: `apps/database/ddl/schemas/progress_tracking/tables/03-exercise_attempts.sql` + +### Tabla 2: `progress_tracking.exercise_submissions` + +**Proposito**: Ejercicios de revision manual (Modulos 4-5) + +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| `id` | UUID | ID del submission | +| `user_id` | UUID | ID del estudiante | +| `exercise_id` | UUID | ID del ejercicio | +| `answer_data` | JSONB | Respuestas enviadas | +| `is_correct` | BOOLEAN | Si fue correcto (NULL hasta calificar) | +| `score` | INTEGER | Puntaje (NULL hasta calificar) | +| `status` | TEXT | draft, submitted, graded, reviewed | +| `feedback` | TEXT | Retroalimentacion del profesor | +| `comodines_used` | TEXT[] | Comodines usados | +| `submitted_at` | TIMESTAMP | Fecha de envio | + +**DDL**: `apps/database/ddl/schemas/progress_tracking/tables/04-exercise_submissions.sql` --- -## SIGUIENTE PASO +## IMPLEMENTACION -**ACCION INMEDIATA**: Implementar Opcion A - Modificar `ExerciseResponsesService` para consultar ambas tablas con UNION. +### Archivos Clave + +| Archivo | Responsabilidad | +|---------|-----------------| +| `apps/backend/src/modules/teacher/services/exercise-responses.service.ts` | UNION query de ambas tablas | +| `apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts` | DTOs con enums `ResponseSource`, `ExerciseSubmissionStatus` | + +### DTOs + +```typescript +// Enums para identificar origen +export enum ResponseSource { + ATTEMPT = 'attempt', // exercise_attempts + SUBMISSION = 'submission', // exercise_submissions +} + +export enum ExerciseSubmissionStatus { + DRAFT = 'draft', + SUBMITTED = 'submitted', + GRADED = 'graded', + REVIEWED = 'reviewed', +} + +// Campos adicionales en AttemptResponseDto +interface AttemptResponseDto { + // ... campos base ... + source?: ResponseSource; // Indica tabla de origen + status?: ExerciseSubmissionStatus; // Solo para submissions + feedback?: string; // Solo para submissions + requires_manual_grading?: boolean; // true para submissions +} +``` + +### Query UNION + +```sql +SELECT * FROM ( + -- Ejercicios autocorregibles + SELECT + 'attempt' AS source, + attempt.id, attempt.user_id, attempt.exercise_id, + attempt.submitted_answers, attempt.is_correct, attempt.score, + attempt.comodines_used, -- JSONB + NULL::text AS status, + NULL::text AS feedback, + false AS requires_manual_grading, + ... + FROM progress_tracking.exercise_attempts attempt + ... + + UNION ALL + + -- Ejercicios de revision manual + SELECT + 'submission' AS source, + sub.id, sub.user_id, sub.exercise_id, + sub.answer_data AS submitted_answers, sub.is_correct, sub.score, + to_jsonb(sub.comodines_used) AS comodines_used, -- text[] -> jsonb + sub.status, + sub.feedback, + true AS requires_manual_grading, + ... + FROM progress_tracking.exercise_submissions sub + ... + WHERE sub.status != 'draft' -- Excluir borradores +) AS combined +ORDER BY submitted_at DESC +``` + +**Nota**: `to_jsonb(sub.comodines_used)` convierte `text[]` a `jsonb` para compatibilidad del UNION. --- -*Analisis realizado: 2025-12-18* +## RESPUESTA API + +### Endpoint + +``` +GET /api/v1/teacher/attempts +Authorization: Bearer +``` + +### Query Parameters + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `page` | number | Pagina (default: 1) | +| `limit` | number | Items por pagina (default: 20) | +| `student_id` | UUID | Filtrar por estudiante | +| `exercise_id` | UUID | Filtrar por ejercicio | +| `module_id` | UUID | Filtrar por modulo | +| `classroom_id` | UUID | Filtrar por aula | +| `is_correct` | boolean | Filtrar por correctitud | +| `from_date` | ISO8601 | Fecha desde | +| `to_date` | ISO8601 | Fecha hasta | +| `sort_by` | enum | submitted_at, score, time | +| `sort_order` | enum | asc, desc | + +### Response + +```json +{ + "success": true, + "data": { + "data": [ + { + "id": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee", + "student_id": "cccccccc-cccc-cccc-cccc-cccccccccccc", + "student_name": "Estudiante Testing", + "exercise_id": "fe944016-0f37-4a8e-b6dc-07f85c0e282c", + "exercise_title": "Crucigrama Cientifico", + "module_name": "Modulo 1: Comprension Literal", + "submitted_answers": {"essay": "Respuesta del estudiante..."}, + "is_correct": false, + "score": 0, + "source": "submission", + "status": "submitted", + "requires_manual_grading": true + }, + { + "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + "student_name": "Estudiante Testing", + "exercise_title": "Linea de Tiempo", + "submitted_answers": {"answers": ["A", "B", "C"]}, + "is_correct": true, + "score": 100, + "source": "attempt", + "status": null, + "requires_manual_grading": false + } + ], + "total": 4, + "page": 1, + "limit": 20, + "total_pages": 1 + } +} +``` + +--- + +## VALIDACION RLS + +El acceso se valida mediante: + +```sql +WHERE c.teacher_id = $1 -- Profesor asignado al aula + AND profile.tenant_id = $2 -- Mismo tenant +``` + +Los profesores solo ven respuestas de estudiantes en sus aulas asignadas. + +--- + +## RELACIONES + +``` +Teacher Portal (Frontend) + β”‚ + β–Ό +GET /api/v1/teacher/attempts + β”‚ + β–Ό +ExerciseResponsesService.getAttempts() + β”‚ + β”œβ”€β”€β–Ί progress_tracking.exercise_attempts + β”‚ └──► Ejercicios autocorregibles (M1-M3) + β”‚ + └──► progress_tracking.exercise_submissions + └──► Ejercicios revision manual (M4-M5) +``` + +--- + +*Documento actualizado: 2025-12-19* *Proyecto: GAMILIT - Portal Teacher* -*Gap ID: G-RESPONSES-001*