docs: add frontend Phase 2 implementation plan

- Add detailed 6-step development plan for frontend
- Define architecture with React Router for multi-store evolution
- Document API endpoints needed (existing + to create)
- Update TODO.md and kanban.md with current status

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-18 19:21:19 +01:00
parent bb1263edb8
commit 9a6448facc
4 changed files with 553 additions and 11 deletions

327
CLAUDE.md Normal file
View File

@@ -0,0 +1,327 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commandes Essentielles
### Backend (Poetry)
```bash
poetry install # Installation des dépendances
poetry run pytest # Tests unitaires
poetry run ruff check backend/ # Linting
poetry run mypy backend/ # Vérification de types
poetry run coverage run -m pytest && poetry run coverage report -m # Couverture
```
### Scraper CLI (test manuel)
```bash
SCRAPE_TEST_MAX=0 poetry run python backend/app/scraper/run_scrape_tests.py
# Avec navigateur visible si blocage Amazon:
SCRAPE_TEST_HEADFUL_ON_BLOCK=1 SCRAPE_TEST_MAX=0 poetry run python backend/app/scraper/run_scrape_tests.py
```
### Serveur de développement
```bash
poetry run uvicorn backend.app.main:app --reload # Backend (port 8008)
cd frontend && npm run dev # Frontend (port 5173)
```
### Frontend (npm)
```bash
cd frontend && npm install && npm run dev # Dev
cd frontend && npm run build # Build production
```
## Architecture
### Stack technique
- **Backend**: FastAPI + SQLAlchemy (SQLite) + APScheduler + Loguru
- **Scraper**: Playwright (Chromium) + BeautifulSoup4, contexte fr-FR
- **Frontend**: React 18 + Vite + Zustand + SCSS Gruvbox dark
### Structure clé
```
├── agent.md
├── backend
│ ├── app
│ │ ├── api
│ │ │ ├── deps.py
│ │ │ ├── __init__.py
│ │ │ ├── routes_config.py
│ │ │ ├── routes_products.py
│ │ │ └── routes_scrape.py
│ │ ├── core
│ │ │ ├── config.py
│ │ │ ├── logging.py
│ │ │ ├── __pycache__
│ │ │ └── scheduler.py
│ │ ├── db
│ │ │ ├── crud.py
│ │ │ ├── database.py
│ │ │ ├── models.py
│ │ │ └── schemas.py
│ │ ├── __init__.py
│ │ ├── main.py
│ │ ├── __pycache__
│ │ │ └── __init__.cpython-313.pyc
│ │ ├── samples
│ │ │ ├── amazon_product.html
│ │ │ ├── debug
│ │ │ ├── scrape_fields.json
│ │ │ ├── scrape_test.json
│ │ │ ├── scrap_result.json
│ │ │ └── storage_state.json
│ │ ├── scraper
│ │ │ ├── amazon
│ │ │ ├── browser.py
│ │ │ ├── normalize.py
│ │ │ ├── __pycache__
│ │ │ ├── runner.py
│ │ │ └── run_scrape_tests.py
│ │ ├── services
│ │ │ ├── __init__.py
│ │ │ ├── pricing.py
│ │ │ └── __pycache__
│ │ └── tests
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ ├── test_normalize.py
│ │ ├── test_parser_samples.py
│ │ └── test_pricing.py
│ ├── config_backend.json
│ ├── data
│ │ ├── raw
│ │ └── screenshots
│ ├── __init__.py
│ ├── logs
│ └── __pycache__
│ └── __init__.cpython-313.pyc
├── CHANGELOG.md
├── CLAUDE.md
├── consigne codex.md
├── docker
├── docs
│ ├── ARCHITECTURE.md
│ ├── db_structure.md
│ ├── frontend_structure.md
│ ├── scrap.md
│ └── tools.md
├── frontend
│ ├── config_frontend.json
│ ├── package.json
│ ├── public
│ │ └── index.html
│ ├── src
│ │ ├── api
│ │ │ └── client.js
│ │ ├── app
│ │ ├── App.jsx
│ │ ├── components
│ │ │ └── ProductCard.jsx
│ │ ├── main.jsx
│ │ └── styles
│ │ └── global.scss
│ └── vite.config.js
├── kanban.md
├── pyproject.toml
├── README.md
└── TODO.md
```
### Flux de scraping
1. Playwright charge la page avec délais aléatoires (1-3s)
2. Détection blocage (captcha/robot) → artéfacts debug (screenshot + HTML)
3. Extraction via CSS selectors → normalisation (prix, stock, ratings)
4. Sauvegarde: snapshot DB + raw JSON dans `backend/data/raw/`
### Base de données (SQLite)
- **products**: URL, ASIN, titre, catégorie, statut actif
- **product_snapshots**: prix, stock, ratings, badges, status scrape, lien vers raw JSON
- **scrape_runs**: métadonnées de chaque exécution (success/fail counts)
### Configuration
- `backend/config_backend.json`: intervalle scrape, timeout, browser settings
- `frontend/config_frontend.json`: thème, layout grille, champs visibles
- `.env`: variables d'environnement (copier `.env.example`)
## Règles de développement
### Libertés accordées
- Créer/modifier fichiers backend, frontend, docs
- Refactorer pour lisibilité/robustesse
- Lancer tests et scripts de validation
### Actions nécessitant approbation
- Refonte architecture (stack, framework)
- Suppression/reset données utilisateur (tables, raw JSON, logs)
- Migrations DB irréversibles
### Qualité code
- Chaque scrape produit un log clair dans `backend/logs/scrap.log` (rotation 10MB, 7j)
- Erreurs scraping = résilience (log + artéfacts) sans crash global
- Logique métier critique accompagnée de tests
### Commits
- Messages courts explicites: `feat: add scraper runner`
- Un commit = une unité cohérente
- Pas de commits fourre-tout
## Notes importantes
- Le scraping est volontairement lent (15-20 produits/jour) pour éviter blocage Amazon
- Raw JSON conservé 30 jours dans `backend/data/raw/`
- Pre-commit hooks configurés (Ruff + MyPy): `pre-commit install`
# Schéma ASCII (UI globale)
Objectif : reproduire lesprit de la capture (vignette + section prix + graphe), en améliorant la lisibilité.
```
┌──────────────────────────────────────────────────────────────────────────┐
│ suivi_produits [Add Product] [Refresh] [Settings] FE vX BE vY │
│ (header fixed) [debug] (⋯) │
├──────────────────────────────────────────────────────────────────────────┤
│ Grid (cols = config_frontend.json) │
│ │
│ ┌──────────────────────────── Card Produit ──────────────────────────┐ │
│ │ Boutique + Titre (2 lignes) │ │
│ │ Amazon │ │
│ │ Samsung SSD Interne 9100 Pro… │ │
│ │ │ │
│ │ ┌───────────────┐ ┌──────────────────────────────────────────┐ │ │
│ │ │ Image │ │ ACTUEL 249€99 │ │ │
│ │ │ (non rognée) │ │ PRIX CONSEILLÉ 329€99 (si présent) │ │ │
│ │ │ │ │ RÉDUCTION -24% (si présent) │ │ │
│ │ └───────────────┘ │ STOCK Disponible │ │ │
│ │ │ NOTE 4,7 (967) │ │ │
│ │ │ CHOIX AMAZON Oui/Non │ │ │
│ │ │ PRIME Oui/Non │ │ │
│ │ │ DEAL Oui/Non │ │ │
│ │ │ Ref: ASIN [Lien produit] │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌────────────────────── Graph 30j (clair) ─────────────────────┐ │ │
│ │ │ ligne + points, axes lisibles, tooltip │ │ │
│ │ └──────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Min 249€99 Max 249€99 Tendance → stable +0.0% Dernier: now │ │
│ │ Catégorie: SSD Type: NVMe │ │
│ │ │ │
│ │ [Scrap] [Edit] [Delete] [Détail] │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────┘
```
page de debug et log qui affiche le contenue des differentes tables sqlite dans des section distincte, une section log qui affiche les log json de scrap
## Vignette produit : exigences UI
- Image **non tronquée** : object-fit `contain`, fond neutre, padding.
- Section prix alignée au niveau de limage (descendue comme sur la capture).
- “Boutique + titre” sur 2 lignes, pleine largeur, icône boutique.
- Badges : Amazon Choice / Prime / Deal / Exclusive (chips).
- Graph 30j :
- axes + labels lisibles
- points visibles
- min/max/tendance affichés sous le graphe
- couleurs + flèches :
- baisse : vert + flèche ↓
- stable : jaune/orange + →
- hausse : rouge + ↑
- Responsive :
- `columns` paramétrable (desktop)
- mobile : 1 colonne + layout empilé
Contraintes clés :
- Scraping : **Python + Playwright** (robuste, peu de produits : 1520/jour).
- Stockage : **JSON** (raw scrap) + persistance en **SQLite** (historique prix + métriques).
- Config :
- `config_backend.json` (paramètres scraping + backend + catégories/types)
- `config_frontend.json` (paramètres UI + colonnes + thème + bouton mode text/icon)
- Logs : fichier de log des scrapes (rotation simple).
- UI : **Gruvbox vintage dark**, moderne (ombres, arrondis, typo lisible), responsive. icon fa
- Déploiement : test en mode .env puis deploiement final dans **docker-compose** (backend + frontend) + cron/worker pour scrapes périodiques.
- Repo : sur mon serveur Gitea, nom : **suivi_produits** : https://gitea.maison43.duckdns.org/gilles/suivi_produit
---
## Objectif produit (fonctionnel)
Application self-hosted pour suivre lévolution de produits Amazon.fr (puis autres stores). Lutilisateur ajoute des URLs de produits, lapp :
- scrape les données clés (prix, stock, note, badges, image, etc.)
- stocke un **snapshot** à chaque scraping
- affiche des **vignettes produit** + **graphique historique** clair (tendance, min/max, %)
- propose actions : **Scrap**, **Edit**, **Delete**, **Détail**
- lance un **scraping planifié** (cron) sur tous les produits à intervalle défini.
---
## Données à capturer (Amazon.fr)
### Champs de base (toujours)
- `url` (canonique) + `asin`
- `title` (nom produit)
- `image_main_url` (image principale)
- `price_current` (valeur numérique + devise)
- `stock_status` (texte) + `in_stock` (bool)
- `rating_value` (float) + `rating_count` (int)
### Champs conditionnels (si présents)
- `price_list` / prix conseillé / prix barré (si affiché)
- `discount_percent` (si affiché ou calculé)
- `lowest_30d_price` (si mention “prix le plus bas des 30 derniers jours”)
- `amazon_choice` (badge)
- `limited_time_deal` (offre à durée limitée)
- `prime_eligible` (badge prime / livraison prime)
- `amazon_exclusive` (mention exclusivité)
### Calculs à faire côté app (pas “inventer”)
> Important : **ne pas “calculer une réduction” si le champ source nexiste pas**. on ne calcule rien sauf demande explicite de ma part ( peut etre tendance dans courbe historique)
---
## Méthode de scraping (sûre/efficace)
### Stratégie Playwright
- Navigateur Chromium.
- Context :
- locale `fr-FR`
- timezone `Europe/Paris`
- viewport réaliste (ex. 1366×768 ou 1920×1080)
- user-agent récent
- Rythme : faible (1520 produits/jour) + **delays aléatoires** 13s entre pages.
- Détection blocages :
- si page contient captcha / robot-check → marquer scrap “blocked” + screenshot + html dump pour debug.
- Résilience :
- retry 12 fois max avec backoff, sinon échec contrôlé.
### Sélecteurs (approche robuste)
- Priorité : **IDs stables** (ex : `#productTitle`, `#acrCustomerReviewText`, `#availability`)
- Prix : gérer variantes (prix fractionné, promo, etc.)
- Fallback : si sélecteur absent, log “missing field”, ne pas planter.
### Artifacts de debug
À chaque scrap :
- sauvegarder un JSON “raw” normalisé
- en cas déchec : `page.screenshot()` + `page.content()` dans un dossier `debug/` horodaté.
---
## Architecture cible
### Backend
- API HTTP (proposé : **FastAPI**) :
- CRUD produits
- déclenchement scrap (produit / tous)
- lecture historique + agrégats (min/max/tendance)
- lecture/écriture configs frontend/backend
- Worker de scraping (Playwright) séparé en module “scraper”
- Scheduler (cron interne ou cron container) qui appelle `scrape_all`
### Frontend
- SPA simple (proposé : **Vite + React** ou **Svelte**) ou HTML server-side minimal (selon simplicité).
- Thème **Gruvbox vintage dark** :
- fond #282828, cartes #3c3836, texte #ebdbb2
- accent orange #fe8019, jaune #fabd2f, vert #b8bb26
- Responsive : nombre de colonnes configurable.
- utilisation de popup lors de l'ajout de produit ou acces a setting
### Stockage
- le stockage se fais uniquement lors de l'enregistrement du produit
- SQLite : tables normalisées (produits, snapshots, tags/catégories/types)
- JSON “raw” : archivage optionnel (dossier `data/raw/YYYY-MM/...json`)

