Commit graph

315 commits

Author SHA1 Message Date
29bd413de3 fix(mobile): corrige les liens vers /releases/latest/download
All checks were successful
CI / lint (push) Successful in 3m3s
CI / build (push) Successful in 3m15s
CI / intent-service-test (push) Successful in 4m28s
CI / e2e (push) Successful in 9m31s
CI / test (push) Successful in 17m39s
CI / build-android (push) Has been skipped
Verifie en conditions reelles apres le premier vrai succes de bout en
bout de release.yml (v0.2.0, Release Forgejo #12 avec batchcooking.apk
attache) : Forgejo, contrairement a GitHub, n'implemente pas le
raccourci /releases/latest/download/<fichier>. Seul /releases/latest
lui-meme resout (redirige vers la page de la release) :

  /releases/latest/download/batchcooking.apk -> 404
  /releases/latest                            -> 303 vers /releases/tag/v0.2.0 (OK)
  /releases/download/v0.2.0/batchcooking.apk  -> 200 (OK, mais pas "latest")

Corrige les deux endroits qui presumaient le raccourci GitHub (issue #65
et #66, deja mergees) pour pointer vers /releases/latest tout court : un
clic de plus via la page de release Forgejo pour atteindre le fichier,
mais un lien qui resout toujours plutot qu'un raccourci qui 404 en
permanence. Met a jour le test Cypress de la page d'accueil et le
commentaire de release.yml en consequence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 22:03:14 +02:00
da3d080124 Merge pull request 'fix(release): installe curl avant les appels API de forgejo-release' (#75) from fix/forgejo-release-curl-install into main
All checks were successful
CI / lint (push) Successful in 3m4s
CI / build (push) Successful in 4m19s
CI / intent-service-test (push) Successful in 8m12s
Release / sanity-build (push) Successful in 10m22s
CI / e2e (push) Successful in 14m30s
Release / build-android-apk (push) Successful in 9m15s
Release / forgejo-release (push) Successful in 28s
Release / notify-portainer (push) Successful in 2s
CI / test (push) Successful in 15m3s
CI / build-android (push) Successful in 4m55s
2026-09-06 21:24:02 +02:00
7d4e7efcce fix(release): installe curl avant les appels API de forgejo-release
All checks were successful
CI / lint (push) Successful in 2m58s
CI / intent-service-test (push) Successful in 4m17s
CI / build (push) Successful in 4m28s
CI / e2e (push) Successful in 9m9s
CI / test (push) Successful in 17m36s
CI / build-android (push) Has been skipped
3e vrai declenchement de release.yml (tag v0.2.0) : forgejo-release
echoue en 25s avec 'curl: command not found' — meme classe de probleme
que le docker manquant deja corrige pour sanity-build (#73) : ce runner
ne fournit pas ces outils par defaut, ci.yml's test job avait deja du
installer curl explicitement pour la meme raison.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 21:05:48 +02:00
f6e501d7b5 Merge pull request 'fix(release): remplace softprops/action-gh-release par l'API Forgejo native' (#74) from fix/forgejo-release-native-api into main
Some checks failed
CI / lint (push) Successful in 4m13s
CI / build (push) Successful in 3m28s
CI / intent-service-test (push) Successful in 6m51s
Release / sanity-build (push) Successful in 11m18s
CI / e2e (push) Successful in 15m16s
Release / build-android-apk (push) Successful in 9m38s
CI / test (push) Failing after 21m38s
CI / build-android (push) Has been skipped
Release / forgejo-release (push) Failing after 25s
Release / notify-portainer (push) Has been skipped
2026-09-06 20:42:03 +02:00
8693498373 fix(release): remplace softprops/action-gh-release par l'API Forgejo native
All checks were successful
CI / lint (push) Successful in 2m57s
CI / build (push) Successful in 2m59s
CI / intent-service-test (push) Successful in 4m14s
CI / e2e (push) Successful in 9m19s
CI / test (push) Successful in 17m23s
CI / build-android (push) Has been skipped
2e vrai declenchement de release.yml (tag v0.2.0, apres le fix du docker
manquant sur sanity-build) : forgejo-release echoue en 35s. Log complet :

  Creating new GitHub release for tag v0.2.0...
  GitHub release failed with status: 405
  (x3, puis "Too many retries. Aborting...")

Pas un souci de ref bare comme les autres actions de ce fichier (deja
corrige) : la requete de creation de release elle-meme repond 405 cote
Forgejo, une vraie incompatibilite d'API entre les deux plateformes sans
contournement connu cote configuration de softprops/action-gh-release.

Remplace ce step par deux appels directs a l'API REST native de Forgejo
(POST /repos/.../releases puis POST .../releases/{id}/assets) avec le
GITHUB_TOKEN deja fourni par le runner (permissions: contents: write
deja declare en tete de fichier) — evite toute dependance a la
compatibilite GitHub-Forgejo d'une action tierce. Pas d'equivalent a
generate_release_notes ici (fonctionnalite propre a GitHub, non repliquee
par Forgejo) : le corps de la release reste minimal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 20:23:48 +02:00
aeea0810cc Merge pull request 'fix(release): installe docker avant le build de sanity-build' (#73) from fix/sanity-build-docker into main
Some checks failed
CI / lint (push) Successful in 7m2s
CI / intent-service-test (push) Successful in 4m19s
CI / build (push) Successful in 3m12s
Release / sanity-build (push) Successful in 9m26s
CI / e2e (push) Successful in 11m39s
Release / build-android-apk (push) Successful in 9m48s
Release / forgejo-release (push) Failing after 35s
Release / notify-portainer (push) Has been skipped
CI / test (push) Failing after 20m59s
CI / build-android (push) Has been skipped
2026-09-06 19:57:57 +02:00
6d868809ac fix(release): installe docker avant le build de sanity-build
All checks were successful
CI / lint (push) Successful in 4m30s
CI / intent-service-test (push) Successful in 6m22s
CI / build (push) Successful in 3m15s
CI / e2e (push) Successful in 8m54s
CI / test (push) Successful in 20m1s
CI / build-android (push) Has been skipped
Premier vrai declenchement de release.yml (tag v0.2.0) : sanity-build
echoue en 17s avec 'docker: command not found' — ce runner Forgejo
self-hoste ne fournit pas docker par defaut dans les conteneurs de job,
meme constat deja rencontre par le job test de ci.yml qui l'installe
explicitement avant ses propres appels docker. sanity-build ne l'avait
jamais fait, presque certainement jamais reellement execute sur ce runner
depuis la migration vers Forgejo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 19:36:38 +02:00
ce168a758c Merge pull request 'fix(release): corrige release.yml pour Forgejo et y attache un APK signé' (#72) from fix/release-yml-forgejo into main
Some checks failed
CI / lint (push) Successful in 2m42s
Release / sanity-build (push) Failing after 17s
CI / build (push) Successful in 2m52s
CI / intent-service-test (push) Successful in 4m57s
CI / test (push) Failing after 10m56s
Release / build-android-apk (push) Successful in 11m48s
CI / e2e (push) Successful in 12m3s
Release / forgejo-release (push) Has been skipped
Release / notify-portainer (push) Has been skipped
CI / build-android (push) Has been skipped
2026-09-06 19:15:55 +02:00
854d795c5d fix(release): corrige release.yml pour Forgejo et y attache un APK signe
All checks were successful
CI / lint (push) Successful in 2m55s
CI / build (push) Successful in 2m58s
CI / intent-service-test (push) Successful in 4m48s
CI / e2e (push) Successful in 9m34s
CI / test (push) Successful in 17m24s
CI / build-android (push) Has been skipped
release.yml datait d'avant la migration vers Forgejo et n'avait jamais ete
reteste : refs d'action bares (actions/checkout@v4, softprops/action-gh-
release@v2) sans le prefixe URL complet qu'exige ce runner self-hosted
(meme contrainte deja rencontree et documentee dans ci.yml).

Ajoute aussi ce que #65 attendait reellement : un job build-android-apk
(meme recette que le job build-android de ci.yml, issue #64) qui construit
et signe l'APK, deduit versionName/versionCode du tag pousse (vX.Y.Z ->
versionName X.Y.Z, versionCode majeur*10000+mineur*100+correctif) et
l'attache a la Release Forgejo sous un nom de fichier stable
(batchcooking.apk) via softprops/action-gh-release. C'est ce nom stable qui
permet a /releases/latest/download/batchcooking.apk (page d'accueil, #65)
de toujours pointer vers la derniere release sans jamais changer de lien.

build.gradle : versionCode/versionName deviennent surchargeables via
-PandroidVersionCode/-PandroidVersionName (defaut inchange : 1 / "1.0"
pour tout build qui ne passe pas ces proprietes, comme le job
build-android existant de ci.yml sur un simple push main).

Duplique le job de build Android plutot que de factoriser en workflow_call
reutilisable — le support des workflows reutilisables sur ce runner
Forgejo/act self-hoste n'est pas verifie, et cette recette de ~15 lignes
est deja eprouvee telle quelle dans ci.yml ; pas la peine de risquer une
nouvelle surprise de compatibilite pour economiser un peu de duplication.

Non teste de bout en bout dans cette PR : release.yml ne se declenche que
sur un vrai tag pousse (jamais sur une simple branche/PR), et pousser un
tag ici declencherait potentiellement un vrai redeploiement Portainer en
production si PORTAINER_WEBHOOK_URL est deja configure — a tester
deliberement avec l'utilisateur, pas par un tag de test improvise.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 18:57:33 +02:00
372988d734 Merge pull request 'fix(ci): retombe sur upload-artifact v3 (v4+ non supporté par ce Forgejo)' (#71) from fix/upload-artifact-ghes-compat into main
All checks were successful
CI / lint (push) Successful in 2m57s
CI / build (push) Successful in 3m19s
CI / intent-service-test (push) Successful in 4m23s
CI / e2e (push) Successful in 9m20s
CI / test (push) Successful in 17m41s
CI / build-android (push) Successful in 5m14s
2026-09-06 18:19:15 +02:00
998f0ac6bc fix(ci): retombe sur upload-artifact v3 (v4+ non supporté par ce Forgejo)
All checks were successful
CI / lint (push) Successful in 2m9s
CI / build (push) Successful in 2m25s
CI / intent-service-test (push) Successful in 4m34s
CI / e2e (push) Successful in 7m22s
CI / test (push) Successful in 16m44s
CI / build-android (push) Has been skipped
Le tout premier build-android complet et signé (keystore enfin correct)
échouait quand même à la toute dernière étape :

  GHESNotSupportedError: @actions/artifact v2.0.0+, upload-artifact@v4+
  et download-artifact@v4+ ne sont pas actuellement supportés sur GHES.

v4+ exige l'API "Results" propre à github.com — non implémentée par ce
runner Forgejo self-hosted. v3 utilise encore l'ancienne API Artifacts,
seule compatible ici ; l'interface name/path utilisée par ce job est
identique entre les deux versions, aucun autre changement nécessaire.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 18:01:34 +02:00
27d82b49ca chore: relance la CI (test du nouveau keystore Android)
Some checks failed
CI / lint (push) Successful in 2m54s
CI / build (push) Successful in 2m56s
CI / intent-service-test (push) Successful in 4m48s
CI / e2e (push) Successful in 9m33s
CI / test (push) Successful in 17m22s
CI / build-android (push) Failing after 4m56s
Commit vide (aucun fichier modifie) — declenche le pipeline push sur main
pour verifier le nouveau secret ANDROID_KEYSTORE_BASE64 fourni par
l'utilisateur, ci.yml n'ayant pas de declenchement manuel (workflow_dispatch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 16:56:53 +02:00
644164b25a Merge pull request 'feat(landing): lien de téléchargement de l'app Android (#65)' (#68) from feat/landing-apk-download into main
Some checks failed
CI / lint (push) Successful in 2m54s
CI / build (push) Successful in 2m58s
CI / intent-service-test (push) Successful in 5m7s
CI / e2e (push) Successful in 9m32s
CI / test (push) Successful in 17m30s
CI / build-android (push) Failing after 5m6s
2026-09-06 16:18:09 +02:00
966a0afa02 chore: relance la CI (#68)
All checks were successful
CI / lint (push) Successful in 47s
CI / build (push) Successful in 1m56s
CI / intent-service-test (push) Successful in 3m46s
CI / e2e (push) Successful in 7m40s
CI / test (push) Successful in 17m12s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 16:00:32 +02:00
68216cf852 Merge pull request 'fix(ci): corrige le bit exécutable de gradlew et le fiabilise en CI' (#70) from fix/gradlew-executable-bit into main
Some checks failed
CI / lint (push) Successful in 2m11s
CI / build (push) Successful in 2m26s
CI / intent-service-test (push) Successful in 4m2s
CI / e2e (push) Successful in 7m29s
CI / test (push) Successful in 16m30s
CI / build-android (push) Failing after 4m54s
2026-09-06 15:27:32 +02:00
9c6feab064 fix(ci): corrige le bit exécutable de gradlew et le fiabilise en CI
All checks were successful
CI / build (push) Successful in 3m5s
CI / lint (push) Successful in 3m12s
CI / intent-service-test (push) Successful in 4m16s
CI / e2e (push) Successful in 9m3s
CI / test (push) Successful in 17m43s
CI / build-android (push) Has been skipped
Le tout premier run réel du job build-android (après le merge de #64)
échouait avec './gradlew: Permission denied' — gradlew était suivi par
git en 100644 (non exécutable) au lieu de 100755, probablement perdu au
commit initial du projet Android natif (#63) sur cette machine Windows.

Corrige le mode suivi par git (git update-index --chmod=+x) et ajoute un
chmod +x défensif juste avant l'exécution dans ci.yml, puisque ce bit
n'a aucun sens sous Windows et peut être reperdu silencieusement par un
futur commit sur cette machine.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 15:09:21 +02:00
c0a07e8adc Merge pull request 'feat(ci): build, teste et empaquette un APK Android signé sur chaque push main' (#67) from feat/mobile-ci-android-apk into main
Some checks failed
CI / lint (push) Successful in 2m48s
CI / build (push) Successful in 2m51s
CI / intent-service-test (push) Successful in 4m9s
CI / e2e (push) Successful in 9m14s
CI / test (push) Successful in 17m18s
CI / build-android (push) Failing after 4m15s
2026-09-06 14:44:35 +02:00
92f364bc1f chore: relance la CI (9e collision infra sur le Postgres partagé)
All checks were successful
CI / build (push) Successful in 3m9s
CI / lint (push) Successful in 3m40s
CI / intent-service-test (push) Successful in 5m11s
CI / e2e (push) Successful in 7m29s
CI / test (push) Successful in 17m34s
CI / build-android (push) Has been skipped
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:26:31 +02:00
c662d02da6 chore: relance la CI (8e collision infra sur le Postgres partagé)
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 4m7s
CI / build (push) Successful in 4m13s
CI / test (push) Failing after 12m19s
CI / intent-service-test (push) Successful in 9m10s
CI / e2e (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:12:46 +02:00
e9c0a61aaf Merge pull request 'feat(mobile): vérification automatique de mise à jour de version' (#69) from feat/mobile-update-check into main
Some checks failed
CI / lint (push) Successful in 1m23s
CI / build (push) Successful in 4m37s
CI / intent-service-test (push) Successful in 4m42s
CI / test (push) Failing after 18m10s
CI / e2e (push) Successful in 17m29s
2026-09-06 14:11:54 +02:00
7bafe39d72 chore: relance la CI (collision infra — violation de clé étrangère pendant le seed Postgres partagé)
All checks were successful
CI / lint (push) Successful in 3m37s
CI / build (push) Successful in 3m22s
CI / intent-service-test (push) Successful in 5m42s
CI / e2e (push) Successful in 10m15s
CI / test (push) Successful in 18m22s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 12:25:05 +02:00
907a68eb8a chore: relance la CI (run précédent annulé — cause inconnue, pas un échec de test)
Some checks failed
CI / lint (push) Successful in 4m25s
CI / intent-service-test (push) Successful in 4m43s
CI / build (push) Successful in 4m5s
CI / test (push) Failing after 11m5s
CI / e2e (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 12:09:19 +02:00
b3581b2fb5 chore: relance la CI (7e collision infra sur le Postgres partagé)
Some checks failed
CI / build (push) Successful in 4m5s
CI / lint (push) Successful in 4m25s
CI / intent-service-test (push) Successful in 6m47s
CI / e2e (push) Successful in 13m15s
CI / test (push) Failing after 20m7s
CI / build-android (push) Has been skipped
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 12:06:53 +02:00
cf7e519883 chore: relance la CI (4e collision infra sur le Postgres partagé)
Some checks failed
CI / intent-service-test (push) Has been cancelled
CI / build (push) Has been cancelled
CI / e2e (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 12:00:53 +02:00
85dd1b6255 chore: relance la CI (6e collision infra sur le Postgres partagé)
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 4m33s
CI / build (push) Successful in 3m50s
CI / intent-service-test (push) Successful in 5m28s
CI / test (push) Failing after 10m28s
CI / e2e (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:54:51 +02:00
59352563c4 chore: relance la CI (3e collision infra — course d'upsert concurrente sur le seed Postgres partagé)
Some checks failed
CI / lint (push) Successful in 4m38s
CI / build (push) Successful in 3m28s
CI / intent-service-test (push) Successful in 6m34s
CI / test (push) Failing after 10m22s
CI / e2e (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:49:11 +02:00
4f7a452924 chore: relance la CI (5e collision infra — course d'upsert concurrente sur le seed Postgres partagé)
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 3m34s
CI / build (push) Successful in 3m17s
CI / intent-service-test (push) Successful in 5m16s
CI / test (push) Failing after 8m39s
CI / e2e (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:45:08 +02:00
f37a61266f chore: relance la CI (4e collision infra — cette fois sur le cache d'actions du runner)
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 4m7s
CI / build (push) Successful in 4m43s
CI / intent-service-test (push) Successful in 7m56s
CI / test (push) Failing after 11m11s
CI / e2e (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:31:39 +02:00
09f6d426d3 chore: relance la CI (2e collision infra sur le Postgres partagé)
Some checks failed
CI / lint (push) Successful in 2m46s
CI / intent-service-test (push) Successful in 4m47s
CI / build (push) Successful in 4m31s
CI / e2e (push) Successful in 13m54s
CI / test (push) Failing after 17m45s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:29:51 +02:00
275cc2d500 chore: relance la CI (3e collision infra sur le Postgres partagé)
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 1m6s
CI / build (push) Failing after 35s
CI / e2e (push) Has been cancelled
CI / intent-service-test (push) Has been cancelled
CI / test (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:27:25 +02:00
a3a949ce08 chore: relance la CI (job test cassé par la course d'infra connue sur le Postgres partagé)
Some checks failed
CI / lint (push) Successful in 5m32s
CI / intent-service-test (push) Successful in 5m49s
CI / build (push) Successful in 4m29s
CI / test (push) Failing after 15m13s
CI / e2e (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:08:16 +02:00
bf994c396a chore: relance la CI (2e collision infra sur le Postgres partagé, connexion coupée en cours de run)
Some checks failed
CI / lint (push) Successful in 2m15s
CI / build (push) Successful in 3m54s
CI / intent-service-test (push) Successful in 6m41s
CI / e2e (push) Successful in 16m11s
CI / test (push) Failing after 17m33s
CI / build-android (push) Has been skipped
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:04:32 +02:00
e90cadcc41 chore: relance la CI (#68)
Some checks failed
CI / lint (push) Successful in 4m15s
CI / intent-service-test (push) Successful in 5m49s
CI / build (push) Successful in 4m1s
CI / test (push) Failing after 10m15s
CI / e2e (push) Successful in 12m4s
Le job `test` de la run précédente a échoué sur une saturation du runner
(P1002 Prisma + timeout Docker), pas sur le code — le même job échouait
au même moment sur toutes les branches, `main` compris. Diff 100 % frontend.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 11:02:53 +02:00
5d4d6be2dc feat(mobile): vérification automatique de mise à jour de version
Some checks failed
CI / lint (push) Successful in 6m25s
CI / intent-service-test (push) Successful in 5m1s
CI / build (push) Successful in 2m38s
CI / test (push) Failing after 11m54s
CI / e2e (push) Has been cancelled
Réutilise l'API Releases de Forgejo (publique, sans authentification) comme
source de vérité pour "quelle est la dernière version" — zéro nouvel
endpoint backend : useAppUpdateCheck compare App.getInfo().version
(@capacitor/app, nouvelle dépendance) au tag_name de
GET .../releases/latest, et pointe "Mettre à jour" vers l'URL stable de
téléchargement (issue #65).

Comparaison de version en logique pure (version-compare.ts), séparée du
hook effectful — testée isolément via un test de composant Cypress
(version-compare.cy.tsx, même patron que highlight-tech-steps.cy.tsx :
aucun montage, juste describe/it/expect sur des fonctions pures).

Natif uniquement (Capacitor.isNativePlatform()) : @capacitor/app et
@capacitor/preferences restent en import dynamique dans le hook, jamais
dans le bundle web (même patron que capacitor-token-store.ts) — vérifié
dans le build (deux petits chunks séparés, pas dans le bundle principal).

Vérification au démarrage à froid + à la reprise depuis l'arrière-plan
(appStateChange), avec un throttle de 6h et une mémorisation de la version
déjà rejetée dans @capacitor/preferences pour ne jamais re-harceler sur la
même version. Bannière discrète (pas une Dialog modale), bouton "Mettre à
jour" ouvrant le lien de téléchargement dans le navigateur système plutôt
qu'un flux PackageInstaller in-app.

Vérifié : pnpm lint, pnpm --filter web build, le test de composant (9/9),
et layout/smoke/planning-page e2e (18/18, la bannière étant un no-op sur
le web ne devait rien casser — confirmé).

Closes #66

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 10:52:35 +02:00
548cee721f chore: relance la CI (job test cassé par la course d'infra connue sur le Postgres partagé)
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 2m22s
CI / intent-service-test (push) Successful in 5m35s
CI / build (push) Successful in 4m17s
CI / test (push) Failing after 10m27s
CI / e2e (push) Has been cancelled
18 échecs éparpillés (timeouts 10s sur des suites sans rapport entre elles,
PrismaClientKnownRequestError, un mismatch d'ID façon ré-seed concurrent) sur
373 passing — signature exacte de la course documentée dans
ci-forgejo-runner-constraints (postgres partagé + contention RAM/CPU du
runner), pas un vrai échec de code : ce PR ne touche que ci.yml/le projet
Android/le README, rien que la suite Mocha exerce différemment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 10:45:05 +02:00
76a99f0e77 feat(ci): build, teste et empaquette un APK Android signé sur chaque push main
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / build (push) Successful in 3m21s
CI / lint (push) Successful in 3m31s
CI / intent-service-test (push) Successful in 4m51s
CI / e2e (push) Successful in 10m34s
CI / test (push) Failing after 14m37s
Nouveau job build-android dans ci.yml, gardé par needs: sur les 5 jobs
existants (lint/test/intent-service-test/build/e2e) et limité à main via
if: github.ref == 'refs/heads/main' — c'est ce qui garantit que l'APK n'est
empaqueté qu'une fois la suite de tests existante verte, pas juste construit
en parallèle d'elle.

APK signé avec un vrai keystore de release (jamais généré par la CI —
Android refuse une mise à jour signée par une clé différente de celle déjà
installée) : ajoute signingConfigs.release à build.gradle, lu depuis
l'environnement (ANDROID_KEYSTORE_PATH/_PASSWORD, ANDROID_KEY_ALIAS/_PASSWORD),
jamais codé en dur. *.jks/*.keystore désormais réellement ignorés par git
(étaient commentés dans le .gitignore généré par Capacitor).

README : documente les 5 secrets Forgejo requis et la génération du
keystore. Aucune suite de tests instrumentés Android n'existe (zéro code
natif au-delà de la coquille Capacitor) — "testée" est satisfait par le
gate sur la suite existante, pas par une suite native à inventer.

Risque documenté, pas résolu par avance : aucun build Android n'a jamais
tourné sur ce runner Forgejo auto-hébergé, contrairement aux 4 autres jobs.

Closes #64

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 10:27:55 +02:00
503781c95f feat(landing): lien de téléchargement de l'app Android (#65)
Some checks failed
CI / lint (push) Successful in 5m4s
CI / build (push) Successful in 3m38s
CI / intent-service-test (push) Successful in 6m41s
CI / test (push) Failing after 11m29s
CI / e2e (push) Successful in 14m56s
Sur la page vitrine `/`, sous la rangée de CTA du hero (pas un 3e bouton :
un compte reste nécessaire quelle que soit la plateforme), un lien discret
vers l'APK Android + une ligne d'aide.

- Cible : l'asset `batchcooking.apk` de la dernière release taguée Forgejo
  (`/releases/latest/download/…`, nom de fichier stable) — pas un artefact
  de CI. 404 tant que #64 + la correction de release.yml ne sont pas faits :
  état transitoire assumé, ce ticket n'ajoute que le lien.
- `mobileHint` : rappel honnête que c'est un .apk à sideloader, pas une
  distribution Play Store.
- i18n `landing.hero.mobileDownload` / `mobileHint` ; style discret dans
  landing-page.scss ; scénario Cypress de plus (présence + href du lien).

Vérifs : `pnpm build` + `pnpm lint` OK. `landing.feature` non lancé en
local (le hoist `tslib` de `@cypress/vite-dev-server` dans ce node_modules
est cassé par un `pnpm install --force` interrompu + un verrou concurrent
sur `@esbuild/win32-x64` ; `pnpm-lock.yaml` inchangé, la CI n'est pas
affectée) → couvert par le job `e2e` de la CI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 10:26:50 +02:00
dcfb86d6c9 Merge pull request 'feat(mobile): projet natif Android Capacitor (#39)' (#63) from feat/capacitor-android-native into main
Some checks failed
CI / lint (push) Successful in 1m15s
CI / build (push) Successful in 1m9s
CI / intent-service-test (push) Successful in 3m31s
CI / e2e (push) Successful in 7m2s
CI / test (push) Failing after 14m7s
2026-09-06 10:09:13 +02:00
fd5841d045 feat(mobile): ajoute le projet natif Android Capacitor (#39)
All checks were successful
CI / lint (push) Successful in 4m59s
CI / build (push) Successful in 3m15s
CI / intent-service-test (push) Successful in 6m5s
CI / e2e (push) Successful in 11m41s
CI / test (push) Successful in 20m16s
Dernière étape du portage mobile #39 : génère et versionne le projet natif
Android (`npx cap add android`) que les phases 1 à 3 (jeton Bearer, passe
responsive, plomberie web) préparaient déjà.

- `apps/web/android/` — projet natif Capacitor 8.5. Permission `INTERNET`
  présente par défaut, `applicationId` = `fr.kyuno.batchcooking`.
- Thème natif aligné sur la palette « Mise en Place » (`_theme.scss`) :
  `colors.xml` redéfinit `colorPrimary`/`Dark`/`Accent` (basilic/vermillon)
  par-dessus les défauts Material de la lib capacitor-android ; barre de
  statut basilic foncé, fond de fenêtre « porcelaine » pour ne pas flasher
  blanc au démarrage à froid ; `postSplashScreenTheme` pour la transition.
- Icône adaptative + splash (clair et sombre, toutes densités) générés
  depuis `apps/web/assets/logo.svg` (monogramme « bC », géométrie seule, pas
  de `<text>`) via `@capacitor/assets` ; sources et commande de régénération
  documentées dans `apps/web/assets/README.md`. `@capacitor/assets` n'est pas
  ajouté aux dépendances (il tire `sharp`, hors `onlyBuiltDependencies`) —
  lancé via `npx`.
- `.gitignore` racine : ignore `/.idea/` (Android Studio ouvre désormais le
  dépôt comme projet). `biome.json` : exclut `apps/web/android` du lint.
- README : section « Application mobile (Android) » (prérequis + flux de
  build `build:capacitor` → `cap sync` → Android Studio).

Le bundle web copié sous `android/app/src/main/assets/public/` reste
git-ignoré (régénéré par `pnpm build:capacitor && npx cap sync android`).
Build de l'APK + test sur appareil : à finir dans Android Studio — la CI
self-hosted ne build pas Android.

Vérifs : `pnpm build` + `pnpm lint` OK ; `npx cap sync android` OK ; tous
les XML natifs bien formés.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 09:32:24 +02:00
ab1cf421d9 Merge pull request 'fix(recipes): rend StepDescription tolérant à un techSteps absent' (#62) from claude/practical-swartz-648594 into main
All checks were successful
CI / lint (push) Successful in 3m51s
CI / build (push) Successful in 3m55s
CI / intent-service-test (push) Successful in 5m9s
CI / e2e (push) Successful in 9m1s
CI / test (push) Successful in 17m55s
2026-09-06 09:24:28 +02:00
8e55f3d3f9 fix(recipes): rend StepDescription tolérant à un techSteps absent
All checks were successful
CI / lint (push) Successful in 4m3s
CI / build (push) Successful in 4m36s
CI / intent-service-test (push) Successful in 5m53s
CI / e2e (push) Successful in 8m56s
CI / test (push) Successful in 18m54s
StepDescription faisait `useState(techSteps)` puis `liveTechSteps.flatMap(...)` :
quand la prop `techSteps` arrivait `undefined`, `.flatMap` levait
`TypeError: Cannot read properties of undefined (reading 'flatMap')`, remontée
par Cypress comme une erreur applicative non capturée. Observé de façon
intermittente sur le parcours « modifier une recette » : après enregistrement,
`RecipeFormPage` navigue vers `/recettes/:id`, dont le détail se rendait parfois
avant que `techSteps` ne soit peuplé.

- `StepDescription` : `techSteps` devient optionnel et `liveTechSteps` retombe
  sur `[]` (dans le `useState` et le `useEffect` de resync), pour que tous les
  consommateurs (`.flatMap`, `splitDescriptionSegments`,
  `findTechStepForTemperature`, lookup `activeStepTechStep`) aient toujours un
  vrai tableau — même posture « tolérer la donnée manquante, ne pas planter »
  que le reste du composant.
- `recipe-form.ts` : le mock de la recette 7 envoyait une étape sans `techSteps`,
  contrairement au vrai `StepView` et à tous les autres mocks de la suite —
  corrigé en `techSteps: []`.
- `recipes.cy.ts` : nouveau test de non-régression déterministe — un payload
  d'étape sans `techSteps` doit rendre la description en texte brut. Vérifié
  qu'il échoue bien (`flatMap` undefined) sans le correctif du composant.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 09:04:36 +02:00
713d6c520d Merge pull request 'feat(web): page admin de CRUD des didacticiels (#44)' (#61) from feat/admin-tour-page into main
All checks were successful
CI / lint (push) Successful in 1m17s
CI / build (push) Successful in 1m10s
CI / intent-service-test (push) Successful in 3m33s
CI / e2e (push) Successful in 6m57s
CI / test (push) Successful in 16m11s
2026-09-06 07:27:16 +02:00
b39105ac27 feat(web): page admin de CRUD des didacticiels (#44)
All checks were successful
CI / lint (push) Successful in 2m10s
CI / build (push) Successful in 2m19s
CI / intent-service-test (push) Successful in 4m41s
CI / e2e (push) Successful in 7m19s
CI / test (push) Successful in 16m20s
L'UI par-dessus l'API `/admin/api/tours*`. Nouvelle entrée
`/admin/didacticiels` dans `AdminLayout` (i18n `admin.nav.tours`), route
sous `RequireAdmin`+`AdminLayout` dans `App.tsx`.

`ToursPage.tsx` : liste des scénarios à gauche (nom, état activé/désactivé,
nombre d'étapes) ; à droite l'éditeur du scénario sélectionné —
- renommer, activer/désactiver ;
- éditer la liste d'étapes (route, cible via `<select>` alimenté par
  `GET /tours/targets`, titre, contenu), réordonner (↑/↓), ajouter,
  retirer ;
- « Enregistrer » → un seul `PATCH /:id` qui remplace tout (name/enabled +
  étapes rénumérotées `order` = index), erreurs API affichées telles quelles ;
- « Supprimer le scénario » (confirmation `window.confirm`) ;
- « Nouveau scénario » → formulaire clé + nom → `POST /`.

`admin-client.ts` gagne `getTourScenarios` / `getTourTargets` /
`createTourScenario` / `updateTourScenario` / `deleteTourScenario`.

Tests Cypress (`admin-tours.cy.ts`, 4) : liste (activés + désactivés,
nombre d'étapes) ; édition nom + réordonnancement d'étapes → un seul PATCH
avec la liste complète réordonnée ; création → POST `{key,name}` ;
suppression après confirmation → DELETE. 4/4 en local ; `pnpm build` +
`pnpm lint` verts.

Closes #44
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 06:53:38 +02:00
d5ac6c4661 Merge pull request 'feat(web): moteur de tutoriel guidé driver.js (#42)' (#60) from feat/tour-engine into main
All checks were successful
CI / lint (push) Successful in 2m23s
CI / build (push) Successful in 2m29s
CI / intent-service-test (push) Successful in 4m5s
CI / e2e (push) Successful in 7m56s
CI / test (push) Successful in 16m29s
2026-09-06 06:53:23 +02:00
38fcf03417 feat(web): moteur de tutoriel guidé driver.js (#42)
All checks were successful
CI / lint (push) Successful in 3m55s
CI / build (push) Successful in 4m53s
CI / intent-service-test (push) Successful in 5m52s
CI / e2e (push) Successful in 10m30s
CI / test (push) Successful in 18m43s
Consomme le socle backend de #42/#44 (`GET /reference/tours`,
`GET/POST /profile/tours`). Deux tours : orientation générale (auto sur
`/`) et correction des métadonnées de recette (auto à l'ouverture du
premier popover de correction).

- Dépendance `driver.js` (~5 ko, MIT, zéro dépendance).
- `features/tour/tour-engine.ts` : wrapper vanilla autour de `driver.js` —
  gère ce que la lib ne fait pas seule : la navigation React Router entre
  étapes situées sur des routes différentes, et un `onFinish` unique
  (`"completed"` seulement si on atteint la fin, `"skipped"` pour la croix
  / Échap / clic sur l'overlay).
- `features/tour/TourContext.tsx` : `TourProvider` (charge scénarios +
  progression, keyed sur `user?.id` comme `ThemeContext`) et `useTour()`
  (`startTour(key)` / `isTourCompleted(key)` / `tours` / `isReady`).
  `isReady` est **calculé au render** contre l'id utilisateur chargé — pas
  stocké — pour qu'un changement de `user` le repasse à `false`
  immédiatement, avant qu'un effet enfant (l'auto-déclenchement) ne tourne
  sur des données de complétion périmées.
- `main.tsx` : `<TourProvider>` sous `ThemeProvider`.
- Attributs `data-tour-*` : liens de nav (`AppLayout`), grille / bouton `+`
  du 1er créneau / bouton Cuisiner (`PlanningPage`), page liste de courses
  (`ShoppingListPage`), description d'étape + section technique du popover
  (`StepDescription` / `TechStepCorrectionPopover`).
- Déclenchement auto : tour `general` sur `/` (`PlanningPage`, ref-gardé),
  tour `techStepMetadata` à `activeCorrection` non-null (`StepDescription`).
- Section « Revoir un tutoriel » dans `/parametres/preferences-utilisateur`
  — un `map` sur `tours`, un bouton « Revoir » par scénario.
- `tour.scss` re-skinne le popover `driver.js` sur les tokens du thème.
- i18n `tour.*` (chrome uniquement : boutons du popover, section « Revoir » ;
  le contenu des étapes vient de la base).

Tests Cypress (`tour.feature`, 5 scénarios) : auto-démarrage + élément
surligné pour un nouveau venu ; « Terminé » → complétion enregistrée
`skipped:false` ; croix → `skipped:true` ; un tour déjà vu ne se relance
pas ; « Revoir » le relance depuis les paramètres. Vérifié 5/5 en local.
`pnpm build` + `pnpm lint` verts.

Refs #42
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 06:17:06 +02:00
c21adeda72 Merge pull request 'feat(api): CRUD admin des scénarios de didacticiel (#44 — API)' (#59) from feat/admin-tour-crud into main
All checks were successful
CI / lint (push) Successful in 1m15s
CI / build (push) Successful in 1m11s
CI / intent-service-test (push) Successful in 3m35s
CI / e2e (push) Successful in 6m30s
CI / test (push) Successful in 16m13s
2026-09-06 06:16:49 +02:00
2beff139a3 feat(api): CRUD admin des scénarios de didacticiel (#44)
All checks were successful
CI / lint (push) Successful in 2m57s
CI / build (push) Successful in 2m59s
CI / intent-service-test (push) Successful in 4m22s
CI / e2e (push) Successful in 9m4s
CI / test (push) Successful in 17m32s
Deuxième volet backend du tutoriel guidé, sur le socle de #42/#44 : permet
à un admin de créer/éditer/supprimer les scénarios que
`GET /reference/tours` sert au moteur front.

`/admin/api/tours` (agrégateur `admin.routes.ts`, tout derrière
`requireAdmin`) :
- `GET /` — tous les scénarios (activés **et** désactivés) + étapes
  ordonnées.
- `GET /targets` — le catalogue `TourTarget` pour le sélecteur de cible de
  l'éditeur.
- `POST /` — crée un scénario vide (`key` + `name`) ; 409
  `TOUR_KEY_ALREADY_IN_USE` (nouveau code 4025) sur une clé prise.
- `PATCH /:id` — édite `name`/`enabled` **et remplace toute la liste
  d'étapes en bloc** (delete-all puis recreate avec `order` = index), même
  convention que `updateRecipe` pour les étapes d'une recette. `key`
  immuable. 404 `TOUR_NOT_FOUND` (id inconnu), 404 `TOUR_TARGET_NOT_FOUND`
  (nouveau code 4054, `targetKey` d'une étape hors catalogue — vérifié
  avant d'écrire, les étapes réelles restent intactes si la requête est
  rejetée).
- `DELETE /:id` — 204 ; les étapes et les `TourProgress` des utilisateurs
  cascadent.

Tests Mocha (`admin-tours.test.ts`) : 401 sans session admin sur chaque
route ; list (activés+désactivés) ; targets ; create→patch pour remplir
les étapes ; remplacement en bloc ; 409 clé dupliquée ; 404 cible
inconnue (sans toucher aux étapes existantes) ; 404 id inconnu ; delete +
cascade vérifiée ; un scénario désactivé disparaît de `/reference/tours`
mais reste dans la liste admin.

Refs #44
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 05:39:37 +02:00
d1948954a6 Merge pull request 'feat(api): modèle de données + API des scénarios de didacticiel (#42/#44 — socle backend)' (#58) from feat/tour-scenarios-backend into main
All checks were successful
CI / lint (push) Successful in 2m52s
CI / build (push) Successful in 3m7s
CI / intent-service-test (push) Successful in 4m54s
CI / e2e (push) Successful in 8m31s
CI / test (push) Successful in 17m21s
2026-09-06 05:39:22 +02:00
cd8ce42df7 feat(api): modèle de données + API des scénarios de didacticiel (#42/#44)
All checks were successful
CI / lint (push) Successful in 1m0s
CI / build (push) Successful in 1m16s
CI / intent-service-test (push) Successful in 3m34s
CI / e2e (push) Successful in 6m38s
CI / test (push) Successful in 15m49s
Socle backend, entièrement testable en CI, pour le tutoriel guidé. Le
moteur front (driver.js), l'instrumentation `data-tour-*` et le CRUD admin
viendront ensuite.

Schéma (`schema.prisma` + migration `20260906120000_tour_scenarios`) — les
4 modèles de #44, qui révisent le registre statique prévu par #42 :
- `TourTarget` (`key` PK + `description`) : catalogue des cibles de
  surlignage valides, seedé, comme `TechStep`/`Unit`.
- `TourScenario` (`key` stable, `name`, `enabled`) : un scénario rejouable.
- `TourScenarioStep` (`order`, `route?`, `targetKey`, `title`, `content`) :
  `title`/`content` sont du **texte libre**, pas des clés i18n (#44 :
  contenu administrable → texte, comme le nom d'une recette).
- `TourProgress` (`userProfileId` + `scenarioId`, PK composite) : présence
  d'une ligne = scénario vu (terminé *ou* passé).

Seed (`reference-seed-data.ts`) : les 9 `TourTarget` correspondant aux
`data-tour-*` à poser côté front, + les 2 scénarios de #42 (`general`,
`techStepMetadata`) **créés seulement s'ils sont absents** (un admin en
devient propriétaire ensuite). `techStepMetadata` reste court pour
l'instant — #36 (popover qui se ferme en pleine sélection) est ouvert, v1
ne couvre que les gestes qui marchent déjà.

API :
- `GET /reference/tours` (public) → scénarios **activés** + étapes
  ordonnées, forme consommée directement par le futur `useTour()`.
- `GET /profile/tours` → `{ completedTourKeys: string[] }`.
- `POST /profile/tours/:tourKey/complete` → upsert idempotent ; corps vide
  = terminé, `{ skipped: true }` = passé. Émet `analytics.recordEvent`
  `tour.completed` / `tour.skipped` (le dashboard admin agrège déjà tout
  type d'`AnalyticsEvent` génériquement — analytics de #44 quasi gratuites).
  404 `TOUR_NOT_FOUND` (nouveau code 4053) sur une clé inconnue/désactivée.

`reset-db.ts` truncate les 4 nouvelles tables (reseedées juste après).

Tests Mocha : `GET /reference/tours` (scénarios + étapes ordonnées,
exclusion d'un scénario désactivé) ; `/profile/tours` GET+POST (upsert
idempotent, `skipped`, 404 clé inconnue, 404 tour désactivé, isolation
par profil). Pas de base Postgres locale → exécutés en CI.

Refs #42, #44
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 05:08:43 +02:00
9174f80282 Merge pull request 'feat(web): page vitrine publique à la racine (#41)' (#57) from feat/landing-page into main
All checks were successful
CI / lint (push) Successful in 3m6s
CI / build (push) Successful in 3m18s
CI / intent-service-test (push) Successful in 4m29s
CI / e2e (push) Successful in 8m51s
CI / test (push) Successful in 16m12s
2026-09-06 05:06:18 +02:00