# Plan : Refonte du Système Watchlist

## TL;DR

> **Objectif** : Refaire le système de watchlist avec auto-téléchargement, notifications et stockage SQLite
> 
> **Deliverables** :
> - Base de données SQLite pour la watchlist
> - API REST pour gérer les animes suivis
> - Système d'auto-téléchargement (vérification automatique des nouveaux épisodes)
> - Système de notifications (in-app)
> - Interface frontend (page séparée, même style que le reste)
> 
> **Effort** : XL
> **Exécution** : En waves parallèles

---

## Contexte

### Système Actuel
- Stockage JSON (`config/watchlist.json`)
- Pas de SQLite
- Auto-download basique via scheduler
- Pas de système de notifications
- Interface intégrée à la page principale

### Besoins Utilisateur
- Auto-téléchargement des nouveaux épisodes ✅
- Notifications quand un nouvel épisode est dispo ✅
- Stockage SQLite ✅
- Même style que le reste du site ✅
- Page séparée ✅

---

## Work Objectives

### Objectif Principal
Créer un système de watchlist complet permettant de :
1. Suivre des animes (ajout via recherche)
2. Détecter automatiquement les nouveaux épisodes
3. Télécharger automatiquement les nouveaux épisodes
4. Notifier l'utilisateur quand un nouvel épisode est disponible

### Deliverables Concrets
- [ ] Base de données SQLite (`config/watchlist.db`)
- [ ] Modèles Pydantic pour la watchlist
- [ ] API endpoints (CRUD + actions)
- [ ] Service d'auto-check (scheduler)
- [ ] Service de notifications
- [ ] Page frontend dédiée
- [ ] Intégration avec le système de download existant

### Définition de Terminé
- [ ] Un anime peut être ajouté à la watchlist
- [ ] La watchlist affiche tous les animes suivis
- [ ] Les épisodes peuvent être téléchargés manuellement
- [ ] Le scheduler vérifie automatiquement les nouveaux épisodes
- [ ] Les nouveaux épisodes sont téléchargés automatiquement
- [ ] Une notification apparaît quand un nouvel épisode est dispo

---

## Architecture

### Structure des Fichiers

```
app/
├── watchlist/
│   ├── __init__.py
│   ├── models.py        # Modèles Pydantic
│   ├── database.py      # Connexion SQLite
│   ├── service.py      # Logique métier
│   ├── scheduler.py    # Auto-check
│   └── notifications.py # Notifications
├── routes/
│   └── watchlist.py    # API endpoints
static/
└── js/
    └── watchlist/     # Frontend
        ├── index.js
        ├── components/
        └── style.css
```

### Schéma Base de Données (SQLite)

```sql
-- Table principale : watchlist items
CREATE TABLE watchlist_items (
    id TEXT PRIMARY KEY,
    user_id TEXT NOT NULL,
    anime_title TEXT NOT NULL,
    anime_url TEXT NOT NULL,
    provider_id TEXT NOT NULL,
    lang TEXT DEFAULT 'vostfr',
    poster_image TEXT,
    cover_image TEXT,
    synopsis TEXT,
    genres TEXT, -- JSON array
    
    -- Tracking
    status TEXT DEFAULT 'active', -- active, paused, completed
    auto_download INTEGER DEFAULT 1,
    quality_preference TEXT DEFAULT 'auto',
    last_episode_downloaded INTEGER DEFAULT 0,
    total_episodes INTEGER,
    last_checked_at TEXT,
    
    -- Metadata
    created_at TEXT NOT NULL,
    updated_at TEXT NOT NULL
);

-- Table : Episodes téléchargés
CREATE TABLE downloaded_episodes (
    id TEXT PRIMARY KEY,
    watchlist_item_id TEXT NOT NULL,
    episode_number INTEGER NOT NULL,
    filename TEXT NOT NULL,
    file_path TEXT,
    file_size INTEGER,
    downloaded_at TEXT NOT NULL,
    FOREIGN KEY (watchlist_item_id) REFERENCES watchlist_items(id)
);

-- Table : Notifications
CREATE TABLE notifications (
    id TEXT PRIMARY KEY,
    user_id TEXT NOT NULL,
    watchlist_item_id TEXT,
    type TEXT NOT NULL, -- new_episode, download_complete, error
    title TEXT NOT NULL,
    message TEXT,
    read INTEGER DEFAULT 0,
    created_at TEXT NOT NULL,
    FOREIGN KEY (watchlist_item_id) REFERENCES watchlist_items(id)
);

-- Table : Settings
CREATE TABLE watchlist_settings (
    id INTEGER PRIMARY KEY CHECK (id = 1),
    check_interval_hours INTEGER DEFAULT 6,
    auto_download_enabled INTEGER DEFAULT 1,
    max_concurrent_downloads INTEGER DEFAULT 2,
    notifications_enabled INTEGER DEFAULT 1
);
```

