Gamilit: Teacher portal fixes, database initialization improvements
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions

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 <noreply@anthropic.com>
This commit is contained in:
rckrdmrd 2025-12-19 01:37:45 -06:00
parent 467603cc62
commit 5a0a29412c
11 changed files with 2827 additions and 421 deletions

View File

@ -35,6 +35,24 @@ export enum SortOrder {
DESC = 'desc', 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 * Query DTO for filtering exercise attempts
*/ */
@ -247,6 +265,31 @@ export class AttemptResponseDto {
example: '2024-11-24T10:30:00Z', example: '2024-11-24T10:30:00Z',
}) })
submitted_at!: string; 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;
} }
/** /**

View File

@ -15,6 +15,8 @@ import {
AttemptResponseDto, AttemptResponseDto,
AttemptDetailDto, AttemptDetailDto,
AttemptsListResponseDto, AttemptsListResponseDto,
ResponseSource,
ExerciseSubmissionStatus,
} from '../dto/exercise-responses.dto'; } from '../dto/exercise-responses.dto';
/** /**
@ -74,6 +76,13 @@ export class ExerciseResponsesService {
* is_correct: true, * 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( async getAttempts(
userId: string, userId: string,
query: GetAttemptsQueryDto, query: GetAttemptsQueryDto,
@ -89,107 +98,175 @@ export class ExerciseResponsesService {
const limit = query.limit || 20; const limit = query.limit || 20;
const offset = (page - 1) * limit; const offset = (page - 1) * limit;
// Sorting // Sorting - use alias for UNION compatibility
const sortField = query.sort_by === 'score' const sortField = query.sort_by === 'score'
? 'attempt.score' ? 'score'
: query.sort_by === 'time' : query.sort_by === 'time'
? 'attempt.time_spent_seconds' ? 'time_spent_seconds'
: 'attempt.submitted_at'; : 'submitted_at';
const sortOrder = query.sort_order?.toUpperCase() === 'ASC' ? 'ASC' : 'DESC'; const sortOrder = query.sort_order?.toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
// Build WHERE conditions dynamically // Build base params
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',
];
const params: any[] = [teacherId, tenantId]; const params: any[] = [teacherId, tenantId];
let paramIndex = 3; 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) { if (query.student_id) {
conditions.push(`profile.id = $${paramIndex}`); attemptsConditions.push(`profile.id = $${paramIndex}`);
params.push(query.student_id); submissionsConditions.push(`profile.id = $${paramIndex}`);
dynamicParams.push(query.student_id);
paramIndex++; paramIndex++;
} }
if (query.exercise_id) { if (query.exercise_id) {
conditions.push(`attempt.exercise_id = $${paramIndex}`); attemptsConditions.push(`attempt.exercise_id = $${paramIndex}`);
params.push(query.exercise_id); submissionsConditions.push(`sub.exercise_id = $${paramIndex}`);
dynamicParams.push(query.exercise_id);
paramIndex++; paramIndex++;
} }
if (query.module_id) { if (query.module_id) {
conditions.push(`exercise.module_id = $${paramIndex}`); attemptsConditions.push(`exercise.module_id = $${paramIndex}`);
params.push(query.module_id); submissionsConditions.push(`exercise.module_id = $${paramIndex}`);
dynamicParams.push(query.module_id);
paramIndex++; paramIndex++;
} }
if (query.classroom_id) { if (query.classroom_id) {
conditions.push(`c.id = $${paramIndex}`); attemptsConditions.push(`c.id = $${paramIndex}`);
params.push(query.classroom_id); submissionsConditions.push(`c.id = $${paramIndex}`);
dynamicParams.push(query.classroom_id);
paramIndex++; paramIndex++;
} }
if (query.from_date) { if (query.from_date) {
conditions.push(`attempt.submitted_at >= $${paramIndex}`); attemptsConditions.push(`attempt.submitted_at >= $${paramIndex}`);
params.push(query.from_date); submissionsConditions.push(`sub.submitted_at >= $${paramIndex}`);
dynamicParams.push(query.from_date);
paramIndex++; paramIndex++;
} }
if (query.to_date) { if (query.to_date) {
conditions.push(`attempt.submitted_at <= $${paramIndex}`); attemptsConditions.push(`attempt.submitted_at <= $${paramIndex}`);
params.push(query.to_date); submissionsConditions.push(`sub.submitted_at <= $${paramIndex}`);
dynamicParams.push(query.to_date);
paramIndex++; paramIndex++;
} }
if (query.is_correct !== undefined) { if (query.is_correct !== undefined) {
conditions.push(`attempt.is_correct = $${paramIndex}`); attemptsConditions.push(`attempt.is_correct = $${paramIndex}`);
params.push(query.is_correct); submissionsConditions.push(`sub.is_correct = $${paramIndex}`);
dynamicParams.push(query.is_correct);
paramIndex++; paramIndex++;
} }
if (query.student_search) { if (query.student_search) {
const searchPattern = `%${query.student_search}%`; const searchPattern = `%${query.student_search}%`;
conditions.push(`( const searchCondition = `(
profile.first_name ILIKE $${paramIndex} profile.first_name ILIKE $${paramIndex}
OR profile.last_name ILIKE $${paramIndex} OR profile.last_name ILIKE $${paramIndex}
OR CONCAT(profile.first_name, ' ', 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++; 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 = ` const sql = `
SELECT SELECT * FROM (
attempt.id AS attempt_id, -- Ejercicios autocorregibles (exercise_attempts)
attempt.user_id AS attempt_user_id, SELECT
attempt.exercise_id AS attempt_exercise_id, 'attempt' AS source,
attempt.attempt_number AS attempt_attempt_number, attempt.id AS id,
attempt.submitted_answers AS attempt_submitted_answers, attempt.user_id AS user_id,
attempt.is_correct AS attempt_is_correct, attempt.exercise_id AS exercise_id,
attempt.score AS attempt_score, attempt.attempt_number AS attempt_number,
attempt.time_spent_seconds AS attempt_time_spent_seconds, attempt.submitted_answers AS submitted_answers,
attempt.hints_used AS attempt_hints_used, attempt.is_correct AS is_correct,
attempt.comodines_used AS attempt_comodines_used, attempt.score AS score,
attempt.xp_earned AS attempt_xp_earned, attempt.time_spent_seconds AS time_spent_seconds,
attempt.ml_coins_earned AS attempt_ml_coins_earned, attempt.hints_used AS hints_used,
attempt.submitted_at AS attempt_submitted_at, attempt.comodines_used AS comodines_used,
profile.id AS profile_id, attempt.xp_earned AS xp_earned,
profile.first_name AS profile_first_name, attempt.ml_coins_earned AS ml_coins_earned,
profile.last_name AS profile_last_name, attempt.submitted_at AS submitted_at,
exercise.id AS exercise_id, NULL::text AS status,
exercise.title AS exercise_title, NULL::text AS feedback,
module.id AS module_id, false AS requires_manual_grading,
module.title AS module_name profile.id AS profile_id,
FROM progress_tracking.exercise_attempts attempt profile.first_name AS first_name,
LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id profile.last_name AS last_name,
LEFT JOIN educational_content.exercises exercise ON exercise.id = attempt.exercise_id exercise.title AS exercise_title,
LEFT JOIN educational_content.modules module ON module.id = exercise.module_id module.title AS module_name
LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id FROM progress_tracking.exercise_attempts attempt
LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id
WHERE ${whereClause} 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} ORDER BY ${sortField} ${sortOrder}
LIMIT $${paramIndex} OFFSET $${paramIndex + 1} LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
`; `;
@ -199,15 +276,25 @@ export class ExerciseResponsesService {
// Execute main query // Execute main query
const rawResults = await this.dataSource.query(sql, params); const rawResults = await this.dataSource.query(sql, params);
// Count query (separate for efficiency) // Count query for both tables
const countSql = ` const countSql = `
SELECT COUNT(DISTINCT attempt.id) as total SELECT (
FROM progress_tracking.exercise_attempts attempt (SELECT COUNT(DISTINCT attempt.id)
LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id FROM progress_tracking.exercise_attempts attempt
LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id
LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id LEFT JOIN social_features.classroom_members cm ON cm.student_id = profile.id
LEFT JOIN educational_content.exercises exercise ON exercise.id = attempt.exercise_id LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id
WHERE ${whereClause} 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 // Remove LIMIT/OFFSET params for count query
@ -215,24 +302,29 @@ export class ExerciseResponsesService {
const countResult = await this.dataSource.query(countSql, countParams); const countResult = await this.dataSource.query(countSql, countParams);
const total = parseInt(countResult[0]?.total || '0', 10); 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) => ({ const data: AttemptResponseDto[] = rawResults.map((row: any) => ({
id: row.attempt_id, id: row.id,
student_id: row.attempt_user_id, student_id: row.user_id,
student_name: `${row.profile_first_name || ''} ${row.profile_last_name || ''}`.trim() || 'Unknown', student_name: `${row.first_name || ''} ${row.last_name || ''}`.trim() || 'Unknown',
exercise_id: row.attempt_exercise_id, exercise_id: row.exercise_id,
exercise_title: row.exercise_title || 'Unknown Exercise', exercise_title: row.exercise_title || 'Unknown Exercise',
module_name: row.module_name || 'Unknown Module', module_name: row.module_name || 'Unknown Module',
attempt_number: row.attempt_attempt_number, attempt_number: row.attempt_number,
submitted_answers: row.attempt_submitted_answers, submitted_answers: row.submitted_answers,
is_correct: row.attempt_is_correct ?? false, is_correct: row.is_correct ?? false,
score: row.attempt_score ?? 0, score: row.score ?? 0,
time_spent_seconds: row.attempt_time_spent_seconds ?? 0, time_spent_seconds: row.time_spent_seconds ?? 0,
hints_used: row.attempt_hints_used, hints_used: row.hints_used ?? 0,
comodines_used: row.attempt_comodines_used, comodines_used: Array.isArray(row.comodines_used) ? row.comodines_used : (row.comodines_used || []),
xp_earned: row.attempt_xp_earned, xp_earned: row.xp_earned ?? 0,
ml_coins_earned: row.attempt_ml_coins_earned, ml_coins_earned: row.ml_coins_earned ?? 0,
submitted_at: row.attempt_submitted_at ? new Date(row.attempt_submitted_at).toISOString() : new Date().toISOString(), 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 { 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 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 * @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 * @throws ForbiddenException if teacher doesn't have access
*/ */
async getAttemptDetail( async getAttemptDetail(
@ -315,30 +411,34 @@ export class ExerciseResponsesService {
const teacherId = teacherProfile.id; const teacherId = teacherProfile.id;
const tenantId = teacherProfile.tenant_id; const tenantId = teacherProfile.tenant_id;
// Raw SQL query for cross-schema JOINs // G20 FIX: First try exercise_attempts table
const sql = ` const attemptSql = `
SELECT SELECT
attempt.id AS attempt_id, 'attempt' AS source,
attempt.user_id AS attempt_user_id, attempt.id AS record_id,
attempt.exercise_id AS attempt_exercise_id, attempt.user_id AS user_id,
attempt.attempt_number AS attempt_attempt_number, attempt.exercise_id AS exercise_id,
attempt.submitted_answers AS attempt_submitted_answers, attempt.attempt_number AS attempt_number,
attempt.is_correct AS attempt_is_correct, attempt.submitted_answers AS submitted_answers,
attempt.score AS attempt_score, attempt.is_correct AS is_correct,
attempt.time_spent_seconds AS attempt_time_spent_seconds, attempt.score AS score,
attempt.hints_used AS attempt_hints_used, attempt.time_spent_seconds AS time_spent_seconds,
attempt.comodines_used AS attempt_comodines_used, attempt.hints_used AS hints_used,
attempt.xp_earned AS attempt_xp_earned, attempt.comodines_used AS comodines_used,
attempt.ml_coins_earned AS attempt_ml_coins_earned, attempt.xp_earned AS xp_earned,
attempt.submitted_at AS attempt_submitted_at, 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.id AS profile_id,
profile.first_name AS profile_first_name, profile.first_name AS first_name,
profile.last_name AS profile_last_name, profile.last_name AS last_name,
exercise.id AS exercise_id, exercise.id AS ex_id,
exercise.title AS exercise_title, exercise.title AS exercise_title,
exercise.exercise_type AS exercise_type, exercise.exercise_type AS exercise_type,
exercise.content AS exercise_content, exercise.content AS exercise_content,
exercise.max_points AS exercise_max_points, exercise.max_points AS max_points,
module.id AS module_id, module.id AS module_id,
module.title AS module_name module.title AS module_name
FROM progress_tracking.exercise_attempts attempt 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 LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id
WHERE attempt.id = $1 WHERE attempt.id = $1
AND profile.tenant_id = $2 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 LIMIT 1
`; `;
const results = await this.dataSource.query(sql, [attemptId, tenantId, teacherId]); let results = await this.dataSource.query(attemptSql, [attemptId, tenantId, teacherId]);
const row = results[0]; 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) { 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 // Parse exercise content if it's a string
@ -377,26 +524,31 @@ export class ExerciseResponsesService {
const correctAnswer = this.extractCorrectAnswers(exerciseContent, row.exercise_type); const correctAnswer = this.extractCorrectAnswers(exerciseContent, row.exercise_type);
return { return {
id: row.attempt_id, id: row.record_id,
student_id: row.attempt_user_id, student_id: row.user_id,
student_name: `${row.profile_first_name || ''} ${row.profile_last_name || ''}`.trim() || 'Unknown', student_name: `${row.first_name || ''} ${row.last_name || ''}`.trim() || 'Unknown',
exercise_id: row.attempt_exercise_id, exercise_id: row.exercise_id,
exercise_title: row.exercise_title || 'Unknown Exercise', exercise_title: row.exercise_title || 'Unknown Exercise',
module_name: row.module_name || 'Unknown Module', module_name: row.module_name || 'Unknown Module',
attempt_number: row.attempt_attempt_number, attempt_number: row.attempt_number,
submitted_answers: row.attempt_submitted_answers, submitted_answers: row.submitted_answers,
is_correct: row.attempt_is_correct ?? false, is_correct: row.is_correct ?? false,
score: row.attempt_score ?? 0, score: row.score ?? 0,
time_spent_seconds: row.attempt_time_spent_seconds ?? 0, time_spent_seconds: row.time_spent_seconds ?? 0,
hints_used: row.attempt_hints_used, hints_used: row.hints_used ?? 0,
comodines_used: row.attempt_comodines_used, comodines_used: Array.isArray(row.comodines_used) ? row.comodines_used : (row.comodines_used || []),
xp_earned: row.attempt_xp_earned, xp_earned: row.xp_earned ?? 0,
ml_coins_earned: row.attempt_ml_coins_earned, ml_coins_earned: row.ml_coins_earned ?? 0,
submitted_at: row.attempt_submitted_at ? new Date(row.attempt_submitted_at).toISOString() : new Date().toISOString(), 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 // Additional detail fields
correct_answer: correctAnswer, correct_answer: correctAnswer,
exercise_type: row.exercise_type || 'unknown', 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; const tenantId = teacherProfile.tenant_id;
// Raw SQL for cross-schema verification // Raw SQL for cross-schema verification
// G20 FIX: Simplified to use only c.teacher_id (removed non-existent teacher_classrooms reference)
const sql = ` const sql = `
SELECT 1 SELECT 1
FROM auth_management.profiles profile FROM auth_management.profiles profile
@ -529,7 +682,7 @@ export class ExerciseResponsesService {
LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id LEFT JOIN social_features.classrooms c ON c.id = cm.classroom_id
WHERE profile.id = $1 WHERE profile.id = $1
AND profile.tenant_id = $2 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 LIMIT 1
`; `;

View File

@ -210,9 +210,20 @@ DO $$ BEGIN
EXCEPTION WHEN duplicate_object THEN null; END $$; EXCEPTION WHEN duplicate_object THEN null; END $$;
-- 📚 Documentación: educational_content.difficulty_level -- 📚 Documentación: educational_content.difficulty_level
-- REMOVIDO (2025-11-11): Migrado a ddl/schemas/educational_content/enums/difficulty_level.sql -- RESTAURADO (2025-12-19): Necesario en prerequisites para que tablas puedan crearse
-- Razón: Evitar duplicación (Política de Carga Limpia) -- 8 niveles CEFR: beginner (A1) → native (C2+)
-- El ENUM se define en el schema específico con documentación completa (8 niveles CEFR) 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 -- 📚 Documentación: educational_content.module_status
-- VERSIÓN: 1.2 (2025-11-23) - Agregado 'backlog' para módulos fuera de alcance de entrega -- 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 $$; EXCEPTION WHEN duplicate_object THEN null; END $$;
-- 📚 Documentación: content_management.content_status -- 📚 Documentación: content_management.content_status
-- REMOVIDO (2025-11-11): Migrado a ddl/schemas/content_management/enums/content_status.sql -- RESTAURADO (2025-12-19): Necesario en prerequisites para que tablas puedan crearse
-- Razón: Evitar duplicación (Política de Carga Limpia) -- Estados del ciclo de vida del contenido educativo
-- El ENUM se define en el schema específico con documentación completa 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 DO $$ BEGIN
CREATE TYPE educational_content.cognitive_level AS ENUM ('recordar', 'comprender', 'aplicar', 'analizar', 'evaluar', 'crear'); 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 -- 4. ENUMs de Progreso
-- 📚 Documentación: progress_tracking.progress_status -- 📚 Documentación: progress_tracking.progress_status
-- REMOVIDO (2025-11-11): Migrado a ddl/schemas/progress_tracking/enums/progress_status.sql -- RESTAURADO (2025-12-19): Necesario en prerequisites para que tablas puedan crearse
-- Razón: Evitar duplicación (Política de Carga Limpia) -- Estados de progreso para módulos y ejercicios
-- El ENUM se define en el schema específico con documentación exhaustiva (112 líneas) 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 -- 📚 Documentación: progress_tracking.attempt_status
-- Requerimiento: docs/01-requerimientos/04-progreso-seguimiento/RF-PRG-001-estados-progreso.md -- Requerimiento: docs/01-requerimientos/04-progreso-seguimiento/RF-PRG-001-estados-progreso.md

View File

@ -9,6 +9,8 @@
-- #1: Added module_progress initialization (CRITICAL) -- #1: Added module_progress initialization (CRITICAL)
-- #2: Added ON CONFLICT to user_ranks (prevents duplicate key errors) -- #2: Added ON CONFLICT to user_ranks (prevents duplicate key errors)
-- #3: Kept initialize_user_missions commented (function not implemented yet) -- #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() CREATE OR REPLACE FUNCTION gamilit.initialize_user_stats()
@ -19,14 +21,16 @@ BEGIN
-- Initialize gamification for students, teachers, and admins -- Initialize gamification for students, teachers, and admins
-- Only these roles have gamification enabled -- Only these roles have gamification enabled
IF NEW.role IN ('student', 'admin_teacher', 'super_admin') THEN 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 ( INSERT INTO gamification_system.user_stats (
user_id, user_id,
tenant_id, tenant_id,
ml_coins, ml_coins,
ml_coins_earned_total ml_coins_earned_total
) VALUES ( ) 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, NEW.tenant_id,
100, -- Welcome bonus 100, -- Welcome bonus
100 100
@ -34,27 +38,25 @@ BEGIN
ON CONFLICT (user_id) DO NOTHING; -- Prevent duplicates ON CONFLICT (user_id) DO NOTHING; -- Prevent duplicates
-- Create comodines inventory -- Create comodines inventory
-- IMPORTANT: comodines_inventory.user_id references profiles.id (NOT auth.users.id)
INSERT INTO gamification_system.comodines_inventory ( INSERT INTO gamification_system.comodines_inventory (
user_id user_id
) VALUES ( ) 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; ON CONFLICT (user_id) DO NOTHING;
-- Create initial user rank (starting with Ajaw - lowest rank) -- 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 ( INSERT INTO gamification_system.user_ranks (
user_id, user_id,
tenant_id, tenant_id,
current_rank current_rank
) )
SELECT SELECT
NEW.user_id, NEW.id, -- FIXED 2025-12-19: usar NEW.id (profiles.id), FK apunta a profiles(id)
NEW.tenant_id, NEW.tenant_id,
'Ajaw'::gamification_system.maya_rank 'Ajaw'::gamification_system.maya_rank
WHERE NOT EXISTS ( 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 -- BUG FIX #1: Initialize module progress for all active modules

View File

@ -821,27 +821,24 @@ load_seeds() {
local failed=0 local failed=0
# Array con orden específico respetando dependencias # 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=( local seed_files=(
# === FASE 1: INFRAESTRUCTURA BASE ===
"$SEEDS_DIR/auth_management/01-tenants.sql" "$SEEDS_DIR/auth_management/01-tenants.sql"
"$SEEDS_DIR/auth_management/02-auth_providers.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/01-system_settings.sql"
"$SEEDS_DIR/system_configuration/02-feature_flags.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/01-achievement_categories.sql"
"$SEEDS_DIR/gamification_system/02-leaderboard_metadata.sql" "$SEEDS_DIR/gamification_system/02-leaderboard_metadata.sql"
"$SEEDS_DIR/gamification_system/03-maya_ranks.sql" "$SEEDS_DIR/gamification_system/03-maya_ranks.sql"
"$SEEDS_DIR/gamification_system/04-achievements.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/01-modules.sql"
"$SEEDS_DIR/educational_content/02-exercises-module1.sql" "$SEEDS_DIR/educational_content/02-exercises-module1.sql"
"$SEEDS_DIR/educational_content/03-exercises-module2.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/05-exercises-module4.sql"
"$SEEDS_DIR/educational_content/06-exercises-module5.sql" "$SEEDS_DIR/educational_content/06-exercises-module5.sql"
"$SEEDS_DIR/educational_content/07-assessment-rubrics.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/01-marie-curie-bio.sql"
"$SEEDS_DIR/content_management/02-media-files.sql" "$SEEDS_DIR/content_management/02-media-files.sql"
"$SEEDS_DIR/content_management/03-tags.sql" "$SEEDS_DIR/content_management/03-tags.sql"

View File

@ -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
-- =====================================================

View File

@ -119,6 +119,37 @@ INSERT INTO auth_management.tenants (
}'::jsonb, }'::jsonb,
gamilit.now_mexico(), gamilit.now_mexico(),
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 ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name, name = EXCLUDED.name,

View File

@ -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
-- =====================================================

View File

@ -119,6 +119,37 @@ INSERT INTO auth_management.tenants (
}'::jsonb, }'::jsonb,
gamilit.now_mexico(), gamilit.now_mexico(),
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 ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name, name = EXCLUDED.name,

View File

@ -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
-- =====================================================

View File

@ -1,275 +1,18 @@
# GAP CRITICO: Responses Page No Muestra Datos Reales # Arquitectura: Teacher Responses Page - Consulta Dual de Tablas
**Fecha**: 18 Diciembre 2025 **Fecha**: 19 Diciembre 2025
**Analista**: Requirements-Analyst **Autor**: Requirements-Analyst
**Prioridad**: P0 - CRITICO (Bloquea funcionalidad core) **Modulo**: Teacher Portal - Responses
**Estado**: ✅ CORREGIDO - Implementación completada
--- ---
## CORRECCION APLICADA ## ARQUITECTURA ACTUAL
**Fecha de corrección**: 19 Diciembre 2025 El endpoint `GET /api/v1/teacher/attempts` consulta **dos tablas** mediante UNION query para mostrar todas las respuestas de estudiantes:
### 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<ApiResponse<SubmitExerciseResponse>>(
'/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<AttemptsListResponseDto> {
// 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
``` ```
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────┐
FLUJO CORREGIDO ✅ │ FLUJO DE DATOS │
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────┤
│ │ │ │
│ ESTUDIANTE TEACHER PORTAL │ │ ESTUDIANTE TEACHER PORTAL │
@ -292,26 +35,228 @@ Crear un nuevo endpoint `/teacher/submissions` que consulte `exercise_submission
│ │ (M1-M3) │ │ │ │ (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) ### Tabla 1: `progress_tracking.exercise_attempts`
- El frontend ya maneja el formato de respuesta (no requiere cambios mayores)
**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 <token>
```
### 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* *Proyecto: GAMILIT - Portal Teacher*
*Gap ID: G-RESPONSES-001*