docs(architecture): concevoir centre documentaire v2 et planning interne
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
8e6a67915c
commit
8e19476bb3
3 changed files with 549 additions and 0 deletions
211
docs/ui-audit/DOCUMENT_CENTER_PROPOSAL_V2.md
Normal file
211
docs/ui-audit/DOCUMENT_CENTER_PROPOSAL_V2.md
Normal 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.
|
||||||
319
docs/ui-audit/PLANNING_ENGINE_PROPOSAL.md
Normal file
319
docs/ui-audit/PLANNING_ENGINE_PROPOSAL.md
Normal 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:00–17: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:00–12: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:00–17: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.
|
||||||
|
|
@ -350,3 +350,22 @@ UI-023 est corrigé localement : `request_enabled` est désormais visible et
|
||||||
modifiable dans `/cleaning/products/<id>/edit`. Le produit
|
modifiable dans `/cleaning/products/<id>/edit`. Le produit
|
||||||
`TEST_UI_DETERGENT_SOL` a été activé et apparaît dans `/cleaning/requests/new`.
|
`TEST_UI_DETERGENT_SOL` a été activé et apparaît dans `/cleaning/requests/new`.
|
||||||
Test automatisé associé : **1 passed** (`product_request_enabled_is_editable`).
|
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.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue