Files
noteflow/scripts/add-cleanup-tracking-fields.js
Claude 86e825b9d1 Feat: Ajout du système de purge automatique de la base de données
Implémente un système complet de purge automatique pour maintenir
la base de données propre et performante.

Fonctionnalités ajoutées :
- Migration pour ajouter les champs de tracking (archived_at, completed_at)
- Triggers PostgreSQL pour mise à jour automatique des dates
- Script de purge manuel avec mode simulation (dry-run)
- Scheduler automatique configurable (défaut: 24h)
- Routes API admin pour contrôle et monitoring
- Documentation complète

Éléments purgés :
- Flux RSS désactivés (tous)
- Tâches complétées > 3 mois (configurable)
- Notes archivées > 6 mois (configurable)
- Rendez-vous passés > 6 mois (configurable)

Scripts npm ajoutés :
- npm run db:migrate - Exécuter la migration
- npm run db:cleanup - Purge manuelle
- npm run db:cleanup:dry-run - Simulation de purge

Routes API ajoutées :
- POST /api/admin/cleanup - Déclencher la purge
- GET /api/admin/cleanup/preview - Prévisualiser la purge
- GET /api/admin/cleanup/status - Statut du scheduler
- GET /api/admin/stats - Statistiques DB

Configuration via variables d'environnement :
- CLEANUP_ENABLED (défaut: true)
- CLEANUP_INTERVAL_HOURS (défaut: 24)
- CLEANUP_COMPLETED_TASKS_DAYS (défaut: 90)
- CLEANUP_ARCHIVED_NOTES_DAYS (défaut: 180)
- CLEANUP_PAST_EVENTS_DAYS (défaut: 180)
2025-11-19 06:49:27 +00:00