25
TODO.md
View File

@@ -1,7 +1,22 @@
# TODO # TODO
- [ ] init repo pour backend FastAPI + logging + config
- [ ] créer scraper Amazon via Playwright avec parser robuste ## Phase 1 - Backend & Scraper (TERMINÉ ✓)
- [ ] définir UI Gruvbox + carte produit + graphique 30j - [x] init repo pour backend FastAPI + logging + config
- [ ] intégrer scheduler APScheduler pour `scrape_all` - [x] créer scraper Amazon via Playwright avec parser robuste
- [x] modèle SQLAlchemy (products, product_snapshots, scrape_runs)
- [x] API CRUD produits + endpoints scraping
- [x] tests unitaires parser, normalisation, pricing
- [x] intégrer scheduler APScheduler pour `scrape_all`
## Phase 2 - Frontend (EN COURS)
- [ ] connecter App.jsx à l'API backend (fetch produits)
- [ ] implémenter ProductCard avec données réelles
- [ ] ajouter formulaire d'ajout de produit (URL Amazon)
- [ ] graphique Chart.js historique 30j
- [ ] store Zustand pour état global
## Phase 3 - Industrialisation
- [ ] dockeriser backend + frontend + scheduler - [ ] dockeriser backend + frontend + scheduler
- [ ] ajouter page debug/logs affichant tables SQLite - [ ] docker-compose avec volumes persistants
- [ ] page debug/logs affichant tables SQLite
- [ ] tests E2E frontend

