- 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>
15 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commandes Essentielles
Backend (Poetry)
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)
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
poetry run uvicorn backend.app.main:app --reload # Backend (port 8008)
cd frontend && npm run dev # Frontend (port 5173)
Frontend (npm)
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
- Playwright charge la page avec délais aléatoires (1-3s)
- Détection blocage (captcha/robot) → artéfacts debug (screenshot + HTML)
- Extraction via CSS selectors → normalisation (prix, stock, ratings)
- 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 settingsfrontend/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 :
columnsparamé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) +asintitle(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
- locale
- 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 dossierdebug/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)