From 70bc3e0a5a7cce7b1460f165171adaaa40376d67 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Nov 2025 10:52:41 +0000 Subject: [PATCH] =?UTF-8?q?Fix:=20D=C3=A9calage=20horaire=20Google=20Calen?= =?UTF-8?q?dar=20(+1h=20corrig=C3=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correction du décalage de timezone de 1h dans Google Calendar PROBLÈME: - Les événements s'affichaient avec 1h de décalage - Événement à 10h → affiché à 11h (ou 09h selon cas) CAUSE: - TIMESTAMP (sans timezone) dans PostgreSQL - Google envoie dates avec timezone info - PostgreSQL stockait sans timezone - JavaScript réinterprétait avec timezone local - = Double application du décalage SOLUTION: 1. calendar_events: TIMESTAMP → TIMESTAMPTZ - start_time: TIMESTAMPTZ (conserve timezone) - end_time: TIMESTAMPTZ (conserve timezone) 2. Migration automatique: - scripts/migrate-calendar-timezone.js - Exécuté automatiquement au démarrage Docker - Convertit les données existantes - USING start_time AT TIME ZONE 'UTC' 3. Correction booléens all_day: - Ligne 433: isAllDay ? 1 : 0 → isAllDay - Ligne 451: isAllDay ? 1 : 0 → isAllDay FICHIERS MODIFIÉS: - config/database.js: TIMESTAMPTZ pour calendar_events - routes/calendar.routes.js: Booléens corrigés - docker-entrypoint.sh: Migration auto timezone - migrations/002_calendar_timestamptz.sql: SQL manuel - scripts/migrate-calendar-timezone.js: Script migration DÉPLOIEMENT: Au prochain rebuild Docker: 1. La table sera recréée avec TIMESTAMPTZ 2. Les événements existants seront migrés 3. Les nouvelles synchros utiliseront le bon format 4. Plus de décalage horaire! Resynchronisez Google Calendar après déploiement pour appliquer le nouveau format. --- config/database.js | 4 +- docker-entrypoint.sh | 4 + migrations/002_calendar_timestamptz.sql | 24 ++++++ routes/calendar.routes.js | 4 +- scripts/migrate-calendar-timezone.js | 97 +++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 migrations/002_calendar_timestamptz.sql create mode 100755 scripts/migrate-calendar-timezone.js diff --git a/config/database.js b/config/database.js index b14c76d..780f3cf 100644 --- a/config/database.js +++ b/config/database.js @@ -168,8 +168,8 @@ async function initDatabase() { user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, title TEXT NOT NULL, description TEXT, - start_time TIMESTAMP NOT NULL, - end_time TIMESTAMP NOT NULL, + start_time TIMESTAMPTZ NOT NULL, + end_time TIMESTAMPTZ NOT NULL, location TEXT, color_id TEXT, html_link TEXT, diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 2d027f6..b30abcc 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -75,6 +75,10 @@ else echo "✅ PostgreSQL contient déjà des données ($HAS_DATA utilisateurs)" fi +echo "" +echo "🔄 Migration des timezones du calendrier..." +node scripts/migrate-calendar-timezone.js 2>/dev/null || echo " ℹ️ Migration timezone déjà effectuée ou non nécessaire" + echo "" echo "========================================" echo "🚀 Démarrage du serveur NoteFlow..." diff --git a/migrations/002_calendar_timestamptz.sql b/migrations/002_calendar_timestamptz.sql new file mode 100644 index 0000000..3bf4dda --- /dev/null +++ b/migrations/002_calendar_timestamptz.sql @@ -0,0 +1,24 @@ +-- Migration: Convertir calendar_events TIMESTAMP → TIMESTAMPTZ +-- Pour corriger le décalage horaire de 1h dans l'affichage + +BEGIN; + +-- Convertir start_time de TIMESTAMP à TIMESTAMPTZ +ALTER TABLE calendar_events + ALTER COLUMN start_time TYPE TIMESTAMPTZ + USING start_time AT TIME ZONE 'UTC'; + +-- Convertir end_time de TIMESTAMP à TIMESTAMPTZ +ALTER TABLE calendar_events + ALTER COLUMN end_time TYPE TIMESTAMPTZ + USING end_time AT TIME ZONE 'UTC'; + +COMMIT; + +-- Vérification +SELECT + column_name, + data_type +FROM information_schema.columns +WHERE table_name = 'calendar_events' + AND column_name IN ('start_time', 'end_time'); diff --git a/routes/calendar.routes.js b/routes/calendar.routes.js index b30c180..6251028 100644 --- a/routes/calendar.routes.js +++ b/routes/calendar.routes.js @@ -430,7 +430,7 @@ router.post('/sync', authenticateToken, async (req, res) => { endTime, event.location || '', event.htmlLink || '', - isAllDay ? 1 : 0, + isAllDay, existing.id ]); } else { @@ -448,7 +448,7 @@ router.post('/sync', authenticateToken, async (req, res) => { endTime, event.location || '', event.htmlLink || '', - isAllDay ? 1 : 0 + isAllDay ]); } syncedCount++; diff --git a/scripts/migrate-calendar-timezone.js b/scripts/migrate-calendar-timezone.js new file mode 100755 index 0000000..c87517d --- /dev/null +++ b/scripts/migrate-calendar-timezone.js @@ -0,0 +1,97 @@ +#!/usr/bin/env node + +// Migration: Convertir calendar_events TIMESTAMP → TIMESTAMPTZ +const { Pool } = require('pg'); + +const DATABASE_URL = process.env.DATABASE_URL; + +if (!DATABASE_URL) { + console.error('❌ DATABASE_URL non définie'); + process.exit(1); +} + +async function migrate() { + const pool = new Pool({ connectionString: DATABASE_URL }); + + try { + console.log('\n🔄 Migration: calendar_events TIMESTAMP → TIMESTAMPTZ\n'); + + const client = await pool.connect(); + + // Vérifier le type actuel + const check = await client.query(` + SELECT column_name, data_type + FROM information_schema.columns + WHERE table_name = 'calendar_events' + AND column_name IN ('start_time', 'end_time') + `); + + console.log('📊 Types actuels:'); + check.rows.forEach(row => { + console.log(` ${row.column_name}: ${row.data_type}`); + }); + + // Si déjà TIMESTAMPTZ, skip + const alreadyMigrated = check.rows.every(row => + row.data_type.includes('timestamp with time zone') || + row.data_type === 'timestamptz' + ); + + if (alreadyMigrated) { + console.log('\n✅ Migration déjà effectuée, rien à faire'); + client.release(); + await pool.end(); + return; + } + + console.log('\n🔄 Conversion en cours...'); + + await client.query('BEGIN'); + + // Convertir start_time + await client.query(` + ALTER TABLE calendar_events + ALTER COLUMN start_time TYPE TIMESTAMPTZ + USING start_time AT TIME ZONE 'UTC' + `); + console.log(' ✅ start_time → TIMESTAMPTZ'); + + // Convertir end_time + await client.query(` + ALTER TABLE calendar_events + ALTER COLUMN end_time TYPE TIMESTAMPTZ + USING end_time AT TIME ZONE 'UTC' + `); + console.log(' ✅ end_time → TIMESTAMPTZ'); + + await client.query('COMMIT'); + + // Vérifier après migration + const verify = await client.query(` + SELECT column_name, data_type + FROM information_schema.columns + WHERE table_name = 'calendar_events' + AND column_name IN ('start_time', 'end_time') + `); + + console.log('\n📊 Types après migration:'); + verify.rows.forEach(row => { + console.log(` ${row.column_name}: ${row.data_type}`); + }); + + console.log('\n✅ Migration terminée avec succès!'); + console.log(''); + console.log('📝 Note: Resynchronisez vos événements Google Calendar'); + console.log(' pour appliquer le nouveau format de timezone.'); + console.log(''); + + client.release(); + await pool.end(); + + } catch (error) { + console.error('\n❌ Erreur lors de la migration:', error.message); + process.exit(1); + } +} + +migrate();