gmao/docs/ui-audit/DOCUMENT_CENTER_PROPOSAL_V2.md
root 8e19476bb3
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
docs(architecture): concevoir centre documentaire v2 et planning interne
2026-08-22 22:02:37 +00:00

10 KiB

Centre documentaire global — proposition V2

Statut : étude et spécification uniquement. Aucun code applicatif, modèle, route, migration, permission ou menu n'est créé par ce document.

A. Décisions de périmètre

La V1 agrégera en lecture les documents déjà attachés à trois sources :

  • interventions (InterventionDocument) ;
  • équipements (EquipmentDocument) ;
  • produits d'entretien (ProductDocument).

Il n'y aura ni table Document commune, ni copie physique, ni upload ou suppression depuis /documents/. Contract.contract_file, la prévention et les données personnelles du personnel sont explicitement hors V1. Outlook, ENT et les autres intégrations restent hors périmètre.

B. Cartographie réelle actuelle

Source Table / modèle Parent obligatoire Métadonnées actuelles Routes observées
Intervention intervention_documents / InterventionDocument (app_new/core/models/maintenance.py) intervention_id filename, filepath, description, uploaded_at, uploaded_by_id /documents/upload/intervention/<id>, téléchargement, édition de description, suppression
Équipement equipment_documents / EquipmentDocument (app_new/core/models/equipment.py) equipment_id filename, filepath, description, uploaded_at, uploaded_by_id famille /documents/... et famille /equipments/<id>/documents/...
Produit cleaning_product_documents / ProductDocument (app_new/core/models/cleaning.py) commercial_product_id document_type, title, filename, filepath, version, published_at, uploaded_at, uploaded_by_id, is_current GET /cleaning/documents ; upload/téléchargement produit à compléter dans une évolution séparée
Contrat contracts.contract_file aucun objet documentaire chemin texte unique non indexé par le centre V1

/documents/ répond actuellement 404 : cette absence est le bug UI-011, mais elle ne justifie pas la création d'un stockage parallèle.

C. Stockage physique et risques

Config.UPLOAD_FOLDER pointe vers app_new/uploads, monté par Docker dans le volume gmao_uploads (/app/app_new/uploads). La limite globale est de 50 MiB. Les conventions historiques sont uploads/interventions/<uuid>_<nom>, uploads/equipments/<uuid>_<nom> et uploads/documents/<equipment_id>/<uuid>.<extension>.

Les extensions autorisées sont contrôlées et secure_filename est utilisé, mais le MIME réel n'est pas inspecté, le nom original n'est pas toujours séparé du nom interne et taille/MIME/hash ne sont pas uniformément conservés. Les téléchargements passent par send_file et ne sont pas exposés comme répertoire statique ; il faut néanmoins vérifier existence, racine autorisée, parent et permission à chaque téléchargement. Les écritures interrompues peuvent laisser un fichier orphelin ou une ligne sans fichier. Une future maintenance devra produire un rapport d'orphelins sans supprimer automatiquement les données.

D. Dette de routes équipement

Deux blueprints écrivent des équipements dans deux chemins et avec deux contrats de métadonnées. La route historique tente notamment de renseigner file_type et file_size, champs absents de EquipmentDocument. Avant le centre, il faut choisir un adaptateur de service de téléchargement commun, conserver les anciens chemins lisibles, puis déprécier une famille de routes sans casser les URL existantes. Cette convergence est une condition de qualité, mais ne doit pas entraîner de déplacement physique automatique en V1.

E. Architecture recommandée : adaptateurs de lecture

Chaque source implémentera conceptuellement un adaptateur qui transforme une ligne spécialisée en un résultat commun en mémoire :

DocumentResult
  source_kind       intervention | equipment | product
  document_id       identifiant de la ligne source
  parent_id         identifiant de l'objet métier
  display_name      nom lisible
  document_type     type métier affichable
  description       description éventuelle
  date              uploaded_at ou published_at
  context_label     Intervention…, Équipement…, Produit…
  context_url       URL de détail autorisée
  location_summary  chemin calculé ou « 3 emplacements »
  download_target   action contrôlée par l'adaptateur

La vue globale ne devient jamais propriétaire du fichier. La recherche peut utiliser trois sélections alignées et UNION ALL, ou trois requêtes paginées fusionnées dans un premier incrément. Les relations parent restent la source de vérité.

Alternative étudiée : index commun

Une table d'index serait utile pour 10 000+ documents, tags, OCR ou recherche plein texte. Elle ajouterait toutefois un backfill, des synchronisations et le risque d'index périmé. Elle pourrait être introduite plus tard comme index réparable (jamais comme propriétaire physique), sans être créée pour la V1.

F. Types métier et migration future

