Repository navigation
Conversation
Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com>
|
Oasis35
deleted the
dependabot/nuget/src/back/InSeconds.Api.IntegrationTests/nuget-minor-patch-bb7edef1a8
branch
October 1, 2026 11:48
Oasis35
added a commit
that referenced
this pull request
Oct 1, 2026
…) (#250) * Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ...
Oasis35
added a commit
that referenced
this pull request
Oct 2, 2026
* Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Conformité aux conditions de l'API Deezer (#251) * Conformité aux conditions de l'API Deezer - Confidentialité : ajoute la mention obligatoire « usage strictement privé, dans le cadre familial » (art. IV des conditions Deezer) et corrige le passage qui affirmait que Deezer ne reçoit rien : le navigateur charge extraits et pochettes depuis les CDN Deezer, qui voient l'adresse IP. - Stories Instagram : plus de pochette Deezer dans les images (Deezer interdit de stocker ses images). L'API du récap hebdo ne renvoie plus de coverUrl, une vignette note de musique la remplace. - Doc : piège 47 (CLAUDE.md) et docs des stories. Claude-Session: https://claude.ai/code/session_01B3wbknbbcPyZg2tJQRtvNX * Spec stories : toHaveSize plutôt que length (Sonar S5906) Claude-Session: https://claude.ai/code/session_01B3wbknbbcPyZg2tJQRtvNX * docs(v2): lecteur audio Howler.js dans le plan et le plan de développement AudioPort de la v2 sur Howler.js en Web Audio (décision du 01/10/2026), CORS du CDN des extraits Deezer vérifié le 02/10/2026, CSP connect-src. Fichiers repris de env/staging avec ces modifications. * docs(v2): retire le plan v2 de cette PR (déplacé dans une PR vers env/staging)
Oasis35
added a commit
that referenced
this pull request
Oct 7, 2026
* Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... * Conformité aux conditions de l'API Deezer (#251) * Conformité aux conditions de l'API Deezer - Confidentialité : ajoute la mention obligatoire « usage strictement privé, dans le cadre familial » (art. IV des conditions Deezer) et corrige le passage qui affirmait que Deezer ne reçoit rien : le navigateur charge extraits et pochettes depuis les CDN Deezer, qui voient l'adresse IP. - Stories Instagram : plus de pochette Deezer dans les images (Deezer interdit de stocker ses images). L'API du récap hebdo ne renvoie plus de coverUrl, une vignette note de musique la remplace. - Doc : piège 47 (CLAUDE.md) et docs des stories. * Spec stories : toHaveSize plutôt que length (Sonar S5906) * docs(v2): lecteur audio Howler.js dans le plan et le plan de développement AudioPort de la v2 sur Howler.js en Web Audio (décision du 01/10/2026), CORS du CDN des extraits Deezer vérifié le 02/10/2026, CSP connect-src. Fichiers repris de env/staging avec ces modifications. * docs(v2): retire le plan v2 de cette PR (déplacé dans une PR vers env/staging) * Bump brace-expansion in /src/front/InSeconds.Client (#267) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.18 to 1.1.21. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.18...v1.1.21) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.21 dependency-type: indirect ... * v2 admin : en-tête recopié de la v1 (titre centré, 5 onglets, déconnexion en bas) - titre et identifiant navigateur centrés, haut de page à 32 px comme en v1 - barre des 5 onglets de la v1 ; ceux de F2 ouvrent une page d'attente sous la barre - déconnexion sous le contenu de l'onglet - plan et suivi de la refonte : mise en page, accès à l'admin du staging, usage à 0 jusqu'en E
Oasis35
added a commit
that referenced
this pull request
Oct 11, 2026
* Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... * Conformité aux conditions de l'API Deezer (#251) * Conformité aux conditions de l'API Deezer - Confidentialité : ajoute la mention obligatoire « usage strictement privé, dans le cadre familial » (art. IV des conditions Deezer) et corrige le passage qui affirmait que Deezer ne reçoit rien : le navigateur charge extraits et pochettes depuis les CDN Deezer, qui voient l'adresse IP. - Stories Instagram : plus de pochette Deezer dans les images (Deezer interdit de stocker ses images). L'API du récap hebdo ne renvoie plus de coverUrl, une vignette note de musique la remplace. - Doc : piège 47 (CLAUDE.md) et docs des stories. * Spec stories : toHaveSize plutôt que length (Sonar S5906) * docs(v2): lecteur audio Howler.js dans le plan et le plan de développement AudioPort de la v2 sur Howler.js en Web Audio (décision du 01/10/2026), CORS du CDN des extraits Deezer vérifié le 02/10/2026, CSP connect-src. Fichiers repris de env/staging avec ces modifications. * docs(v2): retire le plan v2 de cette PR (déplacé dans une PR vers env/staging) * Bump brace-expansion in /src/front/InSeconds.Client (#267) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.18 to 1.1.21. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.18...v1.1.21) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.21 dependency-type: indirect * Bump source-map-js from 1.2.1 to 1.2.2 in /src/front/InSeconds.Client (#269) Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/7rulnik/source-map-js/releases) - [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md) - [Commits](7rulnik/source-map-js@v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: source-map-js dependency-version: 1.2.2 dependency-type: indirect .. * Sauvegardes automatiques de la base de prod (timer VPS + R2 + alerte Grafana) (#293) * Sauvegardes de la base de prod : backup.sh + workflow nocturne - deploy/infra/backup.sh : pg_dump de la base inseconds (tous schémas), vérification (pg_restore --list), 7 jours gardés sur le VPS, envoi chiffré (rclone crypt) vers Cloudflare R2 (daily/ 30 j, monthly/ 365 j) et ping healthchecks.io si configurés ; sous-commandes list-remote, fetch et restore-test (base jetable). - .github/workflows/db-backup.yml : lance le script chaque nuit à 3 h UTC et à la demande, par SSH (le dump ne passe jamais par GitHub). - Doc : deploy/infra/README.md § Sauvegardes, .env.example, CLAUDE.md, README FR/EN, docs/TACHES.md. * Sauvegardes : timer systemd du VPS et alerte Grafana au lieu du workflow Le workflow GitHub Actions est remplacé par un timer systemd (3 h UTC, Persistent=true) qui lance backup.sh depuis le checkout de prod. Le ping healthchecks.io est remplacé par un log OTLP envoyé à Grafana Cloud avec la configuration de l'API ; une alerte Grafana prévient si aucune sauvegarde réussie n'arrive en 26 h. * backup.sh : paramètres positionnels nommés (Sonar) * backup.sh : envoi vers R2 par l'entrée standard (rcat) au lieu d'un dossier monté (#294) Sur le VPS, le conteneur rclone ne voyait pas le dump dans le dossier monté (« Source doesn't exist or is a directory »). Le dump passe désormais par l'entrée standard (rcat) à l'envoi et par la sortie standard (cat) au téléchargement : plus de montage, plus de dépendance aux droits Docker. * docs: SSH par clé et par login/mot de passe, tous deux actifs sur le VPS (#296) * docs: SSH par mot de passe réactivé sur le VPS (accès de secours) * docs: préciser que clé SSH et login/mot de passe restent tous deux actifs
Oasis35
added a commit
that referenced
this pull request
Oct 12, 2026
* Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... * Conformité aux conditions de l'API Deezer (#251) * Conformité aux conditions de l'API Deezer - Confidentialité : ajoute la mention obligatoire « usage strictement privé, dans le cadre familial » (art. IV des conditions Deezer) et corrige le passage qui affirmait que Deezer ne reçoit rien : le navigateur charge extraits et pochettes depuis les CDN Deezer, qui voient l'adresse IP. - Stories Instagram : plus de pochette Deezer dans les images (Deezer interdit de stocker ses images). L'API du récap hebdo ne renvoie plus de coverUrl, une vignette note de musique la remplace. - Doc : piège 47 (CLAUDE.md) et docs des stories. * Spec stories : toHaveSize plutôt que length (Sonar S5906) * docs(v2): lecteur audio Howler.js dans le plan et le plan de développement AudioPort de la v2 sur Howler.js en Web Audio (décision du 01/10/2026), CORS du CDN des extraits Deezer vérifié le 02/10/2026, CSP connect-src. Fichiers repris de env/staging avec ces modifications. * docs(v2): retire le plan v2 de cette PR (déplacé dans une PR vers env/staging) * Bump brace-expansion in /src/front/InSeconds.Client (#267) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.18 to 1.1.21. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.18...v1.1.21) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.21 dependency-type: indirect ... * Bump source-map-js from 1.2.1 to 1.2.2 in /src/front/InSeconds.Client (#269) Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/7rulnik/source-map-js/releases) - [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md) - [Commits](7rulnik/source-map-js@v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: source-map-js dependency-version: 1.2.2 dependency-type: indirect * Sauvegardes automatiques de la base de prod (timer VPS + R2 + alerte Grafana) (#293) * Sauvegardes de la base de prod : backup.sh + workflow nocturne - deploy/infra/backup.sh : pg_dump de la base inseconds (tous schémas), vérification (pg_restore --list), 7 jours gardés sur le VPS, envoi chiffré (rclone crypt) vers Cloudflare R2 (daily/ 30 j, monthly/ 365 j) et ping healthchecks.io si configurés ; sous-commandes list-remote, fetch et restore-test (base jetable). - .github/workflows/db-backup.yml : lance le script chaque nuit à 3 h UTC et à la demande, par SSH (le dump ne passe jamais par GitHub). - Doc : deploy/infra/README.md § Sauvegardes, .env.example, CLAUDE.md, README FR/EN, docs/TACHES.md. * Sauvegardes : timer systemd du VPS et alerte Grafana au lieu du workflow Le workflow GitHub Actions est remplacé par un timer systemd (3 h UTC, Persistent=true) qui lance backup.sh depuis le checkout de prod. Le ping healthchecks.io est remplacé par un log OTLP envoyé à Grafana Cloud avec la configuration de l'API ; une alerte Grafana prévient si aucune sauvegarde réussie n'arrive en 26 h. * backup.sh : paramètres positionnels nommés (Sonar) * backup.sh : envoi vers R2 par l'entrée standard (rcat) au lieu d'un dossier monté (#294) Sur le VPS, le conteneur rclone ne voyait pas le dump dans le dossier monté (« Source doesn't exist or is a directory »). Le dump passe désormais par l'entrée standard (rcat) à l'envoi et par la sortie standard (cat) au téléchargement : plus de montage, plus de dépendance aux droits Docker. * docs: SSH par clé et par login/mot de passe, tous deux actifs sur le VPS (#296) * docs: SSH par mot de passe réactivé sur le VPS (accès de secours) * docs: préciser que clé SSH et login/mot de passe restent tous deux actifs * Bascule v2 : workflow remplaçant minimal pour le rendre lançable depuis env/staging (#302)
Oasis35
added a commit
that referenced
this pull request
Oct 14, 2026
) * Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Conformité aux conditions de l'API Deezer (#251) * Conformité aux conditions de l'API Deezer - Confidentialité : ajoute la mention obligatoire « usage strictement privé, dans le cadre familial » (art. IV des conditions Deezer) et corrige le passage qui affirmait que Deezer ne reçoit rien : le navigateur charge extraits et pochettes depuis les CDN Deezer, qui voient l'adresse IP. - Stories Instagram : plus de pochette Deezer dans les images (Deezer interdit de stocker ses images). L'API du récap hebdo ne renvoie plus de coverUrl, une vignette note de musique la remplace. - Doc : piège 47 (CLAUDE.md) et docs des stories. * Spec stories : toHaveSize plutôt que length (Sonar S5906) * docs(v2): lecteur audio Howler.js dans le plan et le plan de développement AudioPort de la v2 sur Howler.js en Web Audio (décision du 01/10/2026), CORS du CDN des extraits Deezer vérifié le 02/10/2026, CSP connect-src. Fichiers repris de env/staging avec ces modifications. * docs(v2): retire le plan v2 de cette PR (déplacé dans une PR vers env/staging) * Bump brace-expansion in /src/front/InSeconds.Client (#267) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.18 to 1.1.21. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.18...v1.1.21) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.21 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump source-map-js from 1.2.1 to 1.2.2 in /src/front/InSeconds.Client (#269) Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/7rulnik/source-map-js/releases) - [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md) - [Commits](7rulnik/source-map-js@v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: source-map-js dependency-version: 1.2.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Sauvegardes automatiques de la base de prod (timer VPS + R2 + alerte Grafana) (#293) * Sauvegardes de la base de prod : backup.sh + workflow nocturne - deploy/infra/backup.sh : pg_dump de la base inseconds (tous schémas), vérification (pg_restore --list), 7 jours gardés sur le VPS, envoi chiffré (rclone crypt) vers Cloudflare R2 (daily/ 30 j, monthly/ 365 j) et ping healthchecks.io si configurés ; sous-commandes list-remote, fetch et restore-test (base jetable). - .github/workflows/db-backup.yml : lance le script chaque nuit à 3 h UTC et à la demande, par SSH (le dump ne passe jamais par GitHub). - Doc : deploy/infra/README.md § Sauvegardes, .env.example, CLAUDE.md, README FR/EN, docs/TACHES.md. * Sauvegardes : timer systemd du VPS et alerte Grafana au lieu du workflow Le workflow GitHub Actions est remplacé par un timer systemd (3 h UTC, Persistent=true) qui lance backup.sh depuis le checkout de prod. Le ping healthchecks.io est remplacé par un log OTLP envoyé à Grafana Cloud avec la configuration de l'API ; une alerte Grafana prévient si aucune sauvegarde réussie n'arrive en 26 h. * backup.sh : paramètres positionnels nommés (Sonar) * backup.sh : envoi vers R2 par l'entrée standard (rcat) au lieu d'un dossier monté (#294) Sur le VPS, le conteneur rclone ne voyait pas le dump dans le dossier monté (« Source doesn't exist or is a directory »). Le dump passe désormais par l'entrée standard (rcat) à l'envoi et par la sortie standard (cat) au téléchargement : plus de montage, plus de dépendance aux droits Docker. * docs: SSH par clé et par login/mot de passe, tous deux actifs sur le VPS (#296) * docs: SSH par mot de passe réactivé sur le VPS (accès de secours) * docs: préciser que clé SSH et login/mot de passe restent tous deux actifs * Bascule v2 : workflow remplaçant minimal pour le rendre lançable depuis env/staging (#302) * Sauvegarde de la prod : signal healthchecks.io au lieu de Grafana (#315) (#325) Reprend sur main la partie sauvegarde de #324 (mergée dans env/staging) : backup.sh envoie un signal au contrôle inseconds-backup (/fail en échec) avec HEALTHCHECKS_PING_KEY de .env.prod, et n'envoie plus de log OTLP. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Oasis35
added a commit
that referenced
this pull request
Oct 16, 2026
…staging en v2 (#343) * Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Conformité aux conditions de l'API Deezer (#251) * Conformité aux conditions de l'API Deezer - Confidentialité : ajoute la mention obligatoire « usage strictement privé, dans le cadre familial » (art. IV des conditions Deezer) et corrige le passage qui affirmait que Deezer ne reçoit rien : le navigateur charge extraits et pochettes depuis les CDN Deezer, qui voient l'adresse IP. - Stories Instagram : plus de pochette Deezer dans les images (Deezer interdit de stocker ses images). L'API du récap hebdo ne renvoie plus de coverUrl, une vignette note de musique la remplace. - Doc : piège 47 (CLAUDE.md) et docs des stories. Claude-Session: https://claude.ai/code/session_01B3wbknbbcPyZg2tJQRtvNX * Spec stories : toHaveSize plutôt que length (Sonar S5906) Claude-Session: https://claude.ai/code/session_01B3wbknbbcPyZg2tJQRtvNX * docs(v2): lecteur audio Howler.js dans le plan et le plan de développement AudioPort de la v2 sur Howler.js en Web Audio (décision du 01/10/2026), CORS du CDN des extraits Deezer vérifié le 02/10/2026, CSP connect-src. Fichiers repris de env/staging avec ces modifications. * docs(v2): retire le plan v2 de cette PR (déplacé dans une PR vers env/staging) * Bump brace-expansion in /src/front/InSeconds.Client (#267) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.18 to 1.1.21. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.18...v1.1.21) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.21 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump source-map-js from 1.2.1 to 1.2.2 in /src/front/InSeconds.Client (#269) Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/7rulnik/source-map-js/releases) - [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md) - [Commits](7rulnik/source-map-js@v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: source-map-js dependency-version: 1.2.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Sauvegardes automatiques de la base de prod (timer VPS + R2 + alerte Grafana) (#293) * Sauvegardes de la base de prod : backup.sh + workflow nocturne - deploy/infra/backup.sh : pg_dump de la base inseconds (tous schémas), vérification (pg_restore --list), 7 jours gardés sur le VPS, envoi chiffré (rclone crypt) vers Cloudflare R2 (daily/ 30 j, monthly/ 365 j) et ping healthchecks.io si configurés ; sous-commandes list-remote, fetch et restore-test (base jetable). - .github/workflows/db-backup.yml : lance le script chaque nuit à 3 h UTC et à la demande, par SSH (le dump ne passe jamais par GitHub). - Doc : deploy/infra/README.md § Sauvegardes, .env.example, CLAUDE.md, README FR/EN, docs/TACHES.md. * Sauvegardes : timer systemd du VPS et alerte Grafana au lieu du workflow Le workflow GitHub Actions est remplacé par un timer systemd (3 h UTC, Persistent=true) qui lance backup.sh depuis le checkout de prod. Le ping healthchecks.io est remplacé par un log OTLP envoyé à Grafana Cloud avec la configuration de l'API ; une alerte Grafana prévient si aucune sauvegarde réussie n'arrive en 26 h. * backup.sh : paramètres positionnels nommés (Sonar) * backup.sh : envoi vers R2 par l'entrée standard (rcat) au lieu d'un dossier monté (#294) Sur le VPS, le conteneur rclone ne voyait pas le dump dans le dossier monté (« Source doesn't exist or is a directory »). Le dump passe désormais par l'entrée standard (rcat) à l'envoi et par la sortie standard (cat) au téléchargement : plus de montage, plus de dépendance aux droits Docker. * docs: SSH par clé et par login/mot de passe, tous deux actifs sur le VPS (#296) * docs: SSH par mot de passe réactivé sur le VPS (accès de secours) * docs: préciser que clé SSH et login/mot de passe restent tous deux actifs * Bascule v2 : workflow remplaçant minimal pour le rendre lançable depuis env/staging (#302) * Sauvegarde de la prod : signal healthchecks.io au lieu de Grafana (#315) (#325) Reprend sur main la partie sauvegarde de #324 (mergée dans env/staging) : backup.sh envoie un signal au contrôle inseconds-backup (/fail en échec) avec HEALTHCHECKS_PING_KEY de .env.prod, et n'envoie plus de log OTLP. * Doc : la v2 est en prod depuis la bascule du 16/10/2026 * Doc : plans refonte-v2 et TACHES après la bascule (tâches finies retirées) * Doc : retire les références à la v1 comme version vivante (CLAUDE.md, README, docs/) * I1 : copie prod → staging des schémas v2, sauvegarde archivée, suppression des tables v1 - copy-prod-db-to-staging.sh copie les schémas v2 de la prod (players, catalogue, daily, infra sans les clés Data Protection), migre, anonymise, clé neuve : plus d'import v1 → v2 (la prod écrit en v2 depuis la bascule). - backup.sh archive : sauvegarde envoyée dans archive/ sur R2, hors rotation. - drop-v1-tables.sh / drop-v1-tables.sql : suppression des tables v1 de public, à la main ; en prod après l'archive. Garde opened_at, refus sur une table inconnue. - Retire le workflow « Bascule v2 », switch-to-v2.sh et import-to-staging.sh. * I1 : retire les routes de la v1 en 410 (common.new_version) Back : LegacyRoutes et ErrorCodes.NewVersion retirés, les anciennes routes répondent 404. Le test de fumée sonde aussi /api/auth/dev-login (404 attendu). Front : new-version.interceptor et la traduction du code retirés. * Doc I1 : copie prod → staging, suppression des tables v1, routes 410 retirées --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Oasis35
added a commit
that referenced
this pull request
Oct 16, 2026
) * Envoi des emails via Brevo au lieu de Resend (#197) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Staging → main : compteur de gels corrigé (#199) * Envoi des emails via Brevo au lieu de Resend (#196) BrevoEmailSender remplace ResendEmailSender (API transactionnelle Brevo, header api-key). Configuration Brevo:*, variable BREVO_API_KEY, page confidentialité et doc mises à jour. * Gel de série : retirer du compteur les gels déjà engagés sur une série protégée (#198) La gélule du header affichait encore le stock en base (ex. 2) alors que l'accueil annonçait qu'un gel avait sauvé la série : le stock n'est décrémenté qu'à la complétion du défi. StreakView.Freezes déduit désormais les jours manqués en statut protected, ce qui correspond au stock qui restera après la partie. * Déconnexion : ne plus faire tourner le jeton du compte (multi-appareils cassé) (#239) Tous les appareils d'un compte v1 partagent le même AuthToken : le faire tourner à la déconnexion (M6, #179) déconnectait tous les autres appareils. La déconnexion n'efface plus que le cookie de l'appareil courant. * fix(partage): repli execCommand quand clipboard.writeText échoue (#200) (#241) Le bouton « Partager mon score » ne copiait parfois rien au premier clic : navigator.clipboard.writeText rejette de façon intermittente (NotAllowedError, « Document is not focused »). Sur rejet, ClipboardService retombe sur une copie textarea + execCommand('copy') et remonte l'échec (sans le texte) à l'API. * Admin : renommer un morceau du défi du jour depuis le pool (#246) * feat(admin): renommer un morceau du défi du jour depuis le pool Retire le verrou RenameLock (409 track_locked) : le bouton ✎ est actif sur toutes les lignes du pool, défi du jour compris. Les réponses déjà enregistrées gardent leur verdict, les suivantes sont corrigées avec le nouveau nom. * feat(admin): avertissement dans la modale de renommage pour un morceau du défi du jour * fix(audio): palier coupé avant le son sur iPhone (relecture) (#249) Safari iOS émet `playing` dès l'appel à play(), avant que le son reparte, sans second `playing` ensuite : le chrono d'arrêt coupait le palier à l'aveugle (0,5s → 0,1s de son, voire aucun). Le chrono relit désormais la position de lecture à son échéance et se reprogramme tant que le palier n'est pas atteint ; rien ne coupe pendant un seek. * Bump the nuget-minor-patch group with 5 updates (#245) Bumps coverlet.collector from 10.0.1 to 10.1.0 Bumps WolverineFx from 6.40.0 to 6.43.0 Bumps WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0 Bumps WolverineFx.FluentValidation from 6.40.0 to 6.43.0 Bumps WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0 --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: coverlet.collector dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.EntityFrameworkCore dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.FluentValidation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Conformité aux conditions de l'API Deezer (#251) * Conformité aux conditions de l'API Deezer - Confidentialité : ajoute la mention obligatoire « usage strictement privé, dans le cadre familial » (art. IV des conditions Deezer) et corrige le passage qui affirmait que Deezer ne reçoit rien : le navigateur charge extraits et pochettes depuis les CDN Deezer, qui voient l'adresse IP. - Stories Instagram : plus de pochette Deezer dans les images (Deezer interdit de stocker ses images). L'API du récap hebdo ne renvoie plus de coverUrl, une vignette note de musique la remplace. - Doc : piège 47 (CLAUDE.md) et docs des stories. Claude-Session: https://claude.ai/code/session_01B3wbknbbcPyZg2tJQRtvNX * Spec stories : toHaveSize plutôt que length (Sonar S5906) Claude-Session: https://claude.ai/code/session_01B3wbknbbcPyZg2tJQRtvNX * docs(v2): lecteur audio Howler.js dans le plan et le plan de développement AudioPort de la v2 sur Howler.js en Web Audio (décision du 01/10/2026), CORS du CDN des extraits Deezer vérifié le 02/10/2026, CSP connect-src. Fichiers repris de env/staging avec ces modifications. * docs(v2): retire le plan v2 de cette PR (déplacé dans une PR vers env/staging) * Bump brace-expansion in /src/front/InSeconds.Client (#267) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.18 to 1.1.21. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.18...v1.1.21) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.21 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump source-map-js from 1.2.1 to 1.2.2 in /src/front/InSeconds.Client (#269) Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/7rulnik/source-map-js/releases) - [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md) - [Commits](7rulnik/source-map-js@v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: source-map-js dependency-version: 1.2.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Sauvegardes automatiques de la base de prod (timer VPS + R2 + alerte Grafana) (#293) * Sauvegardes de la base de prod : backup.sh + workflow nocturne - deploy/infra/backup.sh : pg_dump de la base inseconds (tous schémas), vérification (pg_restore --list), 7 jours gardés sur le VPS, envoi chiffré (rclone crypt) vers Cloudflare R2 (daily/ 30 j, monthly/ 365 j) et ping healthchecks.io si configurés ; sous-commandes list-remote, fetch et restore-test (base jetable). - .github/workflows/db-backup.yml : lance le script chaque nuit à 3 h UTC et à la demande, par SSH (le dump ne passe jamais par GitHub). - Doc : deploy/infra/README.md § Sauvegardes, .env.example, CLAUDE.md, README FR/EN, docs/TACHES.md. * Sauvegardes : timer systemd du VPS et alerte Grafana au lieu du workflow Le workflow GitHub Actions est remplacé par un timer systemd (3 h UTC, Persistent=true) qui lance backup.sh depuis le checkout de prod. Le ping healthchecks.io est remplacé par un log OTLP envoyé à Grafana Cloud avec la configuration de l'API ; une alerte Grafana prévient si aucune sauvegarde réussie n'arrive en 26 h. * backup.sh : paramètres positionnels nommés (Sonar) * backup.sh : envoi vers R2 par l'entrée standard (rcat) au lieu d'un dossier monté (#294) Sur le VPS, le conteneur rclone ne voyait pas le dump dans le dossier monté (« Source doesn't exist or is a directory »). Le dump passe désormais par l'entrée standard (rcat) à l'envoi et par la sortie standard (cat) au téléchargement : plus de montage, plus de dépendance aux droits Docker. * docs: SSH par clé et par login/mot de passe, tous deux actifs sur le VPS (#296) * docs: SSH par mot de passe réactivé sur le VPS (accès de secours) * docs: préciser que clé SSH et login/mot de passe restent tous deux actifs * Bascule v2 : workflow remplaçant minimal pour le rendre lançable depuis env/staging (#302) * Sauvegarde de la prod : signal healthchecks.io au lieu de Grafana (#315) (#325) Reprend sur main la partie sauvegarde de #324 (mergée dans env/staging) : backup.sh envoie un signal au contrôle inseconds-backup (/fail en échec) avec HEALTHCHECKS_PING_KEY de .env.prod, et n'envoie plus de log OTLP. * Doc : la v2 est en prod depuis la bascule du 16/10/2026 * Doc : plans refonte-v2 et TACHES après la bascule (tâches finies retirées) * Doc : retire les références à la v1 comme version vivante (CLAUDE.md, README, docs/) * I1 : copie prod → staging des schémas v2, sauvegarde archivée, suppression des tables v1 - copy-prod-db-to-staging.sh copie les schémas v2 de la prod (players, catalogue, daily, infra sans les clés Data Protection), migre, anonymise, clé neuve : plus d'import v1 → v2 (la prod écrit en v2 depuis la bascule). - backup.sh archive : sauvegarde envoyée dans archive/ sur R2, hors rotation. - drop-v1-tables.sh / drop-v1-tables.sql : suppression des tables v1 de public, à la main ; en prod après l'archive. Garde opened_at, refus sur une table inconnue. - Retire le workflow « Bascule v2 », switch-to-v2.sh et import-to-staging.sh. * I1 : retire les routes de la v1 en 410 (common.new_version) Back : LegacyRoutes et ErrorCodes.NewVersion retirés, les anciennes routes répondent 404. Le test de fumée sonde aussi /api/auth/dev-login (404 attendu). Front : new-version.interceptor et la traduction du code retirés. * Doc I1 : copie prod → staging, suppression des tables v1, routes 410 retirées * I2 : supprime le code v1 (src/back, src/front), ses jobs CI et ses E2E - src/back, src/front et scripts/ (parité E2E, lanceur E2E v1) supprimés ; e2e/parity-exceptions.json et e2e/disabled-specs.json (vide) du front v2 aussi. - CI : jobs v1, e2e-parity et filtre de chemins retirés, les jobs v2 tournent à chaque run ; CI OK n'agrège plus qu'eux. - Schéma v1 des tests d'import figé dans v1-schema.sql (généré depuis src/back avant sa suppression) ; plus d'étape CI pour le générer. - docker-compose.prod.yml et service api v1 du compose de dev retirés ; deploy.sh ne déploie plus que la v2 (plus de marqueur .bascule-v2-done). - Dependabot : entrées v1 retirées. Part of #236 * Doc I2 : v1 supprimée (CLAUDE.md, README, docs/) Part of #236 * Sonar : v1-schema.sql (généré) à exclure de la détection de duplication Part of #236 * Sonar : v1-schema.sql en Source File Exclusions (avertissements PL/SQL et duplication) Part of #236 * Doc : exclusion Sonar src/front, src/back retirée de l'UI le 16/10 Part of #236 * Doc : section en double après le merge d'env/staging Part of #236 * CI : jobs renommés sans « v2 » (front, nginx-headers, e2e, back) Part of #236 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Updated coverlet.collector from 10.0.1 to 10.1.0.
Release notes
Sourced from coverlet.collector's releases.
10.1.0
Improvements
Fixed
Diff between 10.0.1 and 10.1.0
Commits viewable in compare view.
Updated WolverineFx from 6.40.0 to 6.43.0.
Release notes
Sourced from WolverineFx's releases.
6.43.0
A dependency release. The store pins had been queued behind two releases because every store's current version takes Weasel 9.36.0 as a floor, and 9.36 carried an Oracle regression. That is fixed upstream now, so all three move together.
JasperFx stays at 2.76.1.
This is why 6.43.0 is a minor rather than a patch. Nothing in Wolverine's own public API changed, but crossing six Weasel releases changes what a migration does:
MODIFY.DROP INDEXfor them. Fixed.Oracle: the node tables stop drifting
Two fixes in Wolverine itself, both needed to work with Weasel 9.38.0.
Column defaults are no longer hand-escaped. Wolverine wrote every Oracle timestamp default as
SYSTIMESTAMP AT TIME ZONE ''UTC'', with the quotes already doubled, because Weasel used to paste DDL verbatim into anEXECUTE IMMEDIATE '...'literal. Weasel 9.36 escapes literals itself, so both sides escaped and the executed default becameAT TIME ZONE ''UTC''— not a time zone region, and every table create failed withORA-01882.Identity columns are declared through
AutoIncrement()rather than in the type string.wolverine_nodes.node_numberand the node-record table'sidwere declared asNUMBER(10) GENERATED BY DEFAULT AS IDENTITY— with the clause written into the type. Oracle does not store it there: the catalog reports the type as plainNUMBER(10)and carries identity separately. The model could never equal what came back, so every migration emitted anALTER … MODIFYthat Oracle refuses withORA-01031.That type string was a workaround rather than an oversight —
AutoIncrement()emitted the identity clause after the null constraint, which isORA-03076, so it could not create a table at all. Fixed upstream in weasel#667 along with two related defects: identity was never read back fromALL_TAB_COLUMNS.IDENTITY_COLUMN, and a schema containing an identity column could not be dropped at all, because the teardown tried to drop the system-generated sequence behind it.Existing Oracle deployments should settle rather than migrate: the column is already
NUMBER(10)identity in the database, and 9.38.0 now reads that back, so the model matches it.Verification
Built pinned the way CI builds it (
-c Release -f net9.0), 0 errors and 0 warnings, then 17 database suites locally across PostgreSQL, SQL Server, MySQL, Oracle and SQLite — including Marten, Polecat, Fisher, claim check and leader election on four engines.OracleTestswent from 181 failing to 203 passing.6.42.0
A release driven almost entirely by what users reported. Five of the durability fixes below came from one reporter working a multi-tenant deployment hard enough to find them, and the pattern running through them is the same: a failure that belonged to one tenant was being paid for by every tenant, or was not being reported at all.
GH-4662.
PublishAsync/ScheduleAsyncmade outside a handler and outside any transaction, to a local queue made durable byUseDurableLocalQueues(), used to return without an error when the message store was unreachable. Four attempts inside ~400 ms, one line atInformation, and the message was gone — not even recovered after the database came back, because no inbox row was ever written.The cause was the shape of the retry rather than the retry itself.
RetryBlock.PostAsyncruns one attempt inline and posts the rest to its own worker, so the task the caller awaits completes the moment the first attempt fails. That is the right shape once an envelope is durable somewhere and recovery can find it; it is the wrong shape for the write that makes it durable, because there is no other copy.DurableWriteRetrykeeps the same 50/100/250 ms budget, awaits it inline, and lets the last exception reach the caller.Who is affected is narrower than it sounds. If you enlist a real outbox (EF Core, Marten,
DatabaseEnvelopeTransaction) nothing changes — that path never reached this code. Inside a handler nothing new escapes either; the publish is buffered and a failure is still caught, logged and recorded as a discard, just atErrorwith a real tracking event instead of a buriedInformationline. Only the un-transacted publish from outside a handler can now throw.One tenant's outage stops costing you every tenant
timestampdefault is now a true UTC instant (GH-4663). It depended on the session's time zone, soInboxStaleTimehanded back envelopes that were still running.Partitioning
A scheduled message no longer runs on a node that does not own the slot (GH-4673). Under global partitioning a scheduled envelope took the local shortcut regardless of slot ownership, so two nodes could process the same group id concurrently — the exact thing partitioning exists to prevent. A promoted scheduled envelope also no longer still reports its status as
Scheduled.HTTP
Stream large multipart uploads through a
MultipartReaderendpoint parameter, contributed by @erdtsieck (#4674) — no buffering the whole upload to handle it. F# code generation emits the new frame too, and the F# codegen coverage is now gated against a committed baseline so a new unsupported frame cannot slip in unnoticed.Diagnostics, metrics and operations
local://destination was being classified as System traffic, so a user's own local queue never reached the per-type/per-tenantDeadLettersmetric (GH-4665).BrokerResource.Checkno longer reports a thrown check as a missing resource (GH-4693), which was hiding the real cause behind "Missing known broker resources".ShardStartException.Reason.SqliteNodePersistencehonors the table prefix (GH-4668); node shutdown failed outright on a prefixed store.Dependencies
node_numbercolumn that is alreadyGENERATED BY DEFAULT AS IDENTITYis read back as drift, so every migration emits anALTER ... MODIFYthat Oracle refuses. It will ship once that is fixed upstream.Thank you
MultipartReaderstreaming upload support in #46746.41.0
28 commits since V6.40.0. Minor rather than patch because of the new EF Core and topology features below — and because one change is breaking.
AutoApplyTransactions()now fails the chain build when two persistence providers can own it (#4631). A handler taking both aDbContextand a Marten/Polecat/FisherIDocumentSessionmatched two providers, andAutoApplyTransactionsapplied neither — no transaction support, no warning, no log line, and whatever the un-owned store buffered was discarded when the scope closed.[Transactional]on the same handler took the first ordered provider instead, so the document session was never saved. Both outcomes were silent and the handler reported success.This stops an application that starts today. One that writes through two stores from a single handler has been losing one of those writes all along; it will now refuse to build until the handler says which store owns the transaction. Add
[Transactional(typeof(X))]or[Storage(typeof(X))], or[NonTransactional]to opt out. Two-provider atomicity remains unsupported — the designated store commits, the other does not. Saga chains are exempt.Entity Framework Core
Lightweightmessage handler now enlist in the sameSaveChangesAsync()as the business write, andPublishDomainEventsFromEntityFrameworkCore()— inert inLightweightbefore — runs on every path.EfCoreOpsset-based operations (#4629), which force the eager transaction they need rather than failing quietly.Update<T>orStore<T>rather thanIStorageAction<T>used to silently save nothing.Multi-tenancy
Envelope.TenantIdis normalised throughTenantIdStyle(#4640).MessageContext.TenantIdalways applied the style andEnvelope.TenantIdnever did, so underForceLowerCasea handler saw"RED"on the envelope beside"red"on the context. Polecat and Fisher read the envelope, so they wrote the raw casing — invisible on SQL Server's case-insensitive collation, and on Fisher's BINARY collation the row was unreachable.OutboxedSessionFactoryresolves theMainstore lazily (#4633).Transports and topology
ListenToKafkaTopicsgroup and stamping the topic asDestination— thanks @lahma.Durability and correctness
EnqueueDirectlyAsyncretires the inbox row it forwards (#4645). A delayed message sent from a handler to a database-backed queue that another node owns was silently destroyed: the forwarding node left anIncomingrow behind, and the owning node's anti-duplicate probe then deleted the queue row it had just written. Nothing logged, nothing dead-lettered. Reported with a full four-step reconstruction by @smoqmilus.EndpointCollection._listenersis no longer a plainDictionary(#4646). A failover handing one node several exclusive listener agents at once had up to ten threads writing it while every send read it; aDictionarycorrupted mid-resize is poisoned permanently, and the node never routed again until the pod was replaced. Also reported by @smoqmilus.Activity. Recurring occurrences (#4647), inline receivers (#4649) and the agent plumbing loops (#4650) were parenting every message under whateverActivity.Currenthappened to be live when the agent or listener started.AddMessageHandler.Also
Contributors
Thanks to @erdtsieck, @jakobt, @lahma, @skoging and @smoqmilus.
Commits viewable in compare view.
Updated WolverineFx.EntityFrameworkCore from 6.40.0 to 6.43.0.
Release notes
Sourced from WolverineFx.EntityFrameworkCore's releases.
6.43.0
A dependency release. The store pins had been queued behind two releases because every store's current version takes Weasel 9.36.0 as a floor, and 9.36 carried an Oracle regression. That is fixed upstream now, so all three move together.
JasperFx stays at 2.76.1.
This is why 6.43.0 is a minor rather than a patch. Nothing in Wolverine's own public API changed, but crossing six Weasel releases changes what a migration does:
MODIFY.DROP INDEXfor them. Fixed.Oracle: the node tables stop drifting
Two fixes in Wolverine itself, both needed to work with Weasel 9.38.0.
Column defaults are no longer hand-escaped. Wolverine wrote every Oracle timestamp default as
SYSTIMESTAMP AT TIME ZONE ''UTC'', with the quotes already doubled, because Weasel used to paste DDL verbatim into anEXECUTE IMMEDIATE '...'literal. Weasel 9.36 escapes literals itself, so both sides escaped and the executed default becameAT TIME ZONE ''UTC''— not a time zone region, and every table create failed withORA-01882.Identity columns are declared through
AutoIncrement()rather than in the type string.wolverine_nodes.node_numberand the node-record table'sidwere declared asNUMBER(10) GENERATED BY DEFAULT AS IDENTITY— with the clause written into the type. Oracle does not store it there: the catalog reports the type as plainNUMBER(10)and carries identity separately. The model could never equal what came back, so every migration emitted anALTER … MODIFYthat Oracle refuses withORA-01031.That type string was a workaround rather than an oversight —
AutoIncrement()emitted the identity clause after the null constraint, which isORA-03076, so it could not create a table at all. Fixed upstream in weasel#667 along with two related defects: identity was never read back fromALL_TAB_COLUMNS.IDENTITY_COLUMN, and a schema containing an identity column could not be dropped at all, because the teardown tried to drop the system-generated sequence behind it.Existing Oracle deployments should settle rather than migrate: the column is already
NUMBER(10)identity in the database, and 9.38.0 now reads that back, so the model matches it.Verification
Built pinned the way CI builds it (
-c Release -f net9.0), 0 errors and 0 warnings, then 17 database suites locally across PostgreSQL, SQL Server, MySQL, Oracle and SQLite — including Marten, Polecat, Fisher, claim check and leader election on four engines.OracleTestswent from 181 failing to 203 passing.6.42.0
A release driven almost entirely by what users reported. Five of the durability fixes below came from one reporter working a multi-tenant deployment hard enough to find them, and the pattern running through them is the same: a failure that belonged to one tenant was being paid for by every tenant, or was not being reported at all.
GH-4662.
PublishAsync/ScheduleAsyncmade outside a handler and outside any transaction, to a local queue made durable byUseDurableLocalQueues(), used to return without an error when the message store was unreachable. Four attempts inside ~400 ms, one line atInformation, and the message was gone — not even recovered after the database came back, because no inbox row was ever written.The cause was the shape of the retry rather than the retry itself.
RetryBlock.PostAsyncruns one attempt inline and posts the rest to its own worker, so the task the caller awaits completes the moment the first attempt fails. That is the right shape once an envelope is durable somewhere and recovery can find it; it is the wrong shape for the write that makes it durable, because there is no other copy.DurableWriteRetrykeeps the same 50/100/250 ms budget, awaits it inline, and lets the last exception reach the caller.Who is affected is narrower than it sounds. If you enlist a real outbox (EF Core, Marten,
DatabaseEnvelopeTransaction) nothing changes — that path never reached this code. Inside a handler nothing new escapes either; the publish is buffered and a failure is still caught, logged and recorded as a discard, just atErrorwith a real tracking event instead of a buriedInformationline. Only the un-transacted publish from outside a handler can now throw.One tenant's outage stops costing you every tenant
timestampdefault is now a true UTC instant (GH-4663). It depended on the session's time zone, soInboxStaleTimehanded back envelopes that were still running.Partitioning
A scheduled message no longer runs on a node that does not own the slot (GH-4673). Under global partitioning a scheduled envelope took the local shortcut regardless of slot ownership, so two nodes could process the same group id concurrently — the exact thing partitioning exists to prevent. A promoted scheduled envelope also no longer still reports its status as
Scheduled.HTTP
Stream large multipart uploads through a
MultipartReaderendpoint parameter, contributed by @erdtsieck (#4674) — no buffering the whole upload to handle it. F# code generation emits the new frame too, and the F# codegen coverage is now gated against a committed baseline so a new unsupported frame cannot slip in unnoticed.Diagnostics, metrics and operations
local://destination was being classified as System traffic, so a user's own local queue never reached the per-type/per-tenantDeadLettersmetric (GH-4665).BrokerResource.Checkno longer reports a thrown check as a missing resource (GH-4693), which was hiding the real cause behind "Missing known broker resources".ShardStartException.Reason.SqliteNodePersistencehonors the table prefix (GH-4668); node shutdown failed outright on a prefixed store.Dependencies
node_numbercolumn that is alreadyGENERATED BY DEFAULT AS IDENTITYis read back as drift, so every migration emits anALTER ... MODIFYthat Oracle refuses. It will ship once that is fixed upstream.Thank you
MultipartReaderstreaming upload support in #46746.41.0
28 commits since V6.40.0. Minor rather than patch because of the new EF Core and topology features below — and because one change is breaking.
AutoApplyTransactions()now fails the chain build when two persistence providers can own it (#4631). A handler taking both aDbContextand a Marten/Polecat/FisherIDocumentSessionmatched two providers, andAutoApplyTransactionsapplied neither — no transaction support, no warning, no log line, and whatever the un-owned store buffered was discarded when the scope closed.[Transactional]on the same handler took the first ordered provider instead, so the document session was never saved. Both outcomes were silent and the handler reported success.This stops an application that starts today. One that writes through two stores from a single handler has been losing one of those writes all along; it will now refuse to build until the handler says which store owns the transaction. Add
[Transactional(typeof(X))]or[Storage(typeof(X))], or[NonTransactional]to opt out. Two-provider atomicity remains unsupported — the designated store commits, the other does not. Saga chains are exempt.Entity Framework Core
Lightweightmessage handler now enlist in the sameSaveChangesAsync()as the business write, andPublishDomainEventsFromEntityFrameworkCore()— inert inLightweightbefore — runs on every path.EfCoreOpsset-based operations (#4629), which force the eager transaction they need rather than failing quietly.Update<T>orStore<T>rather thanIStorageAction<T>used to silently save nothing.Multi-tenancy
Envelope.TenantIdis normalised throughTenantIdStyle(#4640).MessageContext.TenantIdalways applied the style andEnvelope.TenantIdnever did, so underForceLowerCasea handler saw"RED"on the envelope beside"red"on the context. Polecat and Fisher read the envelope, so they wrote the raw casing — invisible on SQL Server's case-insensitive collation, and on Fisher's BINARY collation the row was unreachable.OutboxedSessionFactoryresolves theMainstore lazily (#4633).Transports and topology
ListenToKafkaTopicsgroup and stamping the topic asDestination— thanks @lahma.Durability and correctness
EnqueueDirectlyAsyncretires the inbox row it forwards (#4645). A delayed message sent from a handler to a database-backed queue that another node owns was silently destroyed: the forwarding node left anIncomingrow behind, and the owning node's anti-duplicate probe then deleted the queue row it had just written. Nothing logged, nothing dead-lettered. Reported with a full four-step reconstruction by @smoqmilus.EndpointCollection._listenersis no longer a plainDictionary(#4646). A failover handing one node several exclusive listener agents at once had up to ten threads writing it while every send read it; aDictionarycorrupted mid-resize is poisoned permanently, and the node never routed again until the pod was replaced. Also reported by @smoqmilus.Activity. Recurring occurrences (#4647), inline receivers (#4649) and the agent plumbing loops (#4650) were parenting every message under whateverActivity.Currenthappened to be live when the agent or listener started.AddMessageHandler.Also
Contributors
Thanks to @erdtsieck, @jakobt, @lahma, @skoging and @smoqmilus.
Commits viewable in compare view.
Updated WolverineFx.FluentValidation from 6.40.0 to 6.43.0.
Release notes
Sourced from WolverineFx.FluentValidation's releases.
6.43.0
A dependency release. The store pins had been queued behind two releases because every store's current version takes Weasel 9.36.0 as a floor, and 9.36 carried an Oracle regression. That is fixed upstream now, so all three move together.
JasperFx stays at 2.76.1.
This is why 6.43.0 is a minor rather than a patch. Nothing in Wolverine's own public API changed, but crossing six Weasel releases changes what a migration does:
MODIFY.DROP INDEXfor them. Fixed.Oracle: the node tables stop drifting
Two fixes in Wolverine itself, both needed to work with Weasel 9.38.0.
Column defaults are no longer hand-escaped. Wolverine wrote every Oracle timestamp default as
SYSTIMESTAMP AT TIME ZONE ''UTC'', with the quotes already doubled, because Weasel used to paste DDL verbatim into anEXECUTE IMMEDIATE '...'literal. Weasel 9.36 escapes literals itself, so both sides escaped and the executed default becameAT TIME ZONE ''UTC''— not a time zone region, and every table create failed withORA-01882.Identity columns are declared through
AutoIncrement()rather than in the type string.wolverine_nodes.node_numberand the node-record table'sidwere declared asNUMBER(10) GENERATED BY DEFAULT AS IDENTITY— with the clause written into the type. Oracle does not store it there: the catalog reports the type as plainNUMBER(10)and carries identity separately. The model could never equal what came back, so every migration emitted anALTER … MODIFYthat Oracle refuses withORA-01031.That type string was a workaround rather than an oversight —
AutoIncrement()emitted the identity clause after the null constraint, which isORA-03076, so it could not create a table at all. Fixed upstream in weasel#667 along with two related defects: identity was never read back fromALL_TAB_COLUMNS.IDENTITY_COLUMN, and a schema containing an identity column could not be dropped at all, because the teardown tried to drop the system-generated sequence behind it.Existing Oracle deployments should settle rather than migrate: the column is already
NUMBER(10)identity in the database, and 9.38.0 now reads that back, so the model matches it.Verification
Built pinned the way CI builds it (
-c Release -f net9.0), 0 errors and 0 warnings, then 17 database suites locally across PostgreSQL, SQL Server, MySQL, Oracle and SQLite — including Marten, Polecat, Fisher, claim check and leader election on four engines.OracleTestswent from 181 failing to 203 passing.6.42.0
A release driven almost entirely by what users reported. Five of the durability fixes below came from one reporter working a multi-tenant deployment hard enough to find them, and the pattern running through them is the same: a failure that belonged to one tenant was being paid for by every tenant, or was not being reported at all.
GH-4662.
PublishAsync/ScheduleAsyncmade outside a handler and outside any transaction, to a local queue made durable byUseDurableLocalQueues(), used to return without an error when the message store was unreachable. Four attempts inside ~400 ms, one line atInformation, and the message was gone — not even recovered after the database came back, because no inbox row was ever written.The cause was the shape of the retry rather than the retry itself.
RetryBlock.PostAsyncruns one attempt inline and posts the rest to its own worker, so the task the caller awaits completes the moment the first attempt fails. That is the right shape once an envelope is durable somewhere and recovery can find it; it is the wrong shape for the write that makes it durable, because there is no other copy.DurableWriteRetrykeeps the same 50/100/250 ms budget, awaits it inline, and lets the last exception reach the caller.Who is affected is narrower than it sounds. If you enlist a real outbox (EF Core, Marten,
DatabaseEnvelopeTransaction) nothing changes — that path never reached this code. Inside a handler nothing new escapes either; the publish is buffered and a failure is still caught, logged and recorded as a discard, just atErrorwith a real tracking event instead of a buriedInformationline. Only the un-transacted publish from outside a handler can now throw.One tenant's outage stops costing you every tenant
timestampdefault is now a true UTC instant (GH-4663). It depended on the session's time zone, soInboxStaleTimehanded back envelopes that were still running.Partitioning
A scheduled message no longer runs on a node that does not own the slot (GH-4673). Under global partitioning a scheduled envelope took the local shortcut regardless of slot ownership, so two nodes could process the same group id concurrently — the exact thing partitioning exists to prevent. A promoted scheduled envelope also no longer still reports its status as
Scheduled.HTTP
Stream large multipart uploads through a
MultipartReaderendpoint parameter, contributed by @erdtsieck (#4674) — no buffering the whole upload to handle it. F# code generation emits the new frame too, and the F# codegen coverage is now gated against a committed baseline so a new unsupported frame cannot slip in unnoticed.Diagnostics, metrics and operations
local://destination was being classified as System traffic, so a user's own local queue never reached the per-type/per-tenantDeadLettersmetric (GH-4665).BrokerResource.Checkno longer reports a thrown check as a missing resource (GH-4693), which was hiding the real cause behind "Missing known broker resources".ShardStartException.Reason.SqliteNodePersistencehonors the table prefix (GH-4668); node shutdown failed outright on a prefixed store.Dependencies
node_numbercolumn that is alreadyGENERATED BY DEFAULT AS IDENTITYis read back as drift, so every migration emits anALTER ... MODIFYthat Oracle refuses. It will ship once that is fixed upstream.Thank you
MultipartReaderstreaming upload support in #46746.41.0
28 commits since V6.40.0. Minor rather than patch because of the new EF Core and topology features below — and because one change is breaking.
AutoApplyTransactions()now fails the chain build when two persistence providers can own it (#4631). A handler taking both aDbContextand a Marten/Polecat/FisherIDocumentSessionmatched two providers, andAutoApplyTransactionsapplied neither — no transaction support, no warning, no log line, and whatever the un-owned store buffered was discarded when the scope closed.[Transactional]on the same handler took the first ordered provider instead, so the document session was never saved. Both outcomes were silent and the handler reported success.This stops an application that starts today. One that writes through two stores from a single handler has been losing one of those writes all along; it will now refuse to build until the handler says which store owns the transaction. Add
[Transactional(typeof(X))]or[Storage(typeof(X))], or[NonTransactional]to opt out. Two-provider atomicity remains unsupported — the designated store commits, the other does not. Saga chains are exempt.Entity Framework Core
Lightweightmessage handler now enlist in the sameSaveChangesAsync()as the business write, andPublishDomainEventsFromEntityFrameworkCore()— inert inLightweightbefore — runs on every path.EfCoreOpsset-based operations (#4629), which force the eager transaction they need rather than failing quietly.Update<T>orStore<T>rather thanIStorageAction<T>used to silently save nothing.Multi-tenancy
Envelope.TenantIdis normalised throughTenantIdStyle(#4640).MessageContext.TenantIdalways applied the style andEnvelope.TenantIdnever did, so underForceLowerCasea handler saw"RED"on the envelope beside"red"on the context. Polecat and Fisher read the envelope, so they wrote the raw casing — invisible on SQL Server's case-insensitive collation, and on Fisher's BINARY collation the row was unreachable.OutboxedSessionFactoryresolves theMainstore lazily (#4633).Transports and topology
ListenToKafkaTopicsgroup and stamping the topic asDestination— thanks @lahma.Durability and correctness
EnqueueDirectlyAsyncretires the inbox row it forwards (#4645). A delayed message sent from a handler to a database-backed queue that another node owns was silently destroyed: the forwarding node left anIncomingrow behind, and the owning node's anti-duplicate probe then deleted the queue row it had just written. Nothing logged, nothing dead-lettered. Reported with a full four-step reconstruction by @smoqmilus.EndpointCollection._listenersis no longer a plainDictionary(#4646). A failover handing one node several exclusive listener agents at once had up to ten threads writing it while every send read it; aDictionarycorrupted mid-resize is poisoned permanently, and the node never routed again until the pod was replaced. Also reported by @smoqmilus.Activity. Recurring occurrences (#4647), inline receivers (#4649) and the agent plumbing loops (#4650) were parenting every message under whateverActivity.Currenthappened to be live when the agent or listener started.AddMessageHandler.Also
Contributors
Thanks to @erdtsieck, @jakobt, @lahma, @skoging and @smoqmilus.
Commits viewable in compare view.
Updated WolverineFx.RuntimeCompilation from 6.40.0 to 6.43.0.
Release notes
Sourced from WolverineFx.RuntimeCompilation's releases.
6.43.0
A dependency release. The store pins had been queued behind two releases because every store's current version takes Weasel 9.36.0 as a floor, and 9.36 carried an Oracle regression. That is fixed upstream now, so all three move together.
JasperFx stays at 2.76.1.
This is why 6.43.0 is a minor rather than a patch. Nothing in Wolverine's own public API changed, but crossing six Weasel releases changes what a migration does:
MODIFY.DROP INDEXfor them. Fixed.Oracle: the node tables stop drifting
Two fixes in Wolverine itself, both needed to work with Weasel 9.38.0.
Column defaults are no longer hand-escaped. Wolverine wrote every Oracle timestamp default as
SYSTIMESTAMP AT TIME ZONE ''UTC'', with the quotes already doubled, because Weasel used to paste DDL verbatim into anEXECUTE IMMEDIATE '...'literal. Weasel 9.36 escapes literals itself, so both sides escaped and the executed default becameAT TIME ZONE ''UTC''— not a time zone region, and every table create failed withORA-01882.Identity columns are declared through
AutoIncrement()rather than in the type string.wolverine_nodes.node_numberand the node-record table'sidwere declared asNUMBER(10) GENERATED BY DEFAULT AS IDENTITY— with the clause written into the type. Oracle does not store it there: the catalog reports the type as plainNUMBER(10)and carries identity separately. The model could never equal what came back, so every migration emitted anALTER … MODIFYthat Oracle refuses withORA-01031.That type string was a workaround rather than an oversight —
AutoIncrement()emitted the identity clause after the null constraint, which isORA-03076, so it could not create a table at all. Fixed upstream in weasel#667 along with two related defects: identity was never read back fromALL_TAB_COLUMNS.IDENTITY_COLUMN, and a schema containing an identity column could not be dropped at all, because the teardown tried to drop the system-generated sequence behind it.Existing Oracle deployments should settle rather than migrate: the column is already
NUMBER(10)identity in the database, and 9.38.0 now reads that back, so the model matches it.Verification
Built pinned the way CI builds it (
-c Release -f net9.0), 0 errors and 0 warnings, then 17 database suites locally across PostgreSQL, SQL Server, MySQL, Oracle and SQLite — including Marten, Polecat, Fisher, claim check and leader election on four engines.OracleTestswent from 181 failing to 203 passing.6.42.0
A release driven almost entirely by what users reported. Five of the durability fixes below came from one reporter working a multi-tenant deployment hard enough to find them, and the pattern running through them is the same: a failure that belonged to one tenant was being paid for by every tenant, or was not being reported at all.
GH-4662.
PublishAsync/ScheduleAsyncmade outside a handler and outside any transaction, to a local queue made durable byUseDurableLocalQueues(), used to return without an error when the message store was unreachable. Four attempts inside ~400 ms, one line atInformation, and the message was gone — not even recovered after the database came back, because no inbox row was ever written.The cause was the shape of the retry rather than the retry itself.
RetryBlock.PostAsyncruns one attempt inline and posts the rest to its own worker, so the task the caller awaits completes the moment the first attempt fails. That is the right shape once an envelope is durable somewhere and recovery can find it; it is the wrong shape for the write that makes it durable, because there is no other copy.DurableWriteRetrykeeps the same 50/100/250 ms budget, awaits it inline, and lets the last exception reach the caller.Who is affected is narrower than it sounds. If you enlist a real outbox (EF Core, Marten,
DatabaseEnvelopeTransaction) nothing changes — that path never reached this code. Inside a handler nothing new escapes either; the publish is buffered and a failure is still caught, logged and recorded as a discard, just atErrorwith a real tracking event instead of a buriedInformationline. Only the un-transacted publish from outside a handler can now throw.One tenant's outage stops costing you every tenant
timestampdefault is now a true UTC instant (GH-4663). It depended on the session's time zone, soInboxStaleTimehanded back envelopes that were still running.Partitioning
A scheduled message no longer runs on a node that does not own the slot (GH-4673). Under global partitioning a scheduled envelope took the local shortcut regardless of slot ownership, so two nodes could process the same group id concurrently — the exact thing partitioning exists to prevent. A promoted scheduled envelope also no longer still reports its status as
Scheduled.HTTP
Stream large multipart uploads through a
MultipartReaderendpoint parameter, contributed by @erdtsieck (#4674) — no buffering the whole upload to handle it. F# code generation emits the new frame too, and the F# codegen coverage is now gated against a committed baseline so a new unsupported frame cannot slip in unnoticed.Diagnostics, metrics and operations
local://destination was being classified as System traffic, so a user's own local queue never reached the per-type/per-tenantDeadLettersmetric (GH-4665).BrokerResource.Checkno longer reports a thrown check as a missing resource (GH-4693), which was hiding the real cause behind "Missing known broker resources".ShardStartException.Reason.SqliteNodePersistencehonors the table prefix (GH-4668); node shutdown failed outright on a prefixed store.Dependencies
node_numbercolumn that is alreadyGENERATED BY DEFAULT AS IDENTITYis read back as drift, so every migration emits anALTER ... MODIFYthat Oracle refuses. It will ship once that is fixed upstream.Thank you
MultipartReaderstreaming upload support in #46746.41.0
28 commits since V6.40.0. Minor rather than patch because of the new EF Core and topology features below — and because one change is breaking.
AutoApplyTransactions()now fails the chain build when two persistence providers can own it (#4631). A handler taking both aDbContextand a Marten/Polecat/FisherIDocumentSessionmatched two providers, andAutoApplyTransactionsapplied neither — no transaction support, no warning, no log line, and whatever the un-owned store buffered was discarded when the scope closed.[Transactional]on the same handler took the first ordered provider instead, so the document session was never saved. Both outcomes were silent and the handler reported success.This stops an application that starts today. One that writes through two stores from a single handler has been losing one of those writes all along; it will now refuse to build until the handler says which store owns the transaction. Add
[Transactional(typeof(X))]or[Storage(typeof(X))], or[NonTransactional]to opt out. Two-provider atomicity remains unsupported — the designated store commits, the other does not. Saga chains are exempt.Entity Framework Core
Lightweightmessage handler now enlist in the sameSaveChangesAsync()as the business write, andPublishDomainEventsFromEntityFrameworkCore()— inert inLightweightbefore — runs on every path.EfCoreOpsset-based operations (#4629), which force the eager transaction they need rather than failing quietly.Update<T>orStore<T>rather thanIStorageAction<T>used to silently save nothing.Multi-tenancy
Envelope.TenantIdis normalised throughTenantIdStyle(#4640).MessageContext.TenantIdalways applied the style andEnvelope.TenantIdnever did, so underForceLowerCasea handler saw"RED"on the envelope beside"red"on the context. Polecat and Fisher read the envelope, so they wrote the raw casing — invisible on SQL Server's case-insensitive collation, and on Fisher's BINARY collation the row was unreachable.OutboxedSessionFactoryresolves theMainstore lazily (#4633).Transports and topology
ListenToKafkaTopicsgroup and stamping the topic asDestination— thanks @lahma....
Description has been truncated