尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Pousse : web app pilote entreprise (Next.js, Supabase)
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Application web pour le pilote entreprise de Pousse : un salarié rejoint son entreprise avec un code, fait son bilan carbone, relève des défis reliés à ses habitudes, les valide avec une preuve et les partage dans le fil interne de l'entreprise.
Stack : Next.js 15 (App Router) · React 19 · Tailwind CSS 4 · Supabase (auth par lien e-mail, Postgres, stockage des photos). Pensée mobile d'abord, utilisable sur ordinateur.
La v2 ajoute :
src/lib/actions/interpret.ts), confirmée par la personne, puis calculée par la base (log_action_slug) ;/entreprise puis /admin) : lancement en self-serve, tableau de bord agrégé (rien sous
5 personnes), rapport mensuel écrit par des règles, export PDF (impression) et CSV de la mobilité domicile-travail.L'application n'utilise pas d'IA (décision du 26/10/2026, migration 0042_sans_ia.sql). Le CO₂ est
toujours calculé par le code : quantité × facteur, avec la table versionnée emission_factors
(supabase/data/emission_factors.json, généré par node scripts/generate-factors.ts).
| Variable | Rôle |
|---|---|
VAPID_PRIVATE_KEY | Rappels sur téléphone (la seule variable secrète). |
Les tâches planifiées (animateur, rappels, purge des photos) sont déclenchées par la base avec des clés
créées dans Vault (migrations 0032, 0044) : aucun CRON_SECRET ni clé service_role dans Vercel.
Appliquer toutes les migrations (supabase db push). Celles dont la première ligne dit « Supabase
seulement » créent la clé des tâches planifiées dans Vault (nommée « ia » par héritage) et programment
pg_cron : l'animateur (pousse-animateur, lundi 9 h et 14 h, milieu de semaine, vendredi), les
rappels (pousse-rappels) et la purge des photos (pousse-purge, Edge Function). Elles appellent
https://pousse-pilote.vercel.app et le projet Supabase de production.
| Migration | Contenu |
|---|---|
| 0026 – 0028 | Facteurs d'émission, catalogue des actions, calcul sur facteurs, fil jamais automatique |
| 0029 – 0033, 0036, 0039, 0040 | Fonctions d'IA, retirées par 0042 (gardées pour l'historique) |
| 0030 – 0031 | Publication proposée (photo facultative), Mon plan |
| 0034 – 0035 | Animateur du QG |
| 0038 | Espace RSE : organisations, agrégats, export |
| 0041 | Classement du rapport limité au mois |
| 0042 | Retrait de l'IA |
| 0043 | Plus de justificatif : plafonds annuels calés sur le bilan |
| 0044 | Rappels et purge des photos planifiés par la base (Supabase seulement) |
| 0045 – 0046 | Actions universelles du + : repas végé pondéré, appareils, catalogue mis à jour |
| 0047 – 0049 | L'île : graines plantées, déplacées ou arrachées, zones à restaurer |
| 0050 | Île : Graineterie (achats en pousses, prix calés sur la démo), plantes gagnées en défi, migrateur d'équipe, myosotis offerts |
| 0051 | Île : le défi débloque une espèce, les pousses la font grandir (Serre, plantes de départ) |
| 0052 | Compteur du haut : les pousses qu'il reste à dépenser |
| 0053 | Clarté du jeu : bonus gros leviers (+5 au-delà de 1 kg évité, +10 au-delà de 3 kg), pas de bravo à soi-même |
npm run db:demo (avec DATABASE_URL) crée « Verdure Conseil (démo) » : 3 équipes, 30 salariés,
4 semaines d'actions passées par le vrai calcul, des messages de QG. Admin : [email protected].
À ne jamais jouer en production.
npm test # calcul, plafonds, saisie libre, plan, animateur, rapport, CSV
npm run test:sql # migrations et scénarios sur PostgreSQL 16 (dont parité TS/SQL du calcul)
npm run test:e2e # Playwright : action, confirmation, célébration, publication (Supabase local)
| Écran | Rôle |
|---|---|
/rejoindre | Code d'entreprise + e-mail pro → lien de connexion (pas de mot de passe) |
/bienvenue | Prénom, équipe, consentements |
/questionnaire | Bilan en 14 questions |
/bilan | Empreinte par poste, ce que tu fais déjà, plus gros postes restants, plan d'action |
/defis | Garder le cap, défis en cours, plafonds du jour, catalogue (défis expert, défis non proposés et pourquoi) |
/defis/nouveau/[défi] | Choix de la variante et de l'objectif, impact calculé en direct |
/defis/[id]/valider | Validation avec photo et/ou collègue témoin, choix de publier |
/scanner | Scan d'un code-barres (caméra ou saisie), Green-Score, CO₂ Agribalyse, 3 alternatives mieux notées |
/regles | Comment ça marche : points, classement, kg, barème |
/fil | Fil interne de l'entreprise : bravos, signalement, « Relever aussi », et bonnes nouvelles des médias |
/equipes | Classement en points par participant (équipes de 5 minimum), toi, objectif de l'entreprise |
/notifications | Confirmations demandées par des collègues |
/avis | Questionnaire de 3 questions pour le pilote |
/profil | Points Pousse détaillés, série, influence, préférences, export, suppression du compte |
/methodologie, /confidentialite | Pages publiques |
src/lib/co2/factors.ts.validate_challenge_day) :
le navigateur n'envoie jamais de chiffre. Les insertions directes dans validations sont refusées.Le calcul existe en deux exemplaires, qui doivent rester identiques :
src/lib/co2/challenges.ts (aperçus à l'écran) et unit_kg dans
supabase/migrations/0002_functions.sql (calcul officiel). Les tests vérifient les mêmes valeurs des deux côtés.
Deux chiffres, deux rôles, expliqués dans l'app (/regles et l'écran « Comment ça marche » du fil) :
0009_equilibrage.sql) : défi
du quotidien +10 par unité, train +30, défis expert +15 à +150, +5 de bonus de preuve ; sans preuve, le CO₂
compte mais pas les pousses. Garder le cap +10 pour 2 habitudes par semaine au plus, les 3 quêtes du jour
+15 (tirées chaque matin parmi : défi avec preuve, défi expert, lancer un défi, scanner un produit,
meilleur choix au scanner, bravo à un collègue, garder le cap), une seule série : les jours actifs
(+10 à 3 jours, +25 à 7, +50 à 14, +100 à 30), influence +15, témoin +3. Dans la base, la colonne
s'appelle toujours points ; les pousses hors défis sont dans points_ledger, écrites uniquement par la
base (claim_daily_rewards pour les quêtes et les séries, appelée à l'ouverture de l'accueil).companies.pilot_weeks, 8 par défaut).L'accueil est construit pour donner envie de revenir : la plante grandit de niveau en niveau (Graine, Germe, Pousse, Plantule, Arbuste, Arbre, Forêt), le total de pousses monte en direct depuis la dernière visite avec un « +N », les quêtes du jour se cochent, la série de jours actifs promet son prochain bonus, et les dernières pousses gagnées défilent. Le compteur est aussi en haut de chaque page.
Pour garder motivées les personnes déjà sobres : « garder le cap » sur les habitudes déjà acquises,
points d'influence quand un collègue relève un défi depuis leur publication (inspired_by), défis expert
(repas végétalien, vacances en train au lieu du long-courrier, réparer son smartphone ou son ordinateur),
et dans le bilan les plus gros postes restants et « ce que tes habitudes évitent déjà » (une comparaison,
jamais ajoutée au CO₂ évité).
Migrations 0005_engagement.sql à 0009_equilibrage.sql ; scénario supabase/tests/scenario_engagement.sql
(à jouer après scenario.sql).
/scanner lit le code-barres avec la caméra (API BarcodeDetector sur Chrome Android, sinon la bibliothèque
ZXing chargée à la demande depuis unpkg pour Safari) ou par saisie. La fiche vient d'Open Food Facts
(licence ODbL, source citée sur chaque page) : Green-Score (ex-Eco-Score) et empreinte carbone Agribalyse en
kg CO₂e par kg. Les alternatives sont cherchées dans la catégorie la plus précise du produit, puis la
catégorie parente, parmi les produits vendus en France : mieux notées, ou même note et au moins 10 % de CO₂
en moins, une par marque (src/lib/off/). Réponses mises en cache une journée.
Choisir une alternative rapporte +5 pousses, 3 fois par jour au plus (record_swap, migration
0008_scanner.sql), et compte comme un jour actif pour la série. Aucun CO₂ évité n'est compté : on ne sait
pas ce que la personne aurait acheté sinon. Les deux fiches sont relues par le serveur de l'application avant
l'appel ; un utilisateur qui appellerait directement record_swap avec de fausses notes resterait limité à
15 pousses par jour. Seul l'alimentaire est couvert. La caméra demande une page en HTTPS (ou localhost).
Optionnel : OFF_CONTACT (e-mail de contact transmis à Open Food Facts dans l'en-tête User-Agent).
Le fil intercale une bonne nouvelle écologique toutes les 2 publications. Elles viennent des flux RSS de
vrais médias (Vert, Novethic, Kaizen, Socialter, La Relève et La Peste), listés dans
src/lib/news/index.ts. Chaque flux est relu au plus une fois par jour et la sélection change chaque jour
(heure de Paris). Seuls les articles de moins de 10 jours avec une note positive sont gardés (mots qui
signalent une avancée, titre sans mot négatif : src/lib/news/rss.ts), au plus 2 par média. On affiche le
titre, un court extrait et un lien vers l'article d'origine. Un média injoignable est simplement ignoré.
/api/news renvoie la sélection du jour en JSON.
Pousse s'installe sur l'écran d'accueil (manifeste src/app/manifest.ts, icônes dans public/,
service worker public/sw.js avec une page hors ligne). Sur Android et ordinateur, un bandeau propose
« Installer » ; sur iPhone, il indique le geste Safari (Partager → Sur l'écran d'accueil).
Rappel du soir (Web Push, à activer dans le profil) : vers 18 h, /api/cron/rappels relance les personnes
abonnées qui n'ont encore rien fait dans la journée, au plus une fois par jour. La notification part
vide (signature VAPID faite avec node:crypto, sans dépendance) : à l'arrivée, le téléphone lit le
texte sur /api/rappel avec sa propre session (« Ta série de 4 jours s'arrête ce soir »). La base
déclenche la tâche (pg_cron, migration 0044) avec sa clé « rappels », qu'elle vérifie elle-même (seule
l'empreinte SHA-256 est stockée dans cron_keys). Variables : NEXT_PUBLIC_VAPID_PUBLIC_KEY (publique,
dans .env.production) et VAPID_PRIVATE_KEY (dans Vercel). Nouvelle paire de clés :
node src/lib/push/vapid.ts.
Prérequis : Node 22.18 ou plus récent, un compte Supabase (région UE).
supabase db push) :
0001_schema.sql, 0002_functions.sql, 0003_policies.sql, 0004_seed.sql, 0005_engagement.sql, 0006_points.sql, 0007_pousses.sql, 0008_scanner.sql, 0009_equilibrage.sql.
Le dernier crée une entreprise de démonstration, code DEMO-2026, avec 6 équipes.http://localhost:3000 en local, puis l'URL Vercel ;http://localhost:3000/auth/callback et https://<ton-domaine>/auth/callback..env.example en .env.local et remplir l'URL et la clé
anon (Project Settings > API).npm install
npm run dev
Ouvrir http://localhost:3000, cliquer sur « Rejoindre », code DEMO-2026./rejoindre (première fois : code entreprise + e-mail) et /connexion (compte existant : e-mail seul)
envoient un e-mail de connexion. Pour que cet e-mail contienne aussi un code à 6 chiffres, plus fiable sur
téléphone que le lien :
{{ .Token }} ;NEXT_PUBLIC_LOGIN_CODE=1 dans .env.production (ou dans Vercel) et redéployer.Le code de l'entreprise de démo du seed (DEMO-2026) est public : en production, le remplacer par un code
secret (update companies set join_code = '…') et créer les vraies entreprises avec leur email_domain.
Importer le dépôt, ajouter VAPID_PRIVATE_KEY, mettre NEXT_PUBLIC_SITE_URL à l'URL Vercel, et ajouter
https://<ton-domaine>/auth/callback aux Redirect URLs de Supabase.
La suppression des photos (justificatifs à 30 jours, photos du fil à 90 jours), promise aux salariés, est
faite chaque nuit par l'Edge Function Supabase purge-photos (supabase/functions/), déclenchée par
pg_cron (migration 0044). Elle utilise la clé de service fournie par Supabase : aucune clé secrète
Supabase n'est à copier dans Vercel. Déploiement : supabase functions deploy purge-photos --no-verify-jwt.
Dans l'éditeur SQL de Supabase :
with c as (
insert into companies (name, join_code, email_domain)
values ('Nom de l''entreprise', 'ACME-2026', 'acme.fr') -- email_domain : null pour tout domaine
returning id
)
insert into teams (company_id, name)
select c.id, t from c, unnest(array['Data', 'Produit', 'Finance']) as t;
npm test # calcul du bilan, gains des défis, éligibilité, plan d'action
La base se teste sur un PostgreSQL 16 local (sans Supabase), avec une imitation minimale de l'authentification et du stockage. Le scénario se joue sur une base neuve :
createdb pousse_test
# migrations jusqu'à 0013, puis les scénarios qui les testent
for f in supabase/tests/supabase_stub.sql $(ls supabase/migrations/*.sql | awk -F/ '$3 < "0014"'); do psql -d pousse_test -v ON_ERROR_STOP=1 -f "$f"; done
psql -d pousse_test -f supabase/tests/scenario.sql
psql -d pousse_test -f supabase/tests/scenario_engagement.sql
psql -d pousse_test -f supabase/tests/scenario_rappels.sql
psql -d pousse_test -f supabase/tests/scenario_jeu.sql
psql -d pousse_test -f supabase/tests/scenario_actions.sql
psql -d pousse_test -f supabase/tests/scenario_qg.sql
# puis le quiz quotidien (0014 et 0015) et son scénario
for f in $(ls supabase/migrations/*.sql | awk -F/ '$3 >= "0014"'); do psql -d pousse_test -v ON_ERROR_STOP=1 -f "$f"; done
psql -d pousse_test -f supabase/tests/scenario_quiz.sql
psql -d pousse_test -f supabase/tests/scenario_duels.sql
psql -d pousse_test -f supabase/tests/scenario_nature.sql
psql -d pousse_test -f supabase/tests/scenario_coherence.sql
psql -d pousse_test -f supabase/tests/scenario_equite_points.sql
psql -d pousse_test -f supabase/tests/scenario_anti_triche.sql
La banque du quiz (0015_quiz_banque.sql) est générée : node scripts/generate-quiz.ts > supabase/migrations/0015_quiz_banque.sql.
Toutes les questions sont calculées depuis src/lib/co2/factors.ts (ADEME), avec des choix proches pour rester difficiles.
scenario_actions.sql (migration 0012_actions_libres.sql) vérifie le bouton + : action enregistrée sans
preuve, CO₂ tiré du bilan (0 kg si rien n'est remplacé), plafonds du jour, action comptée dans le défi en
cours, publication avec photo par l'auteur seulement, compteur commun de l'entreprise.
scenario_qg.sql (migration 0013_qg_equipe.sql) vérifie le QG : chat réservé à l'équipe, masquage après
deux signalements, vote du lundi de 9 h à 14 h, choix le plus voté, annonce unique, +30 aux contributeurs.
Le premier scénario vérifie 22 points : code d'entreprise, domaine e-mail, calculs identiques au TypeScript, plafond partagé, refus d'une insertion directe, photo hors de son dossier, témoin qui refuse, cloisonnement entre entreprises, classement anonyme (équipes de moins de 5 masquées).
La CI GitHub (.github/workflows/ci.yml) vérifie à chaque commit de v2 : installation, types Supabase
régénérés, typecheck, lint, tests unitaires, tests SQL, build, puis le parcours Playwright sur un
Supabase local.
Pas encore vérifié : l'envoi des e-mails et le rendu sur de vrais téléphones.
@incubateur-ademe/nosgestesclimat avec publicodes), en vérifiant la licence des données ecoinvent
pour un usage commercial.reports, à traiter depuis le tableau de bord Supabase.