mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
Add: Système de logging complet pour débuguer le décalage horaire
Ajout d'un système de logging exhaustif pour tracer le flux complet des dates depuis Google Calendar jusqu'à l'affichage dans NoteFlow. FICHIERS MODIFIÉS: 1. config/database.js: - Logs détaillés dans le parser TIMESTAMPTZ - Affiche l'input, la transformation et l'output - Différencie les dates avec/sans timezone 2. routes/calendar.routes.js: - Logs lors de la synchronisation Google Calendar - Affiche ce que Google renvoie (format brut) - Affiche la conversion en UTC et l'affichage Paris - Logs lors de la récupération des événements (GET /events) - Nouvel endpoint GET /api/calendar/debug pour diagnostic complet 3. DEBUG-TIMEZONE-LOGS.md: - Documentation complète du système de logging - Procédure étape par étape pour débuguer - Commandes utiles pour analyser les logs - Guide d'interprétation des résultats ENDPOINT DE DIAGNOSTIC AJOUTÉ: GET /api/calendar/debug renvoie: - Timezone du serveur Node.js - Timezone de PostgreSQL - Un événement exemple avec toutes ses représentations - Test de parsing complet (input → output → display) UTILISATION: 1. Rebuild avec: docker-compose build --no-cache notes-app 2. Supprimer les événements: DELETE FROM calendar_events 3. Lancer les logs: docker-compose logs -f notes-app 4. Synchroniser Google Calendar 5. Analyser les logs pour identifier où se produit le décalage Les logs permettront de voir EXACTEMENT: - Ce que Google Calendar renvoie - Comment c'est stocké dans PostgreSQL - Comment le parser le transforme - Comment le frontend l'affiche
This commit is contained in:
3 files changed
+329
-6
No files matched your search
@@ -0,0 +1,211 @@
|
||||
# 🔍 SYSTÈME DE LOGGING POUR DÉBUGUER LE TIMEZONE
|
||||
|
||||
Ce document explique comment utiliser le système de logging complet pour identifier le problème de décalage horaire.
|
||||
|
||||
## 📋 Logs ajoutés
|
||||
|
||||
### 1. **Parser PostgreSQL** (`config/database.js`)
|
||||
Logs chaque conversion TIMESTAMPTZ → ISO string
|
||||
|
||||
### 2. **Synchronisation Google Calendar** (`routes/calendar.routes.js`)
|
||||
Logs ce que Google renvoie et ce qui est stocké
|
||||
|
||||
### 3. **Récupération des événements** (`routes/calendar.routes.js`)
|
||||
Logs ce qui est lu de la DB et envoyé au frontend
|
||||
|
||||
### 4. **Endpoint de diagnostic** (`GET /api/calendar/debug`)
|
||||
Affiche un rapport complet du traitement
|
||||
|
||||
---
|
||||
|
||||
## 🚀 PROCÉDURE COMPLÈTE
|
||||
|
||||
### **ÉTAPE 1 : Rebuild avec les logs**
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose build --no-cache notes-app
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### **ÉTAPE 2 : Supprimer les anciens événements**
|
||||
|
||||
```bash
|
||||
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 \
|
||||
-c "DELETE FROM calendar_events"
|
||||
```
|
||||
|
||||
### **ÉTAPE 3 : Activer les logs debug**
|
||||
|
||||
Suivre les logs en temps réel :
|
||||
|
||||
```bash
|
||||
docker-compose logs -f notes-app
|
||||
```
|
||||
|
||||
### **ÉTAPE 4 : Synchroniser avec Google Calendar**
|
||||
|
||||
1. Ouvrez http://localhost:2222
|
||||
2. Allez dans Admin → Google Calendar
|
||||
3. Cliquez sur "🔄 Synchroniser"
|
||||
|
||||
**Observez les logs** dans votre terminal :
|
||||
|
||||
```
|
||||
[SYNC CALENDAR] Événement: "Dr Julian Wlodarczak"
|
||||
[SYNC CALENDAR] - Google startTime brut: {"dateTime":"2024-11-17T10:20:00+01:00"}
|
||||
[SYNC CALENDAR] - startTime extrait: "2024-11-17T10:20:00+01:00"
|
||||
[SYNC CALENDAR] - Type: string
|
||||
[SYNC CALENDAR] - new Date(startTime): 2024-11-17T09:20:00.000Z
|
||||
[SYNC CALENDAR] - Affichage Paris: 17/11/2024 10:20:00
|
||||
```
|
||||
|
||||
**Puis le parser PostgreSQL** :
|
||||
|
||||
```
|
||||
[PARSER TIMESTAMPTZ] Input avec TZ: "2024-11-17 09:20:00+00" → Output: "2024-11-17T09:20:00.000Z"
|
||||
```
|
||||
|
||||
**OU**
|
||||
|
||||
```
|
||||
[PARSER TIMESTAMPTZ] Input sans TZ: "2024-11-17 09:20:00" → ISO+Z: "2024-11-17T09:20:00Z" → Output: "2024-11-17T09:20:00.000Z"
|
||||
```
|
||||
|
||||
### **ÉTAPE 5 : Récupérer les événements**
|
||||
|
||||
Rechargez la page NoteFlow et observez les logs :
|
||||
|
||||
```
|
||||
[GET /events] "Dr Julian Wlodarczak"
|
||||
[GET /events] - start_time de la DB: "2024-11-17T09:20:00.000Z" (type: string)
|
||||
[GET /events] - new Date(): 2024-11-17T09:20:00.000Z
|
||||
[GET /events] - Affichage Paris: 10:20
|
||||
```
|
||||
|
||||
### **ÉTAPE 6 : Utiliser l'endpoint de diagnostic**
|
||||
|
||||
Appelez l'endpoint de diagnostic pour voir un rapport complet :
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer VOTRE_TOKEN" \
|
||||
http://localhost:2222/api/calendar/debug | jq
|
||||
```
|
||||
|
||||
**OU** avec le navigateur :
|
||||
|
||||
1. Ouvrez http://localhost:2222
|
||||
2. Ouvrez la console développeur (F12)
|
||||
3. Exécutez :
|
||||
```javascript
|
||||
fetch('/api/calendar/debug', {
|
||||
headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(console.log)
|
||||
```
|
||||
|
||||
**Résultat attendu** :
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2024-11-17T...",
|
||||
"serverTimezone": "UTC",
|
||||
"postgresTimezone": "UTC",
|
||||
"sampleEvent": {
|
||||
"title": "Dr Julian Wlodarczak",
|
||||
"type_col": "timestamp with time zone",
|
||||
"start_time_raw": "2024-11-17T09:20:00.000Z",
|
||||
"start_time_type": "string",
|
||||
"start_text": "2024-11-17 09:20:00+00",
|
||||
"start_utc_formatted": "2024-11-17T09:20:00Z",
|
||||
"start_paris_formatted": "2024-11-17 10:20:00"
|
||||
},
|
||||
"parsing": {
|
||||
"input": "2024-11-17T09:20:00.000Z",
|
||||
"inputType": "string",
|
||||
"dateObject": "2024-11-17T09:20:00.000Z",
|
||||
"displayUTC": "Sun, 17 Nov 2024 09:20:00 GMT",
|
||||
"displayParis": "17/11/2024 10:20:00",
|
||||
"displayParisTime": "10:20"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 ANALYSE DES LOGS
|
||||
|
||||
### **Si tout est correct** :
|
||||
|
||||
1. Google renvoie : `"2024-11-17T10:20:00+01:00"` (10:20 Paris)
|
||||
2. Conversion en UTC : `2024-11-17T09:20:00.000Z` (09:20 UTC)
|
||||
3. PostgreSQL stocke : `2024-11-17 09:20:00+00` (09:20 UTC)
|
||||
4. Parser renvoie : `"2024-11-17T09:20:00.000Z"`
|
||||
5. Frontend affiche : `10:20` ✅
|
||||
|
||||
### **Si le décalage persiste** :
|
||||
|
||||
Cherchez dans les logs où la conversion échoue :
|
||||
|
||||
- ❌ **Google renvoie une heure incorrecte** → Problème API Google
|
||||
- ❌ **Conversion UTC incorrecte** → Problème dans `new Date()`
|
||||
- ❌ **PostgreSQL stocke mal** → Problème de timezone PostgreSQL
|
||||
- ❌ **Parser renvoie mal** → Problème dans le parser
|
||||
- ❌ **Frontend affiche mal** → Problème dans `toLocaleTimeString`
|
||||
|
||||
---
|
||||
|
||||
## 📊 COMMANDES UTILES
|
||||
|
||||
### Voir les logs en temps réel :
|
||||
```bash
|
||||
docker-compose logs -f notes-app
|
||||
```
|
||||
|
||||
### Voir seulement les logs de timezone :
|
||||
```bash
|
||||
docker-compose logs -f notes-app | grep -E "\[SYNC CALENDAR\]|\[PARSER TIMESTAMPTZ\]|\[GET /events\]"
|
||||
```
|
||||
|
||||
### Vérifier le timezone PostgreSQL :
|
||||
```bash
|
||||
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 -c "SHOW timezone"
|
||||
```
|
||||
|
||||
### Voir les événements bruts dans PostgreSQL :
|
||||
```bash
|
||||
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 -c "
|
||||
SELECT
|
||||
title,
|
||||
start_time,
|
||||
start_time::text,
|
||||
start_time AT TIME ZONE 'Europe/Paris' as paris_time
|
||||
FROM calendar_events
|
||||
ORDER BY start_time DESC
|
||||
LIMIT 5
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 RAPPORT À ENVOYER
|
||||
|
||||
Si le problème persiste, envoyez :
|
||||
|
||||
1. **Les logs de synchronisation** (ÉTAPE 4)
|
||||
2. **Les logs de récupération** (ÉTAPE 5)
|
||||
3. **Le résultat de l'endpoint debug** (ÉTAPE 6)
|
||||
4. **Capture d'écran de NoteFlow** montrant le décalage
|
||||
5. **Capture d'écran de Google Calendar** montrant l'heure correcte
|
||||
|
||||
Avec ces informations, je pourrai identifier EXACTEMENT où se produit le décalage.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ IMPORTANT
|
||||
|
||||
Les logs sont en mode `debug` et peuvent être volumineux. Pour production, pensez à :
|
||||
|
||||
1. Réduire le niveau de log
|
||||
2. Ou désactiver les logs une fois le problème résolu
|
||||
+15
-6
@@ -11,19 +11,28 @@ types.setTypeParser(1184, function(stringValue) {
|
||||
// 1184 = TIMESTAMPTZ
|
||||
if (!stringValue) return null;
|
||||
|
||||
// LOG pour debug
|
||||
const originalValue = stringValue;
|
||||
|
||||
// PostgreSQL avec timezone=UTC renvoie: "2024-11-17 09:20:00" ou "2024-11-17 09:20:00+00"
|
||||
// On doit toujours renvoyer une ISO string UTC propre avec 'Z'
|
||||
|
||||
let result;
|
||||
|
||||
// Si déjà au format ISO avec Z ou timezone (+HH:MM ou +HH)
|
||||
if (stringValue.includes('Z') || stringValue.match(/[+-]\d{2}(:\d{2})?$/)) {
|
||||
return new Date(stringValue).toISOString();
|
||||
result = new Date(stringValue).toISOString();
|
||||
logger.debug(`[PARSER TIMESTAMPTZ] Input avec TZ: "${originalValue}" → Output: "${result}"`);
|
||||
} else {
|
||||
// Si format "YYYY-MM-DD HH:MM:SS" sans timezone
|
||||
// Comme timezone=UTC, on sait que c'est en UTC
|
||||
// On ajoute 'Z' pour forcer JavaScript à l'interpréter comme UTC
|
||||
const isoString = stringValue.replace(' ', 'T') + 'Z';
|
||||
result = new Date(isoString).toISOString();
|
||||
logger.debug(`[PARSER TIMESTAMPTZ] Input sans TZ: "${originalValue}" → ISO+Z: "${isoString}" → Output: "${result}"`);
|
||||
}
|
||||
|
||||
// Si format "YYYY-MM-DD HH:MM:SS" sans timezone
|
||||
// Comme timezone=UTC, on sait que c'est en UTC
|
||||
// On ajoute 'Z' pour forcer JavaScript à l'interpréter comme UTC
|
||||
const isoString = stringValue.replace(' ', 'T') + 'Z';
|
||||
return new Date(isoString).toISOString();
|
||||
return result;
|
||||
});
|
||||
|
||||
// Configuration PostgreSQL depuis DATABASE_URL ou variables d'environnement
|
||||
|
||||
@@ -352,6 +352,17 @@ router.get('/events', authenticateToken, async (req, res) => {
|
||||
LIMIT $3
|
||||
`, [req.user.id, now, limit]);
|
||||
|
||||
// LOG pour chaque événement récupéré
|
||||
events.forEach(event => {
|
||||
logger.debug(`[GET /events] "${event.title}"`);
|
||||
logger.debug(`[GET /events] - start_time de la DB: "${event.start_time}" (type: ${typeof event.start_time})`);
|
||||
if (event.start_time) {
|
||||
const date = new Date(event.start_time);
|
||||
logger.debug(`[GET /events] - new Date(): ${date.toISOString()}`);
|
||||
logger.debug(`[GET /events] - Affichage Paris: ${date.toLocaleString('fr-FR', { timeZone: 'Europe/Paris', hour: '2-digit', minute: '2-digit' })}`);
|
||||
}
|
||||
});
|
||||
|
||||
res.json(events || []);
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors de la récupération des événements:', error);
|
||||
@@ -359,6 +370,87 @@ router.get('/events', authenticateToken, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/calendar/debug
|
||||
* Endpoint de diagnostic détaillé pour le timezone
|
||||
*/
|
||||
router.get('/debug', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const diagnostics = {
|
||||
timestamp: new Date().toISOString(),
|
||||
serverTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
postgresTimezone: null,
|
||||
sampleEvent: null,
|
||||
parsing: {
|
||||
input: null,
|
||||
output: null,
|
||||
display: null
|
||||
}
|
||||
};
|
||||
|
||||
// Récupérer le timezone de PostgreSQL
|
||||
const tzResult = await getOne('SHOW timezone');
|
||||
diagnostics.postgresTimezone = tzResult?.timezone || tzResult?.TimeZone;
|
||||
|
||||
// Récupérer un événement pour test
|
||||
const event = await getOne(`
|
||||
SELECT
|
||||
title,
|
||||
start_time,
|
||||
pg_typeof(start_time) as type_col,
|
||||
start_time::text as start_text,
|
||||
to_char(start_time AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') as start_utc_formatted,
|
||||
to_char(start_time AT TIME ZONE 'Europe/Paris', 'YYYY-MM-DD HH24:MI:SS') as start_paris_formatted
|
||||
FROM calendar_events
|
||||
WHERE user_id = $1
|
||||
ORDER BY start_time DESC
|
||||
LIMIT 1
|
||||
`, [req.user.id]);
|
||||
|
||||
if (event) {
|
||||
diagnostics.sampleEvent = {
|
||||
title: event.title,
|
||||
type_col: event.type_col,
|
||||
start_time_raw: event.start_time,
|
||||
start_time_type: typeof event.start_time,
|
||||
start_text: event.start_text,
|
||||
start_utc_formatted: event.start_utc_formatted,
|
||||
start_paris_formatted: event.start_paris_formatted
|
||||
};
|
||||
|
||||
// Test de parsing
|
||||
if (event.start_time) {
|
||||
const date = new Date(event.start_time);
|
||||
diagnostics.parsing = {
|
||||
input: event.start_time,
|
||||
inputType: typeof event.start_time,
|
||||
dateObject: date.toISOString(),
|
||||
displayUTC: date.toUTCString(),
|
||||
displayParis: date.toLocaleString('fr-FR', {
|
||||
timeZone: 'Europe/Paris',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
}),
|
||||
displayParisTime: date.toLocaleTimeString('fr-FR', {
|
||||
timeZone: 'Europe/Paris',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
res.json(diagnostics);
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors du diagnostic:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/calendar/sync
|
||||
* Synchroniser avec Google Calendar (OAuth2, Service Account ou API Key)
|
||||
@@ -410,6 +502,17 @@ router.post('/sync', authenticateToken, async (req, res) => {
|
||||
const endTime = event.end.dateTime || event.end.date;
|
||||
const isAllDay = !event.start.dateTime; // Si pas de dateTime, c'est un événement toute la journée
|
||||
|
||||
// LOG DÉTAILLÉ pour debug timezone
|
||||
logger.info(`[SYNC CALENDAR] Événement: "${event.summary}"`);
|
||||
logger.info(`[SYNC CALENDAR] - Google startTime brut: ${JSON.stringify(event.start)}`);
|
||||
logger.info(`[SYNC CALENDAR] - startTime extrait: "${startTime}"`);
|
||||
logger.info(`[SYNC CALENDAR] - Type: ${typeof startTime}`);
|
||||
if (startTime) {
|
||||
const testDate = new Date(startTime);
|
||||
logger.info(`[SYNC CALENDAR] - new Date(startTime): ${testDate.toISOString()}`);
|
||||
logger.info(`[SYNC CALENDAR] - Affichage Paris: ${testDate.toLocaleString('fr-FR', { timeZone: 'Europe/Paris' })}`);
|
||||
}
|
||||
|
||||
// Vérifier si l'événement existe déjà
|
||||
const existing = await getOne(
|
||||
'SELECT id FROM calendar_events WHERE google_event_id = $1 AND user_id = $2',
|
||||
|
||||
Reference in new issue
Block a user