Commit Graph
135 Commits
Author SHA1 Message Date
IliesAllaliandClaude Opus 5.5 f37fc329ba Immich : lectures bornées, erreurs de corps en 503, lien retiré avec le portrait
- Vignette lue en flux : au-delà de 5 Mo (ou sans taille annoncée), la lecture
  s'arrête sans charger le reste.
- Vignette servie seulement si les octets sont une image, avec
  X-Content-Type-Options: nosniff (plus de repli sur image/jpeg).
- Liste des personnes : délai global de 30 s sur toutes les pages.
- Corps JSON illisible ou flux interrompu : 503 immich_unreachable, au lieu
  d'une erreur serveur.
- Retirer le portrait à la main (DELETE avatar) ou supprimer une personne
  efface aussi son identifiant Immich, sinon l'association reste invisible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:12:21 +02:00
IliesAllaliandClaude Opus 5.5 c8df8df937 Immich : une clé illisible n'est plus signalée comme configurée
Le résumé ne lisait que l'adresse : après un changement de JWT_SECRET, l'onglet
affichait « Configurée » alors que chaque appel échouait. Le résumé déchiffre
désormais la clé (configured: false, keyNeedsReentry: true, instance gardée pour
préremplir le menu). L'onglet Immich affiche « Clé à ressaisir », garde le
bouton de suppression, et un PUT sans clé est refusé tant que la clé en place
ne se lit pas. Tests : résumé avec clé illisible, refus de conserver la clé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:11:17 +02:00
IliesAllaliandClaude Opus 5.5 265b3b30a0 Immich : les instances se choisissent par leur nom, jamais par leur adresse
L'API ne renvoie plus les adresses brutes d'Immich à un administrateur
d'arbre : la liste IMMICH_ALLOWED_API_URLS devient des instances nommées
(« Libellé=https://adresse », libellé facultatif, nom d'hôte par défaut).
Chaque instance a un identifiant opaque dérivé de son adresse, donc stable
même si l'opérateur réordonne la liste. Le PUT accepte cet identifiant et
stocke l'adresse canonique de la liste. Deux instances au même nom d'hôte
sans libellé sont refusées au démarrage avec un avertissement.

Les variables d'exemple documentent le format, la liste reste compatible
avec les adresses seules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:08:54 +02:00
IliesAllaliandClaude Opus 5.5 fbcac3afd4 Tests Immich : liste d'instances vide explicite, indépendante du .env local
Le test « aucune instance autorisée » héritait de IMMICH_ALLOWED_API_URLS du
backend/.env de développement et échouait sur une machine qui le renseigne.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:05:51 +02:00
IliesAllaliandClaude Opus 5.5 63b9761ec4 Immich : garder le chemin de l'instance, comparer origine et chemin
new URL(chemin, base) effaçait le sous-chemin d'une instance derrière un
proxy (https://hote/immich devenait https://hote/api/...). L'adresse se
concatène désormais. Une adresse avec identifiants, requête ou fragment est
refusée, et le client reçoit l'adresse autorisée normalisée, jamais la
valeur brute de la base. Tests : sous-chemin, domaine préfixe, userinfo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:05:50 +02:00
IliesAllaliandClaude Opus 5.5 44dd203069 Immich : ne jamais suivre une redirection avec la clé d'API
fetch suivait les redirections par défaut : une instance autorisée qui
répond 3xx pouvait recevoir x-api-key sur une autre adresse. Les appels
passent en redirect: 'error' (remontée en immich_unreachable), avec un test
qui le prouve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:04:50 +02:00
Mistral Vibe cf946be617 Immich : un portrait déposé à la main remplace aussi le lien Immich
POST /trees/:id/persons/:personId/avatar lit immichPersonId de la personne et le
remet à null quand une association existe ; l'entrée d'audit person_avatar_updated
trace le retrait via payloadJson immichLinkRemoved. Sans cela, l'association
survivait invisible en base après remplacement du portrait par un fichier.

Test : l'envoi d'un fichier sur un portrait Immich efface l'association (échouait
avant ce fix : immichPersonId absent de l'update) ; sans association, le champ
n'est pas touché.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-13 19:08:52 +02:00
Mistral Vibe 8803463ce4 Immich : le choix de la source passe par un menu sur « Changer » ; « Retirer » désassigne les visages Immich
- PersonCard : le lien « Depuis Immich » empilé sous « Changer »/« Retirer » disparaît ;
  « Changer »/« Ajouter une photo » ouvre un menu contextuel (portail, pz-menu) proposant
  « Depuis un fichier » ou « Depuis Immich », seulement quand l'arbre a une connexion
  Immich ou que la personne garde un portrait venu d'Immich (sinon sélecteur direct).
  La connexion se lit via GET /trees/:id/immich/config à l'ouverture en édition.
- « Retirer » transmet l'origine du portrait ; App route vers unassignImmichPerson quand
  il vient d'Immich (portrait + association retirés ensemble) au lieu de la suppression
  seule qui laissait une association pendante. Erreurs du chemin Immich mappées
  par getImmichErrorMessage.
- i18n en : « Depuis un fichier », « Source du portrait ».

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-13 18:43:16 +02:00
Mistral Vibe 310f2fb597 Immich : publier l'origine du portrait dans le graphe, pas l'identifiant
- avatarFromImmich (fichier préfixé « immich- ») remplace immichPersonId
  côté front : le panneau ne propose le retrait que si le portrait vient
  d'Immich, et le bouton de la fiche retrouve son libellé distinctif
- helper isImmichAvatarPath partagé entre le payload du graphe et la route
  unassign, qui testaient le préfixe chacun de son côté
- tests : origine du portrait dans le payload (vrai/faux/null)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-13 17:47:37 +02:00
Mistral Vibe 8d36a08b11 Immich : retirer l'identifiant Immich du graphe envoyé aux visiteurs
- buildGraphPayload ne mappe plus immichPersonId ; test qu'il n'apparaît pas
- le front ne propage plus le champ (graphAdapter, mockData et son test)
- le panneau Immich propose le retrait d'association en permanence, sans lire
  le champ ; unassign sans association ne fait rien : pas d'écriture, pas
  d'entrée d'audit (test du no-op), et le bouton de la fiche garde un
  libellé fixe

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-13 17:39:23 +02:00
Mistral Vibe 0bda88920d Immich : demander confirmation avant de remplacer un portrait existant
L'association remplaçait et supprimait le portrait en place sans rien
demander. Le serveur refuse maintenant le remplacement d'un portrait
existant (409 avatar_exists), quelle que soit son origine, tant que la
requête ne porte pas replaceAvatar ; le panneau Immich transforme ce
refus en demande de confirmation avant de rejouer la requête. Sans
vignette Immich, l'association ne touche pas au portrait et aucune
confirmation n'est demandée.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-13 15:58:32 +02:00
Mistral Vibe a3386824d3 Immich par arbre : connexion propre à chaque arbre, instances autorisées par l'opérateur
- Nouvelle table tree_immich_configs (adresse + clé d'API chiffrée AES-256-GCM,
  clé dérivée de JWT_SECRET) et routes GET/PUT/DELETE /trees/:id/immich/config
  réservées aux administrateurs de l'arbre ; journal d'audit sans secret
  (adresse et « clé changée » uniquement).
- Fin des variables d'env IMMICH_ENABLED / IMMICH_API_URL / IMMICH_API_KEY :
  l'adresse se choisit parmi IMMICH_ALLOWED_API_URLS, la liste établie par
  l'opérateur du serveur. Elle filtre l'enregistrement ET chaque requête :
  retirer une adresse coupe aussitôt les connexions qui l'utilisent.
- Changer d'instance exige une nouvelle clé : l'ancienne est écrasée et ne
  voyage jamais vers le nouveau serveur.
- Le désassignement reste possible sans connexion : purement local, il nettoie
  association et portrait stocké même après suppression de la connexion ; le
  panneau affiche « Retirer l'association » dans tous les états.
- Onglet Immich dans Paramètres de l'arbre : menu des instances autorisées,
  test de connexion, suppression avec confirmation ; i18n anglais des nouveaux
  messages.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-13 14:04:45 +02:00
Mistral Vibe 50873a4f9e Fix Immich modal positioning with portal to always see the Associate button 2026-10-12 16:48:48 +02:00
Mistral Vibe c703a34165 Immich : vérifier l'existence d'une personne avant l'association
Le 404 de la vignette ne distingue pas une personne inexistante d'une
vignette manquante : l'association pouvait donc être enregistrée pour
une personne Immich qui n'existe pas.

- ImmichClient.getPerson() : GET /api/people/{id} (200 | 404), qui
  établit l'existence de la personne et annonce sa vignette.
- La route d'association rejette une personne inexistante (404
  immich_person_not_found) ; un refus d'authentification (502) ou une
  erreur serveur (503) n'est jamais pris pour une absence.
- La vignette n'est demandée que si Immich en annonce une ; une vignette
  manquante chez une personne existante associe toujours sans portrait.
- Tests : personne inexistante refusée sans toucher base, audit ni
  fichiers ; vignette disparue entre les deux appels ; échec
  d'authentification pendant l'association sans changement en base.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-12 13:40:38 +02:00
Mistral Vibe 2f64ceb41d .env.example : documenter les variables Immich pour l'auto-hébergement
Le .env.example racine (docker compose, env_file de l'API) ne
mentionnait pas IMMICH_ENABLED, IMMICH_API_URL et IMMICH_API_KEY ;
seul le .env.example du backend les documentait.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-12 12:21:52 +02:00
Mistral Vibe 47083ec274 Merge upstream/main : premières photos, Docker tout-en-un, dépendances
Reprise de upstream (IliesAllali/main) dans la branche Immich. Seul
conflit : l'import des icônes dans PersonCard.jsx — les deux lignes
sont gardées (ImagePlus pour le portrait vide de « Premières photos »,
Sparkles pour le bouton « Depuis Immich »). Tout le reste fusionne
automatiquement ; l'intégration Immich (routes, exports de media.ts,
mapping immichPersonId, panneau) est inchangée.

Vérifié après la fusion : tests Immich (16), tests backend focalisés
gedcom-photos (4), build tsc, eslint et les 107 tests du front. Seul
« rate-limits login endpoint » dépasse son délai de 5 s, déjà le cas
sur main avant la fusion (bcrypt, machine lente).

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-12 12:18:41 +02:00
Mistral Vibe 378071bf13 Intégration Immich : associer un visage à une personne de l'arbre
- Colonne persons.immichPersonId (schéma + migration 20261012_001) et
  exposition dans le graphe pour l'afficher côté fiche.
- Client Immich (src/lib/immich.ts) sur le contrat OpenAPI v3.1.0 :
  ping, /api/people paginé, vignette par personne ; erreurs distinctes
  entre injoignable, clé refusée et introuvable, identifiants validés
  comme UUID v4.
- Routes /trees/:id/immich/* (status, people, thumbnail, assign,
  unassign), réservées aux administrateurs de l'arbre ; l'adresse et la
  clé d'Immich ne quittent jamais le backend.
- La vignette passe par le pipeline des portraits (type lu dans les
  octets, métadonnées retirées, quota de l'arbre) : le fichier est écrit
  avant la transaction (personne + journal immich_assign) et l'ancien
  portrait est supprimé après ; un échec du nettoyage est journalisé
  sans faire échouer la requête. Le désassignement retire le portrait
  seulement s'il vient d'Immich (préfixe immich-) et préserve un
  portrait envoyé à la main.
- Côté front : bouton « Depuis Immich » sur la fiche en édition, panneau
  de sélection avec aperçu et retrait de l'association, traductions
  anglaises, messages d'erreur distincts.
- Tests : 16 tests backend (succès, 400/401/403/404/413/502/503, quota,
  échec de transaction, préservation du portrait manuel, serveur
  désactivé) et le mapping immichPersonId côté front.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-10-12 11:53:12 +02:00
IliesAllali abee3c6e19 Merge pull request #57 from IliesAllali/docker/healthcheck-premier-lancement
fix(docker): 120 s de marge au healthcheck de l'API au premier lancement
2026-10-11 20:42:18 +02:00
IliesAllaliandClaude Opus 5.5 a91474f0e6 fix(docker): 120 s de marge au healthcheck de l'API au premier lancement
Les migrations Prisma passent avant que l'API réponde. Avec 30 s, le conteneur
web, qui attend une API saine, abandonnait au premier docker compose up
(signalé sur r/GenealogieFR le 11/10).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:38:04 +02:00
IliesAllali 8103154e02 Merge pull request #56 from IliesAllali/produit/premiere-photo
Premières photos : import dès la création, photos du logiciel retrouvées, premiers visages
2026-10-11 18:59:12 +02:00
IliesAllaliandClaude Opus 5.5 83443ac9dc Premières photos : import dès la création, photos du logiciel retrouvées, premiers visages
- Création d'arbre : « J'ai déjà un arbre » importe le .ged sans fiche « vous » en double.
- Import GEDCOM : lit les photos citées (OBJE / FILE, en ligne ou par renvoi, _PRIM d'abord)
  et renvoie leur chemin ; rien n'est gardé côté serveur.
- Fenêtre « Il manque les visages » après un import : dossier des photos apparié par nom de
  fichier, cinq visages à demander (famille de « Moi », sinon les plus jeunes).
- Portrait vide chez le propriétaire : cadre cliquable sur la fiche hors édition, « + photo »
  au survol sur l'arbre.
- Photos de plus de 5 Mo réduites à 2000 px avant l'envoi ; portraits à 120 envois par minute.
- PostHog : gedcom_imported, portraits_bulk_placed, portrait_added (effectifs arrondis).
- Corrigé : une union à un seul parent connu relie ses enfants à ce parent, sous un seul
  « Inconnu », au lieu de les laisser sans lien.
- Corrigé : réimporter un GEDCOM reprend les personnes, unions et liens déjà présents au lieu
  de tout doubler.

Recette locale (vraie API, vraie base) : 29/29 sur le parcours photos, 47/47 sur la recette
de non-régression des parcours. Tests 123 serveur, 107 app, lint et build propres.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:54:56 +02:00
IliesAllali 2a510bf474 Merge pull request #55 from IliesAllali/docker/api-upstream
Docker : le front lit l'adresse de l'API dans API_UPSTREAM
v1.0.3
2026-10-10 16:23:10 +02:00
IliesAllaliandClaude Opus 5.5 7becb821a3 CHANGELOG : 1.0.3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:18:02 +02:00
IliesAllaliandClaude Opus 5.5 333a11e84b Docker : le front lit l'adresse de l'API dans API_UPSTREAM
Le conteneur web relayait l'API vers `api:4000`, écrit en dur. Sur un réseau
partagé entre plusieurs applications (Umbrel), ce nom peut appartenir à une autre.
L'adresse vient maintenant de API_UPSTREAM, `api:4000` par défaut : rien ne
change pour les installations existantes. L'image tout-en-un garde sa propre
configuration. La CI lance un second front qui joint l'API par le nom de son
conteneur et repasse le test de fumée.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:15:46 +02:00
IliesAllali b774b1dff8 Merge pull request #53 from IliesAllali/docker/aio
Docker : image tout-en-un pour Unraid et les NAS
2026-10-09 17:53:04 +02:00
IliesAllaliandClaude Opus 5.5 30d015f083 Docker tout-en-un : journal sur stderr, il polluait le mot de passe lu par $(secret ...)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:51:29 +02:00
IliesAllaliandClaude Opus 5.5 cea8d1db8f Docker tout-en-un : journal PostgreSQL dans le dossier de la base (écriture refusée à la racine de /data)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:46:58 +02:00
IliesAllaliandClaude Opus 5.5 91abe47614 Docker : image tout-en-un pour Unraid et les NAS
Une seule image (PostgreSQL 15, API, nginx) qui crée sa base et ses secrets dans /data au premier
démarrage. Publiée par images.yml sous ghcr.io/iliesallali/parenthese-aio, testée en CI (démarrage
à vide, redémarrage, test de fumée).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:42:14 +02:00
IliesAllali 5a11d00af9 Merge pull request #38 from IliesAllali/dependabot/npm_and_yarn/landing/landing-minor-patch-0c4d63a201
Bump posthog-js from 1.435.8 to 1.438.0 in /landing in the landing-minor-patch group across 1 directory
2026-10-09 17:04:54 +02:00
IliesAllali c564ebeb05 Merge pull request #52 from IliesAllali/dependabot/npm_and_yarn/frontend/frontend-minor-patch-8178106ae4
Bump the frontend-minor-patch group across 1 directory with 2 updates
2026-10-09 17:04:51 +02:00
dependabot[bot] ada823ab47 Bump the frontend-minor-patch group across 1 directory with 2 updates
Bumps the frontend-minor-patch group with 2 updates in the /frontend directory: [posthog-js](https://github.com/PostHog/posthog-js) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `posthog-js` from 1.436.0 to 1.438.0
- [Release notes](https://github.com/PostHog/posthog-js/releases)
- [Changelog](https://github.com/PostHog/posthog-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PostHog/posthog-js/compare/posthog-js@1.436.0...posthog-js@1.438.0)

Updates `vite` from 8.3.2 to 8.3.3
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.3.3/packages/vite)

---
updated-dependencies:
- dependency-name: posthog-js
  dependency-version: 1.438.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-minor-patch
- dependency-name: vite
  dependency-version: 8.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-09 13:23:56 +00:00
dependabot[bot] 2e638d8a43 Bump posthog-js
Bumps the landing-minor-patch group with 1 update in the /landing directory: [posthog-js](https://github.com/PostHog/posthog-js).


Updates `posthog-js` from 1.435.8 to 1.438.0
- [Release notes](https://github.com/PostHog/posthog-js/releases)
- [Changelog](https://github.com/PostHog/posthog-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PostHog/posthog-js/compare/posthog-js@1.435.8...posthog-js@1.438.0)

---
updated-dependencies:
- dependency-name: posthog-js
  dependency-version: 1.435.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: landing-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-09 13:23:34 +00:00
IliesAllaliandClaude Opus 5.5 52fff2b037 Dépendances du 09/10 et version 1.0.2
fast-jwt 6.3.4 (cache du vérificateur, jetons expirés sans iat), source-map-js 1.2.2 et
postcss-selector-parser 7.1.6 forcé sous Tailwind 3 (CSS produit identique octet pour octet).
Landing en Vite 8 et plugin-react 6, mêmes navigateurs cibles que le front, rendu comparé à
l'écran au build Vite 7 en 1920 et 390 px. Groupes mineurs front (#50) et landing (#38).
Reprend #38, #41, #46, #49, #50, #51. CHANGELOG 1.0.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v1.0.2
2026-10-09 15:21:08 +02:00
IliesAllaliandClaude Opus 5.5 3c263a708d Docker : images API et front publiées sur ghcr.io, installation sans cloner le dépôt
Après chaque CI verte sur main (et sur un tag vX.Y.Z), le workflow Images construit
parenthese-api et parenthese-web en amd64 et arm64, les pousse sur ghcr.io, puis teste
une installation dans un dossier vide avec docker-compose.yml et .env pour seuls fichiers.
docker-compose.yml tire ces images (PARENTHESE_VERSION, latest par défaut) et garde le
build depuis les sources en repli. Demande faite sur r/GenealogieFR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:24:19 +02:00
IliesAllali 4bdf7aa1f3 Merge pull request #43 from IliesAllali/dependabot/npm_and_yarn/frontend/globals-17.13.0
Bump globals from 16.5.0 to 17.13.0 in /frontend
2026-10-08 16:45:38 +02:00
IliesAllali 24e28e98b8 Merge pull request #45 from coutadeurf/fix/random-uuid-insecure-context
Correction : création d'arbre impossible en HTTP simple
2026-10-08 16:45:22 +02:00
Fabrice Coutadeur ebba0c8ce8 Correction : création d'arbre impossible en HTTP simple
crypto.randomUUID n'est exposé par le navigateur qu'en contexte sécurisé
(HTTPS ou localhost). Servie en HTTP simple, l'app plantait dans
generateSecurePassword à l'étape de création de l'arbre.

Repli sur crypto.getRandomValues, disponible partout, qui produit le
même UUID v4 sans tirets.

Signed-off-by: Fabrice Coutadeur <coutadeurf@gmail.com>
2026-10-08 12:00:17 +02:00
dependabot[bot] e49467059e Bump globals from 16.5.0 to 17.13.0 in /frontend
Bumps [globals](https://github.com/sindresorhus/globals) from 16.5.0 to 17.13.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v16.5.0...v17.13.0)

---
updated-dependencies:
- dependency-name: globals
  dependency-version: 17.13.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-08 01:15:29 +00:00
IliesAllaliandClaude Opus 5.5 0365a71618 Suivi avant le Show HN : démo, source jusqu'à l'inscription, un seul clic CTA
- demo_opened (une fois par chargement, visiteur sans compte) et demo_interaction (personne, média, recherche, édition, création d'arbre ; une fois par type, sans contenu)
- Source d'arrivée gardée sur l'appareil (?source=hn) et jointe à account_screen_viewed et account_registered ; la landing transmet la vraie source au CTA et à l'iframe de démo au lieu de source=landing
- Plus de remise à zéro PostHog à chaque ouverture anonyme (effaçait le visiteur de la landing), seulement à la déconnexion
- Landing : un seul événement signup_cta_clicked (hero_cta_clicked retiré, plus utilisé par le funnel), envoyé avant la navigation sans sendBeacon (bloqué par Brave)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:41:21 +02:00
IliesAllaliandClaude Opus 5.5 10f1fc5d14 Typo : plus de mot ni de signe seul en fin de ligne
- text-wrap-style pretty sur les paragraphes, listes, légendes et chapôs, balance sur les titres
  (landing, guides statiques, base pz.css de l'app). Longhand pour ne pas réactiver le retour
  à la ligne là où white-space: nowrap est posé. Les noms de l'arbre sont sur le canvas, non touchés.
- Espaces insécables du français dans le texte visible : fine insécable avant ? ! ;,
  insécable avant : et dans les guillemets, entre un nombre et son unité (Mo, Go, €, dpi).
  Landing (i18n.js, bloc fr hors meta) et pages guides FR (corps de page, hors script).
- App : frenchTypography() appliquée par t() en français, avant le remplacement des variables ;
  le dictionnaire anglais reste indexé sur le français tel qu'écrit. Tests mis à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 17:06:44 +02:00
IliesAllaliandClaude Opus 5.5 d7c86b5ae8 docs(readme): what each backup command saves, GEDCOM is not a backup
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 15:14:53 +02:00
IliesAllaliandClaude Opus 5.5 b41eb7c2ec Landing : capture de l'arbre de démo sous le bouton « Entrer dans la démo »
Avant le chargement de l'iframe, le bloc #demo n'affichait qu'un fond papier
et le bouton n'apparaissait qu'une fois la démo chargée. Une capture fixe de
l'arbre (FR/EN, grand écran et mobile, WebP 29 à 69 Ko, même origine) sert
maintenant de fond, et le bouton est visible dès l'arrivée sur la section.
Le clic garde le même comportement ; s'il arrive avant la fin du chargement,
le symbole de chargement s'affiche par-dessus la capture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:25:16 +02:00
IliesAllaliandClaude Opus 5.5 aeb6db9036 Landing : aplats de la démo et de l'appel final en terracotta vive, démo sans ombre
Choix A de Patch le 02/10/2026 sur la planche des trois terracotta : fond
#D2694A (--a500) sur .sec-demo et .final à la place des roses --a50 et
--peche-50, titres et textes en blanc, bouton final blanc à texte encre.
Le cadre de la démo perd son ombre portée, il garde sa bordure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 17:15:05 +02:00
IliesAllaliandClaude Opus 5.5 8b50356c4b Démo : vraie vidéo d'époque pour le mariage de Simone, vidéos de remplacement retirées
Le souvenir « Mariage Simone 1943 » ouvrait Big Buck Bunny sur YouTube.
Remplacé par 25 s des actualités Polygoon « Bruiloft te Giethoorn » (1947,
Beeld en Geluid via Open Beelden, CC BY-SA 3.0 NL), sans le son, en H.264
pour Safari, servi par le site (media-src 'self'). Crédit dans CREDITS.md
et sources.json. Les trois autres vidéos YouTube de remplacement de la démo
(Témoignage filmé 1960, Anniversaire 2020, Interview archive radio) sont
retirées.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:55:05 +02:00
IliesAllaliandClaude Opus 5.5 75922f3ed3 Sécurité 1.0.1 : audit indépendant de la 1.0
- Vidéo piégée : l'expression régulière de position était quadratique, un faux MP4 de 2 Mo figeait l'API (bornée, linéaire)
- Sessions émises avant le 01/10/2026 refusées (SESSIONS_NOT_BEFORE) : des sessions ont fuité dans les annotations et les journaux jusqu'à la 1.0
- Contributions : l'« avant » montré au propriétaire vient de la base ; une suppression approuvée part en cascade (unions, liens, souvenirs, portrait, fichiers)
- Mot de passe de partage : essai compté avant bcrypt, comparaisons une par une, changement et rattachement dans une transaction
- Quota mesuré sur le disque, 10 arbres par compte, corps à 1 Mo hors envois, bornes sur annotations, contributions et GEDCOM
- GIF réencodés ; anciennes propositions d'annotation sans adresse stockée ; clé d'exemple refusée sans NODE_ENV
- Déploiement du commit validé par la CI, clé d'hôte obligatoire ; nginx : X-Forwarded-For écrasé, version masquée, journal sans query string
- PostHog verrouillé dans le code, sans script externe ; CSP sans *.posthog.com ; sauvegardes hors serveur chiffrées par défaut

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v1.0.1
2026-10-01 12:19:41 +02:00
IliesAllaliandClaude Opus 5.5 ee7d2809fc Front : mêmes navigateurs qu'avec Vite 7
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>
2026-10-01 12:13:19 +02:00
IliesAllali 2f9fa742fa Intègre deps/landing-infra 2026-10-01 11:56:15 +02:00
IliesAllali 6a4b8d9539 Intègre deps/frontend 2026-10-01 11:56:15 +02:00
IliesAllali 0e055a34f7 Intègre deps/backend 2026-10-01 11:56:15 +02:00
IliesAllaliandClaude Opus 5.5 e145cad509 Vitest 5.0 (Dependabot #37)
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>
2026-10-01 11:20:22 +02:00