Les produits conservent fds et fiche_technique ainsi que les valeurs déjà présentes. Les interventions et équipements recevront, lors d'une migration future, un champ document_type court et indexé avec les valeurs :

  • notice — Notice / manuel ;
  • facture — Facture ;
  • devis — Devis ;
  • rapport — Rapport / compte rendu ;
  • certificat — Certificat / contrôle ;
  • photo — Photo ;
  • plan — Plan ;
  • autre — Autre.

La migration ajoutera une colonne nullable ou avec défaut autre, remplira les documents historiques avec autre, puis pourra rendre le champ non nul après vérification. Aucun fichier ne sera réécrit. Les adaptateurs afficheront Autre pour une valeur absente ou inconnue.

G. Localisations multiples

La localisation est calculée à partir des relations : équipement → salle → zone → bâtiment ; produit → lots/stock → emplacements. Si un produit est dans plusieurs emplacements, le résultat affichera par exemple 3 emplacements et ouvrira le détail des chemins individuels. Aucun chemin bâtiment/zone/salle ne sera dénormalisé dans une future table documentaire.

H. RBAC

La permission nouvelle proposée est documents.view. Aucun documents.manage n'est créé. Un résultat est visible uniquement si :

documents.view ET permission de lecture de la source

Donc intervention.view, patrimoine.view ou stock.view s'ajoutent selon la source. Le téléchargement réutilise la même décision en V1 : pas de documents.download séparé, sauf besoin de séparation démontré. Édition et suppression restent dans le module source et ses permissions (manage). Les liens vers un parent sont masqués si l'utilisateur ne peut pas le lire.

I. Interface proposée

/documents/ afficherait :

  1. titre Centre documentaire et phrase d'aide ;
  2. recherche (nom, titre, description, parent, référence) ;
  3. filtres principaux : type, source, période ;
  4. filtres avancés : bâtiment, zone, salle, équipement, produit ;
  5. liste paginée : document, type, lié à, localisation, date, actions.

Les actions sont Consulter/Télécharger et Ouvrir le contexte. Aucun upload global ni suppression globale. Un état vide expliquera que les fichiers s'ajoutent depuis les fiches intervention, équipement ou produit et proposera des liens de création autorisés.

J. Vue FDS

/documents/fds sera une vue filtrée, non un second stockage : produit, référence commerciale, fabricant/fournisseur, version, date, statut courant, emplacements et téléchargement. Une future fonction « Classeur FDS » pourra exporter une liste/PDF, mais n'appartient pas au MVP.

K. Recherche, filtres et performance

SQL classique suffit pour la V1 : recherche préfixe/contient sur les champs déjà disponibles, filtrage par source/type/date et pagination obligatoire. À 100 ou 1 000 documents, les adaptateurs sont suffisants. À 10 000, mesurer les UNION ALL, ajouter index sur parent/date/type et envisager un index commun. Les jointures de localisation seront paginées et chargées de façon prévisible, sans N+1.

L. Sécurité et intégrité

Avant implémentation, spécifier : validation extension + MIME, limite de taille, Content-Disposition sûr, racine de chemin canonique, refus d'IDOR, contrôle parent/RBAC avant téléchargement, absence d'exécution de fichiers, et journalisation des erreurs. Prévoir des tests fichier manquant, ligne orpheline, chemin hors racine, document supprimé et permission source absente.

M. Compatibilité historique

Les trois tables et leurs fichiers restent intacts. Les noms ou types absents sont adaptés à la lecture (Autre, nom de fichier sécurisé). contract_file reste exclu et documenté comme dette, sans conversion silencieuse.

N. Tests avant développement

  • intervention, équipement et produit visibles ;
  • recherche, filtres, pagination et FDS ;
  • plusieurs localisations produit ;
  • lien vers contexte avec permission ;
  • absence d'IDOR et téléchargement contrôlé ;
  • utilisateur sans documents.view ;
  • utilisateur sans permission source ;
  • fichier manquant/orphelin ;
  • suppression depuis le module source retirant le résultat global ;
  • non-régression des routes historiques.

O. MVP et évolutions

V1 obligatoire : agrégation des trois sources, /documents/, recherche, types/source/période, pagination, localisation calculée, téléchargement sécurisé, lien de contexte, RBAC documents.view, vue /documents/fds.

Plus tard : index SQL commun, tags, OCR, plein texte PDF, versionnage, prévisualisation, classeur FDS, contrats, prévention et documents généraux. L'ajout d'un document reste toujours contextuel dans la V1.

P. Questions à valider avant développement

  1. Confirmer les libellés et la liste des types intervention/équipement.
  2. Confirmer que documents.view doit être accordée en plus des permissions sources.
  3. Confirmer qu'aucun documents.download distinct n'est requis en V1.
  4. Choisir l'ordre et le style de consolidation des deux familles de routes équipement.
  5. Définir une politique de rétention pour fichiers orphelins.
  6. Décider plus tard si contract_file mérite une migration dédiée.