chore: Migrar archivos desde workspace-old (2025-12-19)

Database:
- Actualizar backups de producción (usuarios, perfiles, stats)

Orchestration:
- Añadir análisis errores producción 2025-12-18
- Actualizar análisis teacher portal
- Añadir reportes de migración y producción

🤖 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 00:15:05 -06:00
parent fa07affd30
commit 5704222b85
16 changed files with 3411 additions and 11 deletions

View File

@ -72,6 +72,7 @@ INSERT INTO auth.users (instance_id, id, aud, role, email, encrypted_password, e
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', '5ae21325-7450-4c37-82f1-3f9bcd7b6f45', 'authenticated', NULL, 'omarcitogonzalezzavaleta@gmail.com', '$2b$10$RRk3DAgQdiikxVImFIMqquqB.TNpKs3E.RNFtt1rwwTzO24uShri.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '{"provider": "email", "providers": ["email"]}', '{"last_name": "", "first_name": ""}', false, '2025-11-25 08:17:07.610076+00', '2025-11-25 08:17:07.610076+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', 'a4d27774-8a51-4660-ad2f-81d0dfd3a5a7', 'authenticated', NULL, 'gustavobm2024cbtis@gmail.com', '$2b$10$lg7KRUTPofcx4Rtyey8J7.XO0gmdBLCFIfK5uP08mqT0qUIl1aTJq', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '{"provider": "email", "providers": ["email"]}', '{"last_name": "", "first_name": ""}', false, '2025-11-25 08:20:49.649184+00', '2025-11-25 08:20:49.649184+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', '6e30164a-78b0-49b0-bd21-23d7c6c03349', 'authenticated', NULL, 'marianaxsotoxt22@gmail.com', '$2b$10$GQC9yTWiP2vP9GUp0gnhUeLjmw70EI4JQhfJBZbMOlCNXGXb/bt5O', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '{"provider": "email", "providers": ["email"]}', '{"last_name": "", "first_name": ""}', false, '2025-11-25 08:33:18.150784+00', '2025-11-25 08:33:18.150784+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 (NULL, '0ae1bf21-39e3-4168-9632-457418c7a07d', 'authenticated', NULL, 'rckrdmrd@gmail.com', '$2b$10$LiDdaJLA.ZvdFleamkMuvOcIrW0PQMEh5aVZ5Wg5pzhm7gwc5s.1C', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-09 01:22:42.784+00', NULL, '{}', false, '2025-11-29 13:37:09.271457+00', '2025-12-09 01:22:42.785367+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'authenticated', NULL, 'admin@gamilit.com', '$2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga', '2025-11-29 13:26:50.289631+00', NULL, '', NULL, '', NULL, '', '', NULL, '2025-12-01 00:54:19.615+00', '{"provider": "email", "providers": ["email"]}', '{"name": "Admin GAMILIT", "role": "super_admin", "description": "Usuario administrador de testing"}', false, '2025-11-29 13:26:50.289631+00', '2025-12-01 00:54:19.617766+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'super_admin', 'active');
INSERT INTO auth.users (instance_id, 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 (NULL, '69681b09-5077-4f77-84cc-67606abd9755', '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', NULL, '{}', false, '2025-12-08 19:24:06.266895+00', '2025-12-14 03:51:04.123886+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 (NULL, 'f929d6df-8c29-461f-88f5-264facd879e9', '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', NULL, '{}', false, '2025-12-17 17:51:43.530434+00', '2025-12-17 23:51:43.55475+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
@ -126,6 +127,7 @@ INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, fi
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('c0aecfcc-3b2f-4117-9f20-e0920df97dc0', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, '', '', 'segurauriel235@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:30:54.277737+00', '2025-11-29 13:30:54.277737+00', '5d1839f6-b03f-4e12-b236-eca43f4674f2', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('3dfcdc9d-de8a-45b3-a05f-b83b51097ef5', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, '', '', 'omarcitogonzalezzavaleta@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:30:54.277737+00', '2025-11-29 13:30:54.277737+00', '5ae21325-7450-4c37-82f1-3f9bcd7b6f45', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('bb74b280-db90-4240-ab09-b8c6cf63d553', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, '', '', 'erickfranco462@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:30:54.277737+00', '2025-11-29 13:30:54.277737+00', '2d9f05d4-44dd-42cd-97aa-d57bd06fecd0', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('0ae1bf21-39e3-4168-9632-457418c7a07d', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, 'rckrdmrd@gmail.com', NULL, 'rckrdmrd@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:37:09.278078+00', '2025-11-29 13:37:09.278078+00', '0ae1bf21-39e3-4168-9632-457418c7a07d', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('69681b09-5077-4f77-84cc-67606abd9755', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, 'Javier', ' Mar', 'javiermar06@hotmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-12-08 19:24:06.272257+00', '2025-12-08 19:24:06.272257+00', '69681b09-5077-4f77-84cc-67606abd9755', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('f929d6df-8c29-461f-88f5-264facd879e9', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, 'Juan', 'pa', 'ju188an@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-12-17 17:51:43.536295+00', '2025-12-17 17:51:43.536295+00', 'f929d6df-8c29-461f-88f5-264facd879e9', NULL);

View File

@ -45,5 +45,6 @@ instance_id,id,aud,role,email,encrypted_password,email_confirmed_at,invited_at,c
00000000-0000-0000-0000-000000000000,cccccccc-cccc-cccc-cccc-cccccccccccc,authenticated,,student@gamilit.com,$2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga,2025-11-29 13:26:50.289631+00,,"",,"",,"","",,2025-12-07 03:42:02.528+00,"{""provider"": ""email"", ""providers"": [""email""]}","{""name"": ""Estudiante Testing"", ""role"": ""student"", ""description"": ""Usuario estudiante de testing""}",f,2025-11-29 13:26:50.289631+00,2025-12-07 03:42:02.529507+00,,,,,,,,0,,,,f,,student,active
00000000-0000-0000-0000-000000000000,bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb,authenticated,,teacher@gamilit.com,$2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga,2025-11-29 13:26:50.289631+00,,"",,"",,"","",,,"{""provider"": ""email"", ""providers"": [""email""]}","{""name"": ""Profesor Testing"", ""role"": ""admin_teacher"", ""description"": ""Usuario profesor de testing""}",f,2025-11-29 13:26:50.289631+00,2025-11-29 13:26:50.289631+00,,,,,,,,0,,,,f,,admin_teacher,active
00000000-0000-0000-0000-000000000000,aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa,authenticated,,admin@gamilit.com,$2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga,2025-11-29 13:26:50.289631+00,,"",,"",,"","",,2025-12-01 00:54:19.615+00,"{""provider"": ""email"", ""providers"": [""email""]}","{""name"": ""Admin GAMILIT"", ""role"": ""super_admin"", ""description"": ""Usuario administrador de testing""}",f,2025-11-29 13:26:50.289631+00,2025-12-01 00:54:19.617766+00,,,,,,,,0,,,,f,,super_admin,active
,0ae1bf21-39e3-4168-9632-457418c7a07d,authenticated,,rckrdmrd@gmail.com,$2b$10$LiDdaJLA.ZvdFleamkMuvOcIrW0PQMEh5aVZ5Wg5pzhm7gwc5s.1C,,,,,,,,,,2025-12-09 01:22:42.784+00,,{},f,2025-11-29 13:37:09.271457+00,2025-12-09 01:22:42.785367+00,,,,,,,,0,,,,f,,student,active
,69681b09-5077-4f77-84cc-67606abd9755,authenticated,,javiermar06@hotmail.com,$2b$10$3RHyXnR4BG3NaxP8Ez82FuiGDMNCG7GhNaOsMFigy3BpIVOzCqHMW,,,,,,,,,,2025-12-14 03:51:04.122+00,,{},f,2025-12-08 19:24:06.266895+00,2025-12-14 03:51:04.123886+00,,,,,,,,0,,,,f,,student,active
,f929d6df-8c29-461f-88f5-264facd879e9,authenticated,,ju188an@gmail.com,$2b$10$9vUERFnXApdfXuAI7DFve.aa8uDjI5bfm4CI75/EZ2cUre83RytKe,,,,,,,,,,2025-12-17 23:51:43.553+00,,{},f,2025-12-17 17:51:43.530434+00,2025-12-17 23:51:43.55475+00,,,,,,,,0,,,,f,,student,active

1 instance_id 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
45 00000000-0000-0000-0000-000000000000 cccccccc-cccc-cccc-cccc-cccccccccccc authenticated student@gamilit.com $2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga 2025-11-29 13:26:50.289631+00 2025-12-07 03:42:02.528+00 {"provider": "email", "providers": ["email"]} {"name": "Estudiante Testing", "role": "student", "description": "Usuario estudiante de testing"} f 2025-11-29 13:26:50.289631+00 2025-12-07 03:42:02.529507+00 0 f student active
46 00000000-0000-0000-0000-000000000000 bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb authenticated teacher@gamilit.com $2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga 2025-11-29 13:26:50.289631+00 {"provider": "email", "providers": ["email"]} {"name": "Profesor Testing", "role": "admin_teacher", "description": "Usuario profesor de testing"} f 2025-11-29 13:26:50.289631+00 2025-11-29 13:26:50.289631+00 0 f admin_teacher active
47 00000000-0000-0000-0000-000000000000 aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa authenticated admin@gamilit.com $2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga 2025-11-29 13:26:50.289631+00 2025-12-01 00:54:19.615+00 {"provider": "email", "providers": ["email"]} {"name": "Admin GAMILIT", "role": "super_admin", "description": "Usuario administrador de testing"} f 2025-11-29 13:26:50.289631+00 2025-12-01 00:54:19.617766+00 0 f super_admin active
48 0ae1bf21-39e3-4168-9632-457418c7a07d authenticated rckrdmrd@gmail.com $2b$10$LiDdaJLA.ZvdFleamkMuvOcIrW0PQMEh5aVZ5Wg5pzhm7gwc5s.1C 2025-12-09 01:22:42.784+00 {} f 2025-11-29 13:37:09.271457+00 2025-12-09 01:22:42.785367+00 0 f student active
49 69681b09-5077-4f77-84cc-67606abd9755 authenticated javiermar06@hotmail.com $2b$10$3RHyXnR4BG3NaxP8Ez82FuiGDMNCG7GhNaOsMFigy3BpIVOzCqHMW 2025-12-14 03:51:04.122+00 {} f 2025-12-08 19:24:06.266895+00 2025-12-14 03:51:04.123886+00 0 f student active
50 f929d6df-8c29-461f-88f5-264facd879e9 authenticated ju188an@gmail.com $2b$10$9vUERFnXApdfXuAI7DFve.aa8uDjI5bfm4CI75/EZ2cUre83RytKe 2025-12-17 23:51:43.553+00 {} f 2025-12-17 17:51:43.530434+00 2025-12-17 23:51:43.55475+00 0 f student active

View File

@ -45,5 +45,6 @@ de1511df-f963-4ff6-8e3f-2225ba493879,a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,,,"","
26168044-3b5c-43f6-a757-833ba1485d41,a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,,,"","",enriquecuevascbtis136@gmail.com,,,,,,,,student,active,f,f,"{""theme"": ""detective"", ""language"": ""es"", ""timezone"": ""America/Mexico_City"", ""sound_enabled"": true, ""notifications_enabled"": true}",,,{},2025-11-29 13:30:54.277737+00,2025-11-29 13:30:54.277737+00,1efe491d-98ef-4c02-acd1-3135f7289072,
e742724a-0ff6-4760-884b-866835460045,a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,,,"","",fl432025@gmail.com,,,,,,,,student,active,f,f,"{""theme"": ""detective"", ""language"": ""es"", ""timezone"": ""America/Mexico_City"", ""sound_enabled"": true, ""notifications_enabled"": true}",,,{},2025-11-29 13:30:54.277737+00,2025-11-29 13:30:54.277737+00,547eb778-4782-4681-b198-c731bba36147,
3ce354c8-bcac-44c6-9a94-5274e5f9b389,a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,,,"","",abdallahxelhaneriavega@gmail.com,,,,,,,,student,active,f,f,"{""theme"": ""detective"", ""language"": ""es"", ""timezone"": ""America/Mexico_City"", ""sound_enabled"": true, ""notifications_enabled"": true}",,,{},2025-11-29 13:30:54.277737+00,2025-11-29 13:30:54.277737+00,f4c46f46-3fb9-40bf-a52b-a8ad2e6a92e1,
0ae1bf21-39e3-4168-9632-457418c7a07d,a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,,,rckrdmrd@gmail.com,,rckrdmrd@gmail.com,,,,,,,,student,active,f,f,"{""theme"": ""detective"", ""language"": ""es"", ""timezone"": ""America/Mexico_City"", ""sound_enabled"": true, ""notifications_enabled"": true}",,,{},2025-11-29 13:37:09.278078+00,2025-11-29 13:37:09.278078+00,0ae1bf21-39e3-4168-9632-457418c7a07d,
69681b09-5077-4f77-84cc-67606abd9755,a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,,,Javier, Mar,javiermar06@hotmail.com,,,,,,,,student,active,f,f,"{""theme"": ""detective"", ""language"": ""es"", ""timezone"": ""America/Mexico_City"", ""sound_enabled"": true, ""notifications_enabled"": true}",,,{},2025-12-08 19:24:06.272257+00,2025-12-08 19:24:06.272257+00,69681b09-5077-4f77-84cc-67606abd9755,
f929d6df-8c29-461f-88f5-264facd879e9,a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,,,Juan,pa,ju188an@gmail.com,,,,,,,,student,active,f,f,"{""theme"": ""detective"", ""language"": ""es"", ""timezone"": ""America/Mexico_City"", ""sound_enabled"": true, ""notifications_enabled"": true}",,,{},2025-12-17 17:51:43.536295+00,2025-12-17 17:51:43.536295+00,f929d6df-8c29-461f-88f5-264facd879e9,

1 id tenant_id display_name full_name first_name last_name email avatar_url bio phone date_of_birth grade_level student_id school_id role status email_verified phone_verified preferences last_sign_in_at last_activity_at metadata created_at updated_at user_id deleted_at
45 26168044-3b5c-43f6-a757-833ba1485d41 a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 enriquecuevascbtis136@gmail.com student active f f {"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true} {} 2025-11-29 13:30:54.277737+00 2025-11-29 13:30:54.277737+00 1efe491d-98ef-4c02-acd1-3135f7289072
46 e742724a-0ff6-4760-884b-866835460045 a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 fl432025@gmail.com student active f f {"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true} {} 2025-11-29 13:30:54.277737+00 2025-11-29 13:30:54.277737+00 547eb778-4782-4681-b198-c731bba36147
47 3ce354c8-bcac-44c6-9a94-5274e5f9b389 a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 abdallahxelhaneriavega@gmail.com student active f f {"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true} {} 2025-11-29 13:30:54.277737+00 2025-11-29 13:30:54.277737+00 f4c46f46-3fb9-40bf-a52b-a8ad2e6a92e1
48 0ae1bf21-39e3-4168-9632-457418c7a07d a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 rckrdmrd@gmail.com rckrdmrd@gmail.com student active f f {"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true} {} 2025-11-29 13:37:09.278078+00 2025-11-29 13:37:09.278078+00 0ae1bf21-39e3-4168-9632-457418c7a07d
49 69681b09-5077-4f77-84cc-67606abd9755 a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 Javier Mar javiermar06@hotmail.com student active f f {"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true} {} 2025-12-08 19:24:06.272257+00 2025-12-08 19:24:06.272257+00 69681b09-5077-4f77-84cc-67606abd9755
50 f929d6df-8c29-461f-88f5-264facd879e9 a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 Juan pa ju188an@gmail.com student active f f {"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true} {} 2025-12-17 17:51:43.536295+00 2025-12-17 17:51:43.536295+00 f929d6df-8c29-461f-88f5-264facd879e9

View File

@ -67,6 +67,7 @@ INSERT INTO auth.users (instance_id, id, aud, role, email, encrypted_password, e
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', '5ae21325-7450-4c37-82f1-3f9bcd7b6f45', 'authenticated', NULL, 'omarcitogonzalezzavaleta@gmail.com', '$2b$10$RRk3DAgQdiikxVImFIMqquqB.TNpKs3E.RNFtt1rwwTzO24uShri.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '{"provider": "email", "providers": ["email"]}', '{"last_name": "", "first_name": ""}', false, '2025-11-25 08:17:07.610076+00', '2025-11-25 08:17:07.610076+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', 'a4d27774-8a51-4660-ad2f-81d0dfd3a5a7', 'authenticated', NULL, 'gustavobm2024cbtis@gmail.com', '$2b$10$lg7KRUTPofcx4Rtyey8J7.XO0gmdBLCFIfK5uP08mqT0qUIl1aTJq', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '{"provider": "email", "providers": ["email"]}', '{"last_name": "", "first_name": ""}', false, '2025-11-25 08:20:49.649184+00', '2025-11-25 08:20:49.649184+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', '6e30164a-78b0-49b0-bd21-23d7c6c03349', 'authenticated', NULL, 'marianaxsotoxt22@gmail.com', '$2b$10$GQC9yTWiP2vP9GUp0gnhUeLjmw70EI4JQhfJBZbMOlCNXGXb/bt5O', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '{"provider": "email", "providers": ["email"]}', '{"last_name": "", "first_name": ""}', false, '2025-11-25 08:33:18.150784+00', '2025-11-25 08:33:18.150784+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 (NULL, '0ae1bf21-39e3-4168-9632-457418c7a07d', 'authenticated', NULL, 'rckrdmrd@gmail.com', '$2b$10$LiDdaJLA.ZvdFleamkMuvOcIrW0PQMEh5aVZ5Wg5pzhm7gwc5s.1C', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-09 01:22:42.784+00', NULL, '{}', false, '2025-11-29 13:37:09.271457+00', '2025-12-09 01:22:42.785367+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 ('00000000-0000-0000-0000-000000000000', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'authenticated', NULL, 'admin@gamilit.com', '$2b$10$pkqX0/v7H3F5TBTuDTaoYeBjH581pXpjlcNcYmMtXofd/2HjfTuga', '2025-11-29 13:26:50.289631+00', NULL, '', NULL, '', NULL, '', '', NULL, '2025-12-01 00:54:19.615+00', '{"provider": "email", "providers": ["email"]}', '{"name": "Admin GAMILIT", "role": "super_admin", "description": "Usuario administrador de testing"}', false, '2025-11-29 13:26:50.289631+00', '2025-12-01 00:54:19.617766+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'super_admin', 'active');
INSERT INTO auth.users (instance_id, 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 (NULL, '69681b09-5077-4f77-84cc-67606abd9755', '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', NULL, '{}', false, '2025-12-08 19:24:06.266895+00', '2025-12-14 03:51:04.123886+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
INSERT INTO auth.users (instance_id, 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 (NULL, 'f929d6df-8c29-461f-88f5-264facd879e9', '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', NULL, '{}', false, '2025-12-17 17:51:43.530434+00', '2025-12-17 23:51:43.55475+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, false, NULL, 'student', 'active');
@ -122,6 +123,7 @@ INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, fi
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('c0aecfcc-3b2f-4117-9f20-e0920df97dc0', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, '', '', 'segurauriel235@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:30:54.277737+00', '2025-11-29 13:30:54.277737+00', '5d1839f6-b03f-4e12-b236-eca43f4674f2', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('3dfcdc9d-de8a-45b3-a05f-b83b51097ef5', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, '', '', 'omarcitogonzalezzavaleta@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:30:54.277737+00', '2025-11-29 13:30:54.277737+00', '5ae21325-7450-4c37-82f1-3f9bcd7b6f45', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('bb74b280-db90-4240-ab09-b8c6cf63d553', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, '', '', 'erickfranco462@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:30:54.277737+00', '2025-11-29 13:30:54.277737+00', '2d9f05d4-44dd-42cd-97aa-d57bd06fecd0', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('0ae1bf21-39e3-4168-9632-457418c7a07d', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, 'rckrdmrd@gmail.com', NULL, 'rckrdmrd@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-11-29 13:37:09.278078+00', '2025-11-29 13:37:09.278078+00', '0ae1bf21-39e3-4168-9632-457418c7a07d', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('69681b09-5077-4f77-84cc-67606abd9755', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, 'Javier', ' Mar', 'javiermar06@hotmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-12-08 19:24:06.272257+00', '2025-12-08 19:24:06.272257+00', '69681b09-5077-4f77-84cc-67606abd9755', NULL);
INSERT INTO auth_management.profiles (id, tenant_id, display_name, full_name, first_name, last_name, email, avatar_url, bio, phone, date_of_birth, grade_level, student_id, school_id, role, status, email_verified, phone_verified, preferences, last_sign_in_at, last_activity_at, metadata, created_at, updated_at, user_id, deleted_at) VALUES ('f929d6df-8c29-461f-88f5-264facd879e9', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', NULL, NULL, 'Juan', 'pa', 'ju188an@gmail.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'student', 'active', false, false, '{"theme": "detective", "language": "es", "timezone": "America/Mexico_City", "sound_enabled": true, "notifications_enabled": true}', NULL, NULL, '{}', '2025-12-17 17:51:43.536295+00', '2025-12-17 17:51:43.536295+00', 'f929d6df-8c29-461f-88f5-264facd879e9', NULL);

View File

@ -0,0 +1,155 @@
# RESUMEN EJECUTIVO: Análisis de Errores en Producción
**Fecha:** 2025-12-18
**Proyecto:** Gamilit
**Ambiente:** Producción (74.208.126.102:3006)
**Analista:** Requirement Analyst
---
## 1. PROBLEMA REPORTADO
Al registrar un nuevo usuario en producción, múltiples errores impiden el funcionamiento correcto del dashboard:
| Error | Tipo | Endpoint |
|-------|------|----------|
| `gamification_system.notifications` does not exist | 500 | /notifications/unread-count |
| `progress_tracking.module_progress` does not exist | 500 | /progress/users/{id}/summary |
| `educational_content.modules` does not exist | 500 | /educational/modules/user/{id} |
| Resource not found | 404 | /gamification/ranks/current |
| Resource not found | 404 | /gamification/users/{id}/ml-coins |
| Bad Request | 400 | /gamification/missions/daily |
| Bad Request | 400 | /gamification/missions/weekly |
---
## 2. CAUSA RAÍZ
**El script `create-database.sh` NO se ejecutó correctamente en producción.**
Esto significa que:
- ❌ Las tablas de gamificación, progreso y contenido educativo NO existen
- ❌ Los triggers de inicialización automática NO existen
- ❌ Los seeds (mission_templates, maya_ranks, modules) NO se ejecutaron
- ❌ Los ENUMs pueden estar incompletos
**Todos los archivos DDL EXISTEN en el repositorio** - el problema es de deployment, no de código.
---
## 3. SOLUCIÓN RECOMENDADA
### Opción A: Clean Database Load (RECOMENDADA si BD está vacía)
```bash
cd apps/database
./create-database.sh
```
### Opción B: Migración Selectiva (si hay datos existentes)
Ejecutar script validado: `migrate-production-validated.sh`
---
## 4. OBJETOS FALTANTES
### Tablas Críticas (8)
| Schema | Tabla | Archivo DDL |
|--------|-------|-------------|
| gamification_system | user_stats | 01-user_stats.sql |
| gamification_system | maya_ranks | 13-maya_ranks.sql |
| gamification_system | user_ranks | 02-user_ranks.sql |
| gamification_system | notifications | 08-notifications.sql |
| gamification_system | mission_templates | 20-mission_templates.sql |
| gamification_system | missions | 06-missions.sql |
| progress_tracking | module_progress | 01-module_progress.sql |
| educational_content | modules | 01-modules.sql |
### Seeds Críticos (3)
| Seed | Registros | Archivo |
|------|-----------|---------|
| maya_ranks | 5 rangos | 03-maya_ranks.sql |
| mission_templates | 11 templates | 10-mission_templates.sql |
| modules | 5 módulos | 01-modules.sql |
### Trigger Crítico (1)
| Trigger | Tabla | Función |
|---------|-------|---------|
| trg_initialize_user_stats | auth_management.profiles | gamilit.initialize_user_stats() |
---
## 5. ORDEN DE EJECUCIÓN VALIDADO
```
FASE 0: Pre-requisitos (schemas, ENUMs, funciones base)
FASE 1: Tablas sin dependencias (user_stats, maya_ranks, notifications, mission_templates, modules)
FASE 2: Tablas con dependencias (user_ranks, missions, module_progress)
FASE 3: Funciones adicionales (calculate_level, check_rank_promotion, etc.)
FASE 4: Triggers (initialize_user_stats, updated_at, missions, etc.)
FASE 5: Seeds (maya_ranks, mission_templates, modules)
FASE 6: Inicializar usuarios existentes (INSERT user_stats/user_ranks)
```
---
## 6. TIEMPO ESTIMADO DE CORRECCIÓN
| Actividad | Duración |
|-----------|----------|
| Backup de producción | 5 min |
| Migración (Opción A) | 2-5 min |
| Migración (Opción B) | 10-15 min |
| Validación | 5 min |
| Pruebas funcionales | 10 min |
| **Total** | **20-35 min** |
---
## 7. DOCUMENTACIÓN GENERADA
| Documento | Descripción |
|-----------|-------------|
| FASE-1-PLAN-ANALISIS.md | Plan detallado de análisis |
| FASE-2-RESULTADO-ANALISIS.md | Resultados del análisis técnico |
| FASE-3-PLAN-IMPLEMENTACION.md | Plan de correcciones con scripts |
| FASE-4-VALIDACION-PLAN.md | Validación de dependencias y orden |
| 00-RESUMEN-EJECUTIVO.md | Este documento |
---
## 8. ACCIONES PENDIENTES
### Para DevOps/DBA:
1. [ ] Crear backup de BD producción
2. [ ] Ejecutar migración (Opción A o B)
3. [ ] Validar con queries de verificación
4. [ ] Probar endpoints afectados
### Para QA:
1. [ ] Registrar nuevo usuario de prueba
2. [ ] Verificar dashboard carga sin errores
3. [ ] Verificar user_stats y user_ranks creados
4. [ ] Verificar missions daily/weekly funcionan
---
## 9. CONTACTO
**Ubicación de documentación completa:**
```
orchestration/analisis-errores-prod-2025-12-18/
├── 00-RESUMEN-EJECUTIVO.md
├── FASE-1-PLAN-ANALISIS.md
├── FASE-2-RESULTADO-ANALISIS.md
├── FASE-3-PLAN-IMPLEMENTACION.md
└── FASE-4-VALIDACION-PLAN.md
```
---
**Análisis completado. Listo para Fase 5: Ejecución.**

View File

@ -0,0 +1,285 @@
# FASE 1: Plan de Análisis Detallado - Errores Producción
**Fecha:** 2025-12-18
**Proyecto:** Gamilit
**Ambiente:** Producción (https://74.208.126.102:3006)
**Analista:** Requirement Analyst
---
## 1. RESUMEN EJECUTIVO DE ERRORES
| # | Endpoint | Error | Mensaje |
|---|----------|-------|---------|
| 1 | GET /notifications/unread-count | 500 | `gamification_system.notifications` does not exist |
| 2 | GET /gamification/ranks/current | 404 | Resource not found |
| 3 | GET /gamification/users/{id}/ml-coins | 404 | Resource not found |
| 4 | GET /progress/users/{id}/summary | 500 | `progress_tracking.module_progress` does not exist |
| 5 | GET /gamification/ranks/users/{id}/rank-progress | 404 | Resource not found |
| 6 | GET /gamification/missions/daily | 400 | Bad Request |
| 7 | GET /gamification/missions/weekly | 400 | Bad Request |
| 8 | GET /progress/users/{id}/recent-activities | 500 | `progress_tracking.module_progress` does not exist |
| 9 | GET /educational/modules/user/{id} | 500 | `educational_content.modules` does not exist |
---
## 2. DIAGNÓSTICO PRINCIPAL
### 2.1 Hallazgo Crítico
**TODAS LAS TABLAS EXISTEN EN EL DDL DEL REPOSITORIO.**
El problema raíz es que **las migraciones/DDL NO se ejecutaron correctamente en la base de datos de producción**.
### 2.2 Tablas Faltantes en Producción (Confirmadas)
| Schema | Tabla | Archivo DDL | Estado DDL |
|--------|-------|-------------|------------|
| `gamification_system` | `notifications` | `08-notifications.sql` | ✅ EXISTE |
| `progress_tracking` | `module_progress` | `01-module_progress.sql` | ✅ EXISTE |
| `educational_content` | `modules` | `01-modules.sql` | ✅ EXISTE |
### 2.3 Causas Probables de Errores 404/400
| Endpoint | Causa Probable |
|----------|---------------|
| `/gamification/ranks/current` | Usuario sin `user_ranks` inicializado |
| `/gamification/users/{id}/ml-coins` | Usuario sin `user_stats` inicializado |
| `/gamification/ranks/users/{id}/rank-progress` | Usuario sin rango/stats inicializado |
| `/gamification/missions/daily` | Sin `mission_templates` tipo DAILY en BD |
| `/gamification/missions/weekly` | Sin `mission_templates` tipo WEEKLY en BD |
---
## 3. INVENTARIO DE SCHEMAS AFECTADOS
### 3.1 Schema: gamification_system
```
Ubicación DDL: apps/database/ddl/schemas/gamification_system/
├── tables/ (20 archivos)
├── views/ (4 archivos)
├── functions/ (25 archivos)
├── indexes/ (8 archivos)
├── rls-policies/ (8 archivos)
└── triggers/ (múltiples)
```
**Tablas Críticas:**
- `notifications` - Sistema de notificaciones
- `user_stats` - Estadísticas de usuario (XP, nivel, ML-coins)
- `user_ranks` - Rangos Maya del usuario
- `missions` - Misiones activas
- `mission_templates` - Plantillas de misiones (SEEDS REQUERIDOS)
### 3.2 Schema: progress_tracking
```
Ubicación DDL: apps/database/ddl/schemas/progress_tracking/
├── tables/ (18 archivos)
├── views/ (2 archivos)
├── functions/ (11 archivos)
├── indexes/ (3 archivos)
├── rls-policies/ (3 archivos)
└── triggers/ (11 archivos)
```
**Tablas Críticas:**
- `module_progress` - Progreso por módulo
- `learning_sessions` - Sesiones de aprendizaje
- `exercise_attempts` - Intentos de ejercicios
- `exercise_submissions` - Envíos de ejercicios
### 3.3 Schema: educational_content
```
Ubicación DDL: apps/database/ddl/schemas/educational_content/
├── tables/ (16 archivos activos + 2 deprecated)
├── views/ (1 archivo)
├── functions/ (27 archivos)
├── indexes/ (4 archivos)
└── rls-policies/ (2 archivos)
```
**Tablas Críticas:**
- `modules` - Módulos educativos
- `exercises` - Ejercicios con config JSONB
- `classroom_modules` - Módulos asignados a aulas
---
## 4. ANÁLISIS DE BACKEND
### 4.1 Módulo Notifications - PROBLEMA IDENTIFICADO
**Conflicto de Entidades:**
```typescript
// Sistema Básico (deprecated)
@Entity({ schema: 'gamification_system', name: 'notifications' })
export class Notification { ... } // → gamification datasource
// Sistema Consolidado (activo)
@Entity({ schema: 'notifications', name: 'notifications' })
export class Notification { ... } // → notifications datasource
```
**Problema:** `NotificationsService` inyecta `@InjectRepository(Notification, 'gamification')` pero el módulo registra la entidad del sistema consolidado con datasource `'notifications'`.
**Archivos Afectados:**
- `apps/backend/src/modules/notifications/notifications.module.ts`
- `apps/backend/src/modules/notifications/notifications.service.ts`
- `apps/backend/src/modules/notifications/entities/notification.entity.ts`
### 4.2 Endpoints Verificados - TODOS EXISTEN
| Endpoint | Controlador | Línea |
|----------|-------------|-------|
| GET /gamification/ranks/current | ranks.controller.ts | 100-117 |
| GET /gamification/users/:id/ml-coins | ml-coins.controller.ts | 38-69 |
| GET /gamification/ranks/users/:id/rank-progress | ranks.controller.ts | 153-177 |
| GET /gamification/missions/daily | missions.controller.ts | 98-117 |
| GET /gamification/missions/weekly | missions.controller.ts | 167-186 |
| GET /progress/users/:id/summary | module-progress.controller.ts | 449 |
| GET /progress/users/:id/recent-activities | module-progress.controller.ts | 678 |
| GET /educational/modules/user/:id | modules.controller.ts | 249 |
---
## 5. PLAN DE ANÁLISIS FASE 2
### 5.1 Verificaciones en Base de Datos Producción
```sql
-- 1. Verificar schemas existentes
SELECT schema_name FROM information_schema.schemata
WHERE schema_name IN ('gamification_system', 'progress_tracking', 'educational_content', 'notifications');
-- 2. Verificar tablas críticas
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema IN ('gamification_system', 'progress_tracking', 'educational_content')
ORDER BY table_schema, table_name;
-- 3. Verificar seeds de mission_templates
SELECT type, COUNT(*) FROM gamification_system.mission_templates GROUP BY type;
-- 4. Verificar user_stats para usuario de prueba
SELECT * FROM gamification_system.user_stats WHERE user_id = 'd71448b0-67b6-4687-a822-f725c0479c1d';
-- 5. Verificar user_ranks
SELECT * FROM gamification_system.user_ranks WHERE user_id = 'd71448b0-67b6-4687-a822-f725c0479c1d';
```
### 5.2 Archivos DDL a Ejecutar (Orden Crítico)
**Prioridad 1 - Schemas Base:**
1. `apps/database/ddl/schemas/gamification_system/schema.sql`
2. `apps/database/ddl/schemas/progress_tracking/schema.sql`
3. `apps/database/ddl/schemas/educational_content/schema.sql`
**Prioridad 2 - ENUMs:**
1. `apps/database/ddl/schemas/gamification_system/types/*.sql`
2. `apps/database/ddl/schemas/progress_tracking/types/*.sql`
3. `apps/database/ddl/schemas/educational_content/types/*.sql`
**Prioridad 3 - Tablas Críticas:**
1. `gamification_system/tables/01-user_stats.sql`
2. `gamification_system/tables/02-user_ranks.sql`
3. `gamification_system/tables/08-notifications.sql`
4. `gamification_system/tables/20-mission_templates.sql`
5. `progress_tracking/tables/01-module_progress.sql`
6. `educational_content/tables/01-modules.sql`
**Prioridad 4 - Seeds:**
1. `apps/database/seeds/gamification/mission_templates.sql`
2. `apps/database/seeds/gamification/maya_ranks.sql`
### 5.3 Verificación de Datasources
Revisar configuración en:
- `apps/backend/src/config/database.config.ts`
- `apps/backend/src/app.module.ts`
Conexiones esperadas:
| Nombre | Schema |
|--------|--------|
| `default` | `public` |
| `auth` | `auth_management` |
| `gamification` | `gamification_system` |
| `progress` | `progress_tracking` |
| `educational` | `educational_content` |
| `notifications` | `notifications` |
| `social` | `social_features` |
---
## 6. ESTRUCTURA DE DEPENDENCIAS
```
Usuario se registra
├─► auth.profiles (creado) ✅
└─► Falta inicialización automática de:
├─► gamification_system.user_stats
├─► gamification_system.user_ranks
└─► progress_tracking.module_progress (primer módulo)
```
**Flujo esperado post-registro:**
1. Crear profile en `auth.profiles`
2. Crear `user_stats` con valores iniciales (level=1, xp=0, ml_coins=0)
3. Crear `user_ranks` con rango inicial (Semilla)
4. Al acceder a módulo → crear `module_progress`
---
## 7. SIGUIENTE FASE
### Fase 2: Ejecución del Análisis
1. Conectar a BD producción y ejecutar queries de verificación
2. Identificar exactamente qué tablas faltan
3. Identificar qué seeds faltan
4. Verificar configuración de datasources en backend
### Fase 3: Planeación de Correcciones
1. Listar scripts DDL a ejecutar en orden
2. Listar seeds a ejecutar
3. Identificar cambios de código necesarios (notifications)
4. Definir orden de ejecución
### Fase 4: Validación del Plan
1. Verificar dependencias entre objetos
2. Confirmar que no faltan FK, índices, triggers
3. Validar RLS policies
### Fase 5: Ejecución
1. Ejecutar DDL en producción
2. Ejecutar seeds
3. Aplicar fix de código si es necesario
4. Verificar funcionamiento
---
## 8. ARCHIVOS DE REFERENCIA
### DDL Críticos
- `apps/database/ddl/schemas/gamification_system/tables/08-notifications.sql`
- `apps/database/ddl/schemas/progress_tracking/tables/01-module_progress.sql`
- `apps/database/ddl/schemas/educational_content/tables/01-modules.sql`
### Backend Críticos
- `apps/backend/src/modules/notifications/notifications.module.ts`
- `apps/backend/src/modules/notifications/notifications.service.ts`
- `apps/backend/src/modules/gamification/services/missions.service.ts`
- `apps/backend/src/modules/progress/services/module-progress.service.ts`
### Seeds Críticos
- `apps/database/seeds/gamification/mission_templates.sql`
- `apps/database/seeds/gamification/maya_ranks.sql`
- `apps/database/seeds/educational/modules.sql`
---
**Documento generado automáticamente por análisis de Fase 1**

View File

@ -0,0 +1,305 @@
# FASE 2: Resultado del Análisis - Errores Producción
**Fecha:** 2025-12-18
**Proyecto:** Gamilit
**Ambiente:** Producción
---
## 1. DIAGNÓSTICO DEFINITIVO
### 1.1 Causa Raíz Principal
**El script `create-database.sh` NO se ejecutó correctamente en producción.**
Esto implica que:
- ❌ Los schemas pueden existir pero las tablas NO
- ❌ Los triggers NO existen
- ❌ Los seeds NO se ejecutaron
- ❌ Los ENUMs pueden estar incompletos
### 1.2 Evidencia
| Componente | En Repositorio | En Producción |
|------------|---------------|---------------|
| `gamification_system.notifications` | ✅ DDL existe | ❌ Error 500 |
| `progress_tracking.module_progress` | ✅ DDL existe | ❌ Error 500 |
| `educational_content.modules` | ✅ DDL existe | ❌ Error 500 |
| `mission_templates` seeds | ✅ 11 templates | ❌ Error 400 |
| `user_stats` trigger | ✅ Trigger existe | ❌ No se ejecuta |
---
## 2. ESTRUCTURA DE DDL CONFIRMADA
### 2.1 Script Principal: `create-database.sh`
**Ubicación:** `apps/database/create-database.sh`
**Ejecuta 16 Fases en orden:**
```
FASE 0: Extensiones (pgcrypto, uuid-ossp)
FASE 1: Prerequisites (13 schemas + ENUMs base)
FASE 2: Funciones compartidas (gamilit/functions, views)
FASE 3: Auth Schema (Supabase)
FASE 4: Storage Schema
FASE 5: Auth Management (profiles, triggers)
FASE 6: Educational Content
FASE 6.5: Notifications Schema ⭐ CRÍTICO
FASE 7: Gamification System
FASE 8: Progress Tracking
FASE 9: Social Features
FASE 9.5: FK Constraints diferidos
FASE 10: Content Management
FASE 10.5: Communication Schema
FASE 11: Audit Logging
FASE 12: System Configuration
FASE 13: Admin Dashboard (opcional)
FASE 14: LTI Integration
FASE 15: Post-DDL Permissions
FASE 16: Seeds (38 archivos producción)
```
### 2.2 Scripts Auxiliares
| Script | Propósito |
|--------|----------|
| `validate-create-database.sh` | Valida integridad post-creación |
| `validate-db-ready.sh` | Valida BD lista para app |
| `migrate-missing-objects.sh` | Migra objetos faltantes |
| `drop-and-recreate-database.sh` | Reset completo |
---
## 3. SEEDS CONFIRMADOS
### 3.1 Mission Templates (CRÍTICO para Error 400)
**Archivo:** `apps/database/seeds/prod/gamification_system/10-mission_templates.sql`
| ID | Nombre | Tipo | XP | ML Coins |
|----|--------|------|----|----|
| 20000001-...-000000000001 | Calentamiento Científico | daily | 50 | 10 |
| 20000001-...-000000000002 | Mente Brillante | daily | 75 | 15 |
| 20000001-...-000000000003 | Acumulador de Sabiduría | daily | 30 | 5 |
| 20000001-...-000000000004 | Perfeccionista del Día | daily | 100 | 25 |
| 20000002-...-000000000001 | Maratón de Conocimiento | weekly | 200 | 50 |
| 20000002-...-000000000002 | Constancia Científica | weekly | 300 | 75 |
| 20000002-...-000000000003 | Ascenso Semanal | weekly | 150 | 40 |
| 20000002-...-000000000004 | Explorador Curioso | weekly | 175 | 45 |
| 20000002-...-000000000005 | Semana de Excelencia | weekly | 400 | 100 |
| 20000003-...-000000000001 | Dominio del Módulo | special | 500 | 150 |
| 20000003-...-000000000002 | Estratega Sabio | special | 75 | 20 |
**Total:** 11 templates (4 daily + 5 weekly + 2 special)
### 3.2 Maya Ranks (CRÍTICO para Error 404)
**Archivo:** `apps/database/seeds/prod/gamification_system/03-maya_ranks.sql`
| Rango | XP Mínimo | XP Máximo | Multiplicador |
|-------|-----------|-----------|---------------|
| Ajaw | 0 | 499 | 1.00 |
| Nacom | 500 | 999 | 1.10 |
| Ah K'in | 1000 | 1499 | 1.15 |
| Halach Uinic | 1500 | 1899 | 1.20 |
| K'uk'ulkan | 1900 | ∞ | 1.25 |
### 3.3 Modules (CRÍTICO para Error 500)
**Archivo:** `apps/database/seeds/prod/educational_content/01-modules.sql`
| # | Código | Nombre | XP |
|---|--------|--------|-----|
| 1 | MOD-01-LITERAL | Comprensión Literal | 100 |
| 2 | MOD-02-INFERENCIAL | Comprensión Inferencial | 150 |
| 3 | MOD-03-CRITICA | Comprensión Crítica | 200 |
| 4 | MOD-04-DIGITAL | Digital y Multimodal | 175 |
| 5 | MOD-05-PRODUCCION | Producción y Expresión | 250 |
---
## 4. FLUJO DE REGISTRO DE USUARIO
### 4.1 Flujo Esperado
```
1. Usuario se registra
├─► auth.service.ts:register()
│ │
│ ├─► Crear User en auth.users ✅
│ │
│ └─► Crear Profile en auth_management.profiles ✅
│ │
│ └─► TRIGGER: trg_initialize_user_stats
│ │
│ ├─► INSERT gamification_system.user_stats ❌ (tabla no existe)
│ │
│ └─► INSERT gamification_system.user_ranks ❌ (tabla no existe)
```
### 4.2 Trigger de Inicialización
**Archivo:** `apps/database/ddl/schemas/auth_management/triggers/04-trg_initialize_user_stats.sql`
```sql
CREATE TRIGGER trg_initialize_user_stats
AFTER INSERT ON auth_management.profiles
FOR EACH ROW
EXECUTE FUNCTION gamilit.initialize_user_stats();
```
**Función:** `apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql`
```sql
-- Si el rol es elegible para gamificación
IF NEW.role IN ('student', 'admin_teacher', 'super_admin') THEN
-- Crear user_stats con 100 ML coins iniciales
INSERT INTO gamification_system.user_stats (
user_id, tenant_id, ml_coins, ml_coins_earned_total
) VALUES (NEW.user_id, NEW.tenant_id, 100, 100)
ON CONFLICT (user_id) DO NOTHING;
-- Crear user_ranks con rango inicial 'Ajaw'
INSERT INTO gamification_system.user_ranks (
user_id, tenant_id, current_rank
) SELECT NEW.user_id, NEW.tenant_id, 'Ajaw'::gamification_system.maya_rank
WHERE NOT EXISTS (...);
END IF;
```
### 4.3 Problema Identificado
El trigger **NO puede ejecutarse** porque:
1. La tabla `gamification_system.user_stats` NO EXISTE en producción
2. La tabla `gamification_system.user_ranks` NO EXISTE en producción
3. El trigger probablemente falla silenciosamente
---
## 5. DATASOURCES CONFIRMADOS
### 5.1 Configuración TypeORM
**Archivo:** `apps/backend/src/app.module.ts`
| Datasource | Schema | Entidades Principales |
|------------|--------|----------------------|
| `auth` | `auth_management` | User, Profile, Tenant, Role (14) |
| `educational` | `educational_content` | Module, Exercise, Assignment (12) |
| `gamification` | `gamification_system` | UserStats, UserRanks, Mission (18) |
| `progress` | `progress_tracking` | ModuleProgress, LearningSession (13) |
| `social` | `social_features` | School, Classroom, Friendship |
| `content` | `content_management` | ContentTemplate, MediaFile |
| `audit` | `audit_logging` | AuditLog, SystemLog |
| `notifications` | `notifications` | Notification, NotificationQueue (6) |
| `communication` | `communication` | Message, StudentInterventionAlert |
### 5.2 Problema de Notifications
**Conflicto identificado:**
```typescript
// Sistema básico (legacy)
@Entity({ schema: 'gamification_system', name: 'notifications' })
export class Notification // → datasource 'gamification'
// Sistema consolidado (EXT-003)
@Entity({ schema: 'notifications', name: 'notifications' })
export class Notification // → datasource 'notifications'
```
`NotificationsService` inyecta `@InjectRepository(Notification, 'gamification')` pero el módulo registra la entidad del sistema consolidado con datasource `'notifications'`.
---
## 6. VERIFICACIONES PENDIENTES EN PRODUCCIÓN
### 6.1 Queries de Diagnóstico
```sql
-- 1. Verificar schemas existentes
SELECT schema_name FROM information_schema.schemata
WHERE schema_name IN (
'gamification_system', 'progress_tracking',
'educational_content', 'notifications'
);
-- 2. Verificar tablas críticas
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema = 'gamification_system'
AND table_name IN ('notifications', 'user_stats', 'user_ranks', 'mission_templates');
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema = 'progress_tracking'
AND table_name = 'module_progress';
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema = 'educational_content'
AND table_name = 'modules';
-- 3. Verificar trigger
SELECT trigger_name, event_object_table, action_statement
FROM information_schema.triggers
WHERE trigger_name = 'trg_initialize_user_stats';
-- 4. Verificar función
SELECT routine_name, routine_schema
FROM information_schema.routines
WHERE routine_name = 'initialize_user_stats';
-- 5. Contar seeds existentes
SELECT COUNT(*) as mission_templates FROM gamification_system.mission_templates;
SELECT COUNT(*) as maya_ranks FROM gamification_system.maya_ranks;
SELECT COUNT(*) as modules FROM educational_content.modules;
```
---
## 7. RESUMEN DE OBJETOS FALTANTES
### 7.1 Tablas Críticas
| Schema | Tabla | Estado |
|--------|-------|--------|
| `gamification_system` | `notifications` | ❌ Faltante |
| `gamification_system` | `user_stats` | ❌ Faltante |
| `gamification_system` | `user_ranks` | ❌ Faltante |
| `gamification_system` | `mission_templates` | ❌ Faltante |
| `gamification_system` | `missions` | ❌ Faltante |
| `gamification_system` | `maya_ranks` | ❌ Faltante |
| `progress_tracking` | `module_progress` | ❌ Faltante |
| `educational_content` | `modules` | ❌ Faltante |
### 7.2 Seeds Críticos
| Schema | Seed | Registros |
|--------|------|-----------|
| `gamification_system` | `mission_templates` | 11 |
| `gamification_system` | `maya_ranks` | 5 |
| `educational_content` | `modules` | 5 |
### 7.3 Triggers Críticos
| Trigger | Tabla | Función |
|---------|-------|---------|
| `trg_initialize_user_stats` | `auth_management.profiles` | `gamilit.initialize_user_stats()` |
---
## 8. SIGUIENTE FASE
**FASE 3:** Planear implementaciones y correcciones
- Definir orden de ejecución de DDL
- Listar scripts a ejecutar
- Identificar dependencias
- Crear plan de rollback
---
**Documento generado por análisis de Fase 2**

View File

@ -0,0 +1,398 @@
# FASE 3: Plan de Implementación - Correcciones Producción
**Fecha:** 2025-12-18
**Proyecto:** Gamilit
**Ambiente:** Producción (74.208.126.102)
---
## 1. RESUMEN DEL PROBLEMA
La base de datos de producción **NO tiene las tablas/objetos necesarios** porque el script `create-database.sh` no se ejecutó correctamente.
---
## 2. OPCIONES DE SOLUCIÓN
### Opción A: Clean Database Load (RECOMENDADA)
**Descripción:** Ejecutar `create-database.sh` completo para crear todos los objetos.
**Ventajas:**
- ✅ Garantiza integridad completa
- ✅ Incluye todos los triggers, funciones, índices
- ✅ Ejecuta seeds automáticamente
- ✅ Valida automáticamente
**Desventajas:**
- ⚠️ Requiere BD vacía o backup previo
- ⚠️ Pierde datos existentes (usuarios registrados)
**Recomendado si:** La BD está mayormente vacía o los datos pueden recrearse.
### Opción B: Migración Selectiva de Objetos
**Descripción:** Ejecutar solo los DDL de las tablas faltantes.
**Ventajas:**
- ✅ Preserva datos existentes
- ✅ Menor impacto
**Desventajas:**
- ⚠️ Requiere verificar dependencias manualmente
- ⚠️ Puede haber inconsistencias
- ⚠️ Más propenso a errores
**Recomendado si:** Hay datos valiosos que no pueden perderse.
---
## 3. PLAN DE IMPLEMENTACIÓN - OPCIÓN A
### 3.1 Pre-requisitos
```bash
# 1. Conectar al servidor de producción
ssh user@74.208.126.102
# 2. Verificar estado actual
cd /path/to/gamilit
psql -U gamilit_user -d gamilit_platform -c "SELECT COUNT(*) FROM auth.users;"
```
### 3.2 Backup (CRÍTICO)
```bash
# Crear backup completo
pg_dump -U gamilit_user -d gamilit_platform -F c -f backup_$(date +%Y%m%d_%H%M%S).dump
# Verificar backup
pg_restore --list backup_*.dump | head -20
```
### 3.3 Ejecución
```bash
# Navegar al directorio de base de datos
cd apps/database
# Ejecutar script completo
./create-database.sh
# O si necesita recrear desde cero:
./drop-and-recreate-database.sh
```
### 3.4 Validación
```bash
# Ejecutar validación automática
./validate-create-database.sh
./validate-db-ready.sh
```
---
## 4. PLAN DE IMPLEMENTACIÓN - OPCIÓN B
### 4.1 Orden de Ejecución DDL
**IMPORTANTE:** Respetar este orden para evitar errores de dependencias.
#### Paso 1: Verificar/Crear Schemas
```sql
-- Verificar schemas existentes
SELECT schema_name FROM information_schema.schemata
WHERE schema_name IN ('gamification_system', 'progress_tracking', 'educational_content', 'notifications');
-- Crear si no existen
CREATE SCHEMA IF NOT EXISTS gamification_system;
CREATE SCHEMA IF NOT EXISTS progress_tracking;
CREATE SCHEMA IF NOT EXISTS educational_content;
CREATE SCHEMA IF NOT EXISTS notifications;
```
#### Paso 2: ENUMs (si no existen)
```bash
# gamification_system ENUMs
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/types/notification_type.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/types/notification_priority.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/types/maya_rank.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/types/mission_type.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/types/mission_status.sql
# progress_tracking ENUMs
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/progress_tracking/types/progress_status.sql
# educational_content ENUMs
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/educational_content/types/difficulty_level.sql
```
#### Paso 3: Tablas Críticas (en orden de dependencias)
```bash
# 1. gamification_system - tablas base
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/tables/01-user_stats.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/tables/13-maya_ranks.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/tables/02-user_ranks.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/tables/08-notifications.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/tables/20-mission_templates.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/tables/06-missions.sql
# 2. progress_tracking
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/progress_tracking/tables/01-module_progress.sql
# 3. educational_content
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/educational_content/tables/01-modules.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/educational_content/tables/02-exercises.sql
```
#### Paso 4: Funciones Críticas
```bash
# Función de inicialización de usuario
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql
```
#### Paso 5: Triggers
```bash
# Trigger de inicialización automática
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/auth_management/triggers/04-trg_initialize_user_stats.sql
```
#### Paso 6: Índices
```bash
# Índices de gamification_system
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/indexes/01-idx_user_stats_user_id.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/indexes/05-idx_notifications_user_id.sql
# Índices de progress_tracking
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/progress_tracking/indexes/01-idx_module_progress_analytics_gin.sql
```
#### Paso 7: RLS Policies
```bash
# Habilitar RLS y crear políticas
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/rls-policies/01-enable-rls.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/gamification_system/rls-policies/02-policies.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/progress_tracking/rls-policies/01-enable-rls.sql
psql -U gamilit_user -d gamilit_platform -f apps/database/ddl/schemas/educational_content/rls-policies/01-enable-rls.sql
```
#### Paso 8: Seeds Críticos
```bash
# Maya Ranks (PRIMERO - requerido por user_ranks)
psql -U gamilit_user -d gamilit_platform -f apps/database/seeds/prod/gamification_system/03-maya_ranks.sql
# Mission Templates (requerido por missions)
psql -U gamilit_user -d gamilit_platform -f apps/database/seeds/prod/gamification_system/10-mission_templates.sql
# Modules
psql -U gamilit_user -d gamilit_platform -f apps/database/seeds/prod/educational_content/01-modules.sql
```
#### Paso 9: Inicializar Usuarios Existentes
```sql
-- Para usuarios que ya existen sin user_stats/user_ranks
-- Ejecutar manualmente la inicialización
-- 1. Crear user_stats para usuarios sin stats
INSERT INTO gamification_system.user_stats (user_id, tenant_id, ml_coins, ml_coins_earned_total)
SELECT p.user_id, p.tenant_id, 100, 100
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_stats us WHERE us.user_id = p.user_id);
-- 2. Crear user_ranks para usuarios sin ranks
INSERT INTO gamification_system.user_ranks (user_id, tenant_id, current_rank, is_current)
SELECT p.user_id, p.tenant_id, 'Ajaw'::gamification_system.maya_rank, true
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_ranks ur WHERE ur.user_id = p.user_id);
```
---
## 5. SCRIPT CONSOLIDADO PARA OPCIÓN B
Crear un script ejecutable:
```bash
#!/bin/bash
# migrate-production-critical.sh
# Migra solo los objetos críticos faltantes
set -e
DB_HOST="${DB_HOST:-localhost}"
DB_PORT="${DB_PORT:-5432}"
DB_NAME="${DB_NAME:-gamilit_platform}"
DB_USER="${DB_USER:-gamilit_user}"
PSQL="psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME"
echo "=== MIGRACIÓN CRÍTICA PRODUCCIÓN ==="
echo "Base de datos: $DB_NAME"
echo ""
# Función para ejecutar SQL
run_sql() {
echo "Ejecutando: $1"
$PSQL -f "$1"
}
# Paso 1: Verificar conexión
echo "1. Verificando conexión..."
$PSQL -c "SELECT 1" > /dev/null
# Paso 2: ENUMs
echo "2. Creando ENUMs faltantes..."
run_sql "apps/database/ddl/schemas/gamification_system/types/notification_type.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/gamification_system/types/notification_priority.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/gamification_system/types/maya_rank.sql" 2>/dev/null || true
# Paso 3: Tablas
echo "3. Creando tablas faltantes..."
run_sql "apps/database/ddl/schemas/gamification_system/tables/01-user_stats.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/gamification_system/tables/13-maya_ranks.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/gamification_system/tables/02-user_ranks.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/gamification_system/tables/08-notifications.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/gamification_system/tables/20-mission_templates.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/gamification_system/tables/06-missions.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/progress_tracking/tables/01-module_progress.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/educational_content/tables/01-modules.sql" 2>/dev/null || true
# Paso 4: Funciones y Triggers
echo "4. Creando funciones y triggers..."
run_sql "apps/database/ddl/schemas/gamilit/functions/04-initialize_user_stats.sql" 2>/dev/null || true
run_sql "apps/database/ddl/schemas/auth_management/triggers/04-trg_initialize_user_stats.sql" 2>/dev/null || true
# Paso 5: Seeds
echo "5. Ejecutando seeds críticos..."
run_sql "apps/database/seeds/prod/gamification_system/03-maya_ranks.sql"
run_sql "apps/database/seeds/prod/gamification_system/10-mission_templates.sql"
run_sql "apps/database/seeds/prod/educational_content/01-modules.sql"
# Paso 6: Inicializar usuarios existentes
echo "6. Inicializando usuarios existentes..."
$PSQL << 'EOF'
-- Crear user_stats para usuarios sin stats
INSERT INTO gamification_system.user_stats (user_id, tenant_id, ml_coins, ml_coins_earned_total)
SELECT p.user_id, p.tenant_id, 100, 100
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_stats us WHERE us.user_id = p.user_id)
ON CONFLICT (user_id) DO NOTHING;
-- Crear user_ranks para usuarios sin ranks
INSERT INTO gamification_system.user_ranks (user_id, tenant_id, current_rank, is_current)
SELECT p.user_id, p.tenant_id, 'Ajaw'::gamification_system.maya_rank, true
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_ranks ur WHERE ur.user_id = p.user_id)
ON CONFLICT (user_id) DO NOTHING;
EOF
echo ""
echo "=== MIGRACIÓN COMPLETADA ==="
echo "Verificar con: ./validate-db-ready.sh"
```
---
## 6. VERIFICACIÓN POST-IMPLEMENTACIÓN
### 6.1 Queries de Verificación
```sql
-- 1. Tablas creadas
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema IN ('gamification_system', 'progress_tracking', 'educational_content')
ORDER BY table_schema, table_name;
-- 2. Seeds cargados
SELECT 'mission_templates' as tabla, COUNT(*) as registros FROM gamification_system.mission_templates
UNION ALL
SELECT 'maya_ranks', COUNT(*) FROM gamification_system.maya_ranks
UNION ALL
SELECT 'modules', COUNT(*) FROM educational_content.modules;
-- 3. Usuarios con stats
SELECT COUNT(*) as usuarios_con_stats FROM gamification_system.user_stats;
-- 4. Usuarios con ranks
SELECT COUNT(*) as usuarios_con_ranks FROM gamification_system.user_ranks;
-- 5. Trigger activo
SELECT tgname, tgenabled FROM pg_trigger WHERE tgname = 'trg_initialize_user_stats';
```
### 6.2 Prueba Funcional
```bash
# Probar endpoints desde el servidor
curl -k https://74.208.126.102:3006/api/v1/gamification/missions/daily -H "Authorization: Bearer <TOKEN>"
curl -k https://74.208.126.102:3006/api/v1/gamification/ranks/current -H "Authorization: Bearer <TOKEN>"
curl -k https://74.208.126.102:3006/api/v1/notifications/unread-count -H "Authorization: Bearer <TOKEN>"
```
---
## 7. PLAN DE ROLLBACK
### Si algo falla:
```bash
# Restaurar desde backup
pg_restore -U gamilit_user -d gamilit_platform -c backup_YYYYMMDD_HHMMSS.dump
# O si solo se agregaron objetos nuevos, dropearlos:
DROP TABLE IF EXISTS gamification_system.notifications CASCADE;
DROP TABLE IF EXISTS gamification_system.user_stats CASCADE;
DROP TABLE IF EXISTS gamification_system.user_ranks CASCADE;
DROP TABLE IF EXISTS progress_tracking.module_progress CASCADE;
DROP TABLE IF EXISTS educational_content.modules CASCADE;
```
---
## 8. CHECKLIST DE IMPLEMENTACIÓN
- [ ] Crear backup de producción
- [ ] Verificar espacio en disco
- [ ] Notificar a usuarios de mantenimiento
- [ ] Detener backend (PM2 stop)
- [ ] Ejecutar migración (Opción A o B)
- [ ] Validar tablas creadas
- [ ] Validar seeds cargados
- [ ] Validar trigger activo
- [ ] Iniciar backend (PM2 start)
- [ ] Probar endpoints
- [ ] Registrar nuevo usuario de prueba
- [ ] Verificar user_stats y user_ranks creados
- [ ] Confirmar resolución de errores
---
## 9. TIEMPO ESTIMADO
| Actividad | Duración |
|-----------|----------|
| Backup | 5 min |
| Migración Opción A | 2-5 min |
| Migración Opción B | 10-15 min |
| Validación | 5 min |
| Pruebas | 10 min |
| **Total** | **20-35 min** |
---
**Documento generado para Fase 3 - Plan de Implementación**

View File

@ -0,0 +1,372 @@
# FASE 4: Validación del Plan de Implementación
**Fecha:** 2025-12-18
**Proyecto:** Gamilit
**Estado:** VALIDACIÓN COMPLETA
---
## 1. RESUMEN DE VALIDACIÓN
| Componente | Estado | Observaciones |
|------------|--------|---------------|
| Orden de tablas | ⚠️ CORREGIDO | modules antes de module_progress |
| ENUMs | ✅ OK | Todos definidos en DDL |
| Funciones | ✅ OK | 12/12 implementadas |
| Triggers | ✅ OK | 12/12 implementados |
| Dependencias FK | ✅ OK | Todas a auth_management |
---
## 2. CORRECCIÓN DE ORDEN DE EJECUCIÓN
### 2.1 Orden INCORRECTO (Plan Original)
```
1. user_stats
2. maya_ranks
3. user_ranks
4. notifications
5. mission_templates
6. missions
7. module_progress ❌ ERROR: Depende de modules
8. modules
```
### 2.2 Orden CORREGIDO
```
FASE 0 - PRE-REQUISITOS:
0.1 Schema gamilit (functions base)
0.2 ENUMs (00-prerequisites.sql + schema/enums/)
FASE 1 - TABLAS SIN DEPENDENCIAS INTERNAS:
1. user_stats
2. maya_ranks
3. notifications
4. mission_templates
5. modules ← MOVIDO ARRIBA
FASE 2 - TABLAS CON DEPENDENCIAS:
6. user_ranks (depende de: user_stats conceptualmente)
7. missions (depende de: mission_templates)
8. module_progress ← MOVIDO ABAJO (depende de: modules)
```
---
## 3. MATRIZ DE DEPENDENCIAS VALIDADA
### 3.1 Dependencias de FK
| Tabla | FK a auth_management | FK a gamification_system | FK a educational_content |
|-------|---------------------|-------------------------|-------------------------|
| user_stats | profiles, tenants | - | - |
| maya_ranks | - | - | - |
| user_ranks | profiles, tenants | - | - |
| notifications | profiles | - | - |
| mission_templates | profiles | - | - |
| missions | profiles | - | - |
| modules | profiles, tenants | - | - |
| module_progress | profiles | - | modules |
### 3.2 Dependencias de ENUM
| Tabla | ENUMs Requeridos |
|-------|-----------------|
| user_stats | `gamification_system.maya_rank` |
| maya_ranks | `gamification_system.maya_rank` |
| user_ranks | `gamification_system.maya_rank` |
| notifications | `notification_type`, `notification_priority` |
| mission_templates | - (usa CHECK constraints) |
| missions | - (usa CHECK constraints) |
| modules | `maya_rank`, `difficulty_level`, `module_status` |
| module_progress | `progress_tracking.progress_status` |
---
## 4. VALIDACIÓN DE ENUMs
### 4.1 ENUMs Existentes - TODOS OK
| ENUM | Archivo | Valores | Estado |
|------|---------|---------|--------|
| `maya_rank` | `00-prerequisites.sql` | Ajaw, Nacom, Ah K'in, Halach Uinic, K'uk'ulkan | ✅ |
| `notification_type` | `gamification_system/enums/` | 11 tipos | ✅ |
| `notification_priority` | `gamification_system/enums/` | low, medium, high, critical | ✅ |
| `transaction_type` | `gamification_system/enums/` | 14 tipos | ✅ |
| `difficulty_level` | `educational_content/enums/` | beginner, intermediate, advanced | ✅ |
| `module_status` | `educational_content/enums/` | draft, published, archived | ✅ |
| `progress_status` | `progress_tracking/types/` | not_started, in_progress, completed, reviewed, mastered | ✅ |
### 4.2 Tipos sin ENUM (usan CHECK)
| Campo | Tabla | Valores | Recomendación |
|-------|-------|---------|---------------|
| `mission_type` | missions, mission_templates | daily, weekly, special, classroom | Considerar crear ENUM |
| `mission_status` | missions | active, in_progress, completed, claimed, expired | Considerar crear ENUM |
---
## 5. VALIDACIÓN DE FUNCIONES
### 5.1 Funciones Críticas - TODAS OK
| Función | Schema | Estado | Usado Por |
|---------|--------|--------|-----------|
| `now_mexico()` | gamilit | ✅ | Todas las tablas con timestamps |
| `update_updated_at_column()` | gamilit | ✅ | Triggers de updated_at |
| `calculate_level_from_xp()` | gamification_system | ✅ | recalculate_level_on_xp_change |
| `recalculate_level_on_xp_change()` | gamification_system | ✅ | Trigger user_stats |
| `check_rank_promotion()` | gamification_system | ✅ | Trigger xp_gain |
| `promote_to_next_rank()` | gamification_system | ✅ | check_rank_promotion |
| `initialize_user_stats()` | gamilit | ✅ | Trigger en profiles |
| `update_missions_on_earn_xp()` | gamilit | ✅ | Trigger user_stats |
| `update_missions_on_use_comodines()` | gamilit | ✅ | Trigger comodin_usage_log |
| `update_missions_on_daily_streak()` | gamilit | ✅ | Trigger user_stats |
### 5.2 Funciones Deprecated (mantener por compatibilidad)
| Función | Schema | Notas |
|---------|--------|-------|
| `update_notifications_updated_at()` | gamification_system | Usar update_updated_at_column |
| `update_missions_updated_at()` | gamification_system | Usar update_updated_at_column |
---
## 6. VALIDACIÓN DE TRIGGERS
### 6.1 Triggers Críticos - TODOS OK
| Trigger | Tabla | Evento | Función |
|---------|-------|--------|---------|
| `trg_initialize_user_stats` | auth_management.profiles | AFTER INSERT | gamilit.initialize_user_stats() |
| `trg_user_stats_updated_at` | user_stats | BEFORE UPDATE | gamilit.update_updated_at_column() |
| `trg_user_ranks_updated_at` | user_ranks | BEFORE UPDATE | gamilit.update_updated_at_column() |
| `trg_recalculate_level_on_xp_change` | user_stats | BEFORE UPDATE OF total_xp | recalculate_level_on_xp_change() |
| `trg_check_rank_promotion_on_xp_gain` | user_stats | AFTER UPDATE OF total_xp | check_rank_promotion() |
| `trg_update_missions_on_earn_xp` | user_stats | AFTER UPDATE | update_missions_on_earn_xp() |
| `trg_update_missions_on_daily_streak` | user_stats | AFTER UPDATE | update_missions_on_daily_streak() |
| `trg_achievement_unlocked` | user_achievements | AFTER INSERT/UPDATE | fn_on_achievement_unlocked() |
| `notifications_updated_at` | notifications | BEFORE UPDATE | update_notifications_updated_at() |
| `missions_updated_at` | missions | BEFORE UPDATE | update_missions_updated_at() |
---
## 7. ORDEN DE EJECUCIÓN FINAL VALIDADO
### Script Consolidado Corregido
```bash
#!/bin/bash
# migrate-production-validated.sh
# Orden de ejecución VALIDADO para producción
set -e
DB_HOST="${DB_HOST:-localhost}"
DB_PORT="${DB_PORT:-5432}"
DB_NAME="${DB_NAME:-gamilit_platform}"
DB_USER="${DB_USER:-gamilit_user}"
PSQL="psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME"
BASE="apps/database/ddl"
echo "=== MIGRACIÓN VALIDADA PRODUCCIÓN ==="
echo ""
# FASE 0: PRE-REQUISITOS
echo "FASE 0: Pre-requisitos..."
$PSQL -f "$BASE/00-prerequisites.sql" 2>/dev/null || echo " Prerequisites ya existen"
# FASE 0.1: Funciones gamilit
echo "FASE 0.1: Funciones base gamilit..."
$PSQL -f "$BASE/schemas/gamilit/functions/08-now_mexico.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamilit/functions/15-update_updated_at_column.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamilit/functions/04-initialize_user_stats.sql" 2>/dev/null || true
# FASE 0.2: ENUMs gamification_system
echo "FASE 0.2: ENUMs gamification_system..."
$PSQL -f "$BASE/schemas/gamification_system/enums/notification_type.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/enums/notification_priority.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/enums/transaction_type.sql" 2>/dev/null || true
# FASE 0.3: ENUMs progress_tracking
echo "FASE 0.3: ENUMs progress_tracking..."
$PSQL -f "$BASE/schemas/progress_tracking/types/progress_status.sql" 2>/dev/null || true
# FASE 1: TABLAS SIN DEPENDENCIAS INTERNAS
echo ""
echo "FASE 1: Tablas base..."
$PSQL -f "$BASE/schemas/gamification_system/tables/01-user_stats.sql"
$PSQL -f "$BASE/schemas/gamification_system/tables/13-maya_ranks.sql"
$PSQL -f "$BASE/schemas/gamification_system/tables/08-notifications.sql"
$PSQL -f "$BASE/schemas/gamification_system/tables/20-mission_templates.sql"
$PSQL -f "$BASE/schemas/educational_content/tables/01-modules.sql"
# FASE 2: TABLAS CON DEPENDENCIAS
echo ""
echo "FASE 2: Tablas dependientes..."
$PSQL -f "$BASE/schemas/gamification_system/tables/02-user_ranks.sql"
$PSQL -f "$BASE/schemas/gamification_system/tables/06-missions.sql"
$PSQL -f "$BASE/schemas/progress_tracking/tables/01-module_progress.sql"
# FASE 3: FUNCIONES ADICIONALES
echo ""
echo "FASE 3: Funciones gamification..."
$PSQL -f "$BASE/schemas/gamification_system/functions/calculate_level_from_xp.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/functions/08-recalculate_level_on_xp_change.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/functions/check_rank_promotion.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/functions/promote_to_next_rank.sql" 2>/dev/null || true
# FASE 3.1: Funciones de missions
echo "FASE 3.1: Funciones missions..."
$PSQL -f "$BASE/schemas/gamilit/functions/22-update_missions_on_earn_xp.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamilit/functions/21-update_missions_on_use_comodines.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamilit/functions/23-update_missions_on_daily_streak.sql" 2>/dev/null || true
# FASE 4: TRIGGERS
echo ""
echo "FASE 4: Triggers..."
$PSQL -f "$BASE/schemas/auth_management/triggers/04-trg_initialize_user_stats.sql"
$PSQL -f "$BASE/schemas/gamification_system/triggers/20-trg_user_stats_updated_at.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/triggers/19-trg_user_ranks_updated_at.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/triggers/21-trg_recalculate_level_on_xp_change.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/triggers/trg_check_rank_promotion_on_xp_gain.sql" 2>/dev/null || true
$PSQL -f "$BASE/schemas/gamification_system/triggers/27-trg_update_missions_on_earn_xp.sql" 2>/dev/null || true
# FASE 5: SEEDS CRÍTICOS
echo ""
echo "FASE 5: Seeds..."
$PSQL -f "apps/database/seeds/prod/gamification_system/03-maya_ranks.sql"
$PSQL -f "apps/database/seeds/prod/gamification_system/10-mission_templates.sql"
$PSQL -f "apps/database/seeds/prod/educational_content/01-modules.sql"
# FASE 6: INICIALIZAR USUARIOS EXISTENTES
echo ""
echo "FASE 6: Inicializando usuarios existentes..."
$PSQL << 'EOF'
-- Crear user_stats para usuarios sin stats
INSERT INTO gamification_system.user_stats (user_id, tenant_id, ml_coins, ml_coins_earned_total)
SELECT p.user_id, p.tenant_id, 100, 100
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_stats us WHERE us.user_id = p.user_id)
ON CONFLICT (user_id) DO NOTHING;
-- Crear user_ranks para usuarios sin ranks
INSERT INTO gamification_system.user_ranks (user_id, tenant_id, current_rank, is_current)
SELECT p.user_id, p.tenant_id, 'Ajaw'::gamification_system.maya_rank, true
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_ranks ur WHERE ur.user_id = p.user_id)
ON CONFLICT (user_id) DO NOTHING;
SELECT 'Usuarios inicializados: ' || COUNT(*) FROM gamification_system.user_stats;
EOF
echo ""
echo "=== MIGRACIÓN COMPLETADA ==="
```
---
## 8. CHECKLIST DE VALIDACIÓN
### Pre-implementación
- [x] Orden de tablas validado (corregido module_progress)
- [x] ENUMs requeridos identificados (7 ENUMs)
- [x] Funciones requeridas verificadas (12 funciones)
- [x] Triggers requeridos verificados (10 triggers)
- [x] Dependencias FK validadas (todas a auth_management)
- [x] Script consolidado actualizado
### Durante implementación
- [ ] Backup creado antes de ejecutar
- [ ] FASE 0: Pre-requisitos ejecutados
- [ ] FASE 1: Tablas base creadas
- [ ] FASE 2: Tablas dependientes creadas
- [ ] FASE 3: Funciones creadas
- [ ] FASE 4: Triggers creados
- [ ] FASE 5: Seeds ejecutados
- [ ] FASE 6: Usuarios inicializados
### Post-implementación
- [ ] Verificar tablas creadas
- [ ] Verificar ENUMs existen
- [ ] Verificar triggers activos
- [ ] Verificar seeds cargados
- [ ] Probar registro nuevo usuario
- [ ] Probar endpoints con errores
---
## 9. QUERIES DE VERIFICACIÓN POST-IMPLEMENTACIÓN
```sql
-- 1. Verificar tablas críticas
SELECT
table_schema,
table_name,
'EXISTE' as estado
FROM information_schema.tables
WHERE (table_schema = 'gamification_system' AND table_name IN ('user_stats', 'user_ranks', 'notifications', 'mission_templates', 'missions', 'maya_ranks'))
OR (table_schema = 'progress_tracking' AND table_name = 'module_progress')
OR (table_schema = 'educational_content' AND table_name = 'modules')
ORDER BY table_schema, table_name;
-- 2. Verificar ENUMs
SELECT
n.nspname as schema,
t.typname as enum_name,
string_agg(e.enumlabel, ', ' ORDER BY e.enumsortorder) as values
FROM pg_type t
JOIN pg_enum e ON t.oid = e.enumtypid
JOIN pg_namespace n ON t.typnamespace = n.oid
WHERE n.nspname IN ('gamification_system', 'progress_tracking', 'educational_content')
GROUP BY n.nspname, t.typname;
-- 3. Verificar trigger de inicialización
SELECT
tgname as trigger_name,
tgenabled as enabled,
CASE tgenabled
WHEN 'O' THEN 'ACTIVO'
WHEN 'D' THEN 'DESHABILITADO'
ELSE 'OTRO'
END as estado
FROM pg_trigger
WHERE tgname = 'trg_initialize_user_stats';
-- 4. Verificar seeds
SELECT 'mission_templates' as tabla, COUNT(*) as registros FROM gamification_system.mission_templates
UNION ALL
SELECT 'maya_ranks', COUNT(*) FROM gamification_system.maya_ranks
UNION ALL
SELECT 'modules', COUNT(*) FROM educational_content.modules;
-- 5. Verificar usuarios inicializados
SELECT
(SELECT COUNT(*) FROM auth_management.profiles WHERE role IN ('student', 'admin_teacher', 'super_admin')) as total_profiles,
(SELECT COUNT(*) FROM gamification_system.user_stats) as con_stats,
(SELECT COUNT(*) FROM gamification_system.user_ranks) as con_ranks;
```
---
## 10. CONCLUSIÓN
**El plan de implementación ha sido VALIDADO y CORREGIDO.**
Cambios realizados:
1. ✅ Corregido orden: `modules` ahora va ANTES de `module_progress`
2. ✅ Agregados pasos para ENUMs faltantes
3. ✅ Agregados pasos para funciones requeridas
4. ✅ Agregados pasos para triggers requeridos
5. ✅ Script consolidado actualizado con orden correcto
**Siguiente paso:** Fase 5 - Ejecución de implementaciones
---
**Documento de Validación - Fase 4 completada**

View File

@ -0,0 +1,235 @@
# FASE 5: Instrucciones de Ejecución
**Fecha:** 2025-12-18
**Proyecto:** Gamilit
**Ambiente:** Producción (74.208.126.102)
---
## 1. ARCHIVOS GENERADOS
```
orchestration/analisis-errores-prod-2025-12-18/
├── SCRIPT-CORRECCION-PRODUCCION.sql # Script SQL principal
├── ejecutar-correccion.sh # Script bash auxiliar
├── FASE-5-INSTRUCCIONES-EJECUCION.md # Este documento
└── [otros documentos de análisis]
```
---
## 2. OPCIÓN A: Ejecución con Script Bash
### 2.1 Copiar archivos al servidor
```bash
# Desde tu máquina local
scp orchestration/analisis-errores-prod-2025-12-18/SCRIPT-CORRECCION-PRODUCCION.sql user@74.208.126.102:/tmp/
scp orchestration/analisis-errores-prod-2025-12-18/ejecutar-correccion.sh user@74.208.126.102:/tmp/
```
### 2.2 Ejecutar en el servidor
```bash
# Conectar al servidor
ssh user@74.208.126.102
# Ir al directorio
cd /tmp
# Ejecutar
./ejecutar-correccion.sh 74.208.126.102 5432 gamilit_platform gamilit_user
```
---
## 3. OPCIÓN B: Ejecución Manual con psql
### 3.1 Copiar archivo SQL
```bash
scp SCRIPT-CORRECCION-PRODUCCION.sql user@74.208.126.102:/tmp/
```
### 3.2 Ejecutar en servidor
```bash
# Conectar al servidor
ssh user@74.208.126.102
# Crear backup primero
pg_dump -U gamilit_user -d gamilit_platform \
--schema=gamification_system \
--schema=progress_tracking \
--schema=educational_content \
-f backup_$(date +%Y%m%d_%H%M%S).sql
# Ejecutar corrección
psql -U gamilit_user -d gamilit_platform -f /tmp/SCRIPT-CORRECCION-PRODUCCION.sql
```
---
## 4. OPCIÓN C: Ejecutar Directamente desde Local
Si tienes acceso directo a la BD de producción:
```bash
# Desde el directorio del proyecto
cd orchestration/analisis-errores-prod-2025-12-18/
# Ejecutar
PGPASSWORD=<tu_password> psql \
-h 74.208.126.102 \
-p 5432 \
-U gamilit_user \
-d gamilit_platform \
-f SCRIPT-CORRECCION-PRODUCCION.sql
```
---
## 5. VERIFICACIÓN POST-EJECUCIÓN
### 5.1 Verificar tablas creadas
```sql
SELECT table_schema, table_name
FROM information_schema.tables
WHERE (table_schema = 'gamification_system'
AND table_name IN ('user_stats', 'user_ranks', 'notifications',
'mission_templates', 'missions', 'maya_ranks'))
OR (table_schema = 'progress_tracking' AND table_name = 'module_progress')
OR (table_schema = 'educational_content' AND table_name = 'modules')
ORDER BY table_schema, table_name;
```
### 5.2 Verificar seeds
```sql
SELECT 'mission_templates' as tabla, COUNT(*) FROM gamification_system.mission_templates
UNION ALL SELECT 'maya_ranks', COUNT(*) FROM gamification_system.maya_ranks
UNION ALL SELECT 'modules', COUNT(*) FROM educational_content.modules
UNION ALL SELECT 'user_stats', COUNT(*) FROM gamification_system.user_stats
UNION ALL SELECT 'user_ranks', COUNT(*) FROM gamification_system.user_ranks;
```
### 5.3 Verificar trigger
```sql
SELECT tgname, tgenabled
FROM pg_trigger
WHERE tgname = 'trg_initialize_user_stats';
```
---
## 6. REINICIAR BACKEND
Después de ejecutar el script SQL:
```bash
# En el servidor de producción
pm2 restart gamilit-backend
# O si hay múltiples instancias
pm2 restart all
```
---
## 7. PRUEBAS FUNCIONALES
### 7.1 Registrar nuevo usuario
1. Ir a https://74.208.126.102:3005/register
2. Crear cuenta nueva
3. Verificar que el dashboard carga sin errores
### 7.2 Probar endpoints
```bash
# Obtener token de autenticación primero
TOKEN="<jwt_token_del_usuario>"
# Probar notificaciones
curl -k https://74.208.126.102:3006/api/v1/notifications/unread-count \
-H "Authorization: Bearer $TOKEN"
# Probar misiones
curl -k https://74.208.126.102:3006/api/v1/gamification/missions/daily \
-H "Authorization: Bearer $TOKEN"
# Probar ranks
curl -k https://74.208.126.102:3006/api/v1/gamification/ranks/current \
-H "Authorization: Bearer $TOKEN"
# Probar módulos
curl -k https://74.208.126.102:3006/api/v1/educational/modules/user/<user_id> \
-H "Authorization: Bearer $TOKEN"
```
---
## 8. ROLLBACK (si es necesario)
Si algo falla, restaurar desde el backup:
```bash
# Restaurar backup
psql -U gamilit_user -d gamilit_platform -f backup_YYYYMMDD_HHMMSS.sql
# O si necesitas eliminar los objetos creados
psql -U gamilit_user -d gamilit_platform -c "
DROP TABLE IF EXISTS gamification_system.missions CASCADE;
DROP TABLE IF EXISTS gamification_system.mission_templates CASCADE;
DROP TABLE IF EXISTS gamification_system.user_ranks CASCADE;
DROP TABLE IF EXISTS gamification_system.user_stats CASCADE;
DROP TABLE IF EXISTS gamification_system.notifications CASCADE;
DROP TABLE IF EXISTS gamification_system.maya_ranks CASCADE;
DROP TABLE IF EXISTS progress_tracking.module_progress CASCADE;
DROP TABLE IF EXISTS educational_content.modules CASCADE;
"
```
---
## 9. CHECKLIST DE EJECUCIÓN
### Pre-ejecución
- [ ] Acceso SSH al servidor verificado
- [ ] Credenciales de BD disponibles
- [ ] Archivos SQL copiados al servidor
- [ ] Backup creado
### Ejecución
- [ ] Script SQL ejecutado sin errores
- [ ] Verificación de tablas OK
- [ ] Verificación de seeds OK
- [ ] Trigger activo verificado
### Post-ejecución
- [ ] Backend reiniciado
- [ ] Nuevo usuario registrado correctamente
- [ ] Dashboard carga sin errores
- [ ] Endpoints responden correctamente
---
## 10. RESULTADO ESPERADO
Después de ejecutar la corrección:
| Error Original | Estado Esperado |
|---------------|-----------------|
| 500 - notifications does not exist | ✅ 200 OK |
| 500 - module_progress does not exist | ✅ 200 OK |
| 500 - modules does not exist | ✅ 200 OK |
| 404 - ranks/current | ✅ 200 OK |
| 404 - ml-coins | ✅ 200 OK |
| 400 - missions/daily | ✅ 200 OK |
| 400 - missions/weekly | ✅ 200 OK |
---
**Documentación de Fase 5 completada.**

View File

@ -0,0 +1,576 @@
-- ============================================================================
-- SCRIPT DE CORRECCIÓN PARA PRODUCCIÓN - GAMILIT
-- ============================================================================
-- Fecha: 2025-12-18
-- Propósito: Crear objetos faltantes en BD de producción
-- Ejecutar como: psql -U gamilit_user -d gamilit_platform -f SCRIPT-CORRECCION-PRODUCCION.sql
-- ============================================================================
\echo '=============================================='
\echo 'INICIO: Corrección de BD Producción - Gamilit'
\echo '=============================================='
\echo ''
-- ============================================================================
-- FASE 0: VERIFICACIÓN INICIAL
-- ============================================================================
\echo 'FASE 0: Verificación inicial...'
SELECT 'Verificando conexión...' as status;
SELECT current_database() as database, current_user as usuario, now() as timestamp;
-- ============================================================================
-- FASE 1: VERIFICAR/CREAR SCHEMAS
-- ============================================================================
\echo ''
\echo 'FASE 1: Verificando schemas...'
CREATE SCHEMA IF NOT EXISTS gamilit;
CREATE SCHEMA IF NOT EXISTS gamification_system;
CREATE SCHEMA IF NOT EXISTS progress_tracking;
CREATE SCHEMA IF NOT EXISTS educational_content;
CREATE SCHEMA IF NOT EXISTS notifications;
SELECT 'Schemas verificados' as status;
-- ============================================================================
-- FASE 2: CREAR ENUMs (si no existen)
-- ============================================================================
\echo ''
\echo 'FASE 2: Creando ENUMs...'
-- ENUM: maya_rank
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'maya_rank' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'gamification_system')) THEN
CREATE TYPE gamification_system.maya_rank AS ENUM (
'Ajaw',
'Nacom',
'Ah K''in',
'Halach Uinic',
'K''uk''ulkan'
);
RAISE NOTICE 'ENUM maya_rank creado';
ELSE
RAISE NOTICE 'ENUM maya_rank ya existe';
END IF;
END $$;
-- ENUM: notification_type
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'notification_type' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'gamification_system')) THEN
CREATE TYPE gamification_system.notification_type AS ENUM (
'achievement_unlocked',
'rank_up',
'friend_request',
'guild_invitation',
'mission_completed',
'level_up',
'message_received',
'system_announcement',
'ml_coins_earned',
'streak_milestone',
'exercise_feedback'
);
RAISE NOTICE 'ENUM notification_type creado';
ELSE
RAISE NOTICE 'ENUM notification_type ya existe';
END IF;
END $$;
-- ENUM: notification_priority
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'notification_priority' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'gamification_system')) THEN
CREATE TYPE gamification_system.notification_priority AS ENUM (
'low',
'medium',
'high',
'critical'
);
RAISE NOTICE 'ENUM notification_priority creado';
ELSE
RAISE NOTICE 'ENUM notification_priority ya existe';
END IF;
END $$;
-- ENUM: progress_status
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'progress_status' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'progress_tracking')) THEN
CREATE TYPE progress_tracking.progress_status AS ENUM (
'not_started',
'in_progress',
'completed',
'reviewed',
'mastered'
);
RAISE NOTICE 'ENUM progress_status creado';
ELSE
RAISE NOTICE 'ENUM progress_status ya existe';
END IF;
END $$;
-- ENUM: difficulty_level
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'difficulty_level' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'educational_content')) THEN
CREATE TYPE educational_content.difficulty_level AS ENUM (
'beginner',
'intermediate',
'advanced'
);
RAISE NOTICE 'ENUM difficulty_level creado';
ELSE
RAISE NOTICE 'ENUM difficulty_level ya existe';
END IF;
END $$;
-- ENUM: module_status
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'module_status' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'educational_content')) THEN
CREATE TYPE educational_content.module_status AS ENUM (
'draft',
'published',
'archived',
'backlog'
);
RAISE NOTICE 'ENUM module_status creado';
ELSE
RAISE NOTICE 'ENUM module_status ya existe';
END IF;
END $$;
SELECT 'ENUMs verificados/creados' as status;
-- ============================================================================
-- FASE 3: FUNCIONES BASE
-- ============================================================================
\echo ''
\echo 'FASE 3: Creando funciones base...'
-- Función: now_mexico
CREATE OR REPLACE FUNCTION gamilit.now_mexico()
RETURNS TIMESTAMP WITH TIME ZONE
LANGUAGE sql
STABLE
AS $$
SELECT NOW() AT TIME ZONE 'America/Mexico_City';
$$;
-- Función: update_updated_at_column
CREATE OR REPLACE FUNCTION gamilit.update_updated_at_column()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at = gamilit.now_mexico();
RETURN NEW;
END;
$$;
SELECT 'Funciones base creadas' as status;
-- ============================================================================
-- FASE 4: TABLAS CRÍTICAS
-- ============================================================================
\echo ''
\echo 'FASE 4: Creando tablas críticas...'
-- Tabla: user_stats
CREATE TABLE IF NOT EXISTS gamification_system.user_stats (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL UNIQUE,
tenant_id UUID,
total_xp INTEGER DEFAULT 0,
level INTEGER DEFAULT 1,
current_rank gamification_system.maya_rank DEFAULT 'Ajaw',
ml_coins INTEGER DEFAULT 0,
ml_coins_earned_total INTEGER DEFAULT 0,
current_streak INTEGER DEFAULT 0,
longest_streak INTEGER DEFAULT 0,
last_activity_date DATE,
total_exercises_completed INTEGER DEFAULT 0,
total_correct_answers INTEGER DEFAULT 0,
total_time_spent_minutes INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico()
);
-- Tabla: maya_ranks
CREATE TABLE IF NOT EXISTS gamification_system.maya_ranks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
rank_name gamification_system.maya_rank NOT NULL UNIQUE,
display_name TEXT NOT NULL,
description TEXT,
min_xp INTEGER NOT NULL,
max_xp INTEGER,
xp_multiplier DECIMAL(3,2) DEFAULT 1.00,
ml_coins_bonus INTEGER DEFAULT 0,
icon_url TEXT,
badge_url TEXT,
color_primary TEXT DEFAULT '#4A90A4',
color_secondary TEXT DEFAULT '#2C5F6E',
perks JSONB DEFAULT '{}',
next_rank gamification_system.maya_rank,
is_active BOOLEAN DEFAULT true,
order_index INTEGER NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico()
);
-- Tabla: user_ranks
CREATE TABLE IF NOT EXISTS gamification_system.user_ranks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
tenant_id UUID,
current_rank gamification_system.maya_rank NOT NULL DEFAULT 'Ajaw',
previous_rank gamification_system.maya_rank,
rank_achieved_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
is_current BOOLEAN DEFAULT true,
total_xp_at_rank INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
UNIQUE(user_id, current_rank)
);
-- Tabla: notifications
CREATE TABLE IF NOT EXISTS gamification_system.notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
type gamification_system.notification_type NOT NULL,
title TEXT NOT NULL,
message TEXT NOT NULL,
data JSONB DEFAULT '{}',
priority gamification_system.notification_priority DEFAULT 'medium',
read BOOLEAN DEFAULT false,
read_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico()
);
-- Tabla: mission_templates
CREATE TABLE IF NOT EXISTS gamification_system.mission_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
type TEXT NOT NULL CHECK (type IN ('daily', 'weekly', 'special', 'classroom')),
category TEXT DEFAULT 'general',
target_type TEXT NOT NULL,
target_value INTEGER NOT NULL,
xp_reward INTEGER DEFAULT 0,
ml_coins_reward INTEGER DEFAULT 0,
icon TEXT,
difficulty TEXT DEFAULT 'medium',
is_active BOOLEAN DEFAULT true,
metadata JSONB DEFAULT '{}',
created_by UUID,
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico()
);
-- Tabla: missions
CREATE TABLE IF NOT EXISTS gamification_system.missions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
template_id TEXT,
name TEXT NOT NULL,
description TEXT,
mission_type TEXT NOT NULL CHECK (mission_type IN ('daily', 'weekly', 'special')),
target_type TEXT NOT NULL,
target_value INTEGER NOT NULL,
current_value INTEGER DEFAULT 0,
progress DECIMAL(5,2) DEFAULT 0,
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'in_progress', 'completed', 'claimed', 'expired')),
xp_reward INTEGER DEFAULT 0,
ml_coins_reward INTEGER DEFAULT 0,
icon TEXT,
starts_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
expires_at TIMESTAMP WITH TIME ZONE,
completed_at TIMESTAMP WITH TIME ZONE,
claimed_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico()
);
-- Tabla: modules (educational_content)
CREATE TABLE IF NOT EXISTS educational_content.modules (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID,
title TEXT NOT NULL,
subtitle TEXT,
description TEXT,
summary TEXT,
content JSONB DEFAULT '{}',
order_index INTEGER NOT NULL,
module_code TEXT,
difficulty_level educational_content.difficulty_level DEFAULT 'beginner',
status educational_content.module_status DEFAULT 'draft',
is_published BOOLEAN DEFAULT false,
estimated_duration_minutes INTEGER DEFAULT 30,
xp_reward INTEGER DEFAULT 100,
ml_coins_reward INTEGER DEFAULT 50,
thumbnail_url TEXT,
icon_url TEXT,
subjects TEXT[] DEFAULT '{}',
tags TEXT[] DEFAULT '{}',
prerequisites UUID[] DEFAULT '{}',
maya_rank_required gamification_system.maya_rank,
maya_rank_granted gamification_system.maya_rank,
created_by UUID,
reviewed_by UUID,
approved_by UUID,
published_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico()
);
-- Tabla: module_progress (progress_tracking)
CREATE TABLE IF NOT EXISTS progress_tracking.module_progress (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
module_id UUID NOT NULL,
classroom_id UUID,
status progress_tracking.progress_status DEFAULT 'not_started',
progress_percentage DECIMAL(5,2) DEFAULT 0,
completed_exercises INTEGER DEFAULT 0,
total_exercises INTEGER DEFAULT 0,
correct_answers INTEGER DEFAULT 0,
total_attempts INTEGER DEFAULT 0,
time_spent_minutes INTEGER DEFAULT 0,
last_exercise_id UUID,
last_activity_at TIMESTAMP WITH TIME ZONE,
started_at TIMESTAMP WITH TIME ZONE,
completed_at TIMESTAMP WITH TIME ZONE,
score DECIMAL(5,2),
xp_earned INTEGER DEFAULT 0,
ml_coins_earned INTEGER DEFAULT 0,
analytics JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT gamilit.now_mexico(),
UNIQUE(user_id, module_id)
);
SELECT 'Tablas críticas creadas' as status;
-- ============================================================================
-- FASE 5: ÍNDICES
-- ============================================================================
\echo ''
\echo 'FASE 5: Creando índices...'
CREATE INDEX IF NOT EXISTS idx_user_stats_user_id ON gamification_system.user_stats(user_id);
CREATE INDEX IF NOT EXISTS idx_user_ranks_user_id ON gamification_system.user_ranks(user_id);
CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON gamification_system.notifications(user_id);
CREATE INDEX IF NOT EXISTS idx_notifications_read ON gamification_system.notifications(user_id, read);
CREATE INDEX IF NOT EXISTS idx_missions_user_id ON gamification_system.missions(user_id);
CREATE INDEX IF NOT EXISTS idx_missions_status ON gamification_system.missions(status);
CREATE INDEX IF NOT EXISTS idx_module_progress_user ON progress_tracking.module_progress(user_id);
CREATE INDEX IF NOT EXISTS idx_module_progress_module ON progress_tracking.module_progress(module_id);
SELECT 'Índices creados' as status;
-- ============================================================================
-- FASE 6: SEEDS - MAYA RANKS
-- ============================================================================
\echo ''
\echo 'FASE 6: Cargando seed de maya_ranks...'
INSERT INTO gamification_system.maya_ranks (
rank_name, display_name, description, min_xp, max_xp,
xp_multiplier, ml_coins_bonus, order_index, next_rank,
color_primary, color_secondary, perks
) VALUES
('Ajaw', 'Ajaw - Semilla', 'Inicio del camino del conocimiento maya', 0, 499, 1.00, 0, 1, 'Nacom', '#8B4513', '#654321', '{"unlocks": ["basic_exercises"]}'),
('Nacom', 'Nacom - Guerrero', 'Demostración de dedicación al aprendizaje', 500, 999, 1.10, 100, 2, 'Ah K''in', '#CD853F', '#8B4513', '{"unlocks": ["intermediate_exercises", "daily_bonus"]}'),
('Ah K''in', 'Ah K''in - Sacerdote', 'Dominio de conocimientos intermedios', 1000, 1499, 1.15, 250, 3, 'Halach Uinic', '#DAA520', '#B8860B', '{"unlocks": ["advanced_exercises", "weekly_challenges"]}'),
('Halach Uinic', 'Halach Uinic - Líder', 'Sabiduría reconocida por la comunidad', 1500, 1899, 1.20, 500, 4, 'K''uk''ulkan', '#FFD700', '#FFA500', '{"unlocks": ["special_content", "mentor_mode"]}'),
('K''uk''ulkan', 'K''uk''ulkan - Serpiente Emplumada', 'Máximo nivel de conocimiento alcanzado', 1900, NULL, 1.25, 1000, 5, NULL, '#00CED1', '#008B8B', '{"unlocks": ["all_content", "exclusive_rewards", "legend_badge"]}')
ON CONFLICT (rank_name) DO UPDATE SET
display_name = EXCLUDED.display_name,
description = EXCLUDED.description,
min_xp = EXCLUDED.min_xp,
max_xp = EXCLUDED.max_xp,
xp_multiplier = EXCLUDED.xp_multiplier,
ml_coins_bonus = EXCLUDED.ml_coins_bonus,
next_rank = EXCLUDED.next_rank,
updated_at = gamilit.now_mexico();
SELECT 'maya_ranks cargados: ' || COUNT(*) as status FROM gamification_system.maya_ranks;
-- ============================================================================
-- FASE 7: SEEDS - MISSION TEMPLATES
-- ============================================================================
\echo ''
\echo 'FASE 7: Cargando seed de mission_templates...'
INSERT INTO gamification_system.mission_templates (
id, name, description, type, target_type, target_value,
xp_reward, ml_coins_reward, icon, difficulty, is_active
) VALUES
-- Daily missions
('20000001-0000-0000-0000-000000000001', 'Calentamiento Científico', 'Completa 3 ejercicios hoy', 'daily', 'complete_exercises', 3, 50, 10, 'science', 'easy', true),
('20000001-0000-0000-0000-000000000002', 'Mente Brillante', 'Responde 5 ejercicios correctos seguidos', 'daily', 'correct_streak', 5, 75, 15, 'brain', 'medium', true),
('20000001-0000-0000-0000-000000000003', 'Acumulador de Sabiduría', 'Gana 100 XP hoy', 'daily', 'earn_xp', 100, 30, 5, 'star', 'easy', true),
('20000001-0000-0000-0000-000000000004', 'Perfeccionista del Día', 'Obtén puntuación perfecta en 1 ejercicio', 'daily', 'perfect_scores', 1, 100, 25, 'trophy', 'hard', true),
-- Weekly missions
('20000002-0000-0000-0000-000000000001', 'Maratón de Conocimiento', 'Completa 15 ejercicios esta semana', 'weekly', 'complete_exercises', 15, 200, 50, 'running', 'medium', true),
('20000002-0000-0000-0000-000000000002', 'Constancia Científica', 'Mantén una racha de 5 días', 'weekly', 'daily_streak', 5, 300, 75, 'fire', 'hard', true),
('20000002-0000-0000-0000-000000000003', 'Ascenso Semanal', 'Gana 500 XP esta semana', 'weekly', 'earn_xp', 500, 150, 40, 'chart', 'medium', true),
('20000002-0000-0000-0000-000000000004', 'Explorador Curioso', 'Explora 3 módulos diferentes', 'weekly', 'explore_modules', 3, 175, 45, 'compass', 'medium', true),
('20000002-0000-0000-0000-000000000005', 'Semana de Excelencia', 'Obtén 5 puntuaciones perfectas', 'weekly', 'perfect_scores', 5, 400, 100, 'medal', 'hard', true),
-- Special missions
('20000003-0000-0000-0000-000000000001', 'Dominio del Módulo', 'Completa un módulo completo', 'special', 'complete_modules', 1, 500, 150, 'certificate', 'hard', true),
('20000003-0000-0000-0000-000000000002', 'Estratega Sabio', 'Usa 3 comodines estratégicamente', 'special', 'use_comodines', 3, 75, 20, 'lightbulb', 'easy', true)
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
description = EXCLUDED.description,
target_value = EXCLUDED.target_value,
xp_reward = EXCLUDED.xp_reward,
ml_coins_reward = EXCLUDED.ml_coins_reward,
updated_at = gamilit.now_mexico();
SELECT 'mission_templates cargados: ' || COUNT(*) as status FROM gamification_system.mission_templates;
-- ============================================================================
-- FASE 8: SEEDS - MODULES
-- ============================================================================
\echo ''
\echo 'FASE 8: Cargando seed de modules...'
INSERT INTO educational_content.modules (
id, title, subtitle, description, order_index, module_code,
difficulty_level, status, is_published, estimated_duration_minutes,
xp_reward, ml_coins_reward, subjects
) VALUES
('11111111-1111-1111-1111-111111111111', 'Comprensión Literal', 'Entendiendo lo que lees', 'Desarrolla habilidades para identificar información explícita en textos', 1, 'MOD-01-LITERAL', 'beginner', 'published', true, 45, 100, 50, ARRAY['lectura', 'comprensión']),
('22222222-2222-2222-2222-222222222222', 'Comprensión Inferencial', 'Leyendo entre líneas', 'Aprende a deducir información implícita y hacer inferencias', 2, 'MOD-02-INFERENCIAL', 'intermediate', 'published', true, 60, 150, 75, ARRAY['lectura', 'inferencia']),
('33333333-3333-3333-3333-333333333333', 'Comprensión Crítica', 'Análisis profundo', 'Desarrolla pensamiento crítico para evaluar y analizar textos', 3, 'MOD-03-CRITICA', 'advanced', 'published', true, 75, 200, 100, ARRAY['lectura', 'análisis crítico']),
('44444444-4444-4444-4444-444444444444', 'Lectura Digital y Multimodal', 'Navegando el mundo digital', 'Comprende textos digitales y contenido multimedia', 4, 'MOD-04-DIGITAL', 'intermediate', 'published', true, 60, 175, 85, ARRAY['lectura digital', 'multimedia']),
('55555555-5555-5555-5555-555555555555', 'Producción y Expresión Escrita', 'Comunicando tus ideas', 'Desarrolla habilidades de escritura y expresión', 5, 'MOD-05-PRODUCCION', 'advanced', 'published', true, 90, 250, 125, ARRAY['escritura', 'expresión'])
ON CONFLICT (id) DO UPDATE SET
title = EXCLUDED.title,
description = EXCLUDED.description,
xp_reward = EXCLUDED.xp_reward,
ml_coins_reward = EXCLUDED.ml_coins_reward,
updated_at = gamilit.now_mexico();
SELECT 'modules cargados: ' || COUNT(*) as status FROM educational_content.modules;
-- ============================================================================
-- FASE 9: FUNCIÓN DE INICIALIZACIÓN DE USUARIOS
-- ============================================================================
\echo ''
\echo 'FASE 9: Creando función de inicialización...'
CREATE OR REPLACE FUNCTION gamilit.initialize_user_stats()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
-- Solo inicializar para roles elegibles
IF NEW.role IN ('student', 'admin_teacher', 'super_admin') THEN
-- Crear user_stats
INSERT INTO gamification_system.user_stats (
user_id, tenant_id, ml_coins, ml_coins_earned_total
) VALUES (NEW.user_id, NEW.tenant_id, 100, 100)
ON CONFLICT (user_id) DO NOTHING;
-- Crear user_ranks
INSERT INTO gamification_system.user_ranks (
user_id, tenant_id, current_rank, is_current
) VALUES (NEW.user_id, NEW.tenant_id, 'Ajaw', true)
ON CONFLICT (user_id, current_rank) DO NOTHING;
END IF;
RETURN NEW;
END;
$$;
SELECT 'Función initialize_user_stats creada' as status;
-- ============================================================================
-- FASE 10: TRIGGER DE INICIALIZACIÓN
-- ============================================================================
\echo ''
\echo 'FASE 10: Creando trigger de inicialización...'
DROP TRIGGER IF EXISTS trg_initialize_user_stats ON auth_management.profiles;
CREATE TRIGGER trg_initialize_user_stats
AFTER INSERT ON auth_management.profiles
FOR EACH ROW
EXECUTE FUNCTION gamilit.initialize_user_stats();
SELECT 'Trigger trg_initialize_user_stats creado' as status;
-- ============================================================================
-- FASE 11: INICIALIZAR USUARIOS EXISTENTES
-- ============================================================================
\echo ''
\echo 'FASE 11: Inicializando usuarios existentes...'
-- Crear user_stats para usuarios que no tienen
INSERT INTO gamification_system.user_stats (user_id, tenant_id, ml_coins, ml_coins_earned_total)
SELECT p.user_id, p.tenant_id, 100, 100
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_stats us WHERE us.user_id = p.user_id)
ON CONFLICT (user_id) DO NOTHING;
-- Crear user_ranks para usuarios que no tienen
INSERT INTO gamification_system.user_ranks (user_id, tenant_id, current_rank, is_current)
SELECT p.user_id, p.tenant_id, 'Ajaw'::gamification_system.maya_rank, true
FROM auth_management.profiles p
WHERE p.role IN ('student', 'admin_teacher', 'super_admin')
AND NOT EXISTS (SELECT 1 FROM gamification_system.user_ranks ur WHERE ur.user_id = p.user_id)
ON CONFLICT (user_id, current_rank) DO NOTHING;
SELECT 'Usuarios inicializados' as status;
-- ============================================================================
-- FASE 12: VERIFICACIÓN FINAL
-- ============================================================================
\echo ''
\echo 'FASE 12: Verificación final...'
\echo ''
SELECT '=== RESUMEN DE OBJETOS CREADOS ===' as titulo;
SELECT 'Tablas' as tipo, table_schema || '.' || table_name as objeto
FROM information_schema.tables
WHERE (table_schema = 'gamification_system' AND table_name IN ('user_stats', 'user_ranks', 'notifications', 'mission_templates', 'missions', 'maya_ranks'))
OR (table_schema = 'progress_tracking' AND table_name = 'module_progress')
OR (table_schema = 'educational_content' AND table_name = 'modules')
ORDER BY table_schema, table_name;
\echo ''
SELECT '=== CONTEO DE SEEDS ===' as titulo;
SELECT 'mission_templates' as tabla, COUNT(*) as registros FROM gamification_system.mission_templates
UNION ALL SELECT 'maya_ranks', COUNT(*) FROM gamification_system.maya_ranks
UNION ALL SELECT 'modules', COUNT(*) FROM educational_content.modules
UNION ALL SELECT 'user_stats', COUNT(*) FROM gamification_system.user_stats
UNION ALL SELECT 'user_ranks', COUNT(*) FROM gamification_system.user_ranks;
\echo ''
SELECT '=== TRIGGER VERIFICADO ===' as titulo;
SELECT tgname as trigger_name,
CASE tgenabled WHEN 'O' THEN 'ACTIVO' ELSE 'INACTIVO' END as estado
FROM pg_trigger
WHERE tgname = 'trg_initialize_user_stats';
\echo ''
\echo '=============================================='
\echo 'CORRECCIÓN COMPLETADA EXITOSAMENTE'
\echo '=============================================='
\echo ''
\echo 'Próximos pasos:'
\echo '1. Reiniciar el backend (PM2): pm2 restart gamilit-backend'
\echo '2. Probar registro de nuevo usuario'
\echo '3. Verificar que el dashboard carga sin errores'
\echo ''

View File

@ -0,0 +1,110 @@
#!/bin/bash
# ============================================================================
# SCRIPT DE EJECUCIÓN DE CORRECCIÓN - GAMILIT PRODUCCIÓN
# ============================================================================
# Uso: ./ejecutar-correccion.sh [host] [port] [database] [user]
# Ejemplo: ./ejecutar-correccion.sh 74.208.126.102 5432 gamilit_platform gamilit_user
# ============================================================================
set -e
# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Parámetros (con valores por defecto)
DB_HOST="${1:-localhost}"
DB_PORT="${2:-5432}"
DB_NAME="${3:-gamilit_platform}"
DB_USER="${4:-gamilit_user}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SQL_FILE="$SCRIPT_DIR/SCRIPT-CORRECCION-PRODUCCION.sql"
echo -e "${BLUE}=============================================="
echo "CORRECCIÓN DE BD PRODUCCIÓN - GAMILIT"
echo -e "==============================================${NC}"
echo ""
echo -e "Host: ${YELLOW}$DB_HOST${NC}"
echo -e "Puerto: ${YELLOW}$DB_PORT${NC}"
echo -e "Base: ${YELLOW}$DB_NAME${NC}"
echo -e "Usuario: ${YELLOW}$DB_USER${NC}"
echo ""
# Verificar que el archivo SQL existe
if [ ! -f "$SQL_FILE" ]; then
echo -e "${RED}ERROR: No se encontró el archivo SQL: $SQL_FILE${NC}"
exit 1
fi
# Confirmar ejecución
echo -e "${YELLOW}ADVERTENCIA: Este script modificará la base de datos.${NC}"
echo ""
read -p "¿Desea continuar? (s/n): " confirm
if [ "$confirm" != "s" ] && [ "$confirm" != "S" ]; then
echo -e "${RED}Operación cancelada.${NC}"
exit 0
fi
echo ""
echo -e "${BLUE}Verificando conexión...${NC}"
# Verificar conexión
if ! pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" > /dev/null 2>&1; then
echo -e "${RED}ERROR: No se puede conectar a la base de datos.${NC}"
echo "Verifique los parámetros de conexión."
exit 1
fi
echo -e "${GREEN}Conexión verificada.${NC}"
echo ""
# Solicitar contraseña
read -sp "Ingrese la contraseña de $DB_USER: " DB_PASSWORD
echo ""
echo ""
# Crear backup antes de ejecutar
BACKUP_FILE="backup_pre_correccion_$(date +%Y%m%d_%H%M%S).sql"
echo -e "${BLUE}Creando backup en: $BACKUP_FILE${NC}"
PGPASSWORD="$DB_PASSWORD" pg_dump \
-h "$DB_HOST" \
-p "$DB_PORT" \
-U "$DB_USER" \
-d "$DB_NAME" \
--schema=gamification_system \
--schema=progress_tracking \
--schema=educational_content \
-f "$SCRIPT_DIR/$BACKUP_FILE" 2>/dev/null || {
echo -e "${YELLOW}Advertencia: No se pudo crear backup completo (los schemas pueden no existir aún).${NC}"
}
echo ""
echo -e "${BLUE}Ejecutando script de corrección...${NC}"
echo ""
# Ejecutar el script SQL
PGPASSWORD="$DB_PASSWORD" psql \
-h "$DB_HOST" \
-p "$DB_PORT" \
-U "$DB_USER" \
-d "$DB_NAME" \
-f "$SQL_FILE"
echo ""
echo -e "${GREEN}=============================================="
echo "CORRECCIÓN COMPLETADA"
echo -e "==============================================${NC}"
echo ""
echo "Próximos pasos:"
echo "1. Reiniciar el backend: pm2 restart gamilit-backend"
echo "2. Probar registro de nuevo usuario"
echo "3. Verificar dashboard sin errores"
echo ""
echo -e "Backup guardado en: ${YELLOW}$SCRIPT_DIR/$BACKUP_FILE${NC}"
echo ""

View File

@ -0,0 +1,246 @@
# FASE 5: REPORTE DE EJECUCIÓN DE MIGRACIÓN
**Fecha:** 2025-12-18
**Perfil:** Requirements-Analyst
**Proyecto:** GAMILIT
---
## RESUMEN EJECUTIVO
| Sprint | Estado | Acciones Ejecutadas |
|--------|--------|---------------------|
| **Sprint 0: Seguridad** | ✅ COMPLETADO | 4 archivos de credenciales eliminados |
| **Sprint 1: Backend** | ✅ COMPLETADO | 6 servicios sincronizados |
| **Sprint 2: Frontend Crítico** | ✅ COMPLETADO | 4 archivos corregidos |
| **Sprint 3: Teacher Portal** | ✅ COMPLETADO | 7 componentes/hooks sincronizados |
| **Sprint 4: Database Scripts** | ✅ COMPLETADO | Estructura reorganizada + limpieza |
| **Sprint 5: Final** | ✅ COMPLETADO | Docs + páginas + configs sincronizados |
---
## DETALLES DE EJECUCIÓN
### Sprint 0: Mitigación de Seguridad
**Archivos Eliminados:**
```
✅ apps/database/scripts/README-VALIDATION-SCRIPTS.md (credenciales expuestas)
✅ apps/database/database-credentials-dev.txt
✅ apps/database/.env.database
✅ apps/database/.env.dev
```
**IMPORTANTE:** La contraseña `C5hq7253pdVyVKUC` fue expuesta. Se recomienda cambiarla en producción.
---
### Sprint 1: Sincronización Backend
**Servicios Copiados (ORIGEN → DESTINO):**
```
✅ modules/auth/services/password-recovery.service.ts
✅ modules/auth/services/email-verification.service.ts
✅ modules/progress/services/exercise-submission.service.ts
✅ modules/teacher/teacher.module.ts
✅ modules/teacher/services/analytics.service.ts
✅ modules/teacher/services/student-progress.service.ts
✅ modules/teacher/services/student-risk-alert.service.ts
✅ modules/websocket/notifications.gateway.ts
✅ modules/websocket/types/websocket.types.ts
```
**Mejoras Incluidas:**
- SessionManagementService inyectado (logout global post-reset)
- MailService activado (verificación email funcional)
- Logger estructurado (observabilidad mejorada)
---
### Sprint 2: Corrección Frontend Crítico
**Archivos Corregidos:**
1. **ExerciseContentRenderer.tsx** (DESTINO → ORIGEN)
- Agregado caso 'emparejamiento' faltante
- Icon Link2 incluido
2. **APIs con Error Handling** (DESTINO → ORIGEN)
```
✅ services/api/passwordAPI.ts
✅ services/api/profileAPI.ts
✅ services/api/missionsAPI.ts
```
---
### Sprint 3: Teacher Portal
**Componentes Sincronizados (ORIGEN → DESTINO):**
```
✅ apps/teacher/components/grading/RubricEvaluator.tsx
✅ apps/teacher/components/grading/index.ts
✅ apps/teacher/components/responses/ResponseDetailModal.tsx
✅ apps/teacher/hooks/useClassroomRealtime.ts
✅ apps/teacher/hooks/useMasteryTracking.ts
✅ apps/teacher/hooks/useMissionStats.ts
✅ features/mechanics/module1/Emparejamiento/EmparejamientoExerciseDragDrop.tsx
```
---
### Sprint 4: Limpieza Database Scripts
**Estructura Final:**
```
apps/database/scripts/
├── config/
│ ├── dev.conf
│ └── prod.conf
├── inventory/
│ └── list-*.sh (8 scripts)
├── testing/
│ └── CREAR-USUARIOS-TESTING.sql
├── validations/
│ ├── README.md
│ ├── validate-gap-fixes.sql
│ ├── validate-generate-alerts-joins.sql
│ └── VALIDACIONES-RAPIDAS-POST-RECREACION.sql
├── init-database.sh
├── init-database-v3.sh
├── recreate-database.sh
├── reset-database.sh
├── INDEX.md
├── QUICK-START.md
└── README.md
```
**Eliminado:**
```
✅ deprecated/ (versiones obsoletas)
✅ backup/, restore/, utilities/ (directorios vacíos)
✅ Scripts SQL dispersos en raíz
✅ Scripts Python temporales
✅ Logs de creación de BD
```
---
### Sprint 5: Sincronización Final
**Scripts de Deployment:**
```
✅ scripts/setup-ssl-certbot.sh
✅ scripts/validate-deployment.sh
✅ scripts/README.md
```
**Páginas Student Nuevas:**
```
✅ GamificationPage.tsx
✅ GamificationTestPage.tsx
✅ LoginPage.tsx
✅ NewLeaderboardPage.tsx
✅ PasswordRecoveryPage.tsx
✅ ProfilePage.tsx
✅ RegisterPage.tsx
✅ TwoFactorAuthPage.tsx
✅ admin/ (directorio completo)
```
**Documentación:**
```
✅ docs/95-guias-desarrollo/GUIA-DEPLOYMENT-RAPIDO.md
✅ docs/95-guias-desarrollo/GUIA-SSL-CERTBOT-DEPLOYMENT.md
```
**Configuración:**
```
✅ ecosystem.config.js
✅ package.json (frontend)
✅ CODEOWNERS → .github/CODEOWNERS
✅ .eslintrc.js/.eslintrc.cjs eliminados (obsoletos)
```
---
## DIFERENCIAS RESTANTES (ESPERADAS)
Las siguientes diferencias son **esperadas** y no requieren acción:
1. **Logs de aplicación** - Difieren por naturaleza
- `apps/backend/logs/combined.log`
- `apps/backend/logs/error.log`
2. **Logs de creación BD** - Solo existen en desarrollo activo
- `apps/database/create-database-*.log`
3. **MockData y Schemas obsoletos en DESTINO** - Archivos de desarrollo legacy
- `callToActionMockData.ts`, `callToActionSchemas.ts`, etc.
- No afectan funcionalidad, pueden eliminarse opcionalmente
4. **orchestration/ y .claude/** - Excluidos de sincronización por ser específicos de cada entorno
---
## VALIDACIONES PENDIENTES
### Recomendadas Antes de Producción
1. **Cambiar contraseña comprometida:**
```
Usuario: gamilit_user
Password antiguo: C5hq7253pdVyVKUC (EXPUESTO)
Acción: Cambiar en Supabase/PostgreSQL
```
2. **Ejecutar tests backend:**
```bash
cd /home/isem/workspace-old/.../apps/backend
npm run test
```
3. **Ejecutar build frontend:**
```bash
cd /home/isem/workspace-old/.../apps/frontend
npm run build
```
4. **Verificar router para nuevas páginas:**
- Confirmar que las rutas están configuradas en `App.tsx` o `routes/index.tsx`
---
## ARCHIVOS DE ANÁLISIS GENERADOS
| Documento | Ubicación |
|-----------|-----------|
| FASE1-ANALISIS-DIFERENCIAS.md | `orchestration/analisis-migracion-2025-12-18/` |
| FASE2-ANALISIS-DETALLADO.md | `orchestration/analisis-migracion-2025-12-18/` |
| FASE3-PLAN-IMPLEMENTACION.md | `orchestration/analisis-migracion-2025-12-18/` |
| FASE4-VALIDACION-DEPENDENCIAS.md | `orchestration/analisis-migracion-2025-12-18/` |
| FASE5-REPORTE-EJECUCION.md | `orchestration/analisis-migracion-2025-12-18/` |
---
## CONCLUSIÓN
**Estado Final:** ✅ MIGRACIÓN COMPLETADA EXITOSAMENTE
**Principales Logros:**
1. Vulnerabilidades de seguridad mitigadas (credenciales eliminadas)
2. Funcionalidad crítica restaurada (SessionManagementService, MailService)
3. Regresión corregida (EmparejamientoRenderer)
4. Estructura de scripts reorganizada y limpia
5. Documentación y páginas nuevas sincronizadas
**Próximos Pasos Recomendados:**
1. Cambiar contraseña de base de datos
2. Ejecutar tests para validar sincronización
3. Hacer commit de los cambios
4. Actualizar documentación de changelog
---
**Generado por:** Requirements-Analyst Agent
**Fecha:** 2025-12-18

View File

@ -0,0 +1,369 @@
# ANALISIS DE REQUERIMIENTOS - PRODUCCION GAMILIT
**Version:** 1.0.0
**Fecha:** 2025-12-18
**Analista:** Requirements-Analyst (SIMCO)
**Proyecto:** GAMILIT Platform
---
## RESUMEN EJECUTIVO
Este documento presenta el analisis detallado de los requerimientos para preparar el ambiente de produccion de GAMILIT, incluyendo:
1. **SSL/HTTPS:** Configuracion de certificados para backend y frontend
2. **Homologacion de Base de Datos:** Sincronizacion entre dev y prod
3. **Carga Inicial de Usuarios:** Validacion de mas de 30 usuarios, excluyendo rckrdmrd@gmail.com
---
## 1. CONFIGURACION SSL/HTTPS
### 1.1 Estado Actual
| Componente | Estado | Documentacion |
|------------|--------|---------------|
| Script `setup-ssl-certbot.sh` | DISPONIBLE | `/scripts/setup-ssl-certbot.sh` |
| Guia Certbot | COMPLETA | `docs/95-guias-desarrollo/GUIA-SSL-CERTBOT-DEPLOYMENT.md` |
| Guia SSL Nginx | COMPLETA | `docs/95-guias-desarrollo/GUIA-SSL-NGINX-PRODUCCION.md` |
| Guia SSL Autofirmado | COMPLETA | `docs/95-guias-desarrollo/GUIA-SSL-AUTOFIRMADO.md` |
| `.env.production.example` Backend | LISTO | `/apps/backend/.env.production.example` |
| `.env.production.example` Frontend | LISTO | `/apps/frontend/.env.production.example` |
### 1.2 Arquitectura SSL
```
Internet
|
v
+------------------+
| Puerto 80/443 |
| (Nginx) |
+--------+---------+
|
+--------------+--------------+
| | |
v v v
/api/* /socket.io /*
| | |
v v v
+------------+ +------------+ +------------+
| Backend | | WebSocket | | Frontend |
| :3006 | | :3006 | | :3005 |
+------------+ +------------+ +------------+
```
### 1.3 Opciones de Certificados SSL
#### Opcion A: Let's Encrypt (Recomendado para Produccion)
**Requisitos:**
- Dominio registrado (ej: gamilit.com)
- DNS A record apuntando al servidor (IP: 74.208.126.102)
- Puertos 80 y 443 abiertos
**Comando:**
```bash
chmod +x scripts/setup-ssl-certbot.sh
sudo ./scripts/setup-ssl-certbot.sh gamilit.com
```
**Variables de Entorno Resultantes:**
Backend (.env.production):
```env
CORS_ORIGIN=https://gamilit.com
FRONTEND_URL=https://gamilit.com
```
Frontend (.env.production):
```env
VITE_API_HOST=gamilit.com
VITE_API_PROTOCOL=https
VITE_WS_HOST=gamilit.com
VITE_WS_PROTOCOL=wss
```
#### Opcion B: Certificado Auto-firmado (Desarrollo/Staging)
**Comando:**
```bash
sudo ./scripts/setup-ssl-certbot.sh --self-signed
```
### 1.4 Validacion Post-SSL
```bash
# Validacion automatica
./scripts/validate-deployment.sh --ssl --verbose
# Validacion manual
curl -I https://gamilit.com
curl https://gamilit.com/api/health
echo | openssl s_client -connect gamilit.com:443 2>/dev/null | openssl x509 -noout -dates
```
### 1.5 Estado: LISTO PARA IMPLEMENTACION
- Script de configuracion SSL disponible
- Documentacion completa
- Templates de variables de entorno preparados
---
## 2. HOMOLOGACION DE BASE DE DATOS (DEV/PROD)
### 2.1 Estructura de Seeds
```
apps/database/seeds/
├── dev/ # Ambiente de desarrollo
│ ├── audit_logging/
│ ├── auth/
│ ├── auth_management/ # 14 archivos
│ ├── content_management/
│ ├── educational_content/
│ ├── gamification_system/
│ ├── notifications/
│ ├── progress_tracking/
│ ├── social_features/
│ └── system_configuration/
└── prod/ # Ambiente de produccion
├── audit_logging/
├── auth/
├── auth_management/ # 14 archivos + _deprecated/
├── content_management/
├── educational_content/
├── gamification_system/
├── lti_integration/
├── notifications/
├── progress_tracking/
├── social_features/
└── system_configuration/
```
### 2.2 Diferencias Detectadas
#### auth_management (HOMOLOGADO)
| Archivo | Dev | Prod | Estado |
|---------|-----|------|--------|
| 01-tenants.sql | SI | SI | OK |
| 02-auth_providers.sql | SI | SI | OK |
| 02-tenants-production.sql | SI | SI | OK |
| 03-profiles.sql | SI | SI | OK |
| 04-profiles-complete.sql | SI | SI | OK |
| 04-user_roles.sql | SI | SI | OK |
| 05-user_preferences.sql | SI | SI | OK |
| 06-auth_attempts.sql | SI | SI | OK |
| 06-profiles-production.sql | SI | SI | OK (13 perfiles) |
| 07-security_events.sql | SI | SI | OK |
| 07-user_roles.sql | SI | SI | OK |
| 08-assign-admin-schools.sql | SI | SI | OK |
| _deprecated/ | NO | SI | Solo en prod |
#### educational_content (DIFERENCIAS)
| Archivo | Dev | Prod | Estado |
|---------|-----|------|--------|
| 01-modules.sql | SI | SI | DIFIEREN |
| 01-test-exercises-validation.sql | SI | NO | Solo dev (test) |
| 02-test-nuevos-validadores-DB-117.sql | SI | NO | Solo dev (test) |
| 03-exercises-module2.sql | SI | SI | DIFIEREN |
| 04-exercises-module3.sql | SI | SI | DIFIEREN |
| 05-exercises-module4.sql | SI | SI | DIFIEREN |
| 06-exercises-module5.sql | SI | SI | DIFIEREN |
| 10-test-nuevos-validadores-FE-059.sql | SI | NO | Solo dev (test) |
### 2.3 Hallazgos Clave
1. **auth_management:** HOMOLOGADO CORRECTAMENTE
- Todos los archivos de prod coinciden con dev
- Carpeta `_deprecated/` solo existe en prod (esperado)
2. **educational_content:** DIFERENCIAS ACEPTABLES
- Archivos de test (01-test-*, 02-test-*, 10-test-*) solo en dev
- Contenido de ejercicios puede diferir entre ambientes
### 2.4 Estado: PARCIALMENTE HOMOLOGADO
- auth_management: COMPLETO
- educational_content: Archivos de test solo en dev (correcto)
---
## 3. CARGA INICIAL DE USUARIOS
### 3.1 Datos del Backup de Produccion
**Ubicacion:** `/apps/database/backup-prod/`
| Archivo | Registros | Descripcion |
|---------|-----------|-------------|
| auth_users_2025-12-18.csv | 48 | Usuarios de auth.users |
| profiles_2025-12-18.csv | 48 | Perfiles de auth_management.profiles |
| user_ranks_2025-12-18.csv | 49 | Rankings de gamification |
| user_stats_2025-12-18.csv | 49 | Estadisticas de gamification |
| RESTORE_USUARIOS_PRODUCCION_2025-12-18.sql | 194 inserts | Script de restauracion completo |
### 3.2 Validacion de Usuarios
#### Total de Usuarios: 48
- Estudiantes reales: 44
- Usuarios de testing: 3 (admin@gamilit.com, teacher@gamilit.com, student@gamilit.com)
- Nuevos usuarios recientes: 2 (javiermar06@hotmail.com, ju188an@gmail.com)
#### Exclusion Verificada
```
Usuario rckrdmrd@gmail.com: NO ENCONTRADO (CORRECTO)
```
#### Distribucion por Rol
| Rol | Cantidad |
|-----|----------|
| student | 45 |
| admin_teacher | 1 |
| super_admin | 1 |
### 3.3 Usuarios con Nombre Completo (Primeros 13)
| Email | Nombre |
|-------|--------|
| joseal.guirre34@gmail.com | Jose Aguirre |
| sergiojimenezesteban63@gmail.com | Sergio Jimenez |
| Gomezfornite92@gmail.com | Hugo Gomez |
| Aragon494gt54@icloud.com | Hugo Aragon |
| blu3wt7@gmail.com | Azul Valentina |
| ricardolugo786@icloud.com | Ricardo Lugo |
| marbancarlos916@gmail.com | Carlos Marban |
| diego.colores09@gmail.com | Diego Colores |
| hernandezfonsecabenjamin7@gmail.com | Benjamin Hernandez |
| jr7794315@gmail.com | Josue Reyes |
| barraganfer03@gmail.com | Fernando Barragan |
| roman.rebollar.marcoantonio1008@gmail.com | Marco Antonio Roman |
| rodrigoguerrero0914@gmail.com | Rodrigo Guerrero |
### 3.4 Usuarios Sin Nombre Completo (35 usuarios)
Usuarios registrados posteriormente sin first_name/last_name en metadata:
- santiagoferrara78@gmail.com
- alexanserrv917@gmail.com
- aarizmendi434@gmail.com
- (... y 32 mas)
### 3.5 Script de Restauracion
El archivo `RESTORE_USUARIOS_PRODUCCION_2025-12-18.sql` contiene:
- 49 usuarios en auth.users
- 48 perfiles en auth_management.profiles
- 49 user_ranks en gamification_system.user_ranks
- 49 user_stats en gamification_system.user_stats
**Uso:**
```bash
psql -U gamilit_user -d gamilit_platform -h localhost \
-f apps/database/backup-prod/RESTORE_USUARIOS_PRODUCCION_2025-12-18.sql
```
### 3.6 Estado: CUMPLE REQUISITOS
- Total usuarios: 48 (> 30 requeridos)
- rckrdmrd@gmail.com: NO INCLUIDO (correcto)
- Script de restauracion: DISPONIBLE
---
## 4. CHECKLIST DE IMPLEMENTACION
### 4.1 Pre-Deployment
- [x] Script SSL disponible (`setup-ssl-certbot.sh`)
- [x] Documentacion SSL completa
- [x] Templates de variables de entorno listos
- [x] Seeds de auth_management homologados
- [x] Backup de usuarios de produccion disponible
- [x] Script de restauracion de usuarios listo
- [x] Usuario rckrdmrd@gmail.com excluido verificado
### 4.2 Deployment SSL
```bash
# 1. Verificar prerequisitos
pm2 list # Backend y Frontend activos
sudo ufw status # Puertos 80, 443 abiertos
dig +short gamilit.com # DNS configurado
# 2. Ejecutar configuracion SSL
cd /home/isem/workspace/projects/gamilit
chmod +x scripts/setup-ssl-certbot.sh
sudo ./scripts/setup-ssl-certbot.sh gamilit.com
# 3. Validar
./scripts/validate-deployment.sh --ssl --verbose
```
### 4.3 Carga de Usuarios
```bash
# 1. Verificar conexion a base de datos
psql -U gamilit_user -d gamilit_platform -h localhost -c "SELECT 1"
# 2. Ejecutar restauracion
psql -U gamilit_user -d gamilit_platform -h localhost \
-f apps/database/backup-prod/RESTORE_USUARIOS_PRODUCCION_2025-12-18.sql
# 3. Verificar cantidad
psql -U gamilit_user -d gamilit_platform -h localhost \
-c "SELECT COUNT(*) FROM auth.users"
```
---
## 5. RIESGOS Y MITIGACIONES
### 5.1 SSL/HTTPS
| Riesgo | Probabilidad | Impacto | Mitigacion |
|--------|--------------|---------|------------|
| DNS no propagado | Media | Alto | Esperar 24-48h antes de deploy |
| Puerto 80/443 bloqueado | Baja | Alto | Verificar firewall pre-deploy |
| Certificado expira | Baja | Alto | Timer de renovacion automatica |
### 5.2 Base de Datos
| Riesgo | Probabilidad | Impacto | Mitigacion |
|--------|--------------|---------|------------|
| Conflicto de IDs | Media | Alto | Usar ON CONFLICT DO UPDATE |
| Permisos insuficientes | Baja | Alto | Verificar rol gamilit_user |
| Triggers causan errores | Baja | Medio | SET session_replication_role = replica |
---
## 6. PROXIMOS PASOS
1. **Dominio:** Confirmar dominio final (gamilit.com o subdominio)
2. **DNS:** Configurar A record apuntando a 74.208.126.102
3. **SSL:** Ejecutar script de configuracion
4. **Usuarios:** Ejecutar restauracion si es base de datos nueva
5. **Validacion:** Ejecutar suite de pruebas post-deployment
---
## 7. REFERENCIAS
### Documentacion Relacionada
- `docs/95-guias-desarrollo/GUIA-SSL-CERTBOT-DEPLOYMENT.md`
- `docs/95-guias-desarrollo/GUIA-SSL-NGINX-PRODUCCION.md`
- `docs/95-guias-desarrollo/GUIA-DEPLOYMENT-RAPIDO.md`
- `docs/95-guias-desarrollo/GUIA-CORS-PRODUCCION.md`
### Scripts
- `/scripts/setup-ssl-certbot.sh` - Configuracion SSL automatica
- `/scripts/validate-deployment.sh` - Validacion post-deployment
- `/apps/database/backup-prod/RESTORE_USUARIOS_PRODUCCION_2025-12-18.sql`
---
**Fecha de Analisis:** 2025-12-18
**Proximo Review:** Antes del deployment a produccion

View File

@ -1,7 +1,7 @@
# RESUMEN EJECUTIVO: ANÁLISIS PORTAL TEACHER GAMILIT
**Fecha**: 18 Diciembre 2025
**Versión**: 1.0
**Versión**: 1.1 (Actualizado con Gap Critico G20)
**Rol**: Requirements-Analyst (Consolidación)
---
@ -65,6 +65,9 @@
| G02 | Mecánicas | Emparejamiento no envía a backend | Progreso no persiste |
| G03 | Mecánicas | Mecánicas manuales sin visualización | Teacher no puede evaluar |
| G04 | Backend | NotificationService no integrado | Alertas sin notificar |
| ~~G20~~ | ~~Backend~~ | ~~Responses Page lee tabla incorrecta~~ | ✅ **CORREGIDO** |
> **GAP G20 CORREGIDO**: El servicio `ExerciseResponsesService` ahora consulta AMBAS tablas (`exercise_attempts` + `exercise_submissions`) usando UNION. Ver documento `50-GAP-CRITICO-RESPONSES-PAGE.md` para detalles de la implementación.
### P1 - ALTA (Afectan funcionalidad core)
@ -111,18 +114,40 @@
│ │ Panel │ │ (funcional) │ (falta) │
│ └──────────┘ └───────────────┘ │
│ │
│ Student Portal Teacher Portal │
│ ┌──────────┐ ┌───────────────┐ │
│ │ Empareja │──────X──────→│ No recibe │ │
│ │ miento │ (no envía) │ submissions │ │
│ └──────────┘ └───────────────┘ │
│ │
│ Database Backend │
│ ┌──────────┐ ┌───────────────┐ │
│ │ teacher_ │──────────────│ TeacherNotes │ │
│ │ notes │ sin RLS │ Service │ │
│ └──────────┘ └───────────────┘ │
│ │
*** GAP G20 - RESPONSES PAGE (✅ CORREGIDO) *** │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Student Portal Teacher Portal │ │
│ │ ┌────────────┐ ┌────────────────┐ │ │
│ │ │ Submit │ │ ResponsesPage │ │ │
│ │ │ Ejercicio │ │ /teacher/ │ │ │
│ │ │ │ │ responses │ │ │
│ │ └─────┬──────┘ └───────┬────────┘ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ ┌────────────┐ ┌────────────────┐ │ │
│ │ │ exercise_ │◄─────────│ UNION QUERY │ │ │
│ │ │ submissions│ │ attempts + │ │ │
│ │ │ (M4-M5) │ │ submissions │ │ │
│ │ └────────────┘ └────────────────┘ │ │
│ │ ▲ ▲ │ │
│ │ │ │ │ │
│ │ ┌────────────┐ │ │ │
│ │ │ exercise_ │──────────────────┘ │ │
│ │ │ attempts │ │ │
│ │ │ (M1-M3) │ │ │
│ │ └────────────┘ │ │
│ │ │ │
│ │ ✅ CORREGIDO: Teacher VE todas las respuestas │ │
│ │ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
@ -131,10 +156,11 @@
## RECOMENDACIONES POR FASE
### FASE INMEDIATA (Sprint actual)
1. Corregir mock data → consumir APIs reales
2. Forzar submit en Emparejamiento
3. Habilitar RLS en teacher_notes
4. Crear índices críticos
1. ~~**[G20 - CRITICO]** Modificar `ExerciseResponsesService` para consultar AMBAS tablas~~ ✅ COMPLETADO
2. Corregir mock data → consumir APIs reales
3. Forzar submit en Emparejamiento
4. Habilitar RLS en teacher_notes
5. Crear índices críticos
### FASE CORTO PLAZO (1-2 sprints)
1. Implementar visualización de mecánicas manuales

View File

@ -0,0 +1,317 @@
# GAP CRITICO: Responses Page No Muestra Datos Reales
**Fecha**: 18 Diciembre 2025
**Analista**: Requirements-Analyst
**Prioridad**: P0 - CRITICO (Bloquea funcionalidad core)
**Estado**: ✅ CORREGIDO - Implementación completada
---
## CORRECCION APLICADA
**Fecha de corrección**: 19 Diciembre 2025
### Archivos Modificados
| Archivo | Cambio |
|---------|--------|
| `apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts` | Agregados enums `ResponseSource`, `SubmissionStatus` y campos `source`, `status`, `feedback`, `requires_manual_grading` |
| `apps/backend/src/modules/teacher/services/exercise-responses.service.ts` | Método `getAttempts()` ahora usa UNION de ambas tablas; `getAttemptDetail()` busca en ambas tablas |
### Cambios Clave
1. **UNION Query**: El método `getAttempts()` ahora consulta:
- `progress_tracking.exercise_attempts` (ejercicios autocorregibles)
- `progress_tracking.exercise_submissions` (ejercicios de revisión manual)
2. **Nuevo campo `source`**: Indica de qué tabla proviene cada registro (`attempt` o `submission`)
3. **Filtro por status**: Excluye automáticamente submissions con status `draft`
4. **getAttemptDetail mejorado**: Busca primero en `exercise_attempts`, si no encuentra busca en `exercise_submissions`
---
## RESUMEN EJECUTIVO
El Teacher Portal tiene un gap critico: la pagina de Responses (`/teacher/responses`) **NO muestra las respuestas de los estudiantes** porque consulta la tabla incorrecta.
| Aspecto | Estado Actual | Estado Esperado |
|---------|---------------|-----------------|
| Tabla consultada | `exercise_attempts` | `exercise_submissions` + `exercise_attempts` |
| Datos visibles | 0 o datos antiguos | Todas las respuestas |
| Funcionalidad | ROTA | FUNCIONAL |
---
## ANALISIS DEL PROBLEMA
### Arquitectura Dual de Tablas
El sistema GAMILIT tiene **dos tablas** para almacenar respuestas de ejercicios:
```
┌─────────────────────────────────────────────────────────────────────┐
│ FLUJO ACTUAL (ROTO) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ESTUDIANTE TEACHER PORTAL │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Completa │ │ Responses Page │ │
│ │ Ejercicio │ │ /teacher/ │ │
│ │ │ │ responses │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ POST /progress/ │ │ GET /teacher/ │ │
│ │ submissions/ │ │ attempts │ │
│ │ submit │ │ │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ exercise_ │ │ exercise_ │ │
│ │ submissions │─────╳─────────│ attempts │ │
│ │ (AQUI ESTAN │ │ (AQUI BUSCA) │ │
│ │ LOS DATOS!) │ │ │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ ❌ NO HAY CONEXION - EL TEACHER NO VE LAS RESPUESTAS │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
### Tabla 1: `exercise_submissions`
**Proposito**: Ejercicios que requieren revision manual (Modulos 4 y 5)
- Archivo DDL: `apps/database/ddl/schemas/progress_tracking/tables/04-exercise_submissions.sql`
- Campo de respuestas: `answer_data` (JSONB)
- Estados: draft, submitted, graded, reviewed
- Tiene: `feedback`, `graded_at`, columnas de revision manual
**Servicio que escribe**: `ExerciseSubmissionService.submitExercise()`
- Endpoint: `POST /progress/submissions/submit`
- Usado por: Frontend de estudiantes (`progressAPI.ts`)
### Tabla 2: `exercise_attempts`
**Proposito**: Ejercicios autocorregibles (multiples intentos)
- Archivo DDL: `apps/database/ddl/schemas/progress_tracking/tables/03-exercise_attempts.sql`
- Campo de respuestas: `submitted_answers` (JSONB)
- Sin estados de workflow - solo registro de intentos
**Servicio que lee**: `ExerciseResponsesService.getAttempts()`
- Endpoint: `GET /teacher/attempts`
- Usado por: Teacher Portal Responses Page
---
## EVIDENCIA DEL GAP
### 1. Frontend de Estudiantes (progressAPI.ts:384-385)
```typescript
// Backend endpoint: POST /api/progress/submissions/submit
const backendPayload = {
userId,
exerciseId,
answers,
};
const { data } = await apiClient.post<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 ✅ │
├─────────────────────────────────────────────────────────────┤
│ │
│ ESTUDIANTE TEACHER PORTAL │
│ ┌────────────┐ ┌────────────┐ │
│ │ Submit │ │ Responses │ │
│ │ Ejercicio │ │ Page │ │
│ └─────┬──────┘ └──────┬─────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ exercise_ │ │ UNION QUERY │ │
│ │ SUBMISSIONS │◄─────────│ attempts + │ │
│ │ (M4-M5) │ │ submissions │ │
│ └────────────────┘ └────────────────┘ │
│ │ ▲ │
│ │ │ │
│ ┌────────────────┐ │ │
│ │ exercise_ │─────────────────────┘ │
│ │ ATTEMPTS │ │
│ │ (M1-M3) │ │
│ └────────────────┘ │
│ │
│ ✅ CONEXION COMPLETA - Teacher VE todas las respuestas │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## DEPENDENCIAS
- RLS policies ya existen para `exercise_submissions` (linea 168 del DDL)
- El frontend ya maneja el formato de respuesta (no requiere cambios mayores)
---
## SIGUIENTE PASO
**ACCION INMEDIATA**: Implementar Opcion A - Modificar `ExerciseResponsesService` para consultar ambas tablas con UNION.
---
*Analisis realizado: 2025-12-18*
*Proyecto: GAMILIT - Portal Teacher*
*Gap ID: G-RESPONSES-001*