plan.md 4.3 KB

Plan : Modifier la purge pour supprimer les articles lus non épinglés

Contexte actuel

La fonction purge_old_articles protège actuellement tous les articles ayant une interaction utilisateur (lu OU épinglé). Cela signifie que 7 354 articles sont protégés et quasiment rien n'est jamais supprimé.

Nouvelle règle demandée

  • Supprimer : Articles non vus dans les flux depuis 48h+ ET non épinglés
  • Protéger : Uniquement les articles épinglés

Impact estimé

Métrique Valeur
Articles actuels 7 798
Articles > 48h 6 463
Articles qui seraient supprimés ~6 456
Articles protégés (épinglés) 7
Articles restants après purge ~1 342

Modification à effectuer

Migration SQL - Recréer la fonction purge_old_articles :

CREATE OR REPLACE FUNCTION public.purge_old_articles()
RETURNS TABLE(deleted_count integer, admin_emails text[])
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public'
AS $$
DECLARE
  v_deleted_count INTEGER;
  v_admin_emails TEXT[];
  v_cutoff_date TIMESTAMP WITH TIME ZONE;
BEGIN
  -- Calculer la date limite (48 heures)
  v_cutoff_date := NOW() - INTERVAL '48 hours';
  
  -- Récupérer les emails des super users
  SELECT ARRAY_AGG(email) INTO v_admin_emails
  FROM public.super_users;
  
  -- NOUVELLE LOGIQUE : Supprimer les articles non vus depuis 48h
  -- SAUF ceux qui sont épinglés par au moins un utilisateur
  WITH articles_to_delete AS (
    SELECT a.id
    FROM public.articles a
    WHERE a.last_seen_at < v_cutoff_date
    AND NOT EXISTS (
      SELECT 1 
      FROM public.user_articles ua
      WHERE ua.article_id = a.id
      AND ua.is_pinned = true  -- Seuls les articles épinglés sont protégés
    )
    LIMIT 1000  -- Limiter pour éviter les timeouts
  ),
  -- Supprimer d'abord les entrées user_articles associées
  deleted_user_articles AS (
    DELETE FROM public.user_articles
    WHERE article_id IN (SELECT id FROM articles_to_delete)
    RETURNING article_id
  ),
  deleted AS (
    DELETE FROM public.articles
    WHERE id IN (SELECT id FROM articles_to_delete)
    RETURNING id
  )
  SELECT COUNT(*)::INTEGER INTO v_deleted_count FROM deleted;
  
  -- Log l'opération
  RAISE NOTICE 'Purge automatique: % articles supprimés (non vus depuis 48h, non épinglés)', v_deleted_count;
  
  -- Retourner les résultats
  RETURN QUERY SELECT v_deleted_count, v_admin_emails;
END;
$$;

Points techniques importants

  1. Cascade des suppressions : La fonction doit d'abord supprimer les entrées user_articles avant de supprimer les articles eux-mêmes (contrainte de clé étrangère)

  2. Limite de 1000 : Conservée pour éviter les timeouts - la purge s'exécutera plusieurs fois si nécessaire

  3. Sécurité : SECURITY DEFINER conservé pour permettre l'accès aux tables protégées par RLS

Mise à jour de la fonction de test

Également mettre à jour test_purge_articles pour refléter la nouvelle logique :

CREATE OR REPLACE FUNCTION public.test_purge_articles()
RETURNS TABLE(articles_to_delete integer, oldest_article_date timestamp with time zone, newest_article_date timestamp with time zone, sample_titles text[])
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public'
AS $$
DECLARE
  v_cutoff_date TIMESTAMP WITH TIME ZONE;
BEGIN
  v_cutoff_date := NOW() - INTERVAL '48 hours';
  
  RETURN QUERY
  WITH eligible_articles AS (
    SELECT a.id, a.last_seen_at, a.title
    FROM public.articles a
    WHERE a.last_seen_at < v_cutoff_date
    AND NOT EXISTS (
      SELECT 1 
      FROM public.user_articles ua
      WHERE ua.article_id = a.id
      AND ua.is_pinned = true  -- Seuls les épinglés sont protégés
    )
  ),
  sample_articles AS (
    SELECT title
    FROM eligible_articles
    ORDER BY last_seen_at DESC
    LIMIT 5
  )
  SELECT 
    (SELECT COUNT(*)::INTEGER FROM eligible_articles),
    (SELECT MIN(last_seen_at) FROM eligible_articles),
    (SELECT MAX(last_seen_at) FROM eligible_articles),
    (SELECT ARRAY_AGG(title) FROM sample_articles);
END;
$$;

Résumé des changements

Avant Après
Articles lus = protégés Articles lus = supprimés après 48h
Articles épinglés = protégés Articles épinglés = protégés (inchangé)
~0 articles supprimés/jour ~6 400+ articles supprimés