17 KiB
Prompt Codex — Projet suivi_produits (Amazon.fr → extensible multi-stores)
Rôle de Codex
Tu es un agent senior en développement Python web, Playwright, SQL/SQLite, architecture logicielle, UI frontend (responsive). tu me parlera en francais dans la discussion et le code devra etre commenté regulieremnt en francais aussi. Tu dois :
- faire un brainstorming pragmatique, 2) proposer un plan en phases, 3) définir une structure de projet claire, 4) implémenter un MVP testable, 5) industrialiser (tests, logs, cron, docker-compose), 6) préparer l’évolution multi-boutiques.
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)
Structure de projet (proposée et a adpater)
suivi_produits/
README.md
TODO.md
CHANGELOG.md
kanban.md
docs/
backend/
app/
main.py
api/
routes_products.py
routes_scrape.py
routes_config.py
routes_stats.py
core/
config.py # charge config_backend.json
logging.py
scheduler.py # déclenche scrapes (optionnel)
db/
database.py # sqlite connection
models.py # SQLAlchemy models
schemas.py # pydantic
crud.py
migrations/ # si besoin plus tard
scraper/
amazon/
parser.py # extraction DOM -> dict normalisé
selectors.md # doc sélecteurs
browser.py # création context Playwright
runner.py # scrap 1 / scrap all
normalize.py # parsing prix, notes, booléens
services/
pricing.py # calculs 30j si données
images.py
tests/
test_normalize.py
test_parser_samples.py
samples/
amazon_product.html # snapshots HTML (tests)
config_backend.json
logs/
scrap.log
data/
raw/
screenshots/
frontend/
src/
app/
components/
styles/
api/
public/
config_frontend.json
docker/
docker-compose.yml
backend.Dockerfile
frontend.Dockerfile
nginx.conf (option)
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é
config_backend.json (spécification)
Contenu attendu :
app: {env,version,base_url,log_level}scrape:interval_minutes(pour cron/worker)headless(bool)timeout_msretriesdelay_range_ms: [min,max]user_agentviewport: {w,h}locale,timezoneproxy(option) => non pas de proxy
stores_enabled: ["amazon_fr"]taxonomy:categories: ["SSD", "CPU", ...]types_by_category: { "SSD": ["NVMe", "SATA"], ... }
config_frontend.json (spécification)
ui:theme: "gruvbox_vintage_dark"- 'button_mode': " text/icon"
columns_desktop: 3 (ex) => slidercard_density: "comfortable"|"compact"show_fields: { flags }refresh_auto_seconds
versions: {frontend,backend_expected}
Schéma base de données (SQLite)
Proposer un schéma minimal + extensible.
Tables
products
id(PK)store(ex: amazon_fr)urlasintitleimage_urlcategorytypeis_active(bool)created_at,updated_at
scrape_runs
id(PK)started_at,ended_atstatus(success/partial/failed)items_total,items_ok,items_failedlog_path(option)
product_snapshots
id(PK)product_id(FK → products.id)scraped_atprice_currentprice_list(nullable)lowest_30d_price(nullable)stock_text(nullable)in_stock(nullable)rating_value(nullable)rating_count(nullable)prime_eligible(nullable)amazon_choice(nullable)limited_time_deal(nullable)amazon_exclusive(nullable)raw_json_path(nullable)scrape_status(ok/blocked/missing_fields/error)error_message(nullable)
- (option)
tags
id,name
- (option)
product_tags
product_id,tag_id
Relations
products (1) ─── (N) product_snapshotsscrape_runs (1) ─── (N) product_snapshots(optionnel si on lie snapshots à run)
Indices
- index
(product_id, scraped_at) - index
asin
page web : logs et debug
Plan de développement (phases)
Phase 0 — Setup repo & conventions
- initialiser repo
suivi_produits - ajouter
README.md,TODO.md,CHANGELOG.md,kanban.md - définir conventions : formatage, lint, tests
Phase 1 — MVP Backend + DB
- FastAPI + SQLite + SQLAlchemy
- endpoints :
GET /healthGET/POST/PUT/DELETE /productsPOST /scrape/product/{id}POST /scrape/allGET /products/{id}/history?days=30GET/PUT /config/backend
Phase 2 — Scraper Amazon (Playwright)
- module
scraper/amazon/parser.py - normalisation des prix (ex: "249,99 €" → 249.99)
- gestion champs optionnels (pas d’invention)
- logs + debug artifacts
- tests unitaires sur HTML samples (fichiers dans
samples/)
Phase 3 — Frontend (vignettes + graph)
- grille responsive, colonnes paramétrables
- composant CardProduit
- graphique 30j (lib : chart.js / echarts / recharts selon stack)
- page Settings : frontend + backend config éditables
Phase 4 — Scheduler / Cron
- job toutes les X minutes/heures (config)
- stockage des snapshots
- endpoint stats (dernier scrap, erreurs, taux de succès)
Phase 5 — Docker Compose
- dockeriser backend + frontend
- volume persistant SQLite + logs + raw json
- doc d’installation
Phase 6 — Évolution multi-stores
- abstraction
StoreScraper(interface) - un module par boutique :
scraper/<store_name>/... - routing : store → scraper
Tests (exigences)
- Tests unitaires :
- parsing prix FR
- extraction rating/count
- présence/absence champs optionnels
- Tests d’intégration :
- scrap d’un produit réel (option “manual”) avec variable
RUN_LIVE_SCRAPE=1 - sinon, replay HTML sample
- scrap d’un produit réel (option “manual”) avec variable
Livrables attendus
- Code complet backend + frontend (MVP fonctionnel)
docker-compose.yml- docs :
README.md(install, run, config)TODO.md(backlog)CHANGELOG.md(semver simple)kanban.md(colonnes : Backlog / Doing / Review / Done)
- Schéma DB + migrations (si besoin)
Questions à poser (bloquantes ou importantes)
- Frontend : tu préfères React (Vite) ou Svelte ? (sinon choisis la voie la plus simple et robuste)
- Déclenchement cron : tu veux un cron linux (container cron) ou un scheduler interne (APScheduler) ?
- Auth : l’app est-elle accessible uniquement en LAN (pas d’auth) ou tu veux un login simple ? => non
- Stockage raw JSON : tu veux conserver tous les raw ou uniquement les derniers N jours ? => oui
- Mode “captcha” : en cas de blocage, tu veux :
- (a) abandon + log + retry plus tard => oui
- (b) ouvrir navigateur headful pour résolution manuelle
Si pas de réponse, prends des décisions raisonnables : React+Vite, scheduler interne APScheduler, pas d’auth (LAN), raw conservé 30 jours, stratégie (a).
Notes de qualité (non négociables)
- Ne jamais faire planter un scrap si un champ manque.
- Ne pas calculer des métriques si aucune donnée n’est disponible sur la page.
- UI : lisibilité d’abord (contraste, spacing, hiérarchie typographique).
- Logs : chaque scrap doit laisser une trace claire (start/end, erreurs, champs manquants).
Démarrage immédiat (premières tâches)
- Créer squelette repo + outils (poetry/pip-tools, pre-commit, ruff, mypy)
- Implémenter DB + CRUD produits
- Implémenter scrap d’un produit Amazon + snapshot
- Afficher vignettes + graph 30j
- Ajouter Settings + configs JSON éditables
- Dockeriser