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

17 KiB
Raw Permalink Blame History

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
  1. scrape_runs
  • id (PK)
  • started_at, ended_at
  • status (success/partial/failed)
  • items_total, items_ok, items_failed
  • log_path (option)
  1. 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)
  1. (option) tags
  • id, name
  1. (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