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:
327
CLAUDE.md
Normal file
327
CLAUDE.md
Normal 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 l’esprit 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 l’image (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 : 15–20/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). L’utilisateur ajoute des URLs de produits, l’app :
|
||||
- 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 n’existe 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 (15–20 produits/jour) + **delays aléatoires** 1–3s entre pages.
|
||||
- Détection blocages :
|
||||
- si page contient captcha / robot-check → marquer scrap “blocked” + screenshot + html dump pour debug.
|
||||
- Résilience :
|
||||
- retry 1–2 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`)
|
||||
Reference in New Issue
Block a user