View File

@@ -0,0 +1,193 @@
# Plan Frontend Phase 2 - suivi_produits
**Date** : 2026-01-18
**Statut** : Validé
**Priorité** : Fonctionnel d'abord, puis visualisation
---
## Contexte
Le backend (Phase 1) est terminé :
- Scraper Playwright fonctionnel (9/9 produits OK)
- API FastAPI avec CRUD produits complet
- Modèles SQLAlchemy (products, snapshots, scrape_runs)
- Scheduler APScheduler
- Tests unitaires (7 tests OK)
Le frontend est squelettique : App.jsx basique, ProductCard vide, pas de store.
---
## Décisions de design
| Question | Choix |
|----------|-------|
| Priorité | Fonctionnel d'abord |
| Ajout produit | URL seule (backend extrait ASIN + scrape immédiat) |
| State management | Zustand |
| Page debug | Dès le début (utile pendant le dev) |
| Routing | React Router (évolutivité multi-stores) |
---
## Architecture Frontend
```
frontend/src/
├── api/
│ └── client.js # API calls (extensible par store)
├── components/
│ ├── common/ # Composants réutilisables
│ │ ├── Modal.jsx
│ │ ├── Badge.jsx
│ │ └── PriceDisplay.jsx
│ ├── products/
│ │ ├── ProductCard.jsx
│ │ ├── ProductGrid.jsx
│ │ └── AddProductForm.jsx
│ └── debug/
│ ├── DbTable.jsx
│ └── LogViewer.jsx
├── pages/
│ ├── HomePage.jsx # Grille produits
│ ├── DebugPage.jsx # Tables + logs
│ └── SettingsPage.jsx # (futur) Config frontend/backend
├── stores/
│ └── useProductStore.js
├── hooks/ # (futur) Custom hooks
├── styles/
│ ├── _variables.scss # Couleurs Gruvbox
│ └── global.scss
├── App.jsx # React Router setup
└── main.jsx
```
---
## Endpoints API
| Endpoint | Méthode | Statut | Description |
|----------|---------|--------|-------------|
| `/products` | GET | Existe | Liste paginée |
| `/products` | POST | Existe | Créer produit |
| `/products/{id}` | GET/PUT/DELETE | Existe | CRUD |
| `/products/{id}/snapshots` | GET | À créer | Historique prix |
| `/products/{id}/scrape` | POST | À vérifier | Scrape un produit |
| `/scrape/all` | POST | À vérifier | Scrape tous |
| `/debug/tables` | GET | À créer | Dump tables SQLite |
| `/debug/logs` | GET | À créer | Derniers logs scrap |
---
## Plan d'implémentation
### Étape 1 : Page Debug (fondation)
**Objectif** : Avoir une vue sur les données pendant le développement
Backend :
- [ ] Créer endpoint `GET /debug/tables` (dump products, snapshots, scrape_runs)
- [ ] Créer endpoint `GET /debug/logs` (lecture `backend/logs/scrap.log`)
Frontend :
- [ ] Installer react-router-dom
- [ ] Setup React Router avec 2 routes (/, /debug)
- [ ] Créer `DebugPage.jsx` avec composants DbTable et LogViewer
- [ ] Afficher les 3 tables SQLite dans des sections distinctes
- [ ] Afficher les logs JSON de scraping
---
### Étape 2 : Store Zustand + Liste produits
**Objectif** : Connexion frontend-backend fonctionnelle
Frontend :
- [ ] Installer zustand
- [ ] Créer `useProductStore.js` avec actions (fetch, add, delete, scrape)
- [ ] Enrichir `client.js` avec toutes les fonctions fetch
- [ ] Connecter `HomePage.jsx` au store
- [ ] Afficher les produits existants (version basique)
---
### Étape 3 : Ajout de produit
**Objectif** : Permettre d'ajouter un produit via URL Amazon
Backend :
- [ ] Modifier `POST /products` pour accepter juste l'URL
- [ ] Extraire automatiquement l'ASIN de l'URL
- [ ] Déclencher scrape automatique après création
Frontend :
- [ ] Créer `Modal.jsx` (composant réutilisable)
- [ ] Créer `AddProductForm.jsx` (input URL + validation)
- [ ] Intégrer dans Header avec bouton "Add Product"
- [ ] Gestion loading/error dans l'UI
- [ ] Refresh automatique après ajout
---
### Étape 4 : Actions sur produit
**Objectif** : Pouvoir scraper et supprimer un produit
Backend :
- [ ] Vérifier/créer endpoint `POST /products/{id}/scrape`
Frontend :
- [ ] Ajouter boutons Scrap/Delete sur ProductCard
- [ ] Modal de confirmation avant suppression
- [ ] Feedback visuel pendant le scraping (spinner)
- [ ] Refresh automatique après action
---
### Étape 5 : Amélioration visuelle ProductCard
**Objectif** : Vignette produit complète selon le schéma CLAUDE.md
Frontend :
- [ ] Image non tronquée (object-fit: contain)
- [ ] Section prix (actuel, conseillé, réduction)
- [ ] Badges (Prime, Choix Amazon, Deal, Exclusivité)
- [ ] Note + nombre d'avis
- [ ] Stock status
- [ ] Responsive grid (colonnes configurables via config_frontend.json)
---
### Étape 6 : Graphique historique (Phase 2.5)
**Objectif** : Visualiser l'évolution des prix sur 30 jours
Backend :
- [ ] Créer endpoint `GET /products/{id}/snapshots`
Frontend :
- [ ] Installer chart.js + react-chartjs-2
- [ ] Créer composant PriceChart
- [ ] Intégrer dans ProductCard
- [ ] Afficher min/max/tendance sous le graphique
- [ ] Couleurs selon tendance (vert baisse, orange stable, rouge hausse)
---
## Thème visuel
Gruvbox vintage dark (défini dans CLAUDE.md) :
- Fond : #282828
- Cartes : #3c3836
- Texte : #ebdbb2
- Accent orange : #fe8019
- Accent jaune : #fabd2f
- Accent vert : #b8bb26
Icônes : Font Awesome
---
## Critères de succès Phase 2
- [ ] Un utilisateur peut ajouter un produit via URL Amazon
- [ ] Le scraping se déclenche automatiquement
- [ ] Les produits s'affichent dans une grille responsive
- [ ] On peut supprimer un produit
- [ ] On peut déclencher un scrape manuel
- [ ] La page debug montre l'état des tables et logs

View File

@@ -1,15 +1,22 @@
# Kanban # Kanban
## Backlog ## Backlog
- Initialiser FastAPI + SQLite - Docker Compose setup
- Parser Amazon + tests - Page debug/logs SQLite
- UI vignettes + graphique - Tests E2E frontend
## Doing ## Doing
- En cours : structure repo - Frontend: connecter App.jsx à l'API
- Frontend: ProductCard avec données réelles
- Frontend: formulaire ajout produit
## Review ## Review
- - Scheduler APScheduler (fonctionnel, à tester en charge)
## Done ## Done
- - Backend FastAPI + SQLite + logging
- Modèles SQLAlchemy (products, snapshots, runs)
- API CRUD produits + endpoints scraping
- Scraper Playwright + parser Amazon
- Tests unitaires (7 tests OK)
- Tests CLI scraper (9/9 produits OK)