185 lines
7.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Script de migration pour ajouter les champs de tracking pour la purge automatique
* - archived_at pour les notes
* - completed_at pour global_todos et note_todos
*/
const { Pool } = require('pg');
const DATABASE_URL = process.env.DATABASE_URL ||
`postgresql://${process.env.PGUSER || 'noteflow'}:${process.env.PGPASSWORD || 'noteflow_secure_password_change_me'}@${process.env.PGHOST || 'postgres'}:${process.env.PGPORT || '5499'}/${process.env.PGDATABASE || 'noteflow'}`;
async function migrate() {
const pool = new Pool({ connectionString: DATABASE_URL });
try {
console.log('\n╔════════════════════════════════════════════════════════════╗');
console.log('║ MIGRATION: Ajout des champs de tracking pour purge ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');
const client = await pool.connect();
try {
await client.query('BEGIN');
// 1. Ajouter archived_at à la table notes
console.log('📝 Ajout du champ archived_at à la table notes...');
await client.query(`
ALTER TABLE notes
ADD COLUMN IF NOT EXISTS archived_at TIMESTAMP
`);
console.log('✅ Champ archived_at ajouté\n');
// 2. Mettre à jour les notes déjà archivées avec updated_at comme date approximative
console.log('🔄 Mise à jour des notes archivées existantes...');
const archivedNotesUpdate = await client.query(`
UPDATE notes
SET archived_at = updated_at
WHERE archived = TRUE AND archived_at IS NULL
`);
console.log(`✅ ${archivedNotesUpdate.rowCount} note(s) archivée(s) mise(s) à jour\n`);
// 3. Ajouter completed_at à la table global_todos
console.log('📝 Ajout du champ completed_at à la table global_todos...');
await client.query(`
ALTER TABLE global_todos
ADD COLUMN IF NOT EXISTS completed_at TIMESTAMP
`);
console.log('✅ Champ completed_at ajouté à global_todos\n');
// 4. Mettre à jour les global_todos déjà complétées
console.log('🔄 Mise à jour des tâches globales complétées existantes...');
const globalTodosUpdate = await client.query(`
UPDATE global_todos
SET completed_at = created_at
WHERE completed = TRUE AND completed_at IS NULL
`);
console.log(`✅ ${globalTodosUpdate.rowCount} tâche(s) globale(s) mise(s) à jour\n`);
// 5. Ajouter created_at et completed_at à la table note_todos
console.log('📝 Ajout des champs created_at et completed_at à la table note_todos...');
await client.query(`
ALTER TABLE note_todos
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
`);
await client.query(`
ALTER TABLE note_todos
ADD COLUMN IF NOT EXISTS completed_at TIMESTAMP
`);
console.log('✅ Champs created_at et completed_at ajoutés à note_todos\n');
// 6. Mettre à jour les note_todos déjà complétées
console.log('🔄 Mise à jour des tâches de notes complétées existantes...');
const noteTodosUpdate = await client.query(`
UPDATE note_todos
SET completed_at = CURRENT_TIMESTAMP
WHERE completed = TRUE AND completed_at IS NULL
`);
console.log(`✅ ${noteTodosUpdate.rowCount} tâche(s) de note(s) mise(s) à jour\n`);
// 7. Créer les triggers pour mettre à jour automatiquement les dates
console.log('🔧 Création des triggers pour mise à jour automatique...');
// Trigger pour notes.archived_at
await client.query(`
CREATE OR REPLACE FUNCTION update_notes_archived_at()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.archived = TRUE AND OLD.archived = FALSE THEN
NEW.archived_at = CURRENT_TIMESTAMP;
ELSIF NEW.archived = FALSE THEN
NEW.archived_at = NULL;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
`);
await client.query(`
DROP TRIGGER IF EXISTS trigger_notes_archived_at ON notes;
CREATE TRIGGER trigger_notes_archived_at
BEFORE UPDATE ON notes
FOR EACH ROW
EXECUTE FUNCTION update_notes_archived_at();
`);
// Trigger pour global_todos.completed_at
await client.query(`
CREATE OR REPLACE FUNCTION update_global_todos_completed_at()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.completed = TRUE AND OLD.completed = FALSE THEN
NEW.completed_at = CURRENT_TIMESTAMP;
ELSIF NEW.completed = FALSE THEN
NEW.completed_at = NULL;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
`);
await client.query(`
DROP TRIGGER IF EXISTS trigger_global_todos_completed_at ON global_todos;
CREATE TRIGGER trigger_global_todos_completed_at
BEFORE UPDATE ON global_todos
FOR EACH ROW
EXECUTE FUNCTION update_global_todos_completed_at();
`);
// Trigger pour note_todos.completed_at
await client.query(`
CREATE OR REPLACE FUNCTION update_note_todos_completed_at()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.completed = TRUE AND (OLD.completed IS NULL OR OLD.completed = FALSE) THEN
NEW.completed_at = CURRENT_TIMESTAMP;
ELSIF NEW.completed = FALSE THEN
NEW.completed_at = NULL;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
`);
await client.query(`
DROP TRIGGER IF EXISTS trigger_note_todos_completed_at ON note_todos;
CREATE TRIGGER trigger_note_todos_completed_at
BEFORE UPDATE ON note_todos
FOR EACH ROW
EXECUTE FUNCTION update_note_todos_completed_at();
`);
console.log('✅ Triggers créés avec succès\n');
await client.query('COMMIT');
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ ✅ MIGRATION TERMINÉE AVEC SUCCÈS ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');
console.log('📝 RÉSUMÉ DES CHANGEMENTS:\n');
console.log('• Champ archived_at ajouté à la table notes');
console.log('• Champ completed_at ajouté aux tables global_todos et note_todos');
console.log('• Triggers créés pour mise à jour automatique des dates');
console.log('• Données existantes migrées avec succès\n');
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
await pool.end();
} catch (error) {
console.error('\n❌ Erreur:', error.message);
console.error(error.stack);
process.exit(1);
}
}
migrate();