尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Site de suivi budget et workflow de montage pour le projet PC Full White d'AntoniMan31.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Site de suivi du budget et du montage du PC Full White d'AntoniMan31, consultable depuis un téléphone. En ligne : https://antoniman31.github.io/pc-full-white/
HTML, CSS et JS sans framework · Python (relevé des prix) · GitHub Actions et Pages.
data/prices.json est la seule source de vérité : prix, statuts, checklists, historique. Rien n'est codé en dur dans la page.main.revendeurs ──► relevé (Actions, 1er et 15) ──► PR « prix » ──┐
├─► fusion ──► data/prices.json ──► GitHub Pages ──► site
navigateur ──► « Envoyer » ──► PR site-changes/… ────────────┘
(achats, prix saisis) (data/changes.json)
Navigation. Barre du bas sous 600 px ; dès 600 px, barre latérale avec icônes, sous-onglets avec icônes et texte 10 % plus grand. Les sous-onglets se parcourent aussi au swipe.
Thèmes. Réglages ou icône en haut de page. En Auto, le thème suit le système. L'impression repasse toujours en clair.
Fraîcheur d'un prix. Une alerte ambre « à vérifier » apparaît si le prix a plus de 7 jours ou repose sur une seule boutique (IKEA, seul vendeur de ses produits, est exclu de cette règle).
Envoyer ses changements. Achats, prix saisis, produits modifiés, articles ajoutés ou supprimés :
site-changes/…, y écrit data/changes.json et ouvre la PR. Un envoi suivant met à jour la même PR tant qu'elle est ouverte..github/workflows/site-changes.yml applique changes.json à prices.json (scripts/apply_changes.py), contrôle la cohérence et commit le résultat. Il remet aussi à jour les PR site-changes/… ouvertes quand main change.Lancer un relevé. La carte « Relevé des prix » de Réglages propose « Relevé complet » (ouvre une PR de prix) et « Essai » (n'écrit rien, rapport dans le résumé du job). Chaque lancement demande une confirmation : un relevé consomme des recherches SerpApi. La page suit l'avancement toutes les 15 secondes et affiche le lien de la PR. La fusion reste manuelle.
Checklist de montage. Chaque case est enregistrée dans le localStorage de l'appareil : pas de compte, pas de synchronisation entre téléphone et PC.
Le 1er et le 15 de chaque mois à 7 h UTC, ou à la main (Actions → Relevé des prix → Run workflow). Le script ouvre une PR, en brouillon si le contrôle de cohérence échoue.
| Règle | Valeur |
|---|---|
| Prix retenu | l'offre valide la moins chère |
| Offre valide | le nom de la fiche contient les mots attendus et aucun mot interdit (scraper/sources.json) |
| Écarté comme absurde | prix sous 70 % de la médiane, ou hors de 0,5 à 2 fois le prix actuel |
| Écrit seulement si | au moins 2 sites concordent (1 pour IKEA) et la variation reste sous 30 % |
| Sinon | le prix est proposé dans la description de la PR |
| Articles achetés | figés ; sans source : listés « sans source » dans le rapport |
Respect des sites. Données structurées uniquement (JSON-LD, microdata, Open Graph, via extruct), jamais « le premier montant de la page ». Identifiant pc-full-white-price-check, robots.txt respecté, une requête toutes les 3 s par site. Un site qui bloque est signalé, pas contourné.
Liens d'achat. Chaque article garde dans prices.json (offers) les fiches qui ont servi : revendeur, adresse, prix, date. Une fiche momentanément injoignable garde son lien 60 jours.
Google Shopping et Amazon (SerpApi). Pour les articles que les fiches directes ne confirment pas (Cdiscount, Darty et Fnac interdisent les robots, Materiel.net refuse GitHub, Amazon n'a pas d'API ouverte). Forfait gratuit de 250 recherches par mois ; au plus 40 par passage (25 Shopping, 15 Amazon, Amazon en dernier recours). Une offre vue il y a moins de 14 jours reste valable si le vendeur ne ressort pas aujourd'hui (« mémorisée » dans le rapport). Les produits de référence génériques (auto: false) ne sont jamais écrits sans ton accord. Activation : secret de dépôt SERPAPI_KEY (Settings → Secrets and variables → Actions). Sans lui, le complément est désactivé sans rien casser.
Modes manuels (champ mode) :
| Mode | Effet |
|---|---|
releve | relevé complet, écrit les prix, ouvre une PR (mode des passages automatiques) |
essai | idem sans rien écrire ; rapport dans le résumé du job |
decouverte | cherche des fiches par nom chez chaque revendeur, ouvre une PR sur sources.json |
essai-decouverte | idem sans PR |
sonde | teste des adresses collées dans le champ adresses |
Ajouter une source. Dans scraper/sources.json, ajoute {"retailer": "ldlc", "url": "https://…"} à sources de l'article. Pour vérifier qu'une adresse est lisible, utilise d'abord sonde. En local : pip install -r scraper/requirements.txt, puis python3 scraper/update_prices.py --dry-run (ou --probe URL).
pc-full-white/
├── data/
│ ├── prices.json # source de vérité
│ └── changes.json # changements envoyés depuis le site
├── site/
│ ├── index.html # page unique, sprite d'icônes, politique de sécurité
│ ├── style.css # design system Full White (Material 3)
│ ├── app.js # génère tout depuis prices.json
│ └── fonts/ # polices auto-hébergées
├── scraper/ # relevé : update_prices.py, sources.json, retailers.json,
│ └── tests/ # extract / fetch / aggregate / recompute / shopping / discover / changes
├── scripts/
│ ├── check_prices.py # recalcule les totaux, refuse un JSON incohérent
│ ├── apply_changes.py # applique changes.json à prices.json
│ └── stamp_assets.py # numéros de version des fichiers + empreinte de la politique de sécurité
├── tests/ # Playwright (13 fichiers) ; unit/ : logique pure, sans navigateur
├── docs/ # archive : anciens PDFs (Sauvegarde, LITE, Workflow)
├── .github/workflows/
│ ├── checks.yml # données, tests du scraper, tests de logique, accessibilité
│ ├── update-prices.yml # relevé le 1er et le 15 + modes manuels
│ └── site-changes.yml # applique et rafraîchit les PR site-changes/…
├── SPEC.md # spécification accessibilité / Material 3
├── TODO.md # points ouverts
└── index.html # redirection vers site/
python3 -m http.server 8000 # puis http://localhost:8000/site/
Le serveur sert la racine du dépôt, pas site/ : app.js lit ../data/prices.json. C'est aussi ainsi que GitHub Pages sert le projet.
python3 scripts/check_prices.py data/prices.json # cohérence des données (CI)
node --check site/app.js # syntaxe (CI)
node --test tests/unit/logique.mjs # logique du budget, < 1 s (CI)
python3 -m unittest discover -s scraper/tests # scraper, sans réseau (CI)
python3 scripts/stamp_assets.py # après toute modif de app.js, style.css ou du script du <head>
npm ci && npx playwright install chromium # la première fois
npx playwright test # ~390 tests, environ 4 minutes
| Tests | Nombre | Rôle |
|---|---|---|
scraper/tests (Python) | 142 | extraction, concordance, recalcul des totaux, changements, Shopping |
tests/unit (Node) | 9 | nettoyage des changements locaux, calcul du budget |
tests/*.spec.mjs (Playwright, bureau et mobile) | ~390 | accessibilité (axe, clair et sombre), clavier, cohérence visuelle, envoi, relevé, fraîcheur, politique de sécurité |
Conventions.
stamp_assets.py écrit ?v=<empreinte> sur style.css et app.js, et l'empreinte du script du <head> dans la politique de sécurité. La CI échoue si tu l'oublies.light-dark() ; les données gardent des emojis (prices.json), traduits en pictogrammes par EMOJI_ICON dans app.js.// >>> logique pure et // <<< fin logique pure dans app.js.<meta>) : scripts du site uniquement, connexions limitées au site et à api.github.com. Aucune requête vers un tiers : polices auto-hébergées. frame-ancestors n'est pas prise en charge dans une balise meta, donc l'affichage dans une iframe n'est pas bloqué.main : protège-la (PR obligatoire) pour que le token ne puisse rien y pousser directement.main, dossier / (root) : index.html à la racine redirige vers site/.Pictogrammes : Material Symbols (Google, style « outlined », licence Apache 2.0), extraits de @material-symbols/svg-400 et intégrés au sprite de site/index.html.
AntoniMan31, dev Android et web amateur, Toulouse.