---

## Execution Strategy

### Wave 1 (Fondations)
```
Tâches :
├── 1. Créer structure du module watchlist/
├── 2. Créer database.py (connexion SQLite, migrations)
├── 3. Créer models.py (Pydantic models)
├── 4. Créer service.py (CRUD operations)
└── 5. Mettre à jour models/__init__.py

Dépendances :Aucune (start immediate)
```

### Wave 2 (API + Scheduler)
```
Tâches (dépendent de Wave 1) :
├── 6. Créer routes/watchlist.py (API endpoints)
├── 7. Créer scheduler.py (auto-check)
├── 8. Intégrer scheduler dans main.py
└── 9. Créer notifications.py

Bloqué par : 1-5
```

### Wave 3 (Frontend)
```
Tâches (dépendent de Wave 2) :
├── 10. Créer page HTML watchlist.html
├── 11. Créer watchlist-ui.js (logique)
├── 12. Ajouter CSS pour la page
└── 13. Ajouter routes pour servir la page

Bloqué par : 6-9
```

### Wave 4 (Intégration + Tests)
```
Tâches :
├── 14. Tester l'ajout d'un anime
├── 15. Tester le téléchargement manuel
├── 16. Tester l'auto-download
├── 17. Tester les notifications
└── 18. Nettoyer l'ancien code

Bloqué par : 10-13
```

---

## TODOs

