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:
parent
fa07affd30
commit
5704222b85
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
||||
@ -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.**
|
||||
@ -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**
|
||||
@ -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**
|
||||
@ -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**
|
||||
@ -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**
|
||||
@ -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.**
|
||||
@ -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 ''
|
||||
@ -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 ""
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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*
|
||||
Loading…
Reference in New Issue
Block a user