docs(architecture): concevoir centre documentaire v2 et planning interne
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run

This commit is contained in:
root 2026-08-22 22:02:37 +00:00
parent 8e6a67915c
commit 8e19476bb3
3 changed files with 549 additions and 0 deletions

View file

@ -0,0 +1,211 @@
# 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.

View file

@ -0,0 +1,319 @@
# Moteur de planification interne — proposition d'architecture
**Statut : étude et spécification uniquement.** Aucun modèle, route,
migration, synchronisation ou changement applicatif n'est créé par ce
document.
## A. Architecture actuelle
Le dépôt possède déjà plusieurs briques réutilisables :
- `Room` et `RoomSchedule` (`app_new/core/models/college.py`) pour les salles
et un emploi du temps hebdomadaire (`week_start`, jour, début/fin, matière,
enseignant, classe) ;
- `WorkSchedule`, `WorkScheduleTemplate`, `TechnicianAvailability`,
`PersonalLeave`, `Training`, `CollegeClosure`, `ClosureSchedule` et
`ClosureWorkDay` (`app_new/core/models/planning.py`) pour horaires, pauses,
absences, formations, fermetures et permanences ;
- `PreventiveTask` (durée, lot, équipement/catégorie, fenêtre autorisée),
`LotTask` (durée, périodicité, sécurité) et `ScheduledTask` (date, début,
fin, durée, salle, équipement, entreprise, contrat, technicien, statut) ;
- `Intervention` avec date planifiée, priorité, salle/équipement,
technicien et entreprise ;
- `AdminTask`, actuellement récurrente avec heure et durée ;
- `PlanningDay`/`PlanningItem`, qui représentent déjà prévention, curatif,
administratif et formation avec durée, salle, priorité et statut.
`planning_service.py` sait produire une journée et calculer des heures de
travail, mais `schedule_task` ne place pas réellement de créneau et la
disponibilité de salle n'est pas croisée avec toutes les tâches internes.
L'implémentation interroge en outre un symbole `PronoteSchedule` alors que le
modèle local de salle observé est `RoomSchedule` : cette dette doit être
résolue avant d'automatiser la disponibilité.
## B. Limites actuelles
1. `RoomSchedule` ne conserve pas de provenance, identifiant externe,
validité ou récurrence explicite.
2. Le service de planification peut retomber sur 08:0017:00 et certaines
requêtes d'horaires/indisponibilités ne filtrent pas toujours par agent.
3. Les conflits salle, tâches, pauses, fermetures et interventions ne sont
pas évalués dans un même calendrier.
4. `AdminTask` ne porte ni statut d'exécution, priorité, agent ou fenêtre.
5. `PlanningItem` et `ScheduledTask` se recouvrent partiellement, ce qui peut
produire des doublons d'affichage.
6. L'import Pronote est optionnel dans les routes mais ne doit jamais être une
dépendance du calcul interne.
## C. Principe de vérité interne
La GMAO possède des créneaux internes d'occupation. Chaque créneau conserve
sa source : `manual`, `pronote`, `import` ou une future source. Les champs
conceptuels sont `source`, `external_id`, `last_synced_at`,
`source_updated_at`, période de validité et statut actif. Le métier parle de
créneau d'occupation interne ; il ne dépend jamais d'une réponse en direct de
Pronote.
L'application doit démarrer et rester pleinement utilisable avec
`PRONOTE_ENABLED=false`, sans token et sans synchronisation.
## D. Saisie manuelle en début d'année
Une fonction de gestion crée les `RoomSchedule` de source `manual` à partir
des salles, périodes, jours, heures et types d'occupation : cours, réunion,
examen, réservation, travaux, intervention, fermeture ou autre. Les règles de
validation refusent début ≥ fin et signalent les chevauchements. Une saisie
manuelle est toujours conservée, même lorsqu'une source externe est absente.
## E. Pronote facultatif
Pronote peut fournir des créneaux après configuration, mais ne possède jamais
la source interne de vérité. La synchronisation ne doit lire/écrire que les
créneaux qu'elle a créés (`source=pronote`, `external_id` connu).
## F. Synchronisation et conflits
- Créneau manuel : jamais modifié ni supprimé automatiquement par Pronote.
- Créneau Pronote identique : mise à jour de ses champs et de
`last_synced_at`.
- Créneau supprimé côté Pronote : désactivation du seul créneau Pronote
correspondant ; aucune suppression manuelle.
- Collision manuel/Pronote : le manuel gagne, le conflit est signalé à
l'utilisateur avec les deux provenances.
- Pronote indisponible : conserver les dernières données importées, marquer
leur fraîcheur et afficher un avertissement ; ne jamais vider le planning.
- Donnée Pronote obsolète : elle peut être désactivée selon une politique de
rétention explicite, jamais effacée silencieusement.
## G. Disponibilité des salles
Le calcul croise les occupations internes, fermetures de salle/collège,
interventions, tâches planifiées, rendez-vous d'entreprises et permanence.
Les catégories d'occupation sont celles de la saisie manuelle. Une tâche de
45 minutes peut occuper 12:0012:45 entre deux cours si le technicien est
également disponible ; les créneaux hors horaires, pause ou fermeture sont
exclus.
Le futur service doit utiliser `RoomSchedule` pour les cours importés ou
manuels et `ScheduledTask`/`PlanningItem`/`Intervention` pour les activités
internes, sans appeler Pronote en direct.
## H. Préventif et lots
`PreventiveTask` et `LotTask` fournissent la périodicité, la durée, la portée,
les restrictions d'accès et le caractère critique. `ScheduledTask` est la
source d'exécution d'un travail généré : lot, tâche, équipement/local, date
cible, durée, début/fin, priorité, statut, entreprise/contrat et technicien.
Les créneaux proposés doivent afficher **quoi, où, quand, durée** et refuser
une date dépassant une échéance de conformité. Une intervention convertie ne
doit pas être affichée deux fois.
## I. Horaires de travail
Le moteur utilise le `WorkSchedule` de l'agent, les templates, pauses,
`TechnicianAvailability`, congés, formations, fermetures et
`ClosureWorkDay`. Il ne planifie jamais sur la pause ou hors intervalle. La
V1 doit exiger un agent explicite pour une proposition automatique et ne pas
inventer 08:0017:00 lorsque la configuration manque ; l'absence de données
doit être expliquée.
## J. Tâches administratives
Les tâches administratives sont des activités planifiables qui consomment du
temps : commande, devis, compte rendu, registre, dossier ou appels. La V1
doit compléter le modèle actuel par une durée, priorité, statut, fenêtre/date,
heure planifiée et responsable, ou projeter ces données dans
`PlanningItem`. Une récurrence ne doit pas masquer l'instance réellement
faite ou reportée.
## K. Entreprises extérieures
Un rendez-vous doit représenter au minimum entreprise, date/heure fixe,
intervention/contrat lié, durée d'accueil, accompagnement, éventuels passages
et temps administratif final. Pour la V1, réutiliser `ScheduledTask`/`PlanningItem`
avec `company_id` et un type d'étape simple (accueil, contrôle, signature)
plutôt que créer un système de calendrier externe. Une entité
`ExternalCompanyAppointment` séparée ne sera justifiée que si plusieurs
étapes doivent être suivies indépendamment.
## L. Urgences et contraintes
Les niveaux compréhensibles sont :
- **Fixe** : rendez-vous entreprise ou examen à heure imposée ;
- **Urgent** : fuite, sécurité ou panne critique ;
- **Échéance** : conformité ou tâche à terminer avant une date ;
- **Déplaçable** : prévention réalisable dans la fenêtre ;
- **Administratif** : travail planifiable avant une échéance.
Une urgence peut interrompre ou repousser, mais le système conserve chaque
tâche, son ancien créneau, sa raison et sa nouvelle proposition.
## M. Optimisation géographique
La première version calcule un coût ordinal simple : même salle (0), même
zone (1), même bâtiment (2), autre bâtiment (3). Ce coût ne passe jamais avant
sécurité, rendez-vous fixe, échéance, disponibilité, horaires et compétences.
Il sert uniquement à départager des créneaux équivalents, sans GPS ni tournée
complexe.
Ordre d'arbitrage : urgence/sécurité, rendez-vous fixe, échéance,
disponibilité salle, horaires, compétence/affectation, regroupement
géographique, réduction des trous.
## N. Replanification et contrôle humain
Lorsqu'une urgence arrive à 10:00, l'interface propose les tâches décalables,
les conserve avec leur historique et expose les créneaux alternatifs. Elle
classe chaque élément en conservé, décalé, non planifiable ou nouvelle
proposition. Une validation humaine est obligatoire ; aucun déplacement
silencieux.
Un déplacement manuel revalide conflit salle, horaires, pauses, autre tâche,
rendez-vous fixe et fermeture. Le message doit être métier : « Salle 101
occupée jusqu'à 11:00 », avec créneaux disponibles.
## O. Multi-techniciens futur
La colonne actuelle `assigned_to_id` convient à la V1 mono-agent, mais ne doit
pas devenir une contrainte conceptuelle. Une évolution pourra ajouter une
association `PlannedTaskAssignee` (tâche, utilisateur, rôle), avec
`preferred_technician`, `required_skill` et `required_people_count`. Une
personne préférée n'est pas une personne assignée ; une compétence requise
est une contrainte, pas une préférence. Deux personnes seront représentées
par deux affectations liées à la même activité.
## P. Modèle de données recommandé
Réutiliser au maximum les tables présentes :
1. **Étendre `RoomSchedule`** : `source`, `external_id`, horodatage de
synchronisation, validité, type/libellé et statut actif. Index futur sur
`(room_id, week_start, day_of_week, start_time, end_time, source)`.
2. **Conserver `ScheduledTask`** comme échéance/exécution préventive ; ajouter
ultérieurement contrainte de priorité et fenêtre si les champs existants ne
suffisent pas.
3. **Utiliser `PlanningItem` comme projection de placement** (date, début,
fin, durée, salle, statut, priorité) et imposer une règle anti-doublon avec
les références `scheduled_task_id`/`intervention_id`/`admin_task_id`.
4. **Étendre `AdminTask` ou sa projection** pour responsable, statut,
priorité et fenêtre, sans perdre la récurrence.
5. **Rendez-vous entreprise** : d'abord `ScheduledTask`/`PlanningItem` avec
`company_id`; créer `ExternalCompanyAppointment` seulement si les étapes
deviennent des objets suivis.
Chaque futur index doit couvrir les requêtes par date/statut, salle/intervalle
et agent. Aucune table de planning parallèle ne doit être créée sans preuve
que `PlanningItem` ne peut pas être consolidé.
## Q. Migrations futures
Les extensions ci-dessus nécessiteront des migrations Alembic non destructives,
avec valeurs par défaut (`source=manual`, statut actif) et backfill explicite
des `RoomSchedule` existants. Les données Pronote historiques ne doivent pas
être confondues avec le manuel : si leur origine est inconnue, les marquer
`import` et demander validation.
## R. Algorithme V1 déterministe
1. Construire les intervalles de travail de l'agent, en retirant pauses,
congés, formations, fermetures et permanences incompatibles.
2. Construire les intervalles occupés de la salle et du planning interne.
3. Générer les créneaux possibles par durée et fenêtre.
4. Éliminer conflits, hors horaires, échéances et rendez-vous fixes.
5. Classer par contrainte puis coût géographique, puis heure la plus proche.
6. Retourner une proposition explicable, sans commit automatique.
Une heuristique simple est préférable à un solveur d'optimisation complet :
elle est déterministe, testable, lisible et réversible.
## S. Interface proposée
### Vue journalière
Afficher pour chaque bloc : heure, bâtiment/zone/salle, titre, catégorie
(préventif, curatif, urgent, administratif, entreprise), durée, statut et
contrainte. Un panneau « Propositions » explique les créneaux refusés.
### Gestion des salles
Calendrier par salle/semaine, saisie manuelle claire, provenance visible et
indication « données Pronote anciennes » sans bloquer le planning interne.
### Conflits
Afficher la cause, la ressource concernée et deux ou trois créneaux
compatibles. L'utilisateur choisit et confirme.
## T. Tests à prévoir
- salle libre/occupée et chevauchement ;
- planning manuel sans Pronote ;
- Pronote désactivé, indisponible, puis synchronisé ;
- conflit manuel/Pronote et suppression distante ;
- préventif de 45 minutes entre deux cours ;
- durée/échéance d'une tâche liée à un lot ;
- pause, horaires hors travail, fermeture et permanence ;
- tâche administrative récurrente, réalisée et reportée ;
- entreprise avec accueil, accompagnement et signature ;
- urgence décalant deux tâches sans perte d'historique ;
- regroupement même salle/zone/bâtiment ;
- déplacement manuel vers rendez-vous fixe ;
- données sans agent/horaires explicites ;
- futur multi-techniciens compatible (test de structure, pas d'optimiseur).
## U. Scénarios métier de validation
1. **Début d'année manuel** : saisir les créneaux de plusieurs salles,
planifier une maintenance et vérifier l'absence de Pronote.
2. **Mise à jour Pronote** : importer un nouveau cours, modifier un cours
importé et vérifier qu'un créneau manuel reste intact.
3. **Panne Pronote** : simuler une semaine sans connexion, conserver le
dernier planning et afficher sa date de fraîcheur.
4. **Préventif interstitiel** : proposer 45 minutes entre deux cours en
respectant la pause et le temps de travail.
5. **Tournée locale** : cinq préventifs de la même zone sont regroupés avant
un autre bâtiment.
6. **Entreprise fixe** : rendez-vous chaudière à 09:00, accueil, contrôle,
signature et temps administratif visibles.
7. **Urgence** : fuite à 10:00, conserver le rendez-vous fixe, décaler deux
tâches déplaçables et faire valider la proposition.
8. **Journée mixte** : maintenance, commande, entreprise et intervention
curative avec horaires et statuts cohérents.
9. **Fermeture/permanence** : proposer une tâche pendant une journée rouverte
de vacances, refuser les dates fermées.
10. **Salle indisponible** : fermeture d'une salle, replanification vers une
autre salle compatible sans modifier silencieusement l'objet métier.
## V. MVP obligatoire
- planning interne des salles, saisie manuelle et provenance ;
- Pronote optionnel, import limité à ses propres créneaux ;
- durée, début/fin, statut et priorité des tâches ;
- respect horaires, pauses, fermetures et absences ;
- prévention/lot, interventions, tâches administratives ;
- rendez-vous entreprise simple ;
- urgences et propositions de replanification ;
- regroupement salle/zone/bâtiment ;
- déplacement manuel avec avertissements ;
- vue journalière lisible et déterministe.
## W. Évolutions futures et décisions à valider
**Plus tard :** multi-techniciens avancé, compétences, absences détaillées,
deux personnes par tâche, optimisation complexe, calcul de trajets, import
d'autres sources et statistiques de charge.
Avant développement, valider :
1. `RoomSchedule` comme base des occupations internes et ses champs de
provenance ;
2. la règle « Pronote ne modifie jamais le manuel » ;
3. l'usage de `PlanningItem` comme projection anti-doublon ;
4. le périmètre des tâches administratives et des étapes entreprise ;
5. le niveau de priorité/contrainte exposé aux utilisateurs ;
6. le comportement d'une donnée Pronote obsolète ;
7. la politique lorsque les horaires d'un agent sont absents ;
8. la future association multi-techniciens ;
9. les index et volumes acceptables pour la vue semaine/année.

View file

@ -350,3 +350,22 @@ UI-023 est corrigé localement : `request_enabled` est désormais visible et
modifiable dans `/cleaning/products/<id>/edit`. Le produit
`TEST_UI_DETERGENT_SOL` a été activé et apparaît dans `/cleaning/requests/new`.
Test automatisé associé : **1 passed** (`product_request_enabled_is_editable`).
## Étude d'architecture — centre documentaire V2 et moteur de planning interne
Date : 22 août 2026
Étude terminée sans modification du code applicatif. Deux spécifications ont
été produites :
- `DOCUMENT_CENTER_PROPOSAL_V2.md` : agrégation en lecture par adaptateurs
des interventions, équipements et produits, sans table commune ni copie de
fichier ; RBAC `documents.view` combiné à la permission source ;
- `PLANNING_ENGINE_PROPOSAL.md` : planning interne autonome, saisie manuelle
des salles, provenance des créneaux, Pronote facultatif, tâches préventives,
administratives et entreprises, urgences, heuristique déterministe et
compatibilité multi-techniciens future.
Aucune route, migration, permission, modèle, template, synchronisation ou
fonctionnalité n'a été créée. Développement conditionné à la validation des
questions listées dans les deux documents.