Commit Graph
58 Commits
Author SHA1 Message Date
IliesAllali b6eaa6da78 Dates : marques diacritiques retirées par \p{M}, lisible 2026-10-26 11:18:00 +01:00
IliesAllali 8875f2baf0 Dates : ordre et séparateur de la région du navigateur (fr-CA, en-US…), mois en lettres accepté (#152) 2026-10-26 11:08:22 +01:00
IliesAllali 3c4eef1c92 Dates : en anglais, l'ordre jour/mois suit la région du navigateur (#152) 2026-10-26 11:08:21 +01:00
IliesAllaliandClaude Opus 5.5 2f60df2ed9 Relecture depuis l'arbre : une proposition déjà relue le dit, et l'arbre se remet à jour
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:35:34 +01:00
IliesAllaliandClaude Opus 5.5 5ebfa8337d Ajouter un proche depuis la fiche : créer depuis la recherche d'un lien, frère ou sœur, « + » en lecture, panneau prérempli, alerte de doublon
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:20:27 +01:00
IliesAllaliandClaude Opus 5.5 6e42a1f12d Erreurs : la photo posée sur l'arbre dit pourquoi elle échoue ; « Mettre à jour l'arbre » garde dans le brouillon ce qui n'a pas été enregistré
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:16:02 +01:00
IliesAllaliandClaude Opus 5.5 0c74adb012 Fantômes : propositions en attente, brouillon et envois de la famille dessinés sur l'arbre ; acceptation ou refus depuis le fantôme
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:14:58 +01:00
IliesAllali 83e8282d94 Merge remote-tracking branch 'origin/main' into feat/cogestion-145
# Conflicts:
#	CHANGELOG.md
#	backend/src/app.ts
#	frontend/src/i18n/en/index.js
2026-10-25 18:30:28 +01:00
IliesAllaliandClaude Opus 5.5 7c9ea3c95e Chercher quelqu'un : créer la personne trouvée, rattachée à un proche
« Ajouter à l'arbre » s'ouvre sur Nouvelle personne : lien (parent, enfant, conjoint,
frère ou sœur) et proche dans l'arbre, par le même chemin qu'« Ajouter quelqu'un ».
Dates, lieux, sexe, source en note, à vérifier. « Déjà dans l'arbre » complète une fiche.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 18:15:03 +01:00
IliesAllaliandClaude Opus 5.5 d0ab96d634 Pastilles : emoji entier en initiale (arbre, compte, personne) ; fiche : message clair quand les droits ont été retirés
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:35:31 +01:00
IliesAllaliandClaude Opus 5.5 bff3f54b00 Chercher quelqu'un ailleurs : panneau à droite de l'arbre
Entrée « Quelqu'un ailleurs » dans le menu +. On tape un nom, une année et un lieu.
Liens préremplis vers Gallica, FranceArchives, Mémoire des hommes, Léonore, Geneanet,
Open Archives, WikiTree, FreeBMD et FamilySearch, ouverts par le navigateur.
Le serveur interroge les décès INSEE depuis 1970 (matchID) et WikiTree quand
SEARCH_SOURCES les nomme ; MATCHID_TOKEN au-delà d'une centaine de recherches.
Un résultat ajouté ne remplit que les champs vides, passe la personne à vérifier
et garde la source dans sa note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:33:41 +01:00
IliesAllaliandClaude Opus 5.5 07d69896ae Co-gestion (#145), écrans : onglet Gestion, page du lien d'invitation, Quitter pour le co-gestionnaire, avertissement à la suppression du compte, Immich caché
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 16:57:57 +01:00
IliesAllaliandClaude Opus 5.5 07e4fb11f9 1.2.0 : changelog, OIDC marqué expérimental, jamais relié à un compte à mot de passe
- OIDC : une identité n'est plus reliée automatiquement à un compte existant qui a un mot de passe.
  L'inscription ne vérifie pas l'adresse, un tiers aurait pu créer ce compte avec l'email de la victime et lire
  ce qu'elle y met ensuite. Refus avec oidc_email_taken et un message clair (FR, EN). Trouvé par la relecture
  de sécurité avant la release.
- Tests OIDC : chaque connexion simulée a sa propre adresse (limite de 20 appels par minute et par adresse).
- CHANGELOG 1.2.0, OIDC marqué expérimental dans les deux README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:12:42 +02:00
IliesAllali 441693bf43 Merge pull request #118 from IliesAllali/feat/sexe-et-liens
Sexe d'une personne et liens de parenté genrés (#114)
2026-10-20 15:47:57 +02:00
IliesAllaliandClaude Opus 5.5 9ba1aee96f Merge origin/main dans feat/sexe-et-liens, trois choix à bascule, « Décédé(e), date inconnue » sur une ligne (#114)
- Fusion de main : graphAdapter.js supprimé par #119 ; le sexe est relu par
  normalizeSex au chargement du graphe (data/mockData.js), en plus du serveur
  qui renvoie déjà male/female/other/null. Mention retirée de i18n/en/app.js.
- Sexe : trois boutons à bascule (Femme, Homme, Autre, aria-pressed). Rien de
  choisi = non précisé (null), la valeur par défaut ; un second clic sur le
  choix actif y revient. La relecture affiche « Non précisé » pour une valeur
  vide (sexLabel).
- « Ajouter quelqu'un » : « Décédé(e), date inconnue » sort de la colonne Décès
  et tient sur une ligne, comme la case du prénom (règle CSS commune).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:45:26 +02:00
IliesAllaliandClaude Opus 5.5 65900a4372 feat(comptes): connexion par un fournisseur OIDC (#115)
OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET et OIDC_REDIRECT_URI
ajoutent « Se connecter avec … » à l'écran de connexion. Tout le protocole
passe par openid-client 6 : découverte, PKCE S256, state et nonce, échange
du code, vérification de l'ID token (signature, émetteur, audience, dates).
State, nonce et vérificateur PKCE vivent dans un cookie signé, httpOnly,
SameSite=Lax, qui lie le retour au navigateur qui a commencé la connexion.

Le compte est trouvé par (émetteur, sub), sinon relié par email vérifié,
sinon créé sans mot de passe si ALLOW_REGISTRATION le permet (instance
vide comprise). Retour vers l'app par un jeton de passage de 60 s, à usage
unique, dans le fragment, échangé contre une session.

PASSWORD_LOGIN=false retire les mots de passe Parenthèse. Un compte sans
mot de passe se supprime en retapant son email, dans les 15 minutes qui
suivent une connexion. Code OIDC masqué dans les journaux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:26:01 +02:00
IliesAllaliandClaude Opus 5.5 7a43fe4aaf feat(personnes): quatrième choix « Autre » (SEX X), case du prénom inconnu sur une ligne (#114)
- Sexe : Femme, Homme, Autre, Non précisé. Autre est enregistré « other »,
  refusé en 400 comme toute valeur inconnue, et prend les formes neutres ou
  doubles pour nommer un lien.
- GEDCOM : import SEX X (GEDCOM 7) → other, SEX U → non précisé ; export
  other → SEX X, non précisé sans ligne SEX. Aller-retour testé.
- « Ajouter quelqu'un » : « Je ne connais pas son prénom » sort de la colonne
  Prénom et tient sur une ligne (sous les deux champs sur ordinateur, sous
  Prénom sur téléphone) ; les quatre choix du sexe tiennent sur une ligne.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:13:12 +02:00
IliesAllaliandClaude Opus 5.5 34454abc18 Ménage : retirer onze modules de l'interface que plus rien n'importe
AddPersonButton, DropTrashZone, CreateMyTreeButton, EditModeOverlay.jsx (App importe EditSessionBar sous ce
nom, sa feuille de style reste), InitialTreeWizard, InlinePersonForm, ProximityFeedback, useAddPersonDrag,
graphAdapter et graphDataHelpers, avec leurs feuilles de style. Aucun import, test compris ; lint, 253 tests et
build verts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 14:27:49 +02:00
IliesAllaliandClaude Opus 5.5 eaecac8fa5 feat(personnes): saisir le sexe et nommer les liens de parenté en conséquence (#114)
- Champ Sexe (femme, homme, non précisé) dans la fiche en modification, à l'ajout
  d'une personne et dans une proposition de la famille ; relu « Sexe » dans les
  propositions à relire.
- Valeurs ramenées à male / female / null à l'écriture et à la lecture (anciennes
  valeurs M/F relues sans migration), valeur inconnue refusée (400). Export GEDCOM
  inchangé dans sa forme.
- Lien au survol genré quand le sexe est connu (Père, Tante, Cousine germaine,
  Belle-mère…), forme double sinon. Nommage déplacé dans utils/kinship : une
  fonction par langue reçoit le chemin complet (pas, personnes, sexe, année de
  naissance), pour brancher d'autres langues.
- Anglais : beau-parent distingué de parent par alliance selon l'ordre du chemin
  (Stepmother / Mother-in-law).
- Propositions à relire : le nom de la personne modifiée vient de l'avant lu en
  base quand la modification ne porte que le champ changé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 14:25:45 +02:00
IliesAllaliandClaude Opus 5.5 1b2d8ed6e2 feat(comptes): ALLOW_REGISTRATION ferme la création de compte (#113)
À false, POST /auth/register répond 403 registration_closed et l'app ne
propose plus de créer un compte (accueil, connexion, porte d'un arbre
partagé, menu du visiteur). Les comptes existants se connectent et créent
leurs arbres, le partage par lien et mot de passe ne change pas.

Une instance sans aucun compte accepte quand même le premier, sous un
verrou de transaction PostgreSQL (deux inscriptions simultanées n'en
créent qu'un). GET /auth/options expose l'état à l'écran d'accueil.

Défaut true : rien ne change pour les instances existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 14:12:18 +02:00
IliesAllali a88d06c513 Merge remote-tracking branch 'origin/main' into feat/fiche-glisser-fermer 2026-10-19 12:44:06 +02:00
IliesAllaliandClaude Opus 5.5 92c1f25efb feat(recadrage): choisir la forme du cadre (rond, carre, polaroid, vertical, horizontal)
Le cadre suivait le format de la photo : une photo couchee donnait toujours un
cadre couche. Le recadrage propose maintenant les cinq formes de l'arbre, en
dessin, et la forme choisie est gardee avec le cadrage (avatarCrop.shape, sans
migration). L'arbre la respecte ; sans choix, rien ne change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:28:39 +02:00
IliesAllaliandClaude Haiku 5.5 6faaefebee Fiche : fermer en glissant vers le bas sur téléphone
La feuille de la fiche (PersonCard) se ferme en glissant sa poignée ou son en-tête vers le bas, comme le menu de la barre. Le geste est factorisé : logique pure dans utils/sheetDrag.js, hook dans hooks/useSheetDrag.js, utilisé aussi par NavMenu (poignée, seuil de 70 px inchangé).

- Le geste part seulement de la poignée et de l'en-tête. Jamais d'un champ de saisie, d'un libellé ni pendant une sélection de texte. Le contenu des onglets défile comme avant.
- La feuille suit le doigt (transform), ne monte jamais au-delà de sa position de repos.
- Fermeture au-delà d'un tiers de la hauteur, ou sur un lâcher rapide vers le bas. Sinon retour court.
- La fermeture passe par le même chemin que la croix (enregistrement automatique compris). Si l'enregistrement est refusé, la fiche revient et affiche son erreur.
- Mode feuille seulement (PHONE_QUERY et largeur de la feuille CSS). Sur ordinateur, rien ne change.
- prefers-reduced-motion respecté.

Tests : logique du geste (zones, direction, seuil, vitesse) en vitest. Recette Playwright iPhone 13 émulé, gestes tactiles CDP : fermeture par la poignée, retour après un petit glisser, lâcher rapide, défilement du contenu sans fermer, pas de geste depuis un champ, enregistrement puis fermeture, ordinateur inchangé, croix.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-19 11:06:35 +02:00
IliesAllali 86e1d959a7 Merge pull request #101 from IliesAllali/feat/enregistrement-auto
Fiche : enregistrement automatique en quittant
2026-10-19 10:23:06 +02:00
IliesAllaliandClaude Opus 5.5 68ac2fa8f8 fix(vie): une union sans date a sa place logique, plus apres le deces du conjoint
Un mariage sans date tombait tout en bas de l'onglet Vie, apres le deces du
conjoint, ce qui ne voulait rien dire. Il se place maintenant juste avant le
premier enfant du couple, sinon avant la fin de l'union ou le deces du
conjoint. Aucune annee n'est inventee : colonne vide et « date inconnue ».
Seul ce qui n'a aucun repere reste en bas, et tout moment sans date le dit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:22:07 +02:00
IliesAllaliandClaude Haiku 5.5 a25f263451 fiche: enregistrer automatiquement en quittant la fiche
Les modifications en cours d'une fiche ne sont plus perdues quand on
change de personne, ferme la fiche, sort du mode modification, ouvre
un souvenir, ajoute une personne ou envoie les contributions.

- La fiche enregistre par le même chemin que « Enregistrer » (onSave),
  pour la personne quittée. Un échec ou une validation la garde ouverte
  avec le message d'erreur.
- Invité en contribution : les changements vont dans le brouillon, puis
  partent avec « Envoyer ».
- Un petit message confirme l'enregistrement. Rien n'est enregistré
  quand rien n'a changé, ni en démo.
- Un second enregistrement pendant l'envoi reçoit la même promesse
  (utils/saveOnLeave.js), sans double appel.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-19 01:08:26 +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 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 f8d4b4113d Mobile : parents séparés en pointillés, barre d'édition allégée, dates au clavier numérique (#82)
- Deux parents d'un même enfant sans couple enregistré sont reliés en pointillés au lieu
  d'avoir chacun un « Inconnu » (couple propre au dessin, rien en base) ; le tri de la
  fratrie le reconnaît.
- Barre d'édition mobile : X, « Ajouter » et « Plus » (dessin, texte, sticker, photo).
  Les outils s'ouvrent depuis « Plus » avec un retour, la corbeille n'apparaît que s'il y a
  quelque chose à effacer, l'outil actif en aplat. La barre ne passe plus sous le zoom.
- Bandeau d'édition : sur téléphone, seul le bouton reste, le texte se coupait.
- Dates : au-delà de 4 chiffres les barres se posent seules (12031950 → 12/03/1950), le
  message n'apparaît qu'en quittant le champ.
- Ajouter une personne : plus d'erreur « prénom » en quittant le champ vide, le bouton
  reste actif et le dit à l'appui.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 14:08:07 +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
IliesAllali 991a9625a2 Merge pull request #79 from IliesAllali/import-zip
Import d'un zip : le GEDCOM et ses photos en une fois
2026-10-17 12:54:50 +02:00
IliesAllaliandClaude Opus 5.5 5447965243 feat(import): importer un zip qui contient le GEDCOM et ses photos
Le zip est lu dans le navigateur, sans bibliotheque (table des matieres puis
DecompressionStream, fichier par fichier) : le .ged le plus haut s'importe, GEDZIP
compris, et les photos et actes passent directement a l'etape des visages, rapproches
comme un dossier et decompresses seulement a l'envoi. Messages clairs pour un zip sans
.ged, protege par mot de passe ou trop gros. Corrige aussi « citait 1 autres fichiers ».

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:40:32 +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 557956fedd feat(fiche): onglet Vie, la frise de vie d'une personne
Naissance, unions et deces en grands reperes (direction A2 choisie par Patch le 16/10),
evenements importes plus petits, famille proche tiree de l'arbre en retrait, sources
repliees. Evenements charges a l'ouverture de l'onglet via GET /persons/:id/life,
donnees propres a la demo pour Robert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:10:34 +02:00
IliesAllaliandClaude Opus 5.5 2d35bddf27 Import GEDCOM : le fichier est lu avec son vrai encodage
Le navigateur lisait tout en UTF-8. Les fichiers de Heredis PC (ANSI,
Windows-1252), des anciens logiciels (ANSEL) ou de Heredis Mac (MACINTOSH)
arrivaient avec des accents cassés (« é »). L'encodage est maintenant
détecté : marque d'octets, UTF-8 valide, puis la ligne « 1 CHAR », sinon
Windows-1252. Décodeur ANSEL inclus (diacritiques placés avant la lettre).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 22:08:10 +02:00
IliesAllaliandClaude Opus 5.5 63d997b8cf Fiche : lieu lisible à l'affichage pour les arbres déjà importés
Les arbres importés de Heredis avant le nettoyage à l'import gardent des
lieux bruts (« Ville,code INSEE,département,… »). La fiche les affiche avec
la même règle qu'à l'import, sans toucher à la valeur enregistrée ni au
champ d'édition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:29:58 +02:00
IliesAllaliandClaude Opus 5.5 2fccf287b3 Premières photos : compter chaque souvenir par son chemin d'origine
Les correspondances gardent le chemin cité par le logiciel (sourcePath) :
plusieurs fichiers d'une même personne ne se confondent plus, le décompte
des fichiers ajoutés et restants est juste, et le pied du panneau parle de
fichiers quand des documents ont été ajoutés.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:06:03 +02:00
IliesAllaliandClaude Opus 5.5 3097768af5 Premières photos : les autres fichiers cités deviennent des souvenirs
À l'étape du dossier de photos, les fichiers cités par le logiciel en plus
des portraits (actes, registres, photos de famille) sont retrouvés dans le
même dossier et ajoutés aux souvenirs de chaque personne, avec le titre et
la source venus du GEDCOM. Un seul bouton « Tout ajouter » ; les fichiers
restants sont gardés pour rouvrir l'étape depuis les paramètres. Pour #59.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:00:40 +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 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
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
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 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>
2026-10-01 12:19:41 +02:00
IliesAllali bd4f5856ad Intègre securite/front : polices servies par le site, PostHog sans adresse d'arbre, vie privée à jour 2026-09-30 18:09:30 +02:00
IliesAllaliandClaude Opus 5.5 468204c9d3 Images de l'arbre : jeton médias à la place de la session du compte
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>
2026-09-30 18:03:04 +02:00