702 lines
40 KiB
Markdown
702 lines
40 KiB
Markdown
# MOBILE FUNCTIONAL STATUS — État fonctionnel actuel de l'application mobile
|
|
|
|
> **Bilan fonctionnel global** de l'application mobile Omika, tel qu'il est
|
|
> réellement implémenté et validé aujourd'hui. Ce document décrit **ce que
|
|
> l'utilisateur peut réellement faire**, ce qui est en lecture seule, ce qui sait
|
|
> écrire offline, ce qui manque, ce qui est bloqué backend et ce qui reste à
|
|
> développer.
|
|
>
|
|
> Ce document est **orienté fonctionnel** : il ne remplace pas
|
|
> `docs/LOT_MOBILE_0.md` (architecture technique, décisions, principes
|
|
> offline-first, SQLite, Sync, identités, Design System). Il ne duplique pas son
|
|
> contenu.
|
|
>
|
|
> Aucun code de production n'est modifié par ce document.
|
|
|
|
---
|
|
|
|
## 1. Vue d'ensemble — ce que l'utilisateur peut faire aujourd'hui
|
|
|
|
L'application mobile Omika est aujourd'hui une application **de consultation
|
|
offline** du dernier snapshot métier synchronisé. L'utilisateur peut :
|
|
|
|
- **Naviguer** entre les écrans (Agenda, Interventions, Dossiers, Équipe,
|
|
Clients, Sites, Paramètres) via une barre latérale (desktop/tablette) ou une
|
|
barre basse + menu « Plus » (smartphone).
|
|
- **Consulter** l'agenda du jour et le détail d'un rendez-vous.
|
|
- **Consulter** la liste des interventions, les rechercher localement, filtrer
|
|
les archivées, et ouvrir la fiche d'une intervention.
|
|
- **Consulter** les dossiers, clients, sites et collaborateurs (liste + détail).
|
|
- **Consulter** les contacts liés à une intervention et le détail d'un contact.
|
|
- **Consulter** les documents / photos d'une intervention, les **télécharger à
|
|
la demande**, les **ouvrir offline** s'ils sont en cache, et **en ajouter**
|
|
(photo ou document) **offline-first**.
|
|
- **Créer, modifier et archiver une intervention** **offline-first** (formulaire
|
|
partagé Create/Edit, bouton Nouvelle Intervention, action Modifier, action
|
|
Archiver avec confirmation, aucun DELETE).
|
|
- **Synchroniser** manuellement via « Synchroniser maintenant ».
|
|
- **Personnaliser** le thème (clair / sombre / système) et la couleur principale.
|
|
|
|
L'utilisateur **ne peut pas** aujourd'hui : créer/modifier un rendez-vous, un
|
|
dossier, un client, un site ou un collaborateur ; saisir des temps ; rédiger des
|
|
notes ; créer un compte rendu ou un rapport ; envoyer un email ; utiliser le
|
|
GPS ; réinitialiser l'application ; purger le cache depuis l'UI.
|
|
|
|
> **Note importante (vérification Sync)** : le **backend + Sync supportent déjà
|
|
> réellement** la création, la modification et l'archivage d'une **Intervention**
|
|
> (handler `InterventionSyncOperationHandler`, contrat `InterventionSyncPayload`,
|
|
> pipeline SUCCESS/REJECTED). L'**UI + mutation locale** Intervention est
|
|
> **réalisée** (formulaire Create/Edit, bouton Nouvelle Intervention, action
|
|
> Modifier, action Archiver avec confirmation, aucun DELETE, protection double
|
|
> Save, navigation contextuelle, états Pending/Rejected affichés). Les autres
|
|
> entités (RendezVous, Dossier, Client, Site, Collaborateur) ne disposent
|
|
> **d'aucun** handler Sync ni payload : elles restent bloquées backend.
|
|
|
|
|
|
---
|
|
|
|
## 2. Matrice fonctionnelle synthétique
|
|
|
|
Légende des états :
|
|
|
|
| État | Signification |
|
|
|------|---------------|
|
|
| **REAL** | Fonctionnalité réellement implémentée et utilisable |
|
|
| **PARTIAL** | Partiellement implémentée (une partie seulement du périmètre maquette) |
|
|
| **READ-ONLY** | Consultation seule, aucune écriture |
|
|
| **BLOCKED** | Bloqué par un prérequis backend / snapshot / sync manquant |
|
|
| **NOT IMPLEMENTED** | Non implémenté (aucun parcours utilisateur) |
|
|
| **PLACEHOLDER** | Écran d'attente « Fonctionnalité à venir » |
|
|
|
|
| Domaine | Fonctionnalité | État | Offline | Écriture | Réseau requis | Backend requis | Commentaire |
|
|
|---------|----------------|------|---------|----------|---------------|----------------|-------------|
|
|
| Shell / navigation | Navigation entre écrans | **REAL** | Oui | Non | Non | Non | Barre latérale + barre basse + menu « Plus » |
|
|
| Shell / navigation | Thème clair / sombre / système | **REAL** | Oui | Non | Non | Non | Persisté localement |
|
|
| Shell / navigation | Couleur principale | **REAL** | Oui | Non | Non | Non | Presets + personnalisée, persistée |
|
|
| Agenda | Liste des rendez-vous du jour | **REAL** | Oui | Non | Non | Non | Lecture SQLite |
|
|
| Agenda | Navigation jour précédent / suivant | **REAL** | Oui | Non | Non | Non | — |
|
|
| RendezVous | Détail d'un rendez-vous | **REAL** | Oui | Non | Non | Non | Lecture seule |
|
|
| RendezVous | Saisie des temps (accès) | **REAL** (UI CREATE) | Oui | **Oui** | Non (offline-first) | Oui | Accès contextuel RendezVous → liste filtrée → Nouvelle saisie (RendezVousId prérempli) — voir section 7 |
|
|
| RendezVous | Annulation / modification | **NOT IMPLEMENTED** | — | — | — | Oui | Aucun handler Sync RendezVous |
|
|
|
|
| Interventions | Liste des interventions | **REAL** | Oui | Non | Non | Non | Lecture SQLite |
|
|
| Interventions | Recherche locale | **REAL** | Oui | Non | Non | Non | Reference, Titre, ClientNom, SiteNom, DossierReference |
|
|
| Interventions | Filtre Actif / Archivé | **REAL** | Oui | Non | Non | Non | Basé sur `EstArchive` |
|
|
| Interventions | Fiche intervention | **REAL** | Oui | Non | Non | Non | Client/Site/Dossier/RendezVous/Documents |
|
|
| Interventions | Rendez-vous liés | **REAL** | Oui | Non | Non | Non | Liste + tri chronologique |
|
|
| Interventions | Création / modification Intervention | **REAL** (UI + mutation locale) | Oui | **Oui** | Non (offline-first) | Oui | **Backend + Sync SUPPORTED** ; UI Create/Edit + mutation locale + Outbox implémentées (CREATE/UPDATE/ARCHIVE), aucun DELETE |
|
|
| Interventions | Archiver une intervention | **REAL** (UI + mutation locale) | Oui | **Oui** | Non (offline-first) | Oui | Action Archiver + confirmation, `ArchiveAsync` via `IInterventionLocalService`, aucun DELETE |
|
|
| Interventions | État Sync (Pending / Rejected) | **REAL** | Oui | Non | Non | Non | Affiché sur la fiche à partir des vraies données Outbox (`IsPendingSync`, `HasSyncError`, `SyncErrorMessage`) |
|
|
|
|
|
|
| Documents / Photos | Liste des documents d'une intervention | **REAL** | Oui | Non | Non | Non | Métadonnées SQLite |
|
|
| Documents / Photos | Téléchargement à la demande | **REAL** | Non | Non | **Oui** | Oui | HTTP `GET /api/documents/{guid}` |
|
|
| Documents / Photos | Ouverture offline | **REAL** | Oui | Non | Non | Non | Si présent en cache |
|
|
| Documents / Photos | Ajout photo / document | **REAL** | Oui | **Oui** | Non (offline-first) | Oui | Outbox + SyncEngine |
|
|
| Contacts | Contacts liés à une intervention | **REAL** | Oui | Non | Non | Non | Relation `ContactIds` explicite |
|
|
| Contacts | Détail d'un contact | **REAL** | Oui | Non | Non | Non | Téléphone / email plateforme |
|
|
| Dossiers | Liste des dossiers | **REAL** | Oui | Non | Non | Non | Lecture SQLite |
|
|
| Dossiers | Détail d'un dossier | **REAL** | Oui | Non | Non | Non | Interventions liées |
|
|
| Dossiers | Création / modification Dossier | **NOT IMPLEMENTED** | — | — | — | Oui | Aucun handler Sync Dossier |
|
|
| Clients | Liste des clients | **REAL** | Oui | Non | Non | Non | Lecture SQLite |
|
|
| Clients | Détail d'un client | **REAL** | Oui | Non | Non | Non | Sites, contacts, dossiers, interventions |
|
|
| Clients | Création / modification Client | **NOT IMPLEMENTED** | — | — | — | Oui | Aucun handler Sync Client |
|
|
| Sites / Lieux | Liste des sites | **REAL** | Oui | Non | Non | Non | Lecture SQLite |
|
|
| Sites / Lieux | Détail d'un site | **REAL** | Oui | Non | Non | Non | Client, contacts, interventions |
|
|
| Sites / Lieux | GPS / itinéraire | **NOT IMPLEMENTED** | — | — | — | Non | — |
|
|
| Équipe / Collaborateurs | Liste des collaborateurs | **REAL** | Oui | Non | Non | Non | Lecture SQLite |
|
|
| Équipe / Collaborateurs | Détail d'un collaborateur | **REAL** | Oui | Non | Non | Non | Rendez-vous + interventions liés |
|
|
| Paramètres | Thème / couleur / version | **REAL** | Oui | Non | Non | Non | — |
|
|
| Paramètres | Synchroniser maintenant | **REAL** | Non | Non | **Oui** | Oui | Via SyncEngine |
|
|
| Paramètres | Purge cache | **NOT IMPLEMENTED** (UI) | — | — | — | — | `PurgeAsync` existe ; problème technique mobile uniquement |
|
|
| Paramètres | Reset application | **NOT IMPLEMENTED** (UI) | — | — | — | — | Primitives locales existent ; dépendance protection Outbox |
|
|
| Paramètres | Licence / activation | **REAL** | Oui | Non | Non | Oui | Activation par code client + n° licence ; session + token sécurisé ; identité affichée |
|
|
|
|
| Synchronisation | Synchronisation manuelle | **REAL** | Non | Non | **Oui** | Oui | SyncEngine + Outbox |
|
|
| Synchronisation | État de synchronisation | **REAL** | Oui | Non | Non | Non | Idle / Syncing / Synced / Offline / Error |
|
|
| Notes Intervention | Lecture / écriture notes | **NOT IMPLEMENTED** | — | — | — | Oui | CAS E — voir section 6 |
|
|
| SuiviTemps | Consultation des temps | **REAL** (UI LIST) | Oui | Non | Non | Non | Liste offline via `ISuiviTempsLocalService` (PHASE 3) — voir section 7 |
|
|
| SuiviTemps | Saisie des temps | **REAL** (UI CREATE) | Oui | **Oui** | Non (offline-first) | Oui | **UI CREATE READY** — formulaire offline-first via `ISuiviTempsLocalService.CreateAsync` ; TypeTemps depuis `IParametreMetierLocalService.GetTypeTempsAsync()` (Key = PA_CLE) ; aucun UPDATE/ARCHIVE/DELETE — voir section 7 |
|
|
|
|
|
|
| Rapports / CompteRendu | Création / consultation | **NOT IMPLEMENTED** | — | — | — | Oui | Backend only — voir section 8 |
|
|
|
|
---
|
|
|
|
## 3. Écritures offline réellement opérationnelles
|
|
|
|
La seule écriture offline réellement opérationnelle aujourd'hui est
|
|
**l'ajout de documents / photos** à une intervention.
|
|
|
|
### 3.1 Ajout d'une photo ou d'un document (offline-first)
|
|
|
|
Ce que fait l'utilisateur :
|
|
|
|
1. Depuis la fiche intervention, il ouvre l'écran **Documents / Photos**.
|
|
2. Il choisit **Ajouter une photo** ou **Ajouter un document** (sélecteur de
|
|
fichier plateforme).
|
|
3. Le fichier est immédiatement visible dans la liste, marqué comme en attente
|
|
de synchronisation.
|
|
|
|
Ce qui se passe techniquement (chaîne complète vérifiée) :
|
|
|
|
| Étape | Détail |
|
|
|-------|--------|
|
|
| **Mutation SQLite** | Copie du fichier dans l'espace contrôlé de l'application + création de la métadonnée locale `LocalDocumentMetadata` (payload `DocumentSummaryDto`) |
|
|
| **Outbox** | Création d'une opération `OutboxOperation` (`EntityType = Document`, `OperationType = Create`, état `Pending`) |
|
|
| **OperationId** | `Guid.NewGuid()` — distinct du GUID métier |
|
|
| **GUID métier** | `DocumentGuid` (identité publique du document) |
|
|
| **SyncEngine** | À la synchronisation, l'opération Document est envoyée via `POST /api/documents` (multipart) |
|
|
| **SUCCESS** | L'opération passe à l'état `Succeeded` ; le document est marqué synchronisé |
|
|
| **REJECTED** | L'opération passe à l'état `Rejected` ; l'erreur est affichée dans l'UI |
|
|
|
|
Le `DocumentGuid` est **distinct** de l'`OperationId` : le GUID métier identifie
|
|
le document, l'OperationId identifie la transaction de synchronisation.
|
|
|
|
> **Important** : la capacité générique de l'Outbox n'est pas une fonctionnalité
|
|
> utilisateur en soi. Seule l'écriture **Documents / Photos** est réellement
|
|
> branchée de bout en bout (UI → SQLite → Outbox → SyncEngine → backend).
|
|
|
|
---
|
|
|
|
## 4. Domaines actuellement en lecture seule
|
|
|
|
Les domaines suivants sont **strictement en lecture seule** : aucune écriture,
|
|
aucune Outbox, aucun CREATE / UPDATE / DELETE / ARCHIVE depuis le mobile.
|
|
|
|
| Domaine | État réel | Détail |
|
|
|---------|-----------|--------|
|
|
| **RendezVous** | READ-ONLY | Consultation du détail uniquement |
|
|
| **Intervention** | WRITE (mutation locale) | Liste, recherche, filtre, fiche, relations. **Backend + Sync SUPPORTED** pour CREATE/UPDATE/ARCHIVE ; mutation locale + Outbox implémentées (service `InterventionLocalService`) |
|
|
|
|
| **Dossier** | READ-ONLY | Liste + détail |
|
|
| **Client** | READ-ONLY | Liste + détail |
|
|
| **Site / Lieu** | READ-ONLY | Liste + détail |
|
|
| **Collaborateur** | READ-ONLY | Liste + détail |
|
|
| **Contact** | READ-ONLY | Liste + détail (téléphone / email plateforme) |
|
|
|
|
Aucune de ces entités ne dispose d'une écriture mobile **branchée à l'UI**. Les
|
|
données proviennent exclusivement du snapshot synchronisé.
|
|
|
|
> **Capacité Sync réelle** : seul **Intervention** dispose d'un handler Sync
|
|
> (`InterventionSyncOperationHandler`) et d'un contrat public
|
|
> (`InterventionSyncPayload`). Les autres entités (RendezVous, Dossier, Client,
|
|
> Site, Collaborateur) n'ont **aucun** handler ni payload : toute opération Sync
|
|
> sur ces types est rejetée (`NO_HANDLER` → REJECTED).
|
|
|
|
---
|
|
|
|
## 5. Synchronisation, Offline, SQLite, Outbox, cache Documents
|
|
|
|
### 5.1 Synchronisation
|
|
|
|
- **Déclenchement** : manuel via « Synchroniser maintenant » (Paramètres ou
|
|
Shell). Aucune synchronisation automatique périodique.
|
|
- **Moteur** : `SyncEngine` (unique système de mise à jour).
|
|
- **États UI** : `Idle`, `Syncing`, `Synced`, `Offline`, `Error`.
|
|
- **Hors ligne** : aucun appel réseau, état non intrusif (« Hors ligne »).
|
|
- **Erreurs** : nombre d'opérations rejetées / anomalies affiché.
|
|
|
|
### 5.2 Offline / SQLite
|
|
|
|
- Toutes les lectures (liste, fiche, contacts, documents) se font depuis SQLite
|
|
(dernier snapshot).
|
|
- Aucun appel HTTP obligatoire à l'ouverture d'un écran.
|
|
- Le snapshot est reconstruit atomiquement depuis le backend.
|
|
|
|
### 5.3 Outbox
|
|
|
|
- L'Outbox est opérationnelle pour **Documents / Photos** uniquement.
|
|
- Les opérations sont envoyées à la synchronisation, avec états
|
|
`Pending` / `Sending` / `Accepted` / `WaitingResult` / `Succeeded` / `Rejected`.
|
|
- Le mécanisme d'identité `RequestedEntityGuid` / `CanonicalEntityGuid` est
|
|
opérationnel : après un CREATE réussi, le backend retourne le GUID canonique
|
|
(GUID physique Omika ou GUID synthétique réversible Batik), réconcilié côté
|
|
mobile pour les opérations suivantes (UPDATE/ARCHIVE).
|
|
|
|
### 5.4 Cache Documents
|
|
|
|
- Les documents téléchargés sont stockés dans un cache fichier local
|
|
(`DocumentCacheService`).
|
|
- L'ouverture offline est possible si le fichier est présent en cache.
|
|
- **Purge du cache** : la capacité technique `PurgeAsync` existe dans
|
|
`DocumentCacheService`, mais **n'est pas branchée à une interface utilisateur**.
|
|
Aucun bouton « Purger le cache » n'est accessible à l'utilisateur.
|
|
|
|
---
|
|
|
|
## 6. Notes Intervention — état démontré (CAS E)
|
|
|
|
État **déjà démontré**, aucune décision n'est réouverte :
|
|
|
|
- **Aucune Note Intervention exploitable** dans le snapshot / local.
|
|
- **Aucune table SQLite Note**.
|
|
- **Aucune UI** Notes.
|
|
- `CompteRendu` existe côté backend mais **n'est pas peuplé** dans le snapshot.
|
|
- `MessageInterne` / `IN_NoteInterne` restent **backend** (non exposés au mobile).
|
|
- `DocumentNote` est un **concept différent** (document, pas note d'intervention).
|
|
|
|
**État fonctionnel** : `NOT IMPLEMENTED` (bloqué backend — données absentes du
|
|
snapshot).
|
|
|
|
**Classification** : **C — BACKEND + MOBILE** (snapshot / SQLite / Sync manquant)
|
|
+ **D** uniquement pour la décision de représentation métier exacte (Note vs
|
|
DocumentNote). `DocumentNote` reste distinct.
|
|
|
|
---
|
|
|
|
## 7. Suivi des temps — état démontré (CAS C)
|
|
|
|
État **déjà démontré**, aucune décision n'est réouverte :
|
|
|
|
- L'entité métier `SuiviTemps` est **réelle** côté backend.
|
|
- Les relations Intervention / RendezVous / Collaborateur existent.
|
|
- **Présent dans le snapshot** mobile (PHASE 1B) : le `MobileSnapshotResponse`
|
|
expose désormais `SuivisTemps` (liste de `SuiviTempsDto`, lecture seule,
|
|
réutilisant le DTO métier public — aucune colonne HFSQL exposée). Le GUID
|
|
exposé est le **GUID physique existant** (Batik et Omika), aucun GUID
|
|
synthétique n'est créé.
|
|
- **Sync CREATE** (PHASE 1C) : le pipeline Sync serveur moderne supporte la
|
|
création d'une saisie de temps via `SuiviTempsSyncOperationHandler` →
|
|
`ISuiviTempsService` → repository adaptatif. EntityType `SuiviTemps`,
|
|
payload `SuiviTempsSyncPayload` (CollaborateurId, InterventionId,
|
|
RendezVousId, Date, DureeMinutes, TypeTempsKey, Description). Le champ
|
|
`Valide` n'est pas positionnable depuis le mobile (état de validation métier
|
|
géré côté backend). UPDATE / ARCHIVE / DELETE → `PERMANENT_FAILURE`.
|
|
- **SQLite local** (PHASE 2) : la table `SuiviTemps` est présente dans le
|
|
schéma SQLite local, importée atomiquement par le `SnapshotApplier` (avec les
|
|
références typées Collaborateur / Intervention / RendezVous pour la
|
|
réconciliation d'identité A → B). Le service local `SuiviTempsLocalService`
|
|
permet la lecture (liste, par GUID, par intervention) et la création
|
|
offline-first (écriture locale + Outbox CREATE, `Valide` toujours false côté
|
|
mobile).
|
|
- **UI LIST** (PHASE 3) : la vue `SuiviTempsView` + `SuiviTempsViewModel`
|
|
permettent la **consultation offline** des saisies de temps via
|
|
`ISuiviTempsLocalService.GetAllAsync` (et `GetByInterventionAsync` /
|
|
`GetByRendezVousAsync` pour les filtres par intervention / rendez-vous). La
|
|
liste affiche les données métier utiles (date, durée, type de temps,
|
|
description, collaborateur, intervention, rendez-vous, validation, état Sync
|
|
Pending/Rejected/ErrorMessage). Aucun UPDATE / ARCHIVE / DELETE. Accès global
|
|
via la navigation + accès contextuel depuis une Intervention (liste filtrée)
|
|
et depuis un RendezVous (liste filtrée).
|
|
|
|
- **Référentiel TypeTemps local** (micro-lot) : **READY** — le référentiel
|
|
`ParametreMetier` est désormais disponible **offline** au mobile. Le pipeline
|
|
est : HFSQL `ParametreMetier` → repository adaptatif (`AdaptiveParametreMetierRepository`)
|
|
→ `MobileBootstrapService` (chargé au bootstrap) → SQLite local → service
|
|
local `IParametreMetierLocalService.GetTypeTempsAsync()`. Ce service retourne
|
|
une liste ordonnée d'options `ReferenceValueDto` (Key = clé métier `PA_CLE`,
|
|
Label = libellé métier) **sans réseau, sans API, sans HFSQL**, uniquement à
|
|
partir des données snapshot déjà présentes localement. Le filtrage suit la
|
|
convention générique du projet (Actif / Invisible) et l'ordre métier
|
|
(`PA_Ordre`). Aucune valeur métier n'est codée en dur ; les options proviennent
|
|
des vraies données `ParametreMetier`. L'ancienne règle Batik (exclusion
|
|
`PA_Valeur` 0/1/99, cas particulier 2) n'est **pas** reprise faute de règle
|
|
moderne explicite.
|
|
- **UI CREATE** (PHASE 3) : **READY** — le formulaire `SuiviTempsCreateView` +
|
|
`SuiviTempsCreateViewModel` permettent la **saisie offline-first** d'un temps
|
|
via `ISuiviTempsLocalService.CreateAsync` (écriture locale + Outbox CREATE,
|
|
`Valide` toujours false côté mobile). Le formulaire contient uniquement
|
|
CollaborateurId, InterventionId, RendezVousId, Date, DureeMinutes,
|
|
TypeTempsKey, Description. Le champ `Valide` est **absent**. Le TypeTemps est
|
|
chargé depuis `IParametreMetierLocalService.GetTypeTempsAsync()` (affichage
|
|
`ReferenceValueDto.Label`, valeur envoyée `ReferenceValueDto.Key` == PA_CLE,
|
|
aucune valeur hardcodée). `DureeMinutes` est saisie manuellement (aucun calcul
|
|
automatique depuis RendezVous/Intervention). Aucune écriture directe SQLite /
|
|
Outbox / API / SyncEngine depuis le ViewModel (le service local reste
|
|
responsable). Protection double clic : `SaveCommand.CanExecute == false`
|
|
pendant l'exécution (binding Avalonia) + garde interne `IsBusy`. Accès global
|
|
(liste SuiviTemps → Nouvelle saisie) et contextuel depuis une Intervention
|
|
(liste filtrée → Nouvelle saisie → InterventionId prérempli) et depuis un
|
|
RendezVous (liste filtrée → Nouvelle saisie → RendezVousId prérempli, sans
|
|
déduction automatique d'Intervention / durée / date).
|
|
|
|
**État fonctionnel** : `REAL` — **UI LIST READY**, **TYPE TEMPS LOCAL
|
|
REFERENCE READY**, **UI CREATE READY**, **RENDEZVOUS ENTRY POINT READY**.
|
|
Backend métier, snapshot, Sync CREATE, SQLite local, référentiel TypeTemps
|
|
local, consultation et saisie offline-first sont opérationnels. UPDATE /
|
|
ARCHIVE / DELETE : NOT SUPPORTED.
|
|
|
|
|
|
**Classification** : **C — BACKEND + MOBILE** (inchangée, CAS C non rouvert).
|
|
Les PHASE 1B (snapshot), 1C (Sync CREATE), 2 (SQLite local), 3 (UI LIST), le
|
|
micro-lot référentiel TypeTemps local et l'UI CREATE sont réalisés.
|
|
|
|
|
|
**Statut détaillé SuiviTemps** (après correctif snapshot — persistance des
|
|
colonnes de référence) :
|
|
|
|
| Capacité | Statut |
|
|
|----------|--------|
|
|
| BACKEND METIER | **READY** |
|
|
| SNAPSHOT | **READY** |
|
|
| SYNC CREATE | **READY** |
|
|
| LOCAL SQLITE | **READY** |
|
|
| SNAPSHOT LOCAL | **READY** |
|
|
| LOCAL CREATE | **READY** |
|
|
| OUTBOX CREATE | **READY** |
|
|
| RECONCILIATION | **READY** |
|
|
| UI LIST | **READY** |
|
|
| TYPE TEMPS LOCAL REFERENCE | **READY** |
|
|
| UI CREATE | **READY** |
|
|
| UPDATE | **NOT SUPPORTED** |
|
|
|
|
| ARCHIVE | **NOT SUPPORTED** |
|
|
| DELETE | **NOT SUPPORTED** |
|
|
| RENDEZVOUS ENTRY POINT | **READY** |
|
|
|
|
|
|
Le correctif snapshot garantit que le refresh persiste les colonnes structurées
|
|
(`CollaborateurId`, `InterventionId`, `RendezVousId`) de manière **générique**
|
|
(mécanisme partagé avec `LocalRepository`), sans fix spécifique SuiviTemps, et
|
|
préserve l'atomicité de la transaction snapshot ainsi que les données techniques
|
|
(Outbox, Sync state, profil, droits, licence, configuration, cache documents).
|
|
|
|
|
|
---
|
|
|
|
## 8. Rapports / CompteRendu — état réel
|
|
|
|
Il ne faut pas confondre les concepts suivants :
|
|
|
|
| Concept | Nature | État mobile |
|
|
|---------|--------|-------------|
|
|
| **CompteRendu** | Entité backend (`CompteRenduRow`, `CompteRenduDto`) | **BACKEND ONLY** — non peuplé dans le snapshot, aucune UI |
|
|
| **Rapport** | Modèles de rapports (`ModeleRapport`, `ModeleRapportMob`) | **BACKEND ONLY** — aucune UI mobile |
|
|
| **Note** | Note d'intervention | **NOT IMPLEMENTED** (CAS E) |
|
|
| **Document** | Fichier / métadonnée | **REAL** (liste, téléchargement, ajout offline) |
|
|
|
|
**État fonctionnel** :
|
|
- CompteRendu : `BACKEND ONLY` (aucune UI, non peuplé dans le snapshot).
|
|
- Rapports : `BACKEND ONLY` (aucune UI mobile).
|
|
- Aucune création / consultation de compte rendu ou rapport depuis le mobile.
|
|
|
|
---
|
|
|
|
## 9. Paramètres — ce qui est réellement accessible
|
|
|
|
La page Paramètres expose réellement à l'utilisateur :
|
|
|
|
| Réglage | État | Détail |
|
|
|---------|------|--------|
|
|
| **Thème** (Light / Dark / System) | **REAL** | ComboBox + bouton « Appliquer le thème » |
|
|
| **Couleur principale** | **REAL** | Presets + couleur personnalisée |
|
|
| **Synchroniser maintenant** | **REAL** | Bouton + état + erreur |
|
|
| **État de synchronisation** | **REAL** | Texte d'état |
|
|
| **Version** | **REAL** | Affichage « À propos » |
|
|
|
|
**Non accessibles à l'utilisateur** (capacité technique ≠ fonction UI) :
|
|
|
|
| Réglage | État | Détail |
|
|
|---------|------|--------|
|
|
| **Purge cache** | **NOT IMPLEMENTED** (UI) | `PurgeAsync` existe mais non branché à l'UI |
|
|
| **Reset application** | **NOT IMPLEMENTED** (UI) | Aucun parcours utilisateur |
|
|
|
|
|
|
---
|
|
|
|
## 10. Reset application
|
|
|
|
**État** : `NOT IMPLEMENTED` (UI).
|
|
|
|
Il n'existe **aucun parcours utilisateur** de réinitialisation de l'application.
|
|
Même si certaines primitives techniques de suppression existent (ex. purge du
|
|
cache), il n'y a pas de bouton ni d'écran « Reset » accessible à l'utilisateur.
|
|
|
|
**Classification** : **A — MOBILE UNIQUEMENT**. Le comportement fonctionnel est
|
|
déjà défini (réinitialisation des données locales / cache / outbox / licence) et
|
|
**aucune évolution backend n'est nécessaire**. La seule dépendance est
|
|
**technique** : la protection des fichiers référencés par des opérations Outbox
|
|
en attente (Pending / Rejected) avant suppression. Aucune décision métier non
|
|
résolue ne bloque ce lot.
|
|
|
|
---
|
|
|
|
## 11. Purge cache
|
|
|
|
**État** : `NOT IMPLEMENTED` (UI).
|
|
|
|
Le bouton de purge du cache Documents **n'a pas été branché** : la protection
|
|
des fichiers nécessaires aux opérations Outbox en attente n'était pas
|
|
suffisamment fiable. La capacité technique `DocumentCacheService.PurgeAsync`
|
|
existe mais n'est exposée à aucune interface utilisateur.
|
|
|
|
**Classification** : **A — MOBILE UNIQUEMENT**. Le problème est **uniquement
|
|
technique côté mobile** (fiabiliser la protection des fichiers référencés par
|
|
l'Outbox Pending / Rejected avant suppression). Aucune décision métier réelle ne
|
|
manque. Dépendance : protection fichiers Outbox.
|
|
|
|
---
|
|
|
|
## 12. Licence / Bootstrap — état fonctionnel utilisateur
|
|
|
|
- Le **backend** licence / bootstrap est réel : `POST /api/license/activate`,
|
|
`POST /api/license/validate`, `GET /api/mobile/bootstrap`, token signé,
|
|
identité/profil/droits.
|
|
- **Émission du token de session** : `activate` et `validate` retournent une
|
|
réponse de session `MobileLicenseSessionResponse` contenant le **Bearer token**
|
|
(`AccessToken`) et son **expiration exacte** (`AccessTokenExpiresAtUtc`,
|
|
24 h par défaut via `MobileAuth:TokenLifetimeHours`). Le token n'est émis
|
|
**que** si la licence est valide ; en cas d'échec, la réponse contient le code
|
|
d'erreur métier et **aucun token**. Le token est stateless (HMAC-SHA256),
|
|
jamais loggé, jamais stocké en HFSQL.
|
|
- **Côté application** : l'UI d'activation est **réellement branchée**. Au
|
|
premier démarrage sans session valide, l'utilisateur voit l'écran
|
|
**Activation** (code client + numéro de licence). Après activation réussie, le
|
|
token est stocké en **secure storage** (jamais en SQLite en clair), le
|
|
bootstrap (profil, droits, licence, configuration) est persisté en SQLite, et
|
|
l'application bascule vers le **Shell**.
|
|
- **Redémarrage** : si une session valide existe (licence valide ou période
|
|
offline autorisée), l'application démarre directement sur le **Shell** sans
|
|
repasser par l'activation.
|
|
- **Offline** : session déjà validée + période offline autorisée → accès aux
|
|
données SQLite sans connexion obligatoire. Premier démarrage sans session
|
|
valide + offline → activation impossible (message réseau).
|
|
- **Identité** : le nom de l'utilisateur (et ses initiales) est affiché dans le
|
|
**Shell** à partir du bootstrap local. Une licence expirée/révoquée ne
|
|
supprime **jamais** automatiquement les données locales (SQLite métier, cache,
|
|
Documents, Outbox).
|
|
|
|
**État fonctionnel** : `REAL` — activation, validation, bootstrap, token sécurisé
|
|
et identité utilisateur sont opérationnels côté mobile.
|
|
|
|
**Classification** : **A — MOBILE UNIQUEMENT** — réalisé. Le backend activation,
|
|
validation et bootstrap **existaient déjà** ; l'UI mobile d'activation / identité
|
|
a été ajoutée. **Risque sécurité : moyen/élevé** (parcours d'activation, token,
|
|
identité utilisateur) — traité par le secure storage et l'absence de token en
|
|
clair.
|
|
|
|
|
|
|
|
---
|
|
|
|
## 13. Comparaison avec la maquette `maquetteOmika.html`
|
|
|
|
La maquette reste une **référence UX uniquement**. Comparaison des grandes
|
|
fonctions :
|
|
|
|
| Fonction maquette | Application actuelle | État | Écart restant |
|
|
|-------------------|----------------------|------|---------------|
|
|
| Agenda (Mes rendez-vous) | Agenda du jour réel | **PARTIAL** | Pas de vue semaine/équipe, pas de saisie temps |
|
|
| RendezVous (détail) | Détail réel | **PARTIAL** | Pas de saisie temps, pas d'annulation |
|
|
| Interventions (recherche) | Liste + recherche locale | **PARTIAL** | Filtres avancés (relation RDV, date, collaborateur) absents |
|
|
| Interventions (fiche) | Fiche réelle | **PARTIAL** | Pas de GPS, création, planification RDV, compte rendu, rapports, emails |
|
|
| Dossiers | Liste + détail réels | **PARTIAL** | Pas de création / ajout d'intervention |
|
|
| Clients | Liste + détail réels | **PARTIAL** | Pas de création / modification |
|
|
| Sites / Lieux | Liste + détail réels | **PARTIAL** | Pas de GPS / itinéraire |
|
|
| Équipe | Liste + détail réels | **PARTIAL** | Pas d'agenda d'équipe |
|
|
| Documents | Liste + téléchargement + ajout offline | **REAL** | — |
|
|
| Photos | Ajout photo offline | **REAL** | — |
|
|
| Contacts | Liste + détail réels | **REAL** | — |
|
|
| Notes | — | **NOT IMPLEMENTED** | CAS E |
|
|
| Temps | — | **NOT IMPLEMENTED** | CAS C |
|
|
| Rapports | — | **NOT IMPLEMENTED** | Backend only |
|
|
| CompteRendu | — | **NOT IMPLEMENTED** | Backend only |
|
|
| Paramètres | Thème / couleur / sync / version / licence | **PARTIAL** | Pas de purge cache, reset |
|
|
|
|
| Synchronisation | Manuelle via SyncEngine | **REAL** | Pas d'automatique |
|
|
| Reset | — | **NOT IMPLEMENTED** | — |
|
|
|
|
---
|
|
|
|
## 14. Backlog — classification des restes
|
|
|
|
### A — MOBILE UNIQUEMENT
|
|
Données / backend déjà disponibles ; manque UI / service mobile.
|
|
|
|
| Élément | Détail |
|
|
|---------|--------|
|
|
| Filtres de recherche avancés Interventions | Données disponibles (RDV, collaborateur) ; manque l'UI de filtrage |
|
|
| GPS / itinéraire | Données adresse disponibles ; manque l'UI + lanceur carte |
|
|
| Email / appel depuis la fiche intervention | Launcher plateforme existe (contact) ; manque l'UI fiche |
|
|
| **Reset application** | Primitives locales existent ; comportement fonctionnel défini ; aucune évolution backend nécessaire. Dépendance technique : protection fichiers Outbox |
|
|
| **Purge cache** | `DocumentCacheService.PurgeAsync` existe ; problème uniquement technique mobile (protection fichiers Outbox Pending/Rejected). Dépendance : protection fichiers Outbox |
|
|
|
|
|
|
### B — MOBILE WRITE
|
|
Backend / sync réellement capables de l'écriture ; UI + mutation locale réalisées.
|
|
|
|
| Élément | Détail |
|
|
|---------|--------|
|
|
| **Modification Intervention mobile** ✅ RÉALISÉ | **Backend + Sync SUPPORTED** : handler `InterventionSyncOperationHandler`, contrat `InterventionSyncPayload`, CREATE/UPDATE/ARCHIVE réels, pipeline SUCCESS/REJECTED. **UI + mutation locale réalisées** : formulaire Create/Edit, bouton Nouvelle Intervention, action Modifier, action Archiver avec confirmation, aucun DELETE, protection double Save, navigation contextuelle, états Pending/Rejected affichés. |
|
|
|
|
> **Vérification** : CREATE, UPDATE et ARCHIVE Intervention sont réellement
|
|
> supportés de bout en bout par le backend + Sync (contrat public exploitable,
|
|
> EntityType reconnu, handler réel, traitement métier réel via
|
|
> `IInterventionService`, résultat SUCCESS/REJECTED possible). DELETE n'est pas
|
|
> supporté (archivage logique uniquement → PERMANENT_FAILURE). Le lot
|
|
> **Intervention Write UI** est **COMPLET** : CREATE UI COMPLETE, UPDATE UI
|
|
> COMPLETE, ARCHIVE UI COMPLETE, OFFLINE-FIRST, OUTBOX, IDENTITY
|
|
> RECONCILIATION. DELETE : NOT SUPPORTED.
|
|
|
|
|
|
### C — BACKEND + MOBILE
|
|
Contrat / snapshot / sync manquant avant l'UI.
|
|
|
|
| Élément | Détail |
|
|
|---------|--------|
|
|
| Notes Intervention | Absentes du snapshot / SQLite / Sync (CAS E) |
|
|
| Suivi des temps | **Snapshot (PHASE 1B) + Sync CREATE (PHASE 1C) + SQLite local (PHASE 2) faits** ; **UI LIST (PHASE 3) faite** ; **TYPE TEMPS LOCAL REFERENCE READY** ; **UI CREATE (PHASE 3) faite** (offline-first, TypeTemps Key=PA_CLE, aucun UPDATE/ARCHIVE/DELETE) ; **RENDEZVOUS ENTRY POINT RÉALISÉ** (accès contextuel RendezVous → liste filtrée → Nouvelle saisie, RendezVousId prérempli) |
|
|
|
|
|
|
|
|
| CompteRendu | Non peuplé dans le snapshot |
|
|
| Rapports | Modèles backend, aucune exposition mobile |
|
|
| **RendezVous (création / modification / annulation)** | **Aucun handler Sync RendezVous, aucun payload** ; toute opération Sync est rejetée (`NO_HANDLER`) |
|
|
| **Dossier (création / modification)** | **Aucun handler Sync Dossier, aucun payload** |
|
|
| **Client (création / modification)** | **Aucun handler Sync Client, aucun payload** |
|
|
| **Site (création / modification)** | **Aucun handler Sync Site, aucun payload** |
|
|
| **Collaborateur (création / modification)** | **Aucun handler Sync Collaborateur, aucun payload** |
|
|
|
|
### D — DÉCISION MÉTIER
|
|
Sémantique à décider avant développement.
|
|
|
|
| Élément | Détail |
|
|
|---------|--------|
|
|
| Sémantique Note vs DocumentNote | Distinction à confirmer avant développement Notes (décision de représentation métier exacte) |
|
|
|
|
> **Note** : Purge cache et Reset ne sont **plus** en D : ce sont des problèmes
|
|
> **techniques mobiles** (protection fichiers Outbox), sans décision métier non
|
|
> résolue. Ils sont classés en **A — MOBILE UNIQUEMENT** avec dépendance
|
|
> technique sur la protection Outbox.
|
|
|
|
---
|
|
|
|
## 15. Prochains lots recommandés
|
|
|
|
À partir de la cartographie réelle, **5 prochains lots** recommandés (aucun code
|
|
n'est écrit ici). Priorité forte donnée à l'activation/licence/identité, aux
|
|
écritures métier terrain réellement supportées par le Sync, au SuiviTemps et aux
|
|
Notes/CompteRendu, avant les améliorations purement cosmétiques ou les filtres
|
|
avancés.
|
|
|
|
### Lot 1 — Licence / activation + identité utilisateur ✅ RÉALISÉ
|
|
- **Objectif** : brancher l'UI d'activation / validation licence et afficher
|
|
l'identité utilisateur (nom, profil, droits).
|
|
- **Catégorie** : A (MOBILE UNIQUEMENT) — backend activation/validation/bootstrap
|
|
**déjà existants**.
|
|
- **Backend nécessaire** : Non (déjà existant).
|
|
- **Dépendances** : Bootstrap / token / profil.
|
|
- **Risque** : **Moyen/élevé** (sécurité, parcours d'activation, identité).
|
|
- **Raison de la priorité** : **Prérequis de mise en production réelle** — sans
|
|
activation/licence/identité, l'application n'est pas exploitable en production.
|
|
- **Statut** : **RÉALISÉ** — écran d'activation, session + token sécurisé
|
|
(secure storage), bootstrap local, identité Shell, offline grace. Voir
|
|
section 12.
|
|
|
|
### Lot 2 — Modification Intervention mobile (B — MOBILE WRITE) ✅ RÉALISÉ
|
|
|
|
- **Objectif** : brancher l'UI + mutation locale (Outbox) pour créer, modifier et
|
|
archiver une intervention, en s'appuyant sur le handler Sync **déjà
|
|
opérationnel**.
|
|
- **Catégorie** : B (MOBILE WRITE) — backend + Sync **déjà supportés**.
|
|
- **Backend nécessaire** : Non (handler `InterventionSyncOperationHandler` et
|
|
contrat `InterventionSyncPayload` existants).
|
|
- **Dépendances** : UI fiche + mutation locale + Outbox + réconciliation
|
|
RequestedEntityGuid → CanonicalEntityGuid.
|
|
- **Risque** : Moyen (mutation locale, identité, ordre CREATE → UPDATE).
|
|
- **Raison de la priorité** : **Écriture métier terrain réellement déjà
|
|
supportée par le Sync** — valeur terrain immédiate, sans évolution backend.
|
|
- **Statut** : **RÉALISÉ** — formulaire Create/Edit partagé, bouton Nouvelle
|
|
Intervention, action Modifier, action Archiver avec confirmation, aucun
|
|
DELETE, protection double Save, navigation contextuelle, états
|
|
Pending/Rejected affichés. Voir section 14 B.
|
|
|
|
|
|
### Lot 3 — Suivi des temps (CAS C)
|
|
- **Objectif** : exposer le SuiviTemps dans le snapshot / SQLite / Sync, puis
|
|
UI de saisie.
|
|
- **Catégorie** : C (BACKEND + MOBILE).
|
|
- **Backend nécessaire** : Oui (sync + handler ; snapshot **fait**).
|
|
- **Dépendances** : SQLite, Sync, UI.
|
|
- **Risque** : Moyen (contrat + sync).
|
|
- **Raison de la priorité** : **Fonction terrain très attendue** (saisie des
|
|
temps), nécessite le backend.
|
|
- **Statut** : **PHASE 1B (snapshot) RÉALISÉE** — `SuivisTemps` exposé dans le
|
|
`MobileSnapshotResponse` (lecture seule, GUID physique, aucun GUID
|
|
synthétique). **PHASE 1C (Sync CREATE) RÉALISÉE** — handler
|
|
`SuiviTempsSyncOperationHandler` + payload `SuiviTempsSyncPayload`, CREATE
|
|
supporté, UPDATE/ARCHIVE/DELETE non supportés. **PHASE 2 (SQLite local)
|
|
RÉALISÉE** — table `SuiviTemps` dans le schéma SQLite, import snapshot
|
|
(`SnapshotApplier`), service local `SuiviTempsLocalService` (lecture +
|
|
création offline-first via Outbox CREATE, `Valide` toujours false côté
|
|
mobile), réconciliation d'identité A → B. **PHASE 3 (UI LIST) RÉALISÉE** —
|
|
`SuiviTempsView` + `SuiviTempsViewModel` (consultation offline, états
|
|
Pending/Rejected/ErrorMessage, accès global + depuis Intervention).
|
|
**RÉFÉRENTIEL TYPE TEMPS LOCAL RÉALISÉ** — `IParametreMetierLocalService`
|
|
+ `GetTypeTempsAsync()` (options `ReferenceValueDto` Key/Label depuis les
|
|
vraies données `ParametreMetier`, offline). **UI CREATE RÉALISÉE** —
|
|
`SuiviTempsCreateView` + `SuiviTempsCreateViewModel` (saisie offline-first,
|
|
TypeTemps Key=PA_CLE, aucun UPDATE/ARCHIVE/DELETE, protection double clic
|
|
CanExecute). **RENDEZVOUS ENTRY POINT RÉALISÉ** — accès contextuel
|
|
RendezVous → liste filtrée → Nouvelle saisie (RendezVousId prérempli, sans
|
|
déduction automatique d'Intervention / durée / date).
|
|
|
|
|
|
|
|
|
|
### Lot 4 — Notes / CompteRendu (CAS E)
|
|
- **Objectif** : définir la représentation Note, l'exposer dans le snapshot /
|
|
SQLite / Sync, puis UI.
|
|
- **Catégorie** : C (BACKEND + MOBILE) + D (décision métier Note vs DocumentNote).
|
|
- **Backend nécessaire** : Oui (snapshot + sync + handler).
|
|
- **Dépendances** : Décision métier, snapshot, SQLite, Sync, UI.
|
|
- **Risque** : Moyen (sémantique + contrat).
|
|
- **Raison de la priorité** : **Fonction terrain attendue** (notes / compte
|
|
rendu), nécessite une décision métier préalable.
|
|
|
|
### Lot 5 — Reset + Purge cache (A — MOBILE UNIQUEMENT)
|
|
- **Objectif** : brancher l'UI Reset application et Purge cache, avec protection
|
|
des fichiers référencés par l'Outbox en attente.
|
|
- **Catégorie** : A (MOBILE UNIQUEMENT) — primitives locales existantes, aucune
|
|
évolution backend.
|
|
- **Backend nécessaire** : Non.
|
|
- **Dépendances** : Protection fichiers Outbox (Pending / Rejected) avant purge /
|
|
reset.
|
|
- **Risque** : Faible à moyen (intégrité des opérations en attente).
|
|
- **Raison de la priorité** : **Hygiène de production** (réinitialisation /
|
|
libération d'espace), sans backend.
|
|
|
|
---
|
|
|
|
## 16. Baseline de validation
|
|
|
|
| Vérification | Résultat | Commande |
|
|
|--------------|----------|----------|
|
|
| Tests Mobile | **587/587** | `dotnet test tests/Omika.Tests/Omika.Tests.csproj -c Debug --filter "FullyQualifiedName~Omika.Tests.Mobile"` |
|
|
| Tests ViewModel SuiviTemps (List) | **11/11** | `dotnet test tests/Omika.Tests/Omika.Tests.csproj -c Debug --filter "FullyQualifiedName~SuiviTempsViewModelTests"` |
|
|
| Tests ViewModel SuiviTemps (Create) | **18/18** | `dotnet test tests/Omika.Tests/Omika.Tests.csproj -c Debug --filter "FullyQualifiedName~SuiviTempsCreateViewModelTests"` |
|
|
| Tests ViewModel RendezVous (Detail) | **1/1** | `dotnet test tests/Omika.Tests/Omika.Tests.csproj -c Debug --filter "FullyQualifiedName~RendezVousDetailViewModelTests"` |
|
|
| Tests ViewModel Intervention (Edit/List/Detail) | **30/30** | `dotnet test tests/Omika.Tests/Omika.Tests.csproj -c Debug --filter "FullyQualifiedName~InterventionEditViewModelTests\|FullyQualifiedName~InterventionsViewModelTests\|FullyQualifiedName~InterventionDetailViewModelTests"` |
|
|
| Tests Référentiel TypeTemps local | **6/6** | `dotnet test tests/Omika.Tests/Omika.Tests.csproj -c Debug --filter "FullyQualifiedName~ParametreMetierLocalServiceTests"` |
|
|
| Suite unitaire (hors intégration HFSQL) | **1853/1853** | `dotnet test tests/Omika.Tests/Omika.Tests.csproj -c Debug --filter "FullyQualifiedName!~Omika.Tests.Connection.HfSqlOleDb"` |
|
|
|
|
|
|
| Build `Omika.slnx` | **VERT** (projets .NET) | `dotnet build Omika.slnx -c Debug` |
|
|
| Build `Omika.App.Local` | **VERT** | `dotnet build src/Omika.App.Local/Omika.App.Local.csproj -c Debug` |
|
|
| Build `Omika.App` | **VERT** | `dotnet build src/Omika.App/Omika.App.csproj -c Debug` |
|
|
| Build Android | **VERT** | `dotnet build src/Omika.App.Android/Omika.App.Android.csproj -c Debug` |
|
|
|
|
|
|
|
|
> **Note — Lot serveur Licence (connexion physique base HFSQL)** : le lot est en
|
|
> état de **STOP** (voir `docs/LOT_SERVEUR_LICENCE.md`). Les probes de lecture
|
|
> OLEDB ont révélé que la base Licence réelle (`BASE_LICENCES`) ne contient pas
|
|
> les tables `ClientBase`, `Licence`, `LicenceHisto` attendues par le repository
|
|
> (seulement 2 tables de backup système). Aucune écriture n'a été effectuée.
|
|
> La suite complète de tests affiche **1779 réussis / 10 échecs** : les 10 échecs
|
|
> sont des tests d'intégration HFSQL environnementaux (`HfSqlOleDb*IntegrationTests`)
|
|
> qui échouent faute de base d'intégration configurée (connexion `<:0>`), hors
|
|
> périmètre de la baseline unitaire. Les 34 tests de configuration Licence
|
|
|
|
> (`HfSqlTestConfigurationLoaderTests`, `E2EOptionsTests`,
|
|
> `LicenseConnectionOptionsValidatorTests`, `LicenseOleDbConnectionTests`)
|
|
> passent **34/34**.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
*Document de bilan fonctionnel global — ne modifie aucun code de production.*
|