import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import pg from 'pg'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const pool = new pg.Pool({ connectionString: 'postgresql://edumanager:EduManager2026!Seguro@150.230.87.131:5432/edumanager' }); const photoMapping = { // 1. ANA CLARA DA SILVA NASCIMENTO (17:57:55) 'e917ffe5-70d6-451e-9120-7692ec8d7024': '/storage/fotos-alunos/student_1777139875689_4l971l.webp', // 2. ANTÔNIA CERMILANE PEREIRA PINHEIRO (17:58:31) 'b9a7ddee-e03f-411f-9ef2-d22629d38e35': '/storage/fotos-alunos/student_1777139911929_21v6av.webp', // 3. DOUGLAS EMANUEL DE SOUSA PEREIRA (17:59:02) '0ab24299-f583-40eb-8812-d6005ebc50a8': '/storage/fotos-alunos/student_1777139942925_aoxyls.webp', // 4. EVILLA PINHEIRO DA SILVA BORGES (18:00:08) '311709fb-68ab-4168-8684-887b5ec2d731': '/storage/fotos-alunos/student_1777140008401_3966cd.webp', // 5. GABRIELY CAETANO DA SILVA (18:00:38) '0ef75207-3ab1-4524-b737-b543e804d3f0': '/storage/fotos-alunos/student_1777140038192_xntcja.webp', // 6. KARLA BIANCA PINHEIRO TRINDADE (18:01:06) 'c7e2d021-52ab-4229-8550-1aa8549507b3': '/storage/fotos-alunos/student_1777140066701_dfzecd.webp', // 7. NAPOLEÃO DA SILVA CARDOSO (18:01:38) '3653aea3-7e7e-49d6-b372-068863084a27': '/storage/fotos-alunos/student_1777140098875_tcan7k.webp', // 8. Sidney Gomes da silva (15:01) '5a231b04-b95c-4026-ba37-bc7b8144f646': '/storage/fotos-alunos/student_1776870119652_z0tdgp.webp', // 9. MARIA LOHANNY ROQUE DA SILVA (May 2) '05de4757-d36f-4de6-9e57-5792d13ad3e7': '/storage/fotos-alunos/student_1777743393187_rf50t.webp' }; async function run() { const backupPath = path.join(__dirname, '../backup_supabase_2026-04-19.json'); console.log(`Lendo dados completos do backup original de: ${backupPath}`); if (!fs.existsSync(backupPath)) { console.error('ERRO: Arquivo de backup original não encontrado!'); process.exit(1); } const raw = fs.readFileSync(backupPath, 'utf8'); const backupData = JSON.parse(raw); const backupStudents = backupData.students || []; try { // 1. Atualizar registros individuais na tabela alunos console.log('Atualizando a tabela "alunos" no PostgreSQL...'); for (const bs of backupStudents) { const mappedPhoto = photoMapping[bs.id]; if (!mappedPhoto) continue; const birthDate = bs.birthDate ? bs.birthDate.split('T')[0] : null; const rgIssueDate = bs.rgIssueDate ? bs.rgIssueDate.split('T')[0] : null; const guardianBirthDate = bs.guardianBirthDate ? bs.guardianBirthDate.split('T')[0] : null; const registrationDate = bs.registrationDate ? bs.registrationDate.split('T')[0] : null; const query = ` UPDATE alunos SET rg = $1, data_nascimento = $2, rg_data_emissao = $3, cep = $4, rua = $5, numero = $6, bairro = $7, cidade = $8, estado = $9, tem_responsavel = $10, nome_responsavel = $11, cpf_responsavel = $12, telefone_responsavel = $13, data_nascimento_responsavel = $14, numero_matricula = $15, data_matricula = $16, modelo_contrato_id = $17, foto_url = $18, senha_portal = $19 WHERE id = $20 `; const values = [ bs.rg || '', birthDate, rgIssueDate, bs.addressZip || '', bs.addressStreet || '', bs.addressNumber || '', bs.addressNeighborhood || '', bs.addressCity || '', bs.addressState || '', bs.hasGuardian || false, bs.guardianName || '', bs.guardianCpf || '', bs.guardianPhone || '', guardianBirthDate, bs.enrollmentNumber || null, registrationDate, bs.contractTemplateId || 'default-template', mappedPhoto, bs.portalPassword || null, bs.id ]; await pool.query(query, values); console.log(`✅ [SQL] Restaurado e Vinculado: ${bs.name} (${bs.id}) -> ${mappedPhoto}`); } // 2. Buscar, atualizar e salvar o espelho JSONB em school_data console.log('\nSincronizando espelho JSONB na tabela "school_data"...'); const { rows } = await pool.query('SELECT data FROM school_data WHERE id = 1'); const schoolData = rows[0]?.data; if (!schoolData) { console.error('ERRO: Registro do school_data com ID=1 não encontrado!'); return; } let updatedJsonCount = 0; if (schoolData.students && Array.isArray(schoolData.students)) { for (const s of schoolData.students) { const bs = backupStudents.find(x => x.id === s.id); const mappedPhoto = photoMapping[s.id]; if (bs && mappedPhoto) { s.photo = mappedPhoto; s.foto_url = mappedPhoto; s.birthDate = bs.birthDate; s.rg = bs.rg || ''; s.rgIssueDate = bs.rgIssueDate; s.addressZip = bs.addressZip || ''; s.addressStreet = bs.addressStreet || ''; s.addressNumber = bs.addressNumber || ''; s.addressNeighborhood = bs.addressNeighborhood || ''; s.addressCity = bs.addressCity || ''; s.addressState = bs.addressState || ''; s.hasGuardian = bs.hasGuardian || false; s.guardianName = bs.guardianName || ''; s.guardianCpf = bs.guardianCpf || ''; s.guardianPhone = bs.guardianPhone || ''; s.guardianBirthDate = bs.guardianBirthDate; s.enrollmentNumber = bs.enrollmentNumber || null; s.registrationDate = bs.registrationDate; s.portalPassword = bs.portalPassword || null; updatedJsonCount++; console.log(`✅ [JSONB] Atualizado no mirror: ${s.name} (${s.id})`); } } // Salvar de volta ao banco de dados usando COMMIT para persistir a gravação em modo leitura/gravação await pool.query('COMMIT'); await pool.query('BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED'); await pool.query('UPDATE school_data SET data = $1 WHERE id = 1', [JSON.stringify(schoolData)]); await pool.query('COMMIT'); console.log(`\n🎉 Sincronização concluída! ${updatedJsonCount} registros atualizados com sucesso no JSONB.`); } } catch (err) { console.error('ERRO CRÍTICO DURANTE A RESTAURAÇÃO:', err); } finally { await pool.end(); } } run();