Vite 8 relève sa cible par défaut à Safari 16.4 et Chrome 111. La famille ouvre souvent l'arbre sur un vieil iPad ou un ancien téléphone : la cible reste celle de Vite 7 (Chrome et Edge 107, Firefox 104, Safari 16.0), valeurs lues dans le guide de migration de Vite 8.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vitest 5 demande Vite 6.4 ou plus et Node 22.12 ou plus (Vite 8.3 et Node 24 ici). Aucun test n'utilise vi.mock, bench, describe.sequential, toThrow('') ni d'assertion asynchrone non attendue, les points touchés par le guide de migration ; clearMocks activé par défaut est sans effet sans mock. 97 tests passent, comme avant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La PR montait @eslint/js seul, dont la config recommandée ajoute no-useless-assignment, no-unassigned-vars et preserve-caught-error. eslint passe aussi en 10 (configuration à plat déjà en place, aucun commentaire eslint-env, Node 24) ; eslint-plugin-react-hooks 7.1 et eslint-plugin-react-refresh 0.5 la déclarent prise en charge. Les trois signalements de no-useless-assignment étaient fondés : une valeur initiale jamais lue, chaque branche suivante l'écrase ou quitte la fonction (libellé de parenté, contenu JSON d'une photo ou d'un tracé posé sur l'arbre). Valeur initiale retirée, comportement inchangé.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La PR seule ne pouvait pas s'installer : @vitejs/plugin-react 5 n'accepte pas Vite 8 (ERESOLVE à npm ci, en CI comme dans l'image Docker). Les deux montent ensemble : Vite 8 construit avec Rolldown et Oxc, la 6 du plugin abandonne Babel, dont ce projet n'utilisait aucune option. Rien à migrer dans vite.config.js (ni rollupOptions, ni esbuild, ni manualChunks). Le build garde un seul script module externe dans index.html, sans eval ni script en ligne, compatible avec la CSP ; les polices auto-hébergées sortent avec les mêmes empreintes. Changements à connaître : CSS minifiée par Lightning CSS, cible navigateur par défaut relevée (Safari 16.4, Chrome et Edge 111, Firefox 114), Node 20.19 ou 22.12 minimum (Docker et CI en Node 24).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La version 1 ne publie plus dist/esm/icons/*.js ni __iconNode : renderers.js importait ces fichiers internes pour dessiner les vignettes carte et GPX sur le canvas, d'où l'échec du build (CI Frontend et image Docker). Les tracés viennent maintenant de @lucide/icons, le paquet officiel des données d'icônes (export nommé, propriété node), à la même version que lucide-react. Les 47 icônes utilisées existent toujours sous leur nom (Edit3, HelpCircle, MoreHorizontal, Trash2 restent des alias) et rendent un SVG identique à la 0.564, aria-hidden compris. Les icônes de marque retirées en v1 ne sont pas utilisées ici.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #30. La 7.0 adopte les défauts de la 6.0 et rend fatales ses options dépréciées : rien de cela ne touche tsconfig.json, qui fixait déjà rootDir (src), types (["node"]), module et moduleResolution NodeNext, target ES2022, strict, esModuleInterop à true. Le JavaScript produit dans dist/ est identique octet pour octet à celui de TypeScript 5.9.3 (diff -r vide sur les 27 fichiers). La 7.0 n'a plus d'API JavaScript, mais aucun outil du backend ne s'en sert : vitest et tsx ne passent pas par tsc, Prisma ne lit que le numéro de version et tolère son absence. Binaires natifs dans le package-lock pour Linux x64 (CI, Docker, VPS) et Windows. 113 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #34 (18.0.5, correctif publié depuis). Depuis la 17.0.0, config() écrit « ◇ injected env (N) from .env » à chaque démarrage, même sans fichier .env (vu avec la 18.0.5 : « injected env (0) »), ce qui glisse une ligne hors format dans les journaux JSON de production : config({ quiet: true }). Les autres ruptures de la 18.0.0 (préchargement -r dotenv/config retiré, .env.vault retiré) ne touchent pas Parenthèse, qui n'appelle que config() dans config/env.ts. La CLI Prisma garde sa propre copie de dotenv 16. 113 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #32. Rupture de la 11.0.0 : la pré-vérification CORS n'annonce plus par défaut que GET, HEAD et POST, un navigateur d'une autre origine aurait refusé les PUT, PATCH et DELETE de l'API. La liste d'avant est maintenant écrite dans app.ts, et un test vérifie la réponse à un OPTIONS d'une origine autorisée (il échoue sans la ligne). Option origin inchangée. Les ajouts de la 11.x (logLevel du préflight, cors par route dans config.cors) ne sont pas utilisés. 113 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
React et react-dom 19.3.0, @types/react et @types/react-dom 19.3.0, posthog-js 1.434.15, autoprefixer 10.6.1, eslint-plugin-react-hooks 7.1.1, eslint-plugin-react-refresh 0.5.7. La règle react-hooks/refs de la 7.1 voit maintenant les refs lus ou écrits pendant le rendu, corrigés plutôt que désactivés : le nom de l'arbre partagé affiché par l'écran compte passe par un état (un ref ne redessine rien), la personne de départ de l'arbre est recopiée dans un effet déclaré avant celui du cadrage, l'API de zoom est exposée par useImperativeHandle, l'horodatage des portraits est posé au premier chargement au lieu de Date.now() au rendu (react-hooks/purity). react-refresh 0.5 garde l'export par défaut et la config vite utilisés ici.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nginx 1.31 est la branche mainline (développement), la stable est 1.30 (nginx.org au 01/10/2026). Les montées mineures de nginx sont ignorées, les correctifs de la 1.30 arrivent toujours. Passer à la stable suivante à la main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
L'action passe de Node 20 à Node 24, ce qui retire l'avertissement de dépréciation des journaux de déploiement. Empreinte épinglée vérifiée contre le tag v0.10.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Versions mineures. Pages vues à l'écran (accueil FR et EN, téléphone, vie privée), 13 tests, et événements PostHog toujours envoyés (requêtes interceptées, comparées avec main).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #29. La 11.2.0 corrige GHSA-grpc-p53c-r64v : la clé par défaut était l'adresse IP telle quelle, un client IPv6 changeait d'adresse dans son /64 (ou réécrivait la même autrement) et repartait à zéro. La clé est maintenant l'adresse normalisée, IPv4 mappée ramenée en IPv4, IPv6 regroupée par /64. Rupture de la 11.0.0 : option whitelist retirée au profit d'allowList, que Parenthèse n'utilise pas. Aucun changement de code (global: false, limites par route dans config.rateLimit, clé par défaut sur request.ip calculée par Fastify avec TRUST_PROXY). 112 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend le groupe Dependabot backend-minor-patch (#27). vitest arrive en 5.0.3, correctif publié depuis la PR (5.0.2). Aucun changement de code. Compilation propre, 112 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Les versions de sharp antérieures à 0.35.0 sont touchées quand elles décodent des images non fiables (GHSA-f88m-g3jw-g9cj, libvips), et antérieures à 0.35.4 pour libheif (GHSA-rgj7-g3m4-5g8c). Parenthèse décode les photos envoyées par la famille : montée en 0.35.5 (libvips 8.18.7). Aucun changement d'API utilisé ici (Node 24, failOn, rotate, sorties JPEG/PNG/WebP). 112 tests, recette sécurité et comparaison de rotation relues.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le test cherchait l'ancienne barre (« Contribuer à l'arbre »). Il suit maintenant la carte d'accueil, la barre « Ajouter un souvenir » et le menu « Plus » pour créer un compte. 19/19 en local.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Avec un arbre, la fenêtre « Mon compte » ne menait nulle part : elle a maintenant « Gérer mon compte », qui ouvre « Vos arbres » (déconnexion, suppression du compte), la croix ramène à l'arbre. Sans arbre, « Mon compte » renvoyait aussitôt à l'assistant de création : le repli vers la démo ne se déclenche plus quand l'utilisateur a ouvert l'écran lui-même. Sur le lien d'un arbre supprimé, la session du compte est restaurée, « Créer mon arbre » ouvre le compte connecté au lieu d'un écran de connexion. Page vie privée alignée sur le chemin réel.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La page décrivait encore deux mots de passe (visiteur et contributeur). Elle décrit maintenant le mot de passe de partage (haché, et gardé chiffré pour que le propriétaire le relise), la famille qui propose des ajouts, la fermeture des sessions quand il change, le prénom noté sur une contribution, et les photos réenregistrées sans position GPS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Camille et Alex (hero, « Pour qui ») venaient de randomuser.me, sans licence établie pour un site public. Remplacés par deux portraits Pexels recadrés en 400 x 400 (Clay Elliot, Vitaly Gariev), sources dans CREDITS.md. Images d'aperçu refaites depuis le hero actuel, sur le fond de la DA.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pages française et anglaise alignées sur le code. Polices servies sans Google,
vidéos YouTube et cartes chargées seulement à l'ouverture, pas d'enregistrement
de session ni d'adresse d'arbre envoyée à PostHog, arbre entier et export GEDCOM
pour qui a le mot de passe, contributions anonymisées à la suppression du compte.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unsplash pour les souvenirs, Pexels pour Lya, Marc et Jeanne. Les trois
portraits randomuser.me n'ont pas de licence établie pour un site public,
signalé dans le fichier.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Portraits, souvenirs, photos posées sur l'arbre et aperçus de relecture chargeaient leur image avec la session complète dans l'adresse. Ils utilisent maintenant le jeton de lecture des médias fourni avec le graphe (utils/mediaToken.js), jamais ajouté à une adresse externe. L'aperçu d'une photo posée par la famille n'accepte qu'une photo de cet arbre, reconstruite depuis son chemin. Message pour un arbre plein (storage_quota_exceeded).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le cache d'images de l'arbre chargeait l'adresse de chaque média, vidéos YouTube
comprises, sans que personne lance la vidéo. Seules les photos, les seules
dessinées, sont chargées.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
L'identifiant doit faire 11 caractères (lettres, chiffres, - et _), sinon rien
n'est intégré. Le lecteur vient de youtube-nocookie.com. La carte OpenStreetMap
n'envoie plus que l'origine en referrer, plus l'adresse de l'arbre.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
L'API /api/arbre/:slug ne renvoie ni nom ni email du propriétaire. Les lectures
restaient dans le front sans jamais rien recevoir.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le paramètre ?source=app-shared&return_url= affichait n'importe quelle adresse
dans un lien du site. L'app ne l'envoie plus, le bloc part.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Toutes les copies invite_password_* partent au lancement de l'app, plus seulement
celle de l'arbre rouvert. À la déconnexion et à la suppression du compte, les
brouillons d'édition, la fiche « c'est moi » et le profil sont effacés. Le prénom
du contributeur, la langue et les accueils vus restent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Un nom GEDCOM piégé bloquait l'API plusieurs secondes (expression régulière quadratique) : lu par indexOf, lignes et fiches plafonnées. L'export n'injecte plus de lignes. Deux relectures simultanées appliquaient deux fois les ajouts : la session est verrouillée dans la transaction. Au plus 200 changements par envoi, photos refusées effacées du disque.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Les annotations se lisaient avec n'importe quel compte, et une annotation photo enregistrait l'adresse de l'image avec la session de son auteur. Accès vérifié, adresse retirée à l'écriture comme à la lecture. Les images portent un jeton de lecture des médias (12 h, un arbre) au lieu de la session du compte. trustProxy ne croit plus que nginx (TRUST_PROXY), l'API peut n'écouter que la boucle locale (HOST), plafond de 30 échecs par arbre sur le mot de passe de partage, changer ce mot de passe coupe les comptes rattachés, connexion à durée constante, secrets d'exemple refusés en production.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Un SVG ou du HTML déclaré « photo » passait et s'exécutait sur app.parenthese.io à l'ouverture (vol de session du propriétaire). Le type vient maintenant des premiers octets, les photos sont réencodées par sharp (rotation appliquée, EXIF et GPS retirés), les vidéos de téléphone perdent leur position, et chaque fichier est servi avec nosniff et une CSP sandbox (téléchargement pour tout ce qui n'est pas image, son, vidéo ou PDF). Fichiers supprimés effacés du disque, quota par arbre, limite de débit sur les envois.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
VITE_HELP_URL et VITE_PRIVACY_URL remplacent les pages de parenthese.io,
qui restent la valeur par défaut. Documenté dans les deux README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
before_send réécrit /arbre/<slug> en /arbre/:slug dans toutes les propriétés
(URL, chemin, referrer, propriétés initiales de personne). Enregistrement de
session coupé explicitement, appel /flags coupé (aucun feature flag utilisé,
il envoyait les propriétés de personne sans passer par before_send).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chaque action est référencée par son commit, version en commentaire. Le
déploiement lit la clé d'hôte dans le secret SSH_KNOWN_HOSTS et exige sa
vérification ; sans secret, repli sur ssh-keyscan avec un avertissement.
La CI échoue sur une faille critique d'une dépendance de production.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
deploy.sh sauvegarde la base dans $BACKUP_ROOT/pre-migration quand prisma migrate
status signale un écart, garde les 10 derniers dumps et s'arrête si pg_dump échoue.
backup.sh crée ses fichiers en umask 077 et, si BACKUP_AGE_RECIPIENT est renseigné,
n'envoie sur S3 que des copies chiffrées avec age. Commentaires sur les polices
du frontend mis à jour (deploy.sh, ci.yml).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Newsreader et DM Sans : fichiers woff2 identiques à ceux que servait Google Fonts
(mêmes axes, graisses et découpages), licence OFL à côté des fichiers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
X-Frame-Options ALLOWALL (invalide) et X-XSS-Protection retirés. Les location qui
posent leur propre add_header répètent la liste complète, sinon nginx n'hérite
de rien. CSP de l'app et de la landing construites depuis ce que chargent les
builds (PostHog, YouTube sans cookie, OpenStreetMap, blob:, iframe de démo).
Prod seulement : HSTS avec includeSubDomains, ssl_protocols TLSv1.2 TLSv1.3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lancé à la main. Clone, .env, docker compose up -d sur le port 80 comme le
README, test de fumée, puis captures de l'app en anglais jointes au run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>