Commit Graph
79 Commits
Author SHA1 Message Date
IliesAllali e98125b796 Merge pull request #99 from IliesAllali/fix/test-limite-connexion
Test : délai de 20 s pour la limite des connexions
2026-10-19 00:22:08 +02:00
IliesAllaliandClaude Opus 5.5 b1a7a2f489 test: délai de 20 s pour le test de limite des connexions
Onze connexions avec vérification bcrypt dépassaient parfois 5 s sur la CI : quatre échecs le 18/10 sans lien avec les changements.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 00:19:58 +02:00
IliesAllaliandClaude Opus 5.5 1504a1e124 fix(gedcom): import sans union d'une personne avec elle-meme ni boucle parent-enfant
Un fichier abime pouvait marier une personne a elle-meme ou faire de
quelqu'un son propre ancetre, ce que l'API refuse partout ailleurs. Le
controle se fait en memoire pendant l'import (les validateurs relisent tout
l'arbre a chaque lien), et la reponse compte les relations ecartees
(relationsSkipped).

Premier test de la route d'import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 00:06:30 +02:00
IliesAllaliandClaude Opus 5.5 9c84bd0efc fix(visites): duree de conservation d'un an tenue, comptes supprimes anonymises
La purge des visites de plus d'un an ne passait qu'a l'ouverture de l'onglet
Visites par un administrateur : un arbre jamais consulte gardait tout. Elle
passe aussi a l'enregistrement d'une visite, au plus une fois par heure, pour
tous les arbres.

A la suppression d'un compte, ses visites d'autres arbres gardaient son
identifiant dans la cle du visiteur : elles restent comptees, sous une cle
anonyme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 00:06:30 +02:00
IliesAllaliandClaude Opus 5.5 f20b58be32 fix(api): ecritures en plusieurs temps dans une transaction
Une erreur au milieu laissait un etat partiel, et un nouvel essai du client
recreait des doublons.

- Lot d'annotations : creations, modifications, suppressions et trace.
- Moments : session de contribution, moment, souvenirs rattaches et trace ;
  modification et suppression d'un moment avec ses souvenirs.
- Reordonnancement des souvenirs d'une personne.
- La famille ne rattache a son moment que des souvenirs libres : elle ne
  detache plus un souvenir du moment d'un administrateur.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 00:06:29 +02:00
IliesAllaliandClaude Opus 5.5 82f888b1dc perf(gedcom): notes et sources partagees lues une fois par import
Un fichier dont chaque fiche cite une note ou une source enorme faisait relire
ce texte pour chaque personne : environ 35 min de calcul pour 20 000 fiches,
0,1 s maintenant (memo par noeud, pour la duree de l'import).

- La lecture des medias ne descend que dans les branches qui menent a un
  fichier, avec un budget par personne et une profondeur bornee.
- Les niveaux au-dela de 99 (limite de la norme) sont ignores : une chaine de
  sources faisait deborder la pile.
- Les notes ne sont calculees que pour une personne creee, pas reutilisee.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 00:06:29 +02:00
IliesAllaliandClaude Opus 5.5 3d5d9fea21 Merge main dans feat/recadrage-portrait (après #92, #93, #94)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 00:01:14 +02:00
IliesAllali 6a9034cf98 Merge pull request #93 from IliesAllali/feat/fiche-pastilles-adoption
Fiche : pastilles, lieu de décès, adoption
2026-10-18 23:50:10 +02:00
IliesAllali c24be211e1 Merge pull request #94 from IliesAllali/feat/modifier-souvenir
Modifier un souvenir (administrateur)
2026-10-18 23:47:50 +02:00
IliesAllaliandClaude Haiku 5.5 63f5b63f12 feat: recadrage du portrait, photo entière conservée
Le cadrage (centre et zoom) est stocké dans Person.avatarCrop (JSON, nullable),
l'original reste sur disque et le cadrage s'applique à l'affichage (canevas et fiche).
Route PUT /trees/:id/persons/:personId/avatar/crop, réservée aux administrateurs.
La suppression et le nouvel envoi remettent le cadrage à zéro.

Migration additive (colonne nullable, sans défaut), testée sur base vide et sur base avec données.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 23:28:34 +02:00
IliesAllaliandClaude Haiku 5.5 b09f915662 feat(souvenir): modifier le titre, le moment et la citation
Un administrateur, en mode modification, peut modifier un souvenir depuis la visionneuse : crayon à droite du titre (visible au survol sur ordinateur, toujours visible sur écran tactile), formulaire Titre et Moment de sa vie, texte de la citation réécrit dans caption et dans le fichier citation.txt.

Route PATCH /trees/:id/persons/:personId/media/:mediaId, réservée aux administrateurs. Pas de migration : la date vient du moment de vie rattaché. La légende séparée n'existe pas en base et n'est pas ajoutée.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 22:36:21 +02:00
IliesAllaliandClaude Haiku 5.5 cde9c3d44d fiche : infos en pastilles, lieu de décès, adoption (arbre, liens, ajout)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 22:31:15 +02:00
IliesAllaliandClaude Haiku 5.5 ab6564af41 fix: nom de famille facultatif, case du prénom inconnu sous le champ
- Nom de famille facultatif : une personne garde au moins un prénom ou un nom
  (API, contributions, fiche, formulaire). Contributions : seule une personne
  sans aucun nom est ignorée.
- Case « Je ne connais pas son prénom » visible seulement si le prénom est vide
  (ou cochée), placée sous le champ Prénom.
- Panneau d'ajout : sans sur-titres en capitales.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 21:10:17 +02:00
IliesAllali efca97d9cd Merge pull request #87 from IliesAllali/fix/ajout-prenom-inconnu
Prénom inconnu, et fermer l'ajout au clic sur une personne
2026-10-18 20:54:11 +02:00
IliesAllali 1cf3dd0bc3 Merge pull request #88 from IliesAllali/feat/entree-accueil
Accueil à deux choix, porte unique et prénom du compte
2026-10-18 20:54:06 +02:00
IliesAllaliandClaude Haiku 5.5 92ceea6565 feat(entree): accueil à deux choix, porte unique, prénom du compte
- Backend : prénom du compte facultatif à l'inscription (colonne users.firstName,
  migration additive), renvoyé à l'inscription, à la connexion et sur GET /auth/me
- Accueil sans session : deux choix (J'ai reçu un lien, Se connecter) et
  Créer mon arbre en lien, à la place de la démo (variante B validée)
- Porte : mot de passe puis prénom facultatif pour un nouveau venu ; compte
  connecté non rattaché : bandeau avec son prénom, sans champ prénom, et
  « Ce n'est pas mon compte » (déconnexion, retour à la porte du même arbre)
- Sur-titre « Arbre partagé » retiré de la porte
- Compte déjà rattaché : inchangé, la racine ouvre l'arbre directement

Vérifié : vitest front 154/154, back 228/228 (sans .env local, le test CORS
attend localhost:5173), tsc back, eslint front, vite build, landing test et build.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 20:45:58 +02:00
IliesAllaliandClaude Haiku 5.5 7752b96e3d fix: prénom inconnu, et fermer l'ajout quand on clique une personne
- Prénom inconnu : case « Je ne connais pas son prénom » à l'ajout et en
  modification. Enregistré comme prénom vide, affiché « Prénom inconnu »
  en italique (arbre, fiche, recherche). Pas de migration.
- Export GEDCOM : « 1 NAME /Nom/ » sans prénom. Import : prénom absent
  = vide (au lieu de « ? »).
- Cliquer une personne pendant un ajout ferme le panneau d'ajout ; sa
  saisie reste en mémoire comme à la fermeture par la croix.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 20:41:37 +02:00
IliesAllaliandClaude Haiku 5.5 ac5997659b feat(surnoms): surnom facultatif sous le nom, dans l'arbre et la fiche
- API : nickname accepté à la création, à la modification et dans les
  propositions de contribution (trim, vide = null, 120 caractères max)
- Mode direct et circuit des contributions : même validation, avant/après
- Édition et ajout : champ « Surnom » facultatif
- Arbre : surnom en italique sous le nom, coupé avec … au-delà de 150 px
- Recherche : trouve une personne par son surnom (libellé « Surnom »)
- Démo : surnoms sur Marie et Robert

Vérifié : lint, tests (front 159, back 224), builds (front, back tsc, landing).

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 19:34:09 +02:00
IliesAllaliandClaude Opus 5.5 1e8f8f923a feat(dates): une annee seule, et decede(e) sans date (issue #77)
- Champ de date de la fiche et du formulaire « Ajouter quelqu'un » : une annee seule
  (1950) ou une date complete (12/03/1950), une aide si le texte n'en est pas une.
  L'annee seule s'affiche « 1950 » et non plus « 1 janvier 1950 ».
- Statut « Decede(e) » sans date : persons.isDeceased (migration additive), « 1908–? »
  sous le portrait, « Date inconnue » dans la fiche, en bas de la frise. Import de
  « 1 DEAT Y », export en « 1 DEAT Y ». Une date de deces retire le drapeau.
- Parents : plus de « (null) » quand l'union n'a pas de type.

Closes #77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:27:53 +02:00
IliesAllaliandClaude Opus 5.5 8f866d1bd3 feat(vie): la famille propose des moments, et un moment porte photos, videos et actes
- Un moment peut porter plusieurs souvenirs de tout type (photo, video, enregistrement,
  acte en PDF) : media_items.lifeEventId, reprise de l'ancienne colonne mediaId.
- Naissance, mariage et deces se completent depuis la frise : documents, source, note
  (la date et le lieu restent dans Infos).
- La famille propose un moment par le lien de partage : il attend la relecture, avec
  ses fichiers dans la meme proposition, et apparait une fois accepte.
- Fiche : Ajouter un fichier, Choisir parmi ses souvenirs, prenom du contributeur,
  textes qui expliquent ce qui se passe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:29:23 +02:00
IliesAllaliandClaude Opus 5.5 9d34796d11 feat(vie): ajouter, modifier et supprimer un moment depuis l'onglet Vie
Un bouton « Ajouter un moment » pour les administrateurs, une fiche courte (quoi, quand,
environ, ou, une photo), date exacte, fin, source et note sous « Plus de details ».
La photo devient un souvenir de la personne, rattache au moment (life_events.mediaId,
migration additive). Toucher un moment l'ouvre pour le modifier ou le supprimer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:38:35 +02:00
IliesAllaliandClaude Opus 5.5 f47ef8ecac fix(dates): une date corrigee a la main perd la precision importee
Sinon « vers 1879 » restait colle a la date saisie ensuite, et l'export l'aurait ecrite.
Personne, union, et voie contribution.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 22:29:21 +02:00
IliesAllaliandClaude Opus 5.5 f6affa81d6 feat(gedcom): export des evenements de vie, precisions de date, sources et adoption
L'export rend ce que l'import lit : dates qualifiees (ABT, EST, BET ... AND, FROM ... TO)
ou texte d'origine, lieu de deces, surnom, tous les evenements de la personne et du
couple avec lieu, notes et sources, lieu du mariage, PEDI adopted. Test aller-retour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 22:27:51 +02:00
IliesAllaliandClaude Opus 5.5 87c564fd3c API : frise de vie d'une personne
GET /trees/:id/persons/:personId/life rend la précision des dates, le lieu
de décès, le surnom, les unions avec leur lieu de mariage, et les
événements de la personne et de ses couples. Chargée à l'ouverture de la
fiche, pas dans le graphe. Les droits de lecture du graphe sont factorisés
(resolveReadAccess) et servent aux deux. Supprimer une personne supprime
aussi ses événements et ceux de ses unions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 22:20:30 +02:00
IliesAllaliandClaude Opus 5.5 e24c8c86d6 Événements de vie : table, migration, import GEDCOM
Nouvelle table life_events (baptême, résidence, métiers, études, service
militaire, inhumation, divorce, événements libres…) avec date, précision,
lieu, description, notes et sources. Personne : précision et borne des
dates de naissance et de décès, lieu de décès, surnom. Union : lieu et
précision du mariage. Naissance, décès et mariage gardent leur date et leur
lieu sur la personne ou l'union ; leur ligne d'événement ne porte que les
sources et les notes. Migration additive.

L'import lit tous ces événements (balises de la norme, variantes Gramps,
Heredis, RootsMagic), les adresses complètes, et les adoptions déclarées
par PEDI. Une personne ou une union déjà présente ne reçoit rien en double.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 22:16:45 +02:00
IliesAllaliandClaude Opus 5.5 dd738c483a Import GEDCOM : vraies dates, toutes les notes
Dates : « vers », « avant », « après », « entre … et … », dates juliennes,
calendrier républicain converti en grégorien, doubles années (1700/01).
« BET 1794 AND 1796 » ou « @#DFRENCH R@ 18 BRUM 8 » étaient perdues, « ABT
1900 » devient au moins 1900. La précision est déjà lue pour la suite.

Notes : notes partagées (« 1 NOTE @N1@ »), plusieurs notes, RTF nettoyé. Le
lecteur garde la valeur brute de chaque ligne : une note coupée en CONC se
recolle avec ses espaces (« pendant trente-cinq ans », plus « pendanttrente »).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 22:12:16 +02:00
dependabot[bot] bd8ba8ffaa Bump the backend-minor-patch group across 1 directory with 5 updates
Bumps the backend-minor-patch group with 5 updates in the /backend directory:

| Package | From | To |
| --- | --- | --- |
| [dotenv](https://github.com/motdotla/dotenv) | `18.0.6` | `18.0.7` |
| [fastify](https://github.com/fastify/fastify) | `5.12.5` | `5.12.7` |
| [zod](https://github.com/colinhacks/zod) | `4.6.5` | `4.6.7` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `24.19.1` | `24.19.2` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `5.0.3` | `5.0.4` |



Updates `dotenv` from 18.0.6 to 18.0.7
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v18.0.6...v18.0.7)

Updates `fastify` from 5.12.5 to 5.12.7
- [Release notes](https://github.com/fastify/fastify/releases)
- [Commits](https://github.com/fastify/fastify/compare/v5.12.5...v5.12.7)

Updates `zod` from 4.6.5 to 4.6.7
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](https://github.com/colinhacks/zod/compare/v4.6.5...v4.6.7)

Updates `@types/node` from 24.19.1 to 24.19.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `vitest` from 5.0.3 to 5.0.4
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.4/packages/vitest)

---
updated-dependencies:
- dependency-name: dotenv
  dependency-version: 18.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: backend-minor-patch
- dependency-name: fastify
  dependency-version: 5.12.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: backend-minor-patch
- dependency-name: zod
  dependency-version: 4.6.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: backend-minor-patch
- dependency-name: "@types/node"
  dependency-version: 24.19.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: backend-minor-patch
- dependency-name: vitest
  dependency-version: 5.0.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: backend-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-16 18:32:50 +00:00
IliesAllaliandClaude Opus 5.5 bca0543803 Import GEDCOM : lieu lisible, sans colonnes vides ni codes
Heredis remplit toutes les colonnes de son format de lieu, même vides, avec
le code INSEE (« La Roche-sur-Yon,85191,Vendée,Pays de la Loire,France, »).
Le lieu de naissance importé garde les noms seulement, séparés par « , »,
sans case vide, code INSEE ou postal, ni répétition. Un lieu déjà propre
ne change pas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:20:17 +02:00
IliesAllaliandClaude Opus 5.5 897ada2665 Import GEDCOM : tous les fichiers cités deviennent des souvenirs
En plus du portrait, l'import renvoie mediaRefs : les fichiers cités pour
chaque personne créée, où qu'ils soient accrochés (sous la personne, un
événement, une source citée, la fiche de la source, ou la famille pour les
actes de mariage), avec leur titre et leur source. Comme Gramps : adresses
web écartées, un fichier cité deux fois gardé une fois. Particularités
gérées : titre dans la note (Heredis, RTF compris), _PHOTO pour le portrait
(Family Tree Maker), chemins file:// (GEDCOM 7). Pour #59.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:55:56 +02:00
IliesAllali 12ccb520f5 Merge remote-tracking branch 'origin/main' into pr60-fix
# Conflicts:
#	frontend/src/components/PersonCard.jsx
#	frontend/src/i18n/en/fiche.js
2026-10-16 19:27:11 +02:00
IliesAllaliandClaude Opus 5.5 8556d32bce API : l'ordre d'une fratrie s'applique aux deux liens de l'union
L'arbre ne montre qu'un lien par enfant et par union ; le lien vers l'autre
parent de la même union reçoit le même ordre, pour que les deux restent
d'accord.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:08:05 +02:00
IliesAllaliandClaude Opus 5.5 588ac0c4e9 API : un nouvel enfant se place après ses frères et soeurs
Sans ordre fourni, un lien parent-enfant créé (route, contribution, import
GEDCOM) prend l'ordre suivant celui de la fratrie, pour qu'un enfant ajouté
après un réordonnancement ne passe pas devant les autres.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:53:23 +02:00
IliesAllaliandClaude Opus 5.5 1caa090efd API : réordonner une fratrie en une transaction
PUT /trees/:id/links/order réécrit le displayOrder des liens parent-enfant
d'une fratrie, dans l'ordre reçu. Administrateurs seulement ; chaque lien
doit appartenir à l'arbre et à son enfant, et les enfants partager au moins
un parent. Journalisé (children_reordered).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:51:37 +02:00
IliesAllaliandClaude Opus 5.5 8574dfed9e Retour au placement automatique : abandon du placement libre
Le mainteneur préfère un réordonnancement des frères et soeurs au placement
libre (coordonnées enregistrées). Ce commit annule le glisser libre, ses
corrections, la migration des coordonnées et le bouton de remise à zéro ;
le réordonnancement arrive dans les commits suivants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:46:28 +02:00
IliesAllaliandClaude Opus 5.5 d93710a00d Tests Immich : la suppression d'une personne efface aussi son lien Immich
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:16:16 +02:00
IliesAllaliandClaude Opus 5.5 7f159d5111 Immich : route admin pour lire le lien d'une fiche
Le sélecteur doit marquer la personne Immich déjà associée. L'identifiant ne
figure pas dans le graphe public : GET /trees/:id/immich/links/:personId le
renvoie aux seuls administrateurs de l'arbre.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:13:26 +02:00
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 d17cee20df feat(arbre): rétablir la disposition automatique
Route admin POST /trees/:id/layout/reset : remet layoutX/layoutY à null
pour toutes les personnes de l'arbre, dans une transaction, avec une
entrée de journal (tree_layout_reset). Documentée dans l'OpenAPI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:09:11 +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 420bda5e38 fix(arbre): bornes des positions et conflit de relecture
- Les coordonnées de disposition sont bornées à ±1 000 000 (PATCH personne,
  modification en session de contribution, OpenAPI).
- Un déplacement par le propriétaire ne met plus en conflit les
  contributions en attente sur la même personne : layoutX/layoutY sont
  exclus de la comparaison de conflit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:08:50 +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
py5932 43441f31e1 Ajout de la fonctionnalité drag and drop 2026-10-14 23:25:11 +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 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