# Notifications riches — Guide d’atterrissage (abonnements, fréquences, user data)

Ce dossier rassemble la documentation et le suivi de la refonte des notifications riches pour intégrer:
- Des catégories/flux avec audience (EVERYONE/SUBSCRIBERS) et modes d’acheminement (BROADCAST/PERSONALIZED)
- Des fréquences calendrier (IMMEDIATE, EVERY_N_DAYS, WEEKLY, MONTHLY) avec ancre Europe/Paris
- Des abonnements utilisateurs, overrides optionnels, et visibilité pilotée par `available_at`
- Un socle polyvalent `user_data` pour stats/thèmes/Q-R/trophées

Important: AUCUN GO lancé par défaut. Les phases s’exécutent uniquement après validation explicite.

## TL;DR — Par où commencer ?
1) Lire `PLAN.md` (source de vérité du périmètre et des décisions).  
2) Lire `PROGRESS.md` (suivi et checklist DoD).  
3) Respecter strictement les lignes rouges V4:  
   - Mutations via `/api/commands` (utilisateur) et `/api/admin/*` (admin)  
   - Réponses JSON canoniques: `Response::ok/error`  
   - GET pour les lectures (pas de REST parallèle)  

Quand on donnera le GO (Phase 1):
- Étendre le schéma via `SchemaManager.php`
- Étendre Admin Catégories (API + UI) avec les nouveaux champs et validations
- Mettre en place la lecture GET `/api/notifications/rich` avec filtre unique `available_at <= now` + audience
- Créer la table `scheduler_meta` (requis pour BROADCAST)

## Architecture – Où intervenir ?
- DDL/DB: `src/Infrastructure/Persistence/SchemaManager.php`
- API Admin Catégories: `src/Interfaces/Http/Controllers/Admin/NotificationCategoryAdminController.php` + `src/Application/Services/Admin/NotificationCategoryAdminService.php`
- API Notifications Riches (lecture): `src/Interfaces/Http/Controllers/NotificationRichController.php` + `src/Application/Services/NotificationRichReadService.php`
- NonBoardBus (commands côté utilisateur): `src/Application/NonBoard/*` (ajout `User.SubscribeCategory`, `User.UnsubscribeCategory`, `User.SetCategoryFrequencyOverride`)
- UI Admin (catégories + fiche utilisateur): `public/assets/apps/admin/main.js`
- UI Compte (“Mes abonnements”): `public/assets/apps/account/main.js`
- Scheduler CLI: placer le script dans `tools/scheduler/notifications-digest.php`

## Décisions clés (résumé)
- IMMEDIATE unifié: écrire `available_at = created_at` à la création des notifications (aucun backfill historique).  
  Lecture = une seule condition: `available_at <= now` (inclut IMMEDIATE et les digest planifiés).  
- `PERSONALIZED × IMMEDIATE` interdit (UI + back → 422).  
- Séquence d’épisodes: `notifications_rich.sequence_index` requis (UNIQUE par catégorie). Aucun fallback sur `created_at`.  
- BROADCAST: **`scheduler_meta` requis** pour persister un curseur `last_slot_ts` par catégorie.  
- Overrides: autorisés uniquement en `PERSONALIZED` et si `allow_user_override=1` (en BROADCAST → 422).

## Validations (à implémenter Phase 1)
- Plages `frequency_param` strictes:  
  - EVERY_N_DAYS: n ≥ 1 (recommandé 1..7, extension 14/21/30 si nécessaire)  
  - WEEKLY: 1..7 (jour de semaine)  
  - MONTHLY: 1..28  
- Rejeter (422) overrides en `BROADCAST` et overrides non autorisés (`allow_user_override=0`).

## Scheduler (Phase 2)
- Calculs en heure locale Europe/Paris, stockage UTC. Tester les DST (printemps/automne).  
- Idempotence par `ON DUPLICATE KEY UPDATE` et non réécriture d’un `available_at` fixé.  
- BROADCAST: traiter uniquement le **delta** depuis `scheduler_meta.last_slot_ts`.  
- PERSONALIZED: progression individuelle via `last_delivered_notification_id` et ancre `cycle_anchor_ts`.

## Tests & Conformité
- Unit: `next_slot()` (EVERY_N_DAYS/WEEKLY/MONTHLY) + cas DST.  
- Intégration: GET `/api/notifications/rich` (audience, available_at, history).  
- E2E: PERSONNALIZED commence à l’épisode 1; BROADCAST n’upsert que le delta; cron idempotent.

## Notes produit
- Rétention/purge NUS à prévoir si volumétrie importante (Phase ultérieure).  
- Index `delivered_at` à n’ajouter qu’au moment d’activer email/push.  
- Politique de backfill BROADCAST (NONE / IMMEDIATE / STAGED): option produit, **hors Phase 1**.

## Statut
- Cette documentation est en place; pas de code DB/API/CLI lancé tant que le GO n’est pas donné.  
- Mise à jour continue dans `PROGRESS.md`.
