From ea255c184e5d54d7d6ed45f6bd2a21cfae3248cc Mon Sep 17 00:00:00 2001 From: Boris Gallet Date: Tue, 17 Feb 2026 17:52:48 +0100 Subject: [PATCH] [NEW] maintenance_service_http_monitoring : check HTTP 200 for services --- .../drafts/service-http-monitoring.md | 92 ++ .../plans/service-http-monitoring.md | 1003 +++++++++++++++++ .../README.rst | 55 + .../__init__.py | 1 + .../__manifest__.py | 16 + .../data/cron.xml | 23 + .../models/__init__.py | 3 + .../models/maintenance_equipment.py | 97 ++ .../models/service_instance.py | 69 ++ .../views/maintenance_equipment_views.xml | 42 + .../views/service_instance_views.xml | 30 + 11 files changed, 1431 insertions(+) create mode 100644 maintenance_service_http_monitoring/DEV/.sisyphus/drafts/service-http-monitoring.md create mode 100644 maintenance_service_http_monitoring/DEV/.sisyphus/plans/service-http-monitoring.md create mode 100644 maintenance_service_http_monitoring/README.rst create mode 100644 maintenance_service_http_monitoring/__init__.py create mode 100644 maintenance_service_http_monitoring/__manifest__.py create mode 100644 maintenance_service_http_monitoring/data/cron.xml create mode 100644 maintenance_service_http_monitoring/models/__init__.py create mode 100644 maintenance_service_http_monitoring/models/maintenance_equipment.py create mode 100644 maintenance_service_http_monitoring/models/service_instance.py create mode 100644 maintenance_service_http_monitoring/views/maintenance_equipment_views.xml create mode 100644 maintenance_service_http_monitoring/views/service_instance_views.xml diff --git a/maintenance_service_http_monitoring/DEV/.sisyphus/drafts/service-http-monitoring.md b/maintenance_service_http_monitoring/DEV/.sisyphus/drafts/service-http-monitoring.md new file mode 100644 index 0000000..63d8f44 --- /dev/null +++ b/maintenance_service_http_monitoring/DEV/.sisyphus/drafts/service-http-monitoring.md @@ -0,0 +1,92 @@ +# Draft: Monitoring HTTP des services + +## Contexte codebase + +### Architecture des modules +``` +maintenance_server_data (base, maintenance) +├── Définit: service, service.version, service.instance, backup.server +├── Extend maintenance.equipment: server_ip, service_ids (One2many), backup_*, etc. +└── Vues: service list, equipment form (onglet Services) + +maintenance_server_ssh (base, maintenance) +├── Extend maintenance.equipment: server_domain, ssh_private_key_path +└── Méthode: get_ssh_connection() + +maintenance_server_monitoring (base, maintenance, maintenance_server_ssh) +├── Extend maintenance.equipment: monitoring fields + test methods +├── Pattern MonitoringTest inner class (test_ok/warning/error) +├── Cron: toutes les 1 minute sur ALL equipment +├── Création auto de maintenance.request si error/warning +└── PAS de dépendance vers maintenance_server_data actuellement ! +``` + +### Modèle service.instance actuel (dans maintenance_server_data) +- equipment_id (Many2one → maintenance.equipment) +- service_id (Many2one → service, required) +- version_id (Many2one → service.version) +- service_url (Char) ← URL déjà existante, parfait pour les checks HTTP + +### Pattern de création maintenance.request existant +- Vérifie si une request non-done existe déjà avant d'en créer une nouvelle +- Stocke la référence sur equipment: error_maintenance_request / warning_maintenance_request +- Assignation auto: employee_id, technician_user_id, maintenance_team_id + +## Requirements confirmés (depuis les specs) + +- [x] Modifier le module `maintenance_server_monitoring` (pas de nouveau module) +- [x] Ajouter `maintenance_server_data` aux dépendances (nécessaire pour accéder à service.instance) +- [x] Étendre `service.instance` avec: last_status_code (Integer), last_check_date (Datetime), status OK/KO (Boolean) +- [x] Nouvelle vue liste standalone pour service.instance (nom, version, URL, date check, status code, statut) +- [x] Paramètres module: fréquence vérification + durée mode maintenance +- [x] Mode maintenance sur equipment: bool tracked + bandeau +- [x] Si service KO → création maintenance.request (pas de doublon si toujours KO) + +## Décision architecturale : NOUVEAU MODULE + +**Nom**: `maintenance_service_http_monitoring` +**Raison**: Séparation des préoccupations — monitoring infra (SSH/ping) vs monitoring applicatif (HTTP) +**Dépendances**: `base`, `maintenance`, `maintenance_server_data` +**PAS de dépendance** vers `maintenance_server_ssh` ni `maintenance_server_monitoring` + +## Décisions techniques + +- Paramètres via res.config.settings + ir.config_parameter (pattern standard Odoo) +- _inherit = 'service.instance' dans le nouveau module pour étendre le modèle +- Cron dédié pour les checks HTTP (fréquence configurable) +- _inherit = 'maintenance.equipment' pour ajouter maintenance_mode + http_maintenance_request +- mail.thread déjà hérité par maintenance.equipment dans Odoo base → tracking fonctionne + +## Décisions utilisateur (interview) + +1. **Mode maintenance**: HTTP uniquement — le monitoring existant (ping, SSH, mémoire, disque) continue normalement +2. **Lien maintenance.request**: Sur maintenance.equipment — nouveau champ `http_maintenance_request` (Many2one). Si plusieurs services KO sur un même equipment, UNE seule request qui liste les services KO. +3. **Menu service list**: Sous Maintenance > principal, même niveau que Équipements et Demandes +4. **Tests**: OUI — setup pytest-odoo + tests unitaires pour la logique HTTP check et création maintenance requests + +## Scope boundaries + +### IN +- NOUVEAU module `maintenance_service_http_monitoring` +- Étendre service.instance avec champs monitoring HTTP +- Cron dédié pour checks HTTP (fréquence configurable) +- Paramètres module (fréquence + durée mode maintenance) +- Mode maintenance sur equipment (bool tracked, bandeau, HTTP checks only) +- Création maintenance.request si service KO (référence sur equipment) +- Nouvelle vue liste services avec colonnes monitoring +- Setup pytest-odoo + tests unitaires + +### OUT +- Aucune modification de `maintenance_server_monitoring` ni de `maintenance_server_ssh` +- Pas de notification email (juste la maintenance.request) +- Pas de dashboard / reporting +- Pas de tracking sur service.instance (pas de mail.thread sur ce modèle) + +## Décisions Metis (post-gap-analysis) + +- Services orphelins (sans equipment_id): N'existent pas en pratique, filtrés par sécurité +- Récupération service KO→OK: Rien d'automatique, close manuelle de la maintenance.request +- Définition KO: Tout échec = KO (timeout, DNS, SSL, connexion refusée, code != 200). Log le détail. +- Timeout HTTP: Hardcodé (constante, comme les seuils existants dans maintenance_server_monitoring) +- `requests` library: Déclarer dans external_dependencies.python +- Chaque requests.get() DOIT avoir timeout= (pylintrc enforce external-request-timeout) diff --git a/maintenance_service_http_monitoring/DEV/.sisyphus/plans/service-http-monitoring.md b/maintenance_service_http_monitoring/DEV/.sisyphus/plans/service-http-monitoring.md new file mode 100644 index 0000000..8ac4753 --- /dev/null +++ b/maintenance_service_http_monitoring/DEV/.sisyphus/plans/service-http-monitoring.md @@ -0,0 +1,1003 @@ +# Monitoring HTTP des Services — Nouveau Module `maintenance_service_http_monitoring` + +## TL;DR + +> **Quick Summary**: Créer un nouveau module Odoo 16 `maintenance_service_http_monitoring` qui vérifie périodiquement la disponibilité HTTP des services (`service.instance`) et crée automatiquement des demandes de maintenance si un service ne répond plus en 200. +> +> **Deliverables**: +> - Nouveau module complet avec modèles, vues, cron, settings et tests +> - Extension de `service.instance` avec champs de monitoring HTTP (status code, date check, état OK/KO) +> - Extension de `maintenance.equipment` avec mode maintenance (désactive les checks HTTP) et lien vers la maintenance.request HTTP +> - Vue liste standalone des services avec colonnes monitoring +> - Page de paramètres (fréquence de vérification, durée mode maintenance) +> - Cron configurable pour les vérifications HTTP +> - Tests unitaires avec pytest-odoo (HTTP mocké) +> +> **Estimated Effort**: Medium +> **Parallel Execution**: YES — 4 waves +> **Critical Path**: T1 → T3 → T6 → T9 + +--- + +## Context + +### Original Request +Être alerté si un service sur nos serveurs n'est plus disponible (requête HTTP retourne une réponse autre que 200). Un cron envoie des requêtes HTTPS sur tous les services actifs. Si réponse != 200, le service est marqué KO et une demande de maintenance est ouverte. + +### Interview Summary +**Key Discussions**: +- **Architecture module**: Nouveau module indépendant plutôt que modifier `maintenance_server_monitoring` — séparation des préoccupations (monitoring infra SSH/ping vs monitoring applicatif HTTP) +- **Mode maintenance scope**: Désactive les checks HTTP uniquement (pas ping/SSH/mémoire/disque) +- **Lien maintenance.request**: Stocké sur `maintenance.equipment` (champ `http_maintenance_request`), une request par équipement listant tous les services KO +- **Récupération KO→OK**: Close manuelle, pas d'auto-close +- **Définition KO**: Tout échec = KO (timeout, DNS, SSL, connexion refusée, code != 200) +- **Menu**: Sous Maintenance > principal, même niveau que Équipements +- **Tests**: Oui, setup pytest-odoo + tests unitaires + +**Research Findings**: +- `service.instance` a déjà un champ `service_url` (Char) — parfait pour les checks HTTP +- `maintenance.equipment` hérite `mail.thread` dans Odoo 16 base → `tracking=True` fonctionne sur equipment +- `service.instance` n'hérite PAS `mail.thread` → pas de tracking sur ses champs +- Le pattern de création de `maintenance.request` est documenté dans `maintenance_server_monitoring/models/maintenance_equipment.py:194-218` +- Le repo a des hooks pre-commit lourds : prettier, ruff, pylint_odoo (mandatory), docformatter +- pylintrc enforce `external-request-timeout` → tout `requests.get()` DOIT avoir `timeout=` +- `requests` est disponible dans l'environnement Odoo mais doit être déclaré dans `external_dependencies` + +### Metis Review +**Identified Gaps** (addressed): +- Services orphelins (sans `equipment_id`): N'existent pas en pratique, filtrés par sécurité dans le cron +- Récupération KO→OK: Décision prise — close manuelle +- Définition de KO: Clarifié — tout échec réseau ou HTTP != 200 = KO +- Timeout HTTP: Constante hardcodée (pattern existant des seuils de monitoring) +- `requests` dans `external_dependencies`: Ajouté au plan +- `security/ir.model.access.csv`: Nécessaire pour le nouveau module +- Cron overlap potentiel: Documenté — l'intervalle doit excéder le temps total de vérification + +--- + +## Work Objectives + +### Core Objective +Créer un module Odoo 16 qui surveille la disponibilité HTTP des services et crée des demandes de maintenance automatiquement en cas d'indisponibilité. + +### Concrete Deliverables +- Module `maintenance_service_http_monitoring/` complet et installable +- Extension du modèle `service.instance` avec champs de monitoring +- Extension du modèle `maintenance.equipment` avec mode maintenance et lien HTTP request +- Vue liste des services avec statut monitoring +- Page de paramètres configurable +- Cron de vérification HTTP +- Tests unitaires + +### Definition of Done +- [ ] Module installable sans erreur sur une instance Odoo 16 avec `maintenance_server_data` installé +- [ ] Cron de vérification HTTP fonctionne et met à jour les statuts des services +- [ ] Demande de maintenance créée automatiquement quand un service est KO +- [ ] Pas de doublon de maintenance.request si le service reste KO +- [ ] Mode maintenance désactive les checks HTTP pour l'équipement concerné +- [ ] Mode maintenance s'auto-désactive après la durée configurée +- [ ] Vue liste des services accessible depuis le menu Maintenance +- [ ] Tous les tests passent +- [ ] `pre-commit run --all-files` passe sans erreur + +### Must Have +- Vérification HTTP avec `requests.get(url, timeout=X)` +- Champs sur `service.instance`: `last_http_status_code`, `last_http_check_date`, `http_status_ok` +- Champ sur `maintenance.equipment`: `http_maintenance_request` (Many2one), `maintenance_mode` (Boolean tracked), `maintenance_mode_start`, `maintenance_mode_end` +- Cron séparé pour les checks HTTP +- Paramètres: fréquence de vérification, durée du mode maintenance +- Création de `maintenance.request` si KO, vérification doublon avant création +- Vue liste services avec colonnes monitoring +- Tests unitaires avec HTTP mocké + +### Must NOT Have (Guardrails) +- Ne PAS modifier le module `maintenance_server_monitoring` ni `maintenance_server_ssh` +- Ne PAS modifier le module `maintenance_server_data` +- Ne PAS ajouter de notifications email +- Ne PAS ajouter de dashboard/reporting +- Ne PAS ajouter `mail.thread` à `service.instance` +- Ne PAS auto-fermer les maintenance.request quand un service repasse OK +- Ne PAS parser le body des réponses HTTP +- Ne PAS ajouter d'authentification ou de headers custom aux requêtes HTTP +- Ne PAS utiliser `requests.get()` sans `timeout=` (pylintrc enforce `external-request-timeout`) +- Ne PAS utiliser `except Exception` sans logger le détail de l'erreur +- Ne PAS ajouter de commentaires superflus ou de docstrings génériques (AI slop) + +--- + +## Verification Strategy (MANDATORY) + +> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions. + +### Test Decision +- **Infrastructure exists**: NO (greenfield) +- **Automated tests**: YES (Tests-after) +- **Framework**: Odoo `TransactionCase` avec `unittest.mock` pour mocker HTTP + +### QA Policy +Every task MUST include agent-executed QA scenarios. +Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`. + +| Deliverable Type | Verification Tool | Method | +|------------------|-------------------|--------| +| Python models | Bash (python/odoo shell) | Import, instancier, vérifier champs | +| XML views | Bash (odoo --init) | Installation module, vérification logs | +| Cron | Bash (odoo shell) | `env.ref()` du cron, vérification config | +| Settings | Bash (odoo shell) | `ir.config_parameter` get/set | +| Tests | Bash (pytest/odoo test) | Exécution test suite | +| Linting | Bash (pre-commit) | `pre-commit run --all-files` | + +--- + +## Execution Strategy + +### Parallel Execution Waves + +``` +Wave 1 (Start Immediately — scaffolding du module): +├── Task 1: Scaffolding module (manifest, __init__, security) [quick] +└── Task 2: Paramètres module (res.config.settings + vue) [quick] + +Wave 2 (After Wave 1 — modèles core, MAX PARALLEL): +├── Task 3: Extension service.instance (champs + méthode HTTP check) [deep] +├── Task 4: Extension maintenance.equipment (mode maintenance + http_maintenance_request) [unspecified-high] +└── Task 5: Cron HTTP monitoring (XML + méthode cron) [quick] + +Wave 3 (After Wave 2 — vues): +├── Task 6: Vue liste service.instance (tree + action + menu) [quick] +└── Task 7: Vue equipment (bandeau mode maintenance) [quick] + +Wave 4 (After Wave 3 — tests + lint): +└── Task 8: Tests unitaires + pre-commit [unspecified-high] + +Wave FINAL (After ALL tasks — revue indépendante, 4 parallel): +├── Task F1: Plan compliance audit (oracle) +├── Task F2: Code quality review (unspecified-high) +├── Task F3: Real manual QA (unspecified-high) +└── Task F4: Scope fidelity check (deep) + +Critical Path: T1 → T3 → T6 → T8 → F1-F4 +Parallel Speedup: ~50% faster than sequential +Max Concurrent: 3 (Wave 2) +``` + +### Dependency Matrix + +| Task | Depends On | Blocks | Wave | +|------|------------|--------|------| +| T1 | — | T2, T3, T4, T5 | 1 | +| T2 | T1 | T3, T5 | 1 | +| T3 | T1, T2 | T5, T6, T8 | 2 | +| T4 | T1 | T7, T8 | 2 | +| T5 | T1, T2, T3 | T8 | 2 | +| T6 | T3 | T8 | 3 | +| T7 | T4 | T8 | 3 | +| T8 | T3, T4, T5, T6, T7 | F1-F4 | 4 | +| F1-F4 | T8 | — | FINAL | + +### Agent Dispatch Summary + +| Wave | # Parallel | Tasks → Agent Category | +|------|------------|----------------------| +| 1 | **2** | T1 → `quick`, T2 → `quick` | +| 2 | **3** | T3 → `deep`, T4 → `unspecified-high`, T5 → `quick` | +| 3 | **2** | T6 → `quick`, T7 → `quick` | +| 4 | **1** | T8 → `unspecified-high` | +| FINAL | **4** | F1 → `oracle`, F2 → `unspecified-high`, F3 → `unspecified-high`, F4 → `deep` | + +--- + +## TODOs + +- [ ] 1. Scaffolding du module `maintenance_service_http_monitoring` + + **What to do**: + - Créer le répertoire `maintenance_service_http_monitoring/` à la racine du repo (à côté de `maintenance_server_monitoring/`) + - Créer `__manifest__.py` avec : + - `name`: `maintenance_service_http_monitoring` + - `version`: `16.0.1.0.0` + - `author`: `Elabore` + - `license`: `AGPL-3` + - `category`: `Tools` + - `summary`: `Monitor HTTP availability of services` + - `depends`: `["base", "maintenance", "maintenance_server_data"]` + - `external_dependencies`: `{"python": ["requests"]}` + - `data`: liste de tous les fichiers data/views/security (dans l'ordre : security d'abord, puis views, puis data) + - `installable`: `True` + - Créer `__init__.py` qui importe `models` + - Créer `models/__init__.py` qui importe les sous-modules (service_instance, maintenance_equipment, res_config_settings) + - Créer `security/ir.model.access.csv` avec les règles d'accès pour `res.config.settings` (le modèle `service.instance` est déjà couvert par `maintenance_server_data`) + - Créer les répertoires vides : `views/`, `data/`, `tests/` + + **Must NOT do**: + - Ne pas créer de fichiers modèle Python (juste les `__init__.py` avec les imports) + - Ne pas modifier de fichiers dans d'autres modules + + **Recommended Agent Profile**: + - **Category**: `quick` + - Reason: Scaffolding simple, fichiers de configuration, pas de logique métier + - **Skills**: [] + - Aucune skill spéciale nécessaire + - **Skills Evaluated but Omitted**: + - `git-master`: Pas de commit dans cette tâche + + **Parallelization**: + - **Can Run In Parallel**: YES (avec T2) + - **Parallel Group**: Wave 1 (avec Task 2) + - **Blocks**: T2, T3, T4, T5 + - **Blocked By**: None (peut démarrer immédiatement) + + **References** (CRITICAL): + + **Pattern References** (existing code to follow): + - `maintenance_server_monitoring/__manifest__.py` — Structure du manifest à suivre (même format, même auteur, même licence). Adapter les depends et external_dependencies + - `maintenance_server_monitoring/__init__.py` — Pattern d'import module + - `maintenance_server_monitoring/models/__init__.py` — Pattern d'import des sous-modules modèle + + **API/Type References**: + - `maintenance_server_data/security/ir.model.access.csv` — Format exact du CSV de sécurité à reproduire (colonnes, groupes utilisés : `base.group_user` et `maintenance.group_equipment_manager`) + + **WHY Each Reference Matters**: + - Le manifest doit suivre exactement le même format que les autres modules du repo pour la cohérence + - Les imports `__init__.py` doivent lister tous les fichiers Python qui seront créés dans les tâches suivantes + - Le security CSV doit suivre le format exact d'Odoo (headers, colonnes) sinon le module ne s'installe pas + + **Acceptance Criteria**: + + **QA Scenarios (MANDATORY):** + + ``` + Scenario: Structure du module créée correctement + Tool: Bash + Preconditions: Repo cloné, aucun fichier maintenance_service_http_monitoring/ existant + Steps: + 1. ls -la maintenance_service_http_monitoring/ — vérifier que le répertoire existe + 2. ls -la maintenance_service_http_monitoring/models/ — vérifier __init__.py présent + 3. ls -la maintenance_service_http_monitoring/security/ — vérifier ir.model.access.csv présent + 4. ls -la maintenance_service_http_monitoring/views/ — vérifier répertoire existe + 5. ls -la maintenance_service_http_monitoring/data/ — vérifier répertoire existe + 6. ls -la maintenance_service_http_monitoring/tests/ — vérifier répertoire existe + 7. python3 -c "import ast; ast.literal_eval(open('maintenance_service_http_monitoring/__manifest__.py').read())" — vérifier syntaxe Python du manifest + 8. grep "maintenance_server_data" maintenance_service_http_monitoring/__manifest__.py — vérifier dépendance présente + 9. grep "requests" maintenance_service_http_monitoring/__manifest__.py — vérifier external_dependency + Expected Result: Tous les fichiers et répertoires existent, manifest syntaxiquement valide, dépendances correctes + Failure Indicators: Fichier manquant, erreur de syntaxe Python, dépendance absente + Evidence: .sisyphus/evidence/task-1-module-structure.txt + + Scenario: Security CSV bien formé + Tool: Bash + Preconditions: security/ir.model.access.csv créé + Steps: + 1. head -1 maintenance_service_http_monitoring/security/ir.model.access.csv — vérifier header exact + 2. Vérifier que le header est : id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink + Expected Result: Header CSV exact, colonnes correctes + Failure Indicators: Header manquant ou mal formé + Evidence: .sisyphus/evidence/task-1-security-csv.txt + ``` + + **Commit**: YES + - Message: `feat(http_monitoring): scaffold new module maintenance_service_http_monitoring` + - Files: `maintenance_service_http_monitoring/__manifest__.py`, `maintenance_service_http_monitoring/__init__.py`, `maintenance_service_http_monitoring/models/__init__.py`, `maintenance_service_http_monitoring/security/ir.model.access.csv` + - Pre-commit: N/A (pas de code Python significatif) + +--- + +- [ ] 2. Paramètres du module (res.config.settings) + + **What to do**: + - Créer `maintenance_service_http_monitoring/models/res_config_settings.py` : + - `_inherit = 'res.config.settings'` + - Champ `http_check_frequency` (Integer, default=1) — fréquence de vérification en heures + - Champ `http_maintenance_mode_duration` (Integer, default=4) — durée du mode maintenance en heures + - Les deux champs liés à `ir.config_parameter` via `config_parameter=` attribute + - Clés de paramètres : `maintenance_service_http_monitoring.http_check_frequency` et `maintenance_service_http_monitoring.maintenance_mode_duration` + - Créer `maintenance_service_http_monitoring/views/res_config_settings_views.xml` : + - Hériter de la vue settings de Maintenance (`maintenance.res_config_settings_view_form`) + - Ajouter un groupe "HTTP Service Monitoring" avec les deux champs + - S'assurer que le fichier est listé dans `__manifest__.py` data + + **Must NOT do**: + - Ne pas ajouter plus de 2 paramètres (fréquence + durée mode maintenance) + - Ne pas ajouter de paramètres par service (timeout custom, headers custom, etc.) + + **Recommended Agent Profile**: + - **Category**: `quick` + - Reason: Petit modèle + petite vue, pattern Odoo standard + - **Skills**: [] + - **Skills Evaluated but Omitted**: + - `frontend-ui-ux`: Pas de design custom, juste un formulaire Odoo standard + + **Parallelization**: + - **Can Run In Parallel**: YES (avec T1 si les __init__.py sont prêts) + - **Parallel Group**: Wave 1 (avec Task 1) + - **Blocks**: T3, T5 + - **Blocked By**: T1 (besoin du manifest et des __init__.py) + + **References** (CRITICAL): + + **Pattern References**: + - Aucun `res.config.settings` n'existe dans ce repo. Utiliser le pattern standard Odoo 16 : + ```python + class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + http_check_frequency = fields.Integer( + string="HTTP Check Frequency (hours)", + default=1, + config_parameter='maintenance_service_http_monitoring.http_check_frequency' + ) + ``` + + **External References**: + - Pattern Odoo 16 `res.config.settings` : le champ doit avoir `config_parameter=` pour persister dans `ir.config_parameter` + - Vue settings : hériter de `maintenance.res_config_settings_view_form` si elle existe, sinon créer une nouvelle section + + **WHY Each Reference Matters**: + - Le pattern `config_parameter=` est la façon standard Odoo 16 de lier un champ de settings à `ir.config_parameter`. Sans ça, la valeur n'est pas persistée entre les sessions + + **Acceptance Criteria**: + + **QA Scenarios (MANDATORY):** + + ``` + Scenario: Settings model syntaxiquement valide + Tool: Bash + Preconditions: res_config_settings.py créé + Steps: + 1. python3 -c "import ast; ast.parse(open('maintenance_service_http_monitoring/models/res_config_settings.py').read())" — valider syntaxe Python + 2. grep "config_parameter" maintenance_service_http_monitoring/models/res_config_settings.py — vérifier que les 2 champs ont config_parameter + 3. grep "_inherit" maintenance_service_http_monitoring/models/res_config_settings.py — vérifier héritage res.config.settings + Expected Result: Syntaxe OK, 2 occurrences de config_parameter, héritage correct + Failure Indicators: Erreur de syntaxe, config_parameter manquant + Evidence: .sisyphus/evidence/task-2-settings-model.txt + + Scenario: Vue settings XML bien formée + Tool: Bash + Preconditions: res_config_settings_views.xml créé + Steps: + 1. python3 -c "import xml.etree.ElementTree as ET; ET.parse('maintenance_service_http_monitoring/views/res_config_settings_views.xml')" — valider XML + 2. grep "http_check_frequency" maintenance_service_http_monitoring/views/res_config_settings_views.xml — vérifier champ présent + 3. grep "http_maintenance_mode_duration" maintenance_service_http_monitoring/views/res_config_settings_views.xml — vérifier champ présent + Expected Result: XML valide, les 2 champs référencés dans la vue + Failure Indicators: XML malformé, champ manquant + Evidence: .sisyphus/evidence/task-2-settings-view.txt + ``` + + **Commit**: YES (group with T1) + - Message: `feat(http_monitoring): add module settings for check frequency and maintenance mode duration` + - Files: `maintenance_service_http_monitoring/models/res_config_settings.py`, `maintenance_service_http_monitoring/views/res_config_settings_views.xml` + - Pre-commit: N/A + +--- + +- [ ] 3. Extension du modèle `service.instance` — champs + méthode HTTP check + + **What to do**: + - Créer `maintenance_service_http_monitoring/models/service_instance.py` : + - `_inherit = 'service.instance'` + - Champ `last_http_status_code` (Integer, readonly=True, string="Last HTTP Status Code") — dernier code HTTP reçu, -1 si erreur réseau + - Champ `last_http_check_date` (Datetime, readonly=True, string="Last HTTP Check Date") + - Champ `http_status_ok` (Boolean, readonly=True, string="HTTP Status OK", default=True) + - Méthode `check_http_status(self)` qui pour chaque record : + 1. Vérifie que `service_url` est non vide et que `equipment_id` existe + 2. Vérifie que l'équipement n'est PAS en mode maintenance + 3. Envoie `requests.get(self.service_url, timeout=HTTP_CHECK_TIMEOUT)` dans un try/except + 4. Si réponse 200 : `http_status_ok = True`, `last_http_status_code = 200` + 5. Si réponse autre : `http_status_ok = False`, `last_http_status_code = response.status_code` + 6. Si exception (timeout, DNS, SSL, connexion) : `http_status_ok = False`, `last_http_status_code = -1` + 7. Met à jour `last_http_check_date = fields.Datetime.now()` + 8. Si `http_status_ok == False` : appelle la logique de création de maintenance.request (déléguée à T4 sur equipment) + - Constante `HTTP_CHECK_TIMEOUT = 10` (secondes) en haut du fichier + - Méthode `@api.model cron_check_http_services(self)` : + 1. Recherche tous les `service.instance` avec `service_url != False` et `equipment_id != False` + 2. Filtre les équipements en mode maintenance + 3. Appelle `check_http_status()` sur les records filtrés + + **Must NOT do**: + - Ne PAS parser le body de la réponse HTTP + - Ne PAS suivre les redirects manuellement (laisser le comportement par défaut de `requests`) + - Ne PAS ajouter `mail.thread` à `service.instance` + - Ne PAS utiliser `requests.get()` sans `timeout=` + - Ne PAS attraper les exceptions silencieusement — logger le détail dans un champ ou dans les logs Odoo + - Ne PAS modifier `maintenance_server_data/models/service.py` + + **Recommended Agent Profile**: + - **Category**: `deep` + - Reason: Logique métier centrale du module, gestion d'erreurs réseau, interactions avec `requests`, pattern de vérification. Nécessite une implémentation soigneuse + - **Skills**: [] + - **Skills Evaluated but Omitted**: + - `playwright`: Pas de browser automation, c'est du HTTP backend + + **Parallelization**: + - **Can Run In Parallel**: YES (avec T4) + - **Parallel Group**: Wave 2 (avec Tasks 4, 5) + - **Blocks**: T5, T6, T8 + - **Blocked By**: T1, T2 + + **References** (CRITICAL): + + **Pattern References**: + - `maintenance_server_data/models/service.py:15-22` — Définition originale de `service.instance` : les 4 champs existants (`equipment_id`, `service_id`, `version_id`, `service_url`). C'est le modèle qu'on étend via `_inherit` + - `maintenance_server_monitoring/models/maintenance_equipment.py:128-218` — Pattern de la méthode `monitoring_test()` : comment itérer sur les records, exécuter des tests, écrire les logs, et déclencher la création de maintenance.request. S'en inspirer pour la structure générale mais NE PAS réutiliser la classe `MonitoringTest` + - `maintenance_server_monitoring/models/maintenance_equipment.py:122-126` — Pattern de la méthode cron `cron_monitoring_test()` : comment écrire une méthode `@api.model` appelée par le cron qui fait un `self.search([])` puis appelle la méthode de test + + **API/Type References**: + - `maintenance_server_data/models/maintenance_equipment.py:9` — Le champ `service_ids = fields.One2many("service.instance", "equipment_id")` montre la relation inverse : depuis un `service.instance`, on accède à l'équipement via `self.equipment_id` + + **External References**: + - `requests` library : `requests.get(url, timeout=10)` — retourne un `Response` object avec `.status_code` (int). Exceptions possibles : `requests.ConnectionError`, `requests.Timeout`, `requests.RequestException` (base class) + + **WHY Each Reference Matters**: + - La définition originale de `service.instance` montre qu'il n'y a aucune logique métier sur ce modèle — on part d'une base simple + - Le pattern `monitoring_test()` montre comment le repo gère déjà le monitoring : test → résultat → maintenance.request. On doit suivre la même philosophie + - Le champ `service_url` est un simple `Char` — il peut contenir n'importe quoi, donc il faut valider/essayer avec un try/except + + **Acceptance Criteria**: + + **QA Scenarios (MANDATORY):** + + ``` + Scenario: Modèle service.instance étendu correctement + Tool: Bash + Preconditions: service_instance.py créé + Steps: + 1. python3 -c "import ast; ast.parse(open('maintenance_service_http_monitoring/models/service_instance.py').read())" + 2. grep "last_http_status_code" maintenance_service_http_monitoring/models/service_instance.py + 3. grep "last_http_check_date" maintenance_service_http_monitoring/models/service_instance.py + 4. grep "http_status_ok" maintenance_service_http_monitoring/models/service_instance.py + 5. grep "timeout=" maintenance_service_http_monitoring/models/service_instance.py — vérifier que timeout est toujours présent sur requests.get + 6. grep "cron_check_http_services" maintenance_service_http_monitoring/models/service_instance.py + Expected Result: Syntaxe valide, 3 champs présents, timeout sur requests.get, méthode cron présente + Failure Indicators: Champ manquant, pas de timeout sur requests.get, erreur de syntaxe + Evidence: .sisyphus/evidence/task-3-service-instance-model.txt + + Scenario: Gestion d'erreurs réseau présente + Tool: Bash + Preconditions: service_instance.py créé + Steps: + 1. grep -c "except" maintenance_service_http_monitoring/models/service_instance.py — au moins 1 except block + 2. grep "RequestException\|ConnectionError\|Timeout\|Exception" maintenance_service_http_monitoring/models/service_instance.py — exceptions réseau gérées + 3. grep "\-1" maintenance_service_http_monitoring/models/service_instance.py — code -1 pour erreur réseau + Expected Result: Au moins 1 bloc except, exceptions réseau mentionnées, code -1 utilisé + Failure Indicators: Pas de gestion d'erreur, pas de code -1 + Evidence: .sisyphus/evidence/task-3-error-handling.txt + ``` + + **Commit**: YES + - Message: `feat(http_monitoring): add HTTP check logic on service.instance` + - Files: `maintenance_service_http_monitoring/models/service_instance.py` + - Pre-commit: `python3 -c "import ast; ast.parse(open('maintenance_service_http_monitoring/models/service_instance.py').read())"` + +--- + +- [ ] 4. Extension de `maintenance.equipment` — mode maintenance + http_maintenance_request + + **What to do**: + - Créer `maintenance_service_http_monitoring/models/maintenance_equipment.py` : + - `_inherit = 'maintenance.equipment'` + - Champ `maintenance_mode` (Boolean, string="Maintenance Mode", default=False, tracking=True) — tracking car `maintenance.equipment` hérite déjà `mail.thread` + - Champ `maintenance_mode_start` (Datetime, string="Maintenance Mode Start", readonly=True) + - Champ `maintenance_mode_end` (Datetime, string="Maintenance Mode End", readonly=True, help="Computed from start + configured duration") + - Champ `http_maintenance_request` (Many2one to `maintenance.request`, string="HTTP Maintenance Request") + - Méthode `action_activate_maintenance_mode(self)` : + 1. Lit la durée depuis `ir.config_parameter` : `maintenance_service_http_monitoring.maintenance_mode_duration` (default 4h) + 2. Set `maintenance_mode = True` + 3. Set `maintenance_mode_start = fields.Datetime.now()` + 4. Set `maintenance_mode_end = now + timedelta(hours=duration)` + - Méthode `action_deactivate_maintenance_mode(self)` : + 1. Set `maintenance_mode = False` + 2. Clear `maintenance_mode_start` et `maintenance_mode_end` + - Méthode `@api.model cron_deactivate_expired_maintenance_mode(self)` : + 1. Recherche les équipements où `maintenance_mode = True` et `maintenance_mode_end <= now` + 2. Appelle `action_deactivate_maintenance_mode()` sur ces records + - Méthode `create_http_maintenance_request(self, ko_services)` : + 1. Vérifie si `http_maintenance_request` existe ET n'est pas done (`stage_id.done`) + 2. Si pas de request ouverte : crée une `maintenance.request` avec : + - `name`: `[HTTP KO] {equipment.name}` + - `equipment_id`: `self.id` + - `description`: Liste des services KO avec leur URL et code de statut + - `priority`: `'2'` (haute) + - `maintenance_type`: `'corrective'` + - Assignation : `employee_id`, `technician_user_id`, `maintenance_team_id` (même pattern que `maintenance_server_monitoring`) + 3. Stocke la référence dans `http_maintenance_request` + + **Must NOT do**: + - Ne PAS modifier le champ existant `error_maintenance_request` ni `warning_maintenance_request` (ceux-ci appartiennent au monitoring infra) + - Ne PAS ajouter de logique HTTP dans ce fichier (la logique HTTP est dans `service_instance.py`) + - Ne PAS auto-fermer la maintenance.request quand les services repassent OK + + **Recommended Agent Profile**: + - **Category**: `unspecified-high` + - Reason: Logique de mode maintenance avec auto-expiry, création de maintenance.request, interactions avec ir.config_parameter. Pas ultra-complexe mais nécessite rigueur + - **Skills**: [] + - **Skills Evaluated but Omitted**: + - `git-master`: Pas de commit dans cette tâche seule + + **Parallelization**: + - **Can Run In Parallel**: YES (avec T3 et T5) + - **Parallel Group**: Wave 2 (avec Tasks 3, 5) + - **Blocks**: T7, T8 + - **Blocked By**: T1 + + **References** (CRITICAL): + + **Pattern References**: + - `maintenance_server_monitoring/models/maintenance_equipment.py:194-218` — **PATTERN CLÉ** : Création de `maintenance.request` avec vérification de doublon. Reproduire EXACTEMENT ce pattern : vérifier `stage_id.done` avant de créer, assigner `employee_id`, `technician_user_id`, `maintenance_team_id`. Utiliser le même fallback `self.env["maintenance.team"].search([], limit=1)` si pas de team assignée + - `maintenance_server_monitoring/models/maintenance_equipment.py:37-53` — Champs existants sur equipment pour comprendre la convention de nommage (readonly, strings) + - `maintenance_server_monitoring/models/maintenance_equipment.py:52-53` — Champs `error_maintenance_request` et `warning_maintenance_request` : même type de champ Many2one vers `maintenance.request`. Le nouveau `http_maintenance_request` suit le même pattern + + **API/Type References**: + - `maintenance.request` fields utilisés dans la création : `name`, `equipment_id`, `employee_id`, `user_id`, `maintenance_team_id`, `priority`, `maintenance_type`, `description` + + **WHY Each Reference Matters**: + - Le pattern de création de maintenance.request (lignes 194-218) est LE pattern à reproduire — c'est la logique anti-doublon qui évite de spammer les requests + - Les champs existants sur equipment montrent la convention du repo (readonly pour les champs calculés, tracking quand pertinent) + + **Acceptance Criteria**: + + **QA Scenarios (MANDATORY):** + + ``` + Scenario: Champs equipment ajoutés correctement + Tool: Bash + Preconditions: maintenance_equipment.py créé + Steps: + 1. python3 -c "import ast; ast.parse(open('maintenance_service_http_monitoring/models/maintenance_equipment.py').read())" + 2. grep "maintenance_mode" maintenance_service_http_monitoring/models/maintenance_equipment.py + 3. grep "maintenance_mode_start" maintenance_service_http_monitoring/models/maintenance_equipment.py + 4. grep "maintenance_mode_end" maintenance_service_http_monitoring/models/maintenance_equipment.py + 5. grep "http_maintenance_request" maintenance_service_http_monitoring/models/maintenance_equipment.py + 6. grep "tracking=True" maintenance_service_http_monitoring/models/maintenance_equipment.py — vérifier tracking sur maintenance_mode + Expected Result: Syntaxe valide, 4 champs présents, tracking activé + Failure Indicators: Champ manquant, pas de tracking + Evidence: .sisyphus/evidence/task-4-equipment-fields.txt + + Scenario: Pattern maintenance.request suivi + Tool: Bash + Preconditions: maintenance_equipment.py créé + Steps: + 1. grep "stage_id.done" maintenance_service_http_monitoring/models/maintenance_equipment.py — vérification anti-doublon + 2. grep "maintenance.request" maintenance_service_http_monitoring/models/maintenance_equipment.py — création de request + 3. grep "maintenance_team_id" maintenance_service_http_monitoring/models/maintenance_equipment.py — assignation team + 4. grep "corrective" maintenance_service_http_monitoring/models/maintenance_equipment.py — type maintenance + Expected Result: Vérification doublon via stage_id.done, création request, assignation team, type corrective + Failure Indicators: Pas de vérification anti-doublon, pas d'assignation + Evidence: .sisyphus/evidence/task-4-request-pattern.txt + + Scenario: Auto-expiry maintenance mode + Tool: Bash + Preconditions: maintenance_equipment.py créé + Steps: + 1. grep "cron_deactivate_expired_maintenance_mode" maintenance_service_http_monitoring/models/maintenance_equipment.py + 2. grep "timedelta" maintenance_service_http_monitoring/models/maintenance_equipment.py — calcul de la date de fin + 3. grep "ir.config_parameter" maintenance_service_http_monitoring/models/maintenance_equipment.py — lecture de la durée depuis les settings + Expected Result: Méthode cron d'expiry présente, calcul timedelta, lecture paramètre + Failure Indicators: Méthode manquante, pas de calcul de date + Evidence: .sisyphus/evidence/task-4-maintenance-mode-expiry.txt + ``` + + **Commit**: YES + - Message: `feat(http_monitoring): add maintenance mode and HTTP request tracking on equipment` + - Files: `maintenance_service_http_monitoring/models/maintenance_equipment.py` + - Pre-commit: `python3 -c "import ast; ast.parse(open('maintenance_service_http_monitoring/models/maintenance_equipment.py').read())"` + +--- + +- [ ] 5. Cron HTTP monitoring (XML) + + **What to do**: + - Créer `maintenance_service_http_monitoring/data/cron.xml` avec 2 crons : + 1. **Cron HTTP check** : + - `id`: `ir_cron_http_service_monitoring` + - `name`: `HTTP Service Monitoring : check all services` + - `model_id`: ref vers `model_service_instance` + - `code`: `model.cron_check_http_services()` + - `interval_number`: `1` + - `interval_type`: `hours` + - `numbercall`: `-1` + - `doall`: `False` + 2. **Cron maintenance mode expiry** : + - `id`: `ir_cron_maintenance_mode_expiry` + - `name`: `HTTP Service Monitoring : deactivate expired maintenance mode` + - `model_id`: ref vers `model_maintenance_equipment` + - `code`: `model.cron_deactivate_expired_maintenance_mode()` + - `interval_number`: `15` + - `interval_type`: `minutes` + - `numbercall`: `-1` + - `doall`: `False` + - S'assurer que `data/cron.xml` est listé dans `__manifest__.py` data (après les views) + + **Must NOT do**: + - Ne PAS modifier le cron existant `ir_cron_server_monitoring` dans `maintenance_server_monitoring` + - Ne PAS mettre une fréquence trop basse (< 15 minutes) pour le cron d'expiry + + **Recommended Agent Profile**: + - **Category**: `quick` + - Reason: Fichier XML simple suivant un pattern existant + - **Skills**: [] + + **Parallelization**: + - **Can Run In Parallel**: YES (avec T3 et T4) + - **Parallel Group**: Wave 2 (avec Tasks 3, 4) + - **Blocks**: T8 + - **Blocked By**: T1, T2, T3 (le cron appelle des méthodes définies dans T3) + + **References** (CRITICAL): + + **Pattern References**: + - `maintenance_server_monitoring/data/cron.xml:1-12` — **Pattern exact** à reproduire pour le format XML du cron. Même structure ``, mêmes champs. Adapter `model_id`, `code`, `interval_number`, `interval_type` + + **WHY Each Reference Matters**: + - Le format du cron XML doit être EXACTEMENT celui d'Odoo 16 sinon le module ne s'installe pas. Le fichier existant montre le format validé + + **Acceptance Criteria**: + + **QA Scenarios (MANDATORY):** + + ``` + Scenario: Crons XML bien formés + Tool: Bash + Preconditions: data/cron.xml créé + Steps: + 1. python3 -c "import xml.etree.ElementTree as ET; ET.parse('maintenance_service_http_monitoring/data/cron.xml')" + 2. grep "ir_cron_http_service_monitoring" maintenance_service_http_monitoring/data/cron.xml + 3. grep "ir_cron_maintenance_mode_expiry" maintenance_service_http_monitoring/data/cron.xml + 4. grep "cron_check_http_services" maintenance_service_http_monitoring/data/cron.xml + 5. grep "cron_deactivate_expired_maintenance_mode" maintenance_service_http_monitoring/data/cron.xml + 6. grep "hours" maintenance_service_http_monitoring/data/cron.xml — intervalle HTTP check + 7. grep "minutes" maintenance_service_http_monitoring/data/cron.xml — intervalle expiry + Expected Result: XML valide, 2 crons présents avec les bons IDs et méthodes + Failure Indicators: XML malformé, cron manquant, mauvaise méthode référencée + Evidence: .sisyphus/evidence/task-5-cron-xml.txt + ``` + + **Commit**: YES + - Message: `feat(http_monitoring): add HTTP check and maintenance mode expiry crons` + - Files: `maintenance_service_http_monitoring/data/cron.xml` + - Pre-commit: N/A + +--- + +- [ ] 6. Vue liste `service.instance` (tree + action + menu) + + **What to do**: + - Créer `maintenance_service_http_monitoring/views/service_instance_views.xml` : + - **Tree view** `service_instance_http_monitoring_tree` : + - Colonnes : `equipment_id`, `service_id` (nom du service), `version_id`, `service_url`, `last_http_check_date`, `last_http_status_code`, `http_status_ok` + - Décoration conditionnelle : `decoration-danger="http_status_ok == False"` pour les lignes KO + - **Action** `service_instance_http_monitoring_action` : + - `res_model`: `service.instance` + - `view_mode`: `tree` + - `view_id`: ref vers la tree view ci-dessus + - `domain`: `[('service_url', '!=', False)]` — ne montrer que les services avec une URL + - Texte d'aide pour la vue vide + - **Menu item** : + - `parent`: `maintenance.menu_maintenance_title` (menu principal Maintenance) + - `action`: ref vers l'action ci-dessus + - `sequence`: adapté pour apparaître après "Equipments" et "Maintenance Requests" + - `name`: `Services HTTP Monitoring` (ou similaire) + - S'assurer que le fichier est listé dans `__manifest__.py` data + + **Must NOT do**: + - Ne PAS créer de form view, kanban, pivot ou graph + - Ne PAS ajouter de search panel complexe + - Ne PAS modifier les vues existantes dans `maintenance_server_data` + + **Recommended Agent Profile**: + - **Category**: `quick` + - Reason: Vue XML standard, pas de logique complexe + - **Skills**: [] + - **Skills Evaluated but Omitted**: + - `frontend-ui-ux`: Pas de design custom, c'est une tree view Odoo standard + + **Parallelization**: + - **Can Run In Parallel**: YES (avec T7) + - **Parallel Group**: Wave 3 (avec Task 7) + - **Blocks**: T8 + - **Blocked By**: T3 (les champs de la tree view sont définis dans T3) + + **References** (CRITICAL): + + **Pattern References**: + - `maintenance_server_data/views/service.xml:4-12` — Tree view existante de `service` : format exact d'une tree view pour un modèle service. Pattern à suivre pour la structure XML + - `maintenance_server_data/views/service.xml:37-47` — Action existante pour `service` : format d'un `ir.actions.act_window`. Reproduire la structure + - `maintenance_server_data/views/service.xml:74-93` — Menus existants : comment les menus sont enregistrés sous `maintenance.menu_maintenance_configuration`. Notre menu ira sous `maintenance.menu_maintenance_title` (un niveau plus haut) + - `maintenance_server_monitoring/views/maintenance_equipment_views.xml:27-39` — Tree view avec `optional="hide"` : pattern pour les colonnes optionnelles + + **WHY Each Reference Matters**: + - Les vues service existantes montrent le format XML exact utilisé dans ce repo + - Le menu existant montre la hiérarchie des menus Maintenance — notre menu doit se placer au bon niveau + - Le pattern `decoration-danger` est standard Odoo pour colorer les lignes en rouge + + **Acceptance Criteria**: + + **QA Scenarios (MANDATORY):** + + ``` + Scenario: Vue XML bien formée avec toutes les colonnes + Tool: Bash + Preconditions: service_instance_views.xml créé + Steps: + 1. python3 -c "import xml.etree.ElementTree as ET; ET.parse('maintenance_service_http_monitoring/views/service_instance_views.xml')" + 2. grep "last_http_status_code" maintenance_service_http_monitoring/views/service_instance_views.xml + 3. grep "last_http_check_date" maintenance_service_http_monitoring/views/service_instance_views.xml + 4. grep "http_status_ok" maintenance_service_http_monitoring/views/service_instance_views.xml + 5. grep "service_url" maintenance_service_http_monitoring/views/service_instance_views.xml + 6. grep "decoration-danger" maintenance_service_http_monitoring/views/service_instance_views.xml + 7. grep "menuitem" maintenance_service_http_monitoring/views/service_instance_views.xml + Expected Result: XML valide, toutes les colonnes monitoring présentes, décoration conditionnelle, menu item + Failure Indicators: XML malformé, colonne manquante, pas de menu + Evidence: .sisyphus/evidence/task-6-service-views.txt + ``` + + **Commit**: YES + - Message: `feat(http_monitoring): add service instance list view with HTTP monitoring columns` + - Files: `maintenance_service_http_monitoring/views/service_instance_views.xml` + - Pre-commit: N/A + +--- + +- [ ] 7. Vue equipment — bandeau mode maintenance + + **What to do**: + - Créer `maintenance_service_http_monitoring/views/maintenance_equipment_views.xml` : + - **Form view** (hérite de `maintenance.hr_equipment_view_form`) : + - **Banner** : widget `web_ribbon` ou `div` conditionnel en haut du formulaire, visible quand `maintenance_mode == True` + - Texte : "Mode maintenance actif — Vérifications HTTP désactivées" + - Afficher la date de fin prévue (`maintenance_mode_end`) + - **Boutons** dans le header ou dans un groupe : + - Bouton "Activer le mode maintenance" (`action_activate_maintenance_mode`) visible si `maintenance_mode == False` + - Bouton "Désactiver le mode maintenance" (`action_deactivate_maintenance_mode`) visible si `maintenance_mode == True` + - **Champs** dans un groupe ou dans l'onglet Monitoring existant : + - `maintenance_mode` (si pas déjà montré via le bandeau) + - `maintenance_mode_start` (readonly) + - `maintenance_mode_end` (readonly) + - `http_maintenance_request` (readonly, lien cliquable vers la maintenance.request) + - **Tree view** (optionnel) : ajouter `maintenance_mode` comme colonne optionnelle dans la liste des équipements + + **Must NOT do**: + - Ne PAS modifier la vue existante dans `maintenance_server_monitoring/views/maintenance_equipment_views.xml` + - Ne PAS modifier la vue existante dans `maintenance_server_data/views/maintenance_equipment.xml` + - Ne PAS ajouter de JS/OWL custom pour le bandeau — utiliser les widgets XML standard d'Odoo + + **Recommended Agent Profile**: + - **Category**: `quick` + - Reason: Vue XML standard avec héritage, pas de logique complexe + - **Skills**: [] + + **Parallelization**: + - **Can Run In Parallel**: YES (avec T6) + - **Parallel Group**: Wave 3 (avec Task 6) + - **Blocks**: T8 + - **Blocked By**: T4 (les champs sont définis dans T4) + + **References** (CRITICAL): + + **Pattern References**: + - `maintenance_server_monitoring/views/maintenance_equipment_views.xml:3-24` — **Pattern exact** d'héritage de la form view equipment. Utilise `xpath expr="//notebook" position="inside"` pour ajouter un onglet. Pour le bandeau, utiliser `xpath expr="//sheet" position="before"` ou similaire + - `maintenance_server_data/views/maintenance_equipment.xml:3-35` — Autre héritage de la même form view, montre comment utiliser différents `xpath` positions + - `maintenance_server_monitoring/views/maintenance_equipment_views.xml:27-39` — Pattern tree view héritage avec `optional="hide"` + + **External References**: + - Odoo 16 banner/ribbon patterns : `