212 lines
10 KiB
Markdown
212 lines
10 KiB
Markdown
|
|
# 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 :
|
||
|
|
|
||
|
|
```text
|
||
|
|
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 :
|
||
|
|
|
||
|
|
```text
|
||
|
|
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.
|