- [ ] 1. **Créer la structure du module watchlist/**

  **Quoi faire** :
  - Créer le répertoire `app/watchlist/`
  - Créer `__init__.py` avec exports
  
  **Pas faire** :
  - Toucher aux autres modules
  
  **Agent recommandé** : `quick`
  
  **QA Scenarios** :
  ```
  Scenario: Le répertoire existe
    Tool: Bash
    Command: ls -la app/watchlist/
    Expected: Le répertoire existe avec __init__.py
  ```

- [ ] 2. **Créer database.py (connexion SQLite)**

  **Quoi faire** :
  - Créer `app/watchlist/database.py`
  - Implémenter connexion SQLite avec `sqlite3`
  - Implémenter fonctions : `init_db()`, `get_connection()`, `migrate()`
  - Créer les tables définies dans le schéma
  
  **Pas faire** :
  - Toucher aux autres fichiers
  
  **Agent recommandé** : `quick`
  
  **QA Scenarios** :
  ```
  Scenario: La base de données est créée
    Tool: Bash
    Command: python3 -c "from app.watchlist.database import init_db; init_db(); import os; print(os.path.exists('config/watchlist.db'))"
    Expected: True
  
  Scenario: Les tables existent
    Tool: Bash
    Command: sqlite3 config/watchlist.db ".tables"
    Expected: watchlist_items downloaded_episodes notifications watchlist_settings
  ```

- [ ] 3. **Créer models.py**

  **Quoi faire** :
  - Créer `app/watchlist/models.py`
  - Définir les modèles Pydantic :
    - WatchlistItem, WatchlistItemCreate, WatchlistItemUpdate
    - DownloadedEpisode
    - Notification, NotificationCreate
    - WatchlistSettings
  - Utiliser les types existants de `app/models/`
  
  **Pas faire** :
  - Dupliquer les types existants
  
  **Agent recommandé** : `quick`
  
  **QA Scenarios** :
  ```
  Scenario: Les modèles peuvent être importés
    Tool: Bash
    Command: python3 -c "from app.watchlist.models import WatchlistItem, Notification; print('OK')"
    Expected: OK (no error)
  ```

- [ ] 4. **Créer service.py**

  **Quoi faire** :
  - Créer `app/watchlist/service.py`
  - Implémenter `WatchlistService` avec :
    - `add_item()`, `get_items()`, `get_item()`, `update_item()`, `delete_item()`
    - `mark_episode_downloaded()`, `get_downloaded_episodes()`
    - `create_notification()`, `get_notifications()`, `mark_notification_read()`
    - `get_settings()`, `update_settings()`
    - `get_items_due_for_check()`
  - Utiliser SQLite directement (pas d'ORM)
  
  **Pas faire** :
  - Toucher au frontend
  
  **Agent recommandé** : `unspecified-high`
  
  **QA Scenarios** :
  ```
  Scenario: Ajouter un item à la watchlist
    Tool: Bash
    Command: python3 -c "
from app.watchlist.service import WatchlistService
svc = WatchlistService()
item = svc.add_item(user_id='test', anime_title='Test Anime', anime_url='https://example.com', provider_id='anime-sama')
print(f'Created: {item.id}')
"
    Expected: Un UUID est retourné
  
  Scenario: Récupérer les items
    Tool: Bash
    Command: python3 -c "
from app.watchlist.service import WatchlistService
svc = WatchlistService()
items = svc.get_items()
print(f'Count: {len(items)}')
"
    Expected: Count: 1
  ```

- [ ] 5. **Mettre à jour models/__init__.py**

  **Quoi faire** :
  - Ajouter export des nouveaux modèles si besoin
  
  **Agent recommandé** : `quick`

- [ ] 6. **Créer routes/watchlist.py**

  **Quoi faire** :
  - Créer `app/routes/watchlist.py`
  - Définir les endpoints :
    - `GET /api/watchlist` - Liste des items
    - `POST /api/watchlist` - Ajouter un item
    - `GET /api/watchlist/{id}` - Détail d'un item
    - `PUT /api/watchlist/{id}` - Modifier un item
    - `DELETE /api/watchlist/{id}` - Supprimer un item
    - `POST /api/watchlist/{id}/download/{episode}` - Télécharger un épisode
    - `GET /api/watchlist/{id}/episodes` - Épisodes téléchargés
    - `GET /api/watchlist/notifications` - Liste des notifications
    - `PUT /api/watchlist/notifications/{id}/read` - Marquer comme lu
    - `GET /api/watchlist/settings` - Settings
    - `PUT /api/watchlist/settings` - Mettre à jour settings
  - Ajouter auth (Bearer token)
  - Intégrer avec `download_manager` pour les téléchargements
  
  **Agent recommandé** : `unspecified-high`
  
  **QA Scenarios** :
  ```
  Scenario: L'API répond
    Tool: Bash
    Command: curl -s http://127.0.0.1:3000/api/watchlist
    Expected: {"items": [...], "count": N}
  ```

- [ ] 7. **Créer scheduler.py**

  **Quoi faire** :
  - Créer `app/watchlist/scheduler.py`
  - Implémenter `WatchlistScheduler` :
    - `start()`, `stop()`
    - `_check_loop()` - Boucle principale
    - `check_item(item)` - Vérifier un anime
    - `download_new_episodes(item, new_episodes)` - Télécharger
  - Utiliser `APScheduler` (déjà dans requirements)
  - Intervalle configurable (défaut: 6h)
  
  **Agent recommandé** : `unspecified-high`

- [ ] 8. **Intégrer scheduler dans main.py**

  **Quoi faire** :
  - Importer et initialiser le scheduler
  - Ajouter au startup event
  - Ajouter au shutdown event
  
  **Agent recommandé** : `quick`

- [ ] 9. **Créer notifications.py**

  **Quoi faire** :
  - Créer `app/watchlist/notifications.py`
  - Implémenter `NotificationService`
  - Types de notifications :
    - `new_episode` - Nouvel épisode détecté
    - `download_started` - Téléchargement commencé
    - `download_complete` - Téléchargement terminé
    - `download_error` - Erreur de téléchargement
  - Stocker dans SQLite
  - Retourner via API pour affichage
  
  **Agent recommandé** : `quick`

- [ ] 10. **Créer page HTML watchlist.html**

  **Quoi faire** :
  - Créer `templates/watchlist.html`
  - Même structure que `index.html`
  - Sections :
    - Header avec stats
    - Liste des animes (cards)
    - Zone de notifications
    - Modal pour les détails
  
  **Agent recommandé** : `visual-engineering`
  
  **QA Scenarios** :
  ```
  Scenario: La page se charge
    Tool: playwright
    Navigate: http://127.0.0.1:3000/watchlist
    Expected: Titre "Ma Watchlist" affiché
  ```

- [ ] 11. **Créer watchlist-ui.js**

  **Quoi faire** :
  - Créer `static/js/watchlist/main.js`
  - Fonctions :
    - `loadWatchlist()` - Charger la liste
    - `renderWatchlist(items)` - Afficher les cards
    - `addAnime(animeData)` - Ajouter un anime
    - `removeAnime(id)` - Retirer
    - `downloadEpisode(itemId, episode)` - Télécharger
    - `loadNotifications()` - Charger les notifs
    - `renderNotifications(notifs)` - Afficher
    - `markAsRead(id)` - Marquer lu
  - Appels API vers les endpoints créés
  
  **Agent recommandé** : `visual-engineering`

- [ ] 12. **Ajouter CSS**

  **Quoi faire** :
  - Créer `static/css/watchlist.css`
  - Style cohérent avec `style.css` existant
  - Cards, badges, buttons, notifications
  
  **Agent recommandé** : `visual-engineering`

- [ ] 13. **Ajouter routes pour servir la page**

  **Quoi faire** :
  - Ajouter route `GET /watchlist` dans main.py
  - Servir le template
  
  **Agent recommandé** : `quick`

- [ ] 14-17. **Tests d'intégration**

  **Quoi faire** :
  - Tester le flux complet :
    1. Ajouter un anime via API
    2. Voir dans la liste
    3. Télécharger un épisode manuellement
    4. Recevoir une notification
  - Tester l'auto-download (simuler un nouvel épisode)
  
  **Agent recommandé** : `unspecified-high`

- [ ] 18. **Nettoyer l'ancien code**

  **Quoi faire** :
  - Supprimer `app/watchlist.py` (l'ancien)
  - Supprimer les fichiers JSON `config/watchlist*.json`
  - Mettre à jour les imports
  
  **Agent recommandé** : `quick`

---

## Stratégie de Vérification

### Test Manual (Agent QA)

**Scenario: Ajout d'un anime**
```
1. Ouvrir /watchlist
2. Cliquer "Ajouter un anime"
3. Rechercher "Frieren"
4. Sélectionner un résultat
5. Cliquer "Suivre"
Expected: L'anime apparaît dans la liste
```

**Scenario: Téléchargement manuel**
```
1. Dans la watchlist, cliquer sur un anime
2. Voir la liste des épisodes
3. Cliquer "Télécharger" sur épisode 1
4. Vérifier dans /downloads
Expected: Le téléchargement commence
```

**Scenario: Auto-download**
```
1. Ajouter un anime avec auto-download activé
2. Simuler l'apparition d'un nouvel épisode (via scheduler)
3. Vérifier dans les downloads
Expected: L'épisode est téléchargé automatiquement
```

**Scenario: Notification**
```
1. Un nouvel épisode est détecté
2. Une notification apparaît
3. Cliquer sur la notification
Expected: Redirection vers l'épisode
```

---

## Critères de Succès

- [ ] La base SQLite est créée et fonctionnelle
- [ ] Les animes peuvent être ajoutés/retirés de la watchlist
- [ ] Les épisodes peuvent être téléchargés manuellement
- [ ] Le scheduler vérifie automatiquement les nouveaux épisodes
- [ ] L'auto-téléchargement fonctionne
- [ ] Les notifications sont créées et affichées
- [ ] L'interface est cohérente avec le reste du site
- [ ] L'ancien code est nettoyé

---

## Commit Strategy

- Wave 1: `feat(watchlist): add SQLite database and models`
- Wave 2: `feat(watchlist): add API routes and scheduler`
- Wave 3: `feat(watchlist): add frontend UI`
- Wave 4: `feat(watchlist): integrate and test`

---

## Notes

- Le système de download existant (`download_manager`) est réutilisé
- Les providers existants (anime-sama, vostfree, etc.) sont réutilisés
- Le système de notification est simple (in-app) pour éviter les dépendances supplémentaires
- Le scheduler utilise APScheduler déjà présent dans le projet
