docs(audit): proposer le centre documentaire global
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
This commit is contained in:
parent
c58bcbd5fb
commit
8e6a67915c
2 changed files with 502 additions and 0 deletions
493
docs/ui-audit/DOCUMENT_CENTER_PROPOSAL.md
Normal file
493
docs/ui-audit/DOCUMENT_CENTER_PROPOSAL.md
Normal file
|
|
@ -0,0 +1,493 @@
|
||||||
|
# Proposition d'architecture — Centre documentaire global
|
||||||
|
|
||||||
|
État : étude uniquement, aucune route, table, migration ou modification du
|
||||||
|
code n'est créée par cette proposition.
|
||||||
|
|
||||||
|
## A. État documentaire actuel
|
||||||
|
|
||||||
|
Le dépôt ne possède pas de modèle `Document` générique ni de table commune.
|
||||||
|
Les documents sont spécialisés par module :
|
||||||
|
|
||||||
|
| Modèle | Table | Parent métier | Métadonnées | État UI / routes |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `InterventionDocument` | `intervention_documents` | `Intervention` obligatoire | `filename`, `filepath`, `description`, `uploaded_at`, `uploaded_by_id` | upload, édition de description, téléchargement et suppression depuis la fiche intervention |
|
||||||
|
| `EquipmentDocument` | `equipment_documents` | `Equipment` obligatoire | `filename`, `filepath`, `description`, `uploaded_at`, `uploaded_by_id` | deux familles de routes et upload depuis la fiche équipement |
|
||||||
|
| `ProductDocument` | `cleaning_product_documents` | `CommercialProduct` obligatoire | `document_type`, `title`, `filename`, `filepath`, `version`, `published_at`, `uploaded_at`, `uploaded_by_id`, `is_current` | liste FDS/fiches techniques ; aucun upload ou téléchargement produit clairement exposé dans les routes actuelles |
|
||||||
|
|
||||||
|
Le modèle `Contract` possède en plus un champ historique `contract_file` qui
|
||||||
|
est un simple chemin de fichier, sans ligne documentaire ni métadonnées
|
||||||
|
associées. Aucun modèle documentaire dédié aux entreprises, à la prévention
|
||||||
|
ou aux contrats n'a été trouvé. Les pièces jointes Outlook/ENT sont un autre
|
||||||
|
système d'intégration et restent hors périmètre de ce centre documentaire.
|
||||||
|
|
||||||
|
Le centre devra donc fonctionner par adaptateurs de sources et non par
|
||||||
|
copie des objets existants.
|
||||||
|
|
||||||
|
## B. Modèles et relations existants
|
||||||
|
|
||||||
|
### Interventions
|
||||||
|
|
||||||
|
`Intervention.documents` est une relation vers
|
||||||
|
`InterventionDocument`. Le document pointe vers l'intervention par
|
||||||
|
`intervention_id`; l'uploader est facultatif (`users.id`, `SET NULL` côté
|
||||||
|
modèle logique). Il n'existe pas de type métier normalisé pour le document.
|
||||||
|
|
||||||
|
### Équipements
|
||||||
|
|
||||||
|
`Equipment.documents` est une relation vers `EquipmentDocument`. Le parent
|
||||||
|
est obligatoire. La localisation doit être calculée via l'équipement,
|
||||||
|
éventuellement son parent et `effective_room`, puis `Room → Zone → Building`.
|
||||||
|
|
||||||
|
### Produits d'entretien
|
||||||
|
|
||||||
|
`CommercialProduct.documents` est une relation vers `ProductDocument`.
|
||||||
|
Le produit commercial remonte vers le produit générique, le fabricant et le
|
||||||
|
fournisseur. Une localisation éventuelle doit être calculée via les lots,
|
||||||
|
balances et `StockLocation → Building/Zone/Room`; elle ne doit pas être
|
||||||
|
recopiée dans le document.
|
||||||
|
|
||||||
|
### Ce qui n'est pas encore un document global
|
||||||
|
|
||||||
|
- `Contract.contract_file` est un chemin historique, pas un document
|
||||||
|
normalisé.
|
||||||
|
- Outlook/ENT ont leurs propres pièces jointes distantes et ne doivent pas
|
||||||
|
être aspirés dans le centre pendant cette phase.
|
||||||
|
- Les photos, plans, certificats ou documents de prévention n'ont pas de
|
||||||
|
modèle local identifié dans le dépôt.
|
||||||
|
|
||||||
|
## C. Stockage actuel
|
||||||
|
|
||||||
|
La configuration définit `UPLOAD_FOLDER` sous
|
||||||
|
`app_new/uploads`. Docker monte ce répertoire dans le volume
|
||||||
|
`gmao_uploads` (`/app/app_new/uploads`). La limite globale est de 50 MiB.
|
||||||
|
|
||||||
|
Les routes historiques utilisent actuellement plusieurs conventions :
|
||||||
|
|
||||||
|
- intervention : `uploads/interventions/<uuid>_<secure_filename>` ;
|
||||||
|
- équipement, blueprint `documents` : `uploads/equipments/<uuid>_<secure_filename>` ;
|
||||||
|
- équipement, blueprint `equipments_documents` :
|
||||||
|
`uploads/documents/<equipment_id>/<uuid>.<extension>` ;
|
||||||
|
- produit : le modèle stocke un chemin, mais aucune route locale d'upload
|
||||||
|
produit n'a été identifiée.
|
||||||
|
|
||||||
|
Le fichier physique est donc unique aujourd'hui, mais l'organisation n'est
|
||||||
|
pas homogène. Les noms sont générés avec UUID ; `secure_filename` réduit le
|
||||||
|
risque de traversal. Les extensions sont allowlistées (`pdf`, images,
|
||||||
|
documents Office), mais le MIME réel n'est pas inspecté. Les modèles ne
|
||||||
|
stockent généralement ni MIME, ni taille, ni hash, et le nom original n'est
|
||||||
|
pas distingué proprement du nom interne dans toutes les routes.
|
||||||
|
|
||||||
|
Le volume n'est pas servi comme répertoire statique public : les téléchargements
|
||||||
|
passent par `send_file`. Cependant, plusieurs téléchargements font confiance
|
||||||
|
directement au `filepath` DB et certaines routes ne vérifient pas l'existence
|
||||||
|
du fichier avant `send_file`.
|
||||||
|
|
||||||
|
État observé sur la copie locale au moment de l'étude : 2 lignes
|
||||||
|
`intervention_documents`, 0 ligne `equipment_documents` et 0 ligne
|
||||||
|
`cleaning_product_documents`. Les deux fichiers d'intervention présents dans
|
||||||
|
le volume correspondent aux deux lignes DB. Ce constat est un instantané, pas
|
||||||
|
une hypothèse de conception.
|
||||||
|
|
||||||
|
## D. Routes actuelles
|
||||||
|
|
||||||
|
### Blueprint `documents` (`/documents`)
|
||||||
|
|
||||||
|
- `POST /documents/upload/intervention/<id>`
|
||||||
|
- `POST /documents/upload/equipment/<id>`
|
||||||
|
- `POST /documents/intervention/delete/<doc_id>`
|
||||||
|
- `POST /documents/intervention/<doc_id>/edit`
|
||||||
|
- `GET /documents/intervention/download/<doc_id>`
|
||||||
|
- `POST /documents/equipment/delete/<doc_id>`
|
||||||
|
- `GET /documents/equipment/download/<doc_id>`
|
||||||
|
|
||||||
|
Ces routes utilisent `login_required` et la garde globale d'autorisation,
|
||||||
|
qui déduit actuellement `intervention.view/manage` ou
|
||||||
|
`patrimoine.view/manage` du nom d'endpoint.
|
||||||
|
|
||||||
|
### Blueprint `equipments_documents` (préfixé `/equipments`)
|
||||||
|
|
||||||
|
- `POST /equipments/<id>/documents/upload`
|
||||||
|
- `GET /equipments/documents/<doc_id>/download`
|
||||||
|
- `POST /equipments/documents/<doc_id>/delete`
|
||||||
|
|
||||||
|
Il s'agit d'une seconde famille d'upload/téléchargement pour les équipements.
|
||||||
|
Elle utilise un autre répertoire et un autre format de nom. Cette duplication
|
||||||
|
de routes devra être résolue ou encapsulée avant d'exposer un index global.
|
||||||
|
|
||||||
|
### Produits
|
||||||
|
|
||||||
|
`GET /cleaning/documents` liste les `ProductDocument`, mais n'offre pas de
|
||||||
|
route globale, ni de téléchargement produit identifié dans le code inspecté.
|
||||||
|
`GET /documents/` n'est donc pas l'index attendu par UI-011 et répond 404.
|
||||||
|
|
||||||
|
## E. Problèmes actuels à traiter avant ou pendant le MVP
|
||||||
|
|
||||||
|
1. Trois schémas de documents et plusieurs conventions de chemin coexistent.
|
||||||
|
2. Le nom affiché/téléchargé n'est pas toujours le nom original (la route
|
||||||
|
intervention stocke notamment le nom UUID comme `filename`).
|
||||||
|
3. Une route d'upload équipement tente de renseigner `file_type` et
|
||||||
|
`file_size`, alors que ces colonnes ne sont pas déclarées sur
|
||||||
|
`EquipmentDocument` ; les deux chemins d'upload ne sont donc pas
|
||||||
|
équivalents et doivent être consolidés avant extension.
|
||||||
|
4. Les types métier sont riches pour les produits, mais absents pour les
|
||||||
|
interventions et équipements.
|
||||||
|
5. Le stockage de document produit est modélisé, mais son workflow d'upload/
|
||||||
|
download n'est pas complet.
|
||||||
|
6. `Contract.contract_file` n'est pas interrogeable comme un document.
|
||||||
|
7. Les routes de téléchargement doivent vérifier parent, permission et
|
||||||
|
fichier sous la racine autorisée afin d'éviter IDOR et chemins arbitraires.
|
||||||
|
8. Une erreur après écriture physique mais avant commit DB peut laisser un
|
||||||
|
fichier orphelin ; l'inverse peut laisser une ligne sans fichier.
|
||||||
|
9. La validation par extension seule ne suffit pas pour les exécutables
|
||||||
|
renommés et les fichiers malformés.
|
||||||
|
|
||||||
|
## F. Architecture recommandée
|
||||||
|
|
||||||
|
### Recommandation : option A pour la V1, avec adaptateurs de lecture
|
||||||
|
|
||||||
|
La V1 doit agréger les trois tables spécialisées sans créer une table de
|
||||||
|
stockage ou recopier les fichiers. Un service de lecture produira un
|
||||||
|
descripteur commun en mémoire, par exemple :
|
||||||
|
|
||||||
|
```text
|
||||||
|
DocumentResult
|
||||||
|
source_kind intervention | equipment | product
|
||||||
|
source_id identifiant de la ligne documentaire
|
||||||
|
parent_id identifiant de l'objet métier
|
||||||
|
display_name nom lisible
|
||||||
|
document_type type métier normalisé à l'affichage
|
||||||
|
description
|
||||||
|
uploaded_at / published_at
|
||||||
|
stored_path utilisé seulement côté téléchargement sécurisé
|
||||||
|
context_label Intervention #… / Équipement … / Produit …
|
||||||
|
context_url URL de détail autorisée
|
||||||
|
location calculée par relations métier
|
||||||
|
capabilities view / download / edit / delete
|
||||||
|
```
|
||||||
|
|
||||||
|
Chaque adaptateur sait lire sa table, construire le contexte, appliquer la
|
||||||
|
permission du module source et produire l'action de téléchargement vers la
|
||||||
|
ligne propriétaire. Le centre est ainsi un index de recherche logique, pas
|
||||||
|
un second propriétaire de fichier.
|
||||||
|
|
||||||
|
Pour une recherche SQL paginée, les adaptateurs peuvent exposer des sélections
|
||||||
|
alignées combinées par `UNION ALL` (ou trois requêtes paginées fusionnées pour
|
||||||
|
le premier incrément). Aucune modification de schéma n'est nécessaire pour
|
||||||
|
la V1.
|
||||||
|
|
||||||
|
### Pourquoi cette option
|
||||||
|
|
||||||
|
- aucune migration ni backfill destructif ;
|
||||||
|
- conservation immédiate des documents existants ;
|
||||||
|
- aucun fichier copié ;
|
||||||
|
- réutilisation des relations et permissions existantes ;
|
||||||
|
- retour arrière simple : retirer la vue globale ne touche pas aux sources.
|
||||||
|
|
||||||
|
La contrepartie est une couche d'adaptation plus explicite et une pagination
|
||||||
|
globale plus complexe si le volume devient très élevé.
|
||||||
|
|
||||||
|
## G. Alternative étudiée : option B — index documentaire commun
|
||||||
|
|
||||||
|
Une table `document_index` pourrait contenir une ligne par document source,
|
||||||
|
avec `source_kind`, `source_document_id`, `parent_type`, `parent_id`, type,
|
||||||
|
dates et éventuellement un hash. Elle ne contiendrait pas une copie du
|
||||||
|
fichier : le chemin et la suppression resteraient propriétaires de la table
|
||||||
|
source.
|
||||||
|
|
||||||
|
### Avantages
|
||||||
|
|
||||||
|
- recherche et pagination uniformes ;
|
||||||
|
- index SQL uniques et filtres simples ;
|
||||||
|
- base future pour tags, OCR et classement ;
|
||||||
|
- détection centralisée des documents orphelins.
|
||||||
|
|
||||||
|
### Inconvénients et risques
|
||||||
|
|
||||||
|
- migration et backfill des trois tables ;
|
||||||
|
- synchronisation lors de chaque création, modification, suppression et
|
||||||
|
changement de parent ;
|
||||||
|
- gestion des documents historiques incomplets et de `contract_file` ;
|
||||||
|
- risque de ligne d'index périmée ou d'un faux sentiment de stockage unifié ;
|
||||||
|
- complexité supplémentaire avant d'avoir validé les besoins de recherche.
|
||||||
|
|
||||||
|
### Recommandation de trajectoire
|
||||||
|
|
||||||
|
Ne pas créer cette table pour le MVP. La réévaluer si les mesures montrent
|
||||||
|
que l'agrégation SQL dépasse les objectifs à 10 000+ documents ou si les tags,
|
||||||
|
l'OCR et la recherche plein texte deviennent prioritaires. Dans ce cas, la
|
||||||
|
table restera un index réparable, jamais le propriétaire physique du fichier.
|
||||||
|
|
||||||
|
## H. Règle RBAC recommandée
|
||||||
|
|
||||||
|
Le centre ne doit jamais élargir l'accès d'un module.
|
||||||
|
|
||||||
|
Pour afficher un résultat, appliquer :
|
||||||
|
|
||||||
|
```text
|
||||||
|
permission d'accès au Centre (documents.view)
|
||||||
|
ET
|
||||||
|
permission de lecture de la source
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemples :
|
||||||
|
|
||||||
|
- document d'intervention : `documents.view` + `intervention.view` ;
|
||||||
|
- document équipement : `documents.view` + `patrimoine.view` ;
|
||||||
|
- FDS produit : `documents.view` + `stock.view` ;
|
||||||
|
- contrat futur : `documents.view` + `contract.view` ;
|
||||||
|
- prévention future : `documents.view` + `prevention.view`.
|
||||||
|
|
||||||
|
Si `documents.view` n'est pas accordée, le menu et l'URL globale sont
|
||||||
|
refusés. Si la source est refusée, le résultat est absent, même si sa ligne
|
||||||
|
documentaire est connue.
|
||||||
|
|
||||||
|
Le téléchargement réévalue les deux permissions et l'existence du parent ;
|
||||||
|
il ne doit jamais accepter uniquement un `doc_id` global. La suppression ou
|
||||||
|
la modification reste dans la fiche source et utilise la permission de
|
||||||
|
mutation du module (`intervention.manage`, `patrimoine.manage`, etc.). Il
|
||||||
|
n'est pas recommandé d'introduire un vague `documents.manage` pour remplacer
|
||||||
|
ces contrôles.
|
||||||
|
|
||||||
|
`super_admin` bénéficie de son wildcard existant. Le rôle `admin` et les
|
||||||
|
rôles métier devront recevoir `documents.view` seulement après décision du
|
||||||
|
catalogue RBAC ; aucune permission d'intégration ne doit être impliquée.
|
||||||
|
|
||||||
|
## I. Classification métier proposée
|
||||||
|
|
||||||
|
V1 : un type principal, peu de valeurs et une valeur de repli :
|
||||||
|
|
||||||
|
- FDS ;
|
||||||
|
- Fiche technique ;
|
||||||
|
- Notice / manuel ;
|
||||||
|
- Facture ;
|
||||||
|
- Devis ;
|
||||||
|
- Rapport / compte rendu ;
|
||||||
|
- Contrat ;
|
||||||
|
- Certificat / contrôle ;
|
||||||
|
- Photo / plan ;
|
||||||
|
- Autre.
|
||||||
|
|
||||||
|
Pour les produits, `ProductDocument.document_type` est conservé et mappé
|
||||||
|
vers les libellés métier. Pour les interventions et équipements, le type
|
||||||
|
sera `Autre` tant qu'aucune donnée source ne le porte. Les tags et sous-types
|
||||||
|
sont différés ; ils ne doivent pas être simulés dans `description`.
|
||||||
|
|
||||||
|
## J. Recherche
|
||||||
|
|
||||||
|
### Recherche simple visible
|
||||||
|
|
||||||
|
Un champ unique recherche : nom de fichier, titre, description, nom de
|
||||||
|
l'objet parent, référence équipement, produit, intervention et entreprise
|
||||||
|
accessible par relation.
|
||||||
|
|
||||||
|
### SQL classique suffisant
|
||||||
|
|
||||||
|
Pour les volumes attendus, SQL/MariaDB suffit avec `LIKE` ciblé et des indexes
|
||||||
|
sur les clés étrangères, dates, `document_type`, `filename`, `uploaded_at` et
|
||||||
|
`expiry`/`is_current` côté produits. La recherche plein texte PDF, OCR et
|
||||||
|
Elasticsearch sont explicitement hors MVP.
|
||||||
|
|
||||||
|
### Résultats
|
||||||
|
|
||||||
|
Les requêtes doivent filtrer par source avant pagination et ne jamais charger
|
||||||
|
en mémoire tous les fichiers. Le contenu binaire n'est jamais recherché.
|
||||||
|
|
||||||
|
## K. Filtres
|
||||||
|
|
||||||
|
### Visibles par défaut
|
||||||
|
|
||||||
|
- Type de document ;
|
||||||
|
- Source/module ;
|
||||||
|
- période (date d'ajout ou de publication) ;
|
||||||
|
- recherche libre.
|
||||||
|
|
||||||
|
### Filtres avancés repliés
|
||||||
|
|
||||||
|
- bâtiment, zone, salle ;
|
||||||
|
- équipement ;
|
||||||
|
- produit/FDS ;
|
||||||
|
- entreprise ;
|
||||||
|
- actif/courant pour les produits.
|
||||||
|
|
||||||
|
Les filtres non applicables à une source doivent rester neutres, pas produire
|
||||||
|
un faux « aucun résultat ».
|
||||||
|
|
||||||
|
## L. UI proposée pour `/documents/`
|
||||||
|
|
||||||
|
Titre : **Centre documentaire**. Sous le titre, une phrase explique que les
|
||||||
|
fichiers restent attachés à leur fiche métier et sont seulement regroupés
|
||||||
|
pour la recherche.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Recherche [ nom, titre, équipement, produit... ] [Rechercher]
|
||||||
|
|
||||||
|
Filtres principaux : Type | Source | Période
|
||||||
|
Filtres avancés : Bâtiment | Zone | Salle | Équipement | Produit | Entreprise
|
||||||
|
|
||||||
|
Document | Type | Lié à | Localisation | Date | Actions
|
||||||
|
```
|
||||||
|
|
||||||
|
Chaque ligne présente : nom lisible, icône non porteuse d'information seule,
|
||||||
|
type, source (« Intervention #142 »), localisation calculée, date, bouton
|
||||||
|
Télécharger si autorisé et lien Ouvrir la fiche. Aucun terme technique
|
||||||
|
(`source_kind`, `entity_type`, nom de classe Python) ne doit être affiché.
|
||||||
|
|
||||||
|
La pagination est obligatoire, avec conservation des filtres dans l'URL. La
|
||||||
|
V1 est consultation/recherche uniquement : aucun upload global et aucun
|
||||||
|
bouton de suppression dans ce centre.
|
||||||
|
|
||||||
|
## M. Vue FDS `/documents/fds`
|
||||||
|
|
||||||
|
Vue filtrée ou route dédiée sur les `ProductDocument` de type FDS et
|
||||||
|
`is_current=True`. Colonnes : produit commercial, fabricant/fournisseur,
|
||||||
|
version, date de publication, statut courant, localisation des balances de
|
||||||
|
stock lorsque disponible, téléchargement et fiche produit.
|
||||||
|
|
||||||
|
Un état vide doit expliquer : « Les FDS sont ajoutées depuis la fiche du
|
||||||
|
produit commercial » et proposer ce lien si `stock.view` le permet.
|
||||||
|
|
||||||
|
Le futur « classeur FDS » pourra réutiliser exactement le même service de
|
||||||
|
sélection autorisé pour produire une liste ou un PDF ; aucune génération n'est
|
||||||
|
incluse dans le MVP.
|
||||||
|
|
||||||
|
## N. Documents et localisation
|
||||||
|
|
||||||
|
Ne pas dénormaliser les chemins bâtiment/zone/salle dans une nouvelle table.
|
||||||
|
|
||||||
|
- équipement : `Equipment → effective_room → Zone → Building` ;
|
||||||
|
- intervention : salle directe, sinon équipement lié ;
|
||||||
|
- FDS produit : `CommercialProduct → StockLot → StockLotBalance →
|
||||||
|
StockLocation → Room/Zone/Building`, en signalant « plusieurs
|
||||||
|
emplacements » si nécessaire ;
|
||||||
|
- contrat : relation équipement/lot/entreprise si le document historique est
|
||||||
|
finalement inclus.
|
||||||
|
|
||||||
|
Si aucune localisation n'est calculable, afficher « Localisation non
|
||||||
|
renseignée », jamais `None` ou un identifiant interne.
|
||||||
|
|
||||||
|
## O. Sécurité
|
||||||
|
|
||||||
|
Avant développement, les contrôles suivants sont requis :
|
||||||
|
|
||||||
|
- autoriser une liste d'extensions métier limitée et contrôler aussi le MIME
|
||||||
|
réel / signatures connues ;
|
||||||
|
- refuser exécutables, scripts et archives non prévues ;
|
||||||
|
- conserver un nom original d'affichage séparé d'un nom interne UUID ;
|
||||||
|
- résoudre le chemin avec `Path.resolve()` et vérifier qu'il reste sous la
|
||||||
|
racine `UPLOAD_FOLDER` ;
|
||||||
|
- vérifier parent, source et permission pour chaque download/delete ;
|
||||||
|
- ne jamais exposer le volume par une route statique ;
|
||||||
|
- définir explicitement `Content-Disposition: attachment` et un nom sûr ;
|
||||||
|
- conserver la limite 50 MiB et afficher une erreur utilisateur claire ;
|
||||||
|
- supprimer le fichier si l'insertion DB échoue, ou journaliser une tâche de
|
||||||
|
réconciliation ;
|
||||||
|
- fournir un diagnostic non destructif des lignes DB sans fichier et des
|
||||||
|
fichiers sans ligne DB ;
|
||||||
|
- ajouter des tests IDOR avec deux utilisateurs et deux sources.
|
||||||
|
|
||||||
|
Les documents de prévention, personnel et contrats peuvent contenir des
|
||||||
|
données sensibles. Leur inclusion doit rester soumise à la permission source;
|
||||||
|
aucun filtrage global par simple URL ne suffit.
|
||||||
|
|
||||||
|
## P. Performance
|
||||||
|
|
||||||
|
| Volume | Stratégie V1 attendue |
|
||||||
|
|---:|---|
|
||||||
|
| 100 | `UNION ALL`/adaptateurs, pagination 20–50 lignes, eager loading des parents |
|
||||||
|
| 1 000 | mêmes principes, indexes FK/date/type, count limité aux lignes filtrées |
|
||||||
|
| 10 000 | mesurer les plans SQL ; envisager vue/index commun réparable si la fusion paginée devient lente |
|
||||||
|
|
||||||
|
Indexes utiles côté sources : clés étrangères parent, `uploaded_at`,
|
||||||
|
`document_type`, `is_current`, `published_at`, et éventuellement index
|
||||||
|
composé parent/date. Aucun index de contenu PDF n'est proposé.
|
||||||
|
|
||||||
|
## Q. Migrations éventuelles
|
||||||
|
|
||||||
|
### Option A recommandée
|
||||||
|
|
||||||
|
Aucune migration nécessaire. Il faut seulement ajouter un service de lecture,
|
||||||
|
des requêtes, des tests et une route protégée.
|
||||||
|
|
||||||
|
### Option B différée
|
||||||
|
|
||||||
|
Une future migration créerait un index documentaire avec `source_kind`,
|
||||||
|
`source_document_id`, `parent_type`, `parent_id`, type, dates et hash
|
||||||
|
optionnels, puis un backfill idempotent. Elle ne déplacerait ni ne copierait
|
||||||
|
les fichiers et devrait prévoir la réparation des entrées obsolètes. Elle
|
||||||
|
serait déployée séparément après validation des volumes.
|
||||||
|
|
||||||
|
## R. Compatibilité historique
|
||||||
|
|
||||||
|
La V1 lit les trois tables sans transformer les lignes existantes. Les
|
||||||
|
documents sans type reçoivent `Autre`; les descriptions nulles restent vides;
|
||||||
|
les noms UUID sont présentés avec une règle d'affichage documentée. Les
|
||||||
|
fichiers manquants apparaissent éventuellement dans une vue d'administration
|
||||||
|
diagnostique, mais ne sont jamais supprimés automatiquement.
|
||||||
|
|
||||||
|
`Contract.contract_file` doit faire l'objet d'une décision séparée : soit il
|
||||||
|
reste exclu du MVP, soit il est adapté par un lecteur temporaire avec
|
||||||
|
permission `contract.view`, soit il est converti plus tard en document source
|
||||||
|
normalisé. Il ne faut pas le mélanger silencieusement aux trois tables.
|
||||||
|
|
||||||
|
## S. Tests à prévoir avant implémentation
|
||||||
|
|
||||||
|
1. Intervention, équipement et produit présents dans la liste globale.
|
||||||
|
2. Recherche sur filename, titre, description et parent.
|
||||||
|
3. Filtres type/source/date et filtres localisation.
|
||||||
|
4. Pagination stable et conservation des paramètres d'URL.
|
||||||
|
5. FDS : uniquement documents courants et accès produit autorisé.
|
||||||
|
6. Lien vers chaque fiche métier et absence de lien si source interdite.
|
||||||
|
7. Téléchargement autorisé, refusé et IDOR entre deux utilisateurs.
|
||||||
|
8. Document DB présent mais fichier manquant : réponse contrôlée, jamais 500.
|
||||||
|
9. Fichier présent sans ligne DB : diagnostic, aucune exposition publique.
|
||||||
|
10. Parent supprimé/inaccessible : résultat masqué ou marqué orphelin selon
|
||||||
|
politique validée.
|
||||||
|
11. Aucun upload, suppression ou modification possible depuis `/documents/`.
|
||||||
|
12. Wildcard `super_admin`, rôles source et deny individuel.
|
||||||
|
13. Compatibilité avec noms spéciaux, extensions refusées et taille maximale.
|
||||||
|
14. Non-régression des téléchargements depuis les fiches existantes.
|
||||||
|
|
||||||
|
## T. MVP et évolutions
|
||||||
|
|
||||||
|
### V1 obligatoire
|
||||||
|
|
||||||
|
- `GET /documents/` protégé ;
|
||||||
|
- agrégation lecture seule des interventions, équipements et produits ;
|
||||||
|
- recherche simple, pagination et trois filtres principaux ;
|
||||||
|
- type/source/localisation lisibles ;
|
||||||
|
- téléchargement sécurisé sans duplication ;
|
||||||
|
- lien vers le parent métier ;
|
||||||
|
- contrôle `documents.view` + permission source ;
|
||||||
|
- vue FDS courante ;
|
||||||
|
- états vides et messages d'accès compréhensibles ;
|
||||||
|
- tests de sécurité, IDOR, fichier manquant et non-régression.
|
||||||
|
|
||||||
|
### Plus tard
|
||||||
|
|
||||||
|
- index commun matérialisé si le volume le justifie ;
|
||||||
|
- tags métier ;
|
||||||
|
- recherche plein texte/OCR ;
|
||||||
|
- prévisualisation avancée ;
|
||||||
|
- versionnement transversal ;
|
||||||
|
- classeur FDS exportable ;
|
||||||
|
- intégration explicite des contrats et documents généraux ;
|
||||||
|
- diagnostic et réparation assistés des orphelins.
|
||||||
|
|
||||||
|
## Questions nécessitant validation
|
||||||
|
|
||||||
|
1. Le centre doit-il inclure les chemins historiques `Contract.contract_file`
|
||||||
|
dès la V1, ou les laisser dans les contrats ?
|
||||||
|
2. Le catalogue RBAC accepte-t-il deux nouvelles permissions
|
||||||
|
`documents.view` et `documents.download`, ou la visibilité doit-elle être
|
||||||
|
dérivée uniquement des permissions sources ?
|
||||||
|
3. Le téléchargement global doit-il être séparé de la consultation, ou
|
||||||
|
`documents.view` suffit-il pour la V1 ?
|
||||||
|
4. Quel est le type officiel des documents d'intervention et d'équipement
|
||||||
|
actuellement sans classification ?
|
||||||
|
5. Les documents prévention/personnel/contrats doivent-ils être inclus après
|
||||||
|
une revue de confidentialité ?
|
||||||
|
6. Faut-il afficher une localisation quand plusieurs emplacements stock sont
|
||||||
|
possibles, et sous quel libellé ?
|
||||||
|
7. Quel seuil de volume déclenche l'étude d'un index matérialisé ?
|
||||||
|
8. La V1 reste-t-elle strictement consultation/recherche, sans document
|
||||||
|
général non lié à un objet métier ?
|
||||||
|
|
@ -31,6 +31,15 @@ implémenté.
|
||||||
Contrôle post-rebuild effectué : `/health/` répond 200 avec la version
|
Contrôle post-rebuild effectué : `/health/` répond 200 avec la version
|
||||||
`0.1.0-dev.4`, le commit `b6fbfe6` et une base MariaDB connectée.
|
`0.1.0-dev.4`, le commit `b6fbfe6` et une base MariaDB connectée.
|
||||||
|
|
||||||
|
## Étude Centre documentaire global — 22 août 2026
|
||||||
|
|
||||||
|
Étude d'architecture terminée dans `DOCUMENT_CENTER_PROPOSAL.md`. Le dépôt
|
||||||
|
possède trois modèles documentaires spécialisés, plusieurs conventions de
|
||||||
|
stockage et aucune table commune. La recommandation est une agrégation de
|
||||||
|
lecture par adaptateurs pour la V1, sans migration ni copie de fichier, avec
|
||||||
|
contrôle conjoint `documents.view` et permission du module source. Aucune
|
||||||
|
modification applicative, route, migration ou donnée de test n'a été créée.
|
||||||
|
|
||||||
Couverture estimée : **environ 85 %**. Les principaux workflows patrimoine,
|
Couverture estimée : **environ 85 %**. Les principaux workflows patrimoine,
|
||||||
interventions, stock, prévention et RBAC ont été testés localement ; restent
|
interventions, stock, prévention et RBAC ont été testés localement ; restent
|
||||||
partiels la recherche documentaire globale, certaines variantes de planning,
|
partiels la recherche documentaire globale, certaines variantes de planning,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue