Files
suivi_produit/consigne codex.md
2026-01-18 12:23:01 +01:00

421 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 :
1) 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 : 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`)
---
## 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 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é
---
## `config_backend.json` (spécification)
Contenu attendu :
- `app`: { `env`, `version`, `base_url`, `log_level` }
- `scrape`:
- `interval_minutes` (pour cron/worker)
- `headless` (bool)
- `timeout_ms`
- `retries`
- `delay_range_ms`: [min,max]
- `user_agent`
- `viewport`: {w,h}
- `locale`, `timezone`
- `proxy` (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) => slider
- `card_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
1) `products`
- `id` (PK)
- `store` (ex: amazon_fr)
- `url`
- `asin`
- `title`
- `image_url`
- `category`
- `type`
- `is_active` (bool)
- `created_at`, `updated_at`
2) `scrape_runs`
- `id` (PK)
- `started_at`, `ended_at`
- `status` (success/partial/failed)
- `items_total`, `items_ok`, `items_failed`
- `log_path` (option)
3) `product_snapshots`
- `id` (PK)
- `product_id` (FK → products.id)
- `scraped_at`
- `price_current`
- `price_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)
4) (option) `tags`
- `id`, `name`
5) (option) `product_tags`
- `product_id`, `tag_id`
### Relations
- `products (1) ─── (N) product_snapshots`
- `scrape_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 /health`
- `GET/POST/PUT/DELETE /products`
- `POST /scrape/product/{id}`
- `POST /scrape/all`
- `GET /products/{id}/history?days=30`
- `GET/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 dinvention)
- 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 dinstallation
### 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 dintégration :
- scrap dun produit réel (option “manual”) avec variable `RUN_LIVE_SCRAPE=1`
- sinon, replay HTML sample
---
## 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)
1) Frontend : tu préfères **React** (Vite) ou **Svelte** ? (sinon choisis la voie la plus simple et robuste)
2) Déclenchement cron : tu veux un **cron linux** (container cron) ou un **scheduler interne** (APScheduler) ?
3) Auth : lapp est-elle accessible uniquement en LAN (pas dauth) ou tu veux un login simple ? => non
4) Stockage raw JSON : tu veux conserver **tous** les raw ou uniquement les derniers N jours ? => oui
5) 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 dauth (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 nest disponible sur la page.
- UI : lisibilité dabord (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)
1) Créer squelette repo + outils (poetry/pip-tools, pre-commit, ruff, mypy)
2) Implémenter DB + CRUD produits
3) Implémenter scrap dun produit Amazon + snapshot
4) Afficher vignettes + graph 30j
5) Ajouter Settings + configs JSON éditables
6) Dockeriser