Commit Graph
12 Commits
Author SHA1 Message Date
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 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 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 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 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 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