Files
Omika/docs/diagnostics/crud-implementation.md
T
2026-10-23 18:46:50 +02:00

164 lines
10 KiB
Markdown

# État d'implémentation CRUD
État réel de l'implémentation CRUD par agrégat métier, basé sur le code et les tests réellement présents.
## Légende
- **VERIFIED** : implémenté et testé (unitaire et/ou intégration).
- **PARTIAL** : implémenté mais avec des zones non couvertes (intégration réelle, relations).
- **NOT_STARTED** : non implémenté.
- **NOT_APPLICABLE** : opération non pertinente pour l'entité.
- **NOT_COVERED** : non exécuté (intégration réelle absente).
## Client — VERIFIED
- Create / ReadOne / ReadList / Update / Delete : implémentés et testés.
- Via `ClientService` / `AdaptiveClientRepository` / `ClientEndpoints`.
- Suppression : archivage logique.
## Personne — VERIFIED
- Create / ReadOne / ReadList / Update / Delete : implémentés et testés.
- Via `ContactService` / `AdaptiveContactRepository` / `ContactEndpoints`.
- Suppression : archivage logique.
## Lieu/Site — VERIFIED
- Create / ReadOne / ReadList / Update / Delete : implémentés et testés.
- Via `SiteService` / `AdaptiveSiteRepository` / `BatikSiteRepository` / `OmikaSiteRepository` / `SiteEndpoints`.
- BATIK : table physique `Lieu`, création Adresse transactionnelle, type résolu via `ParametreMetier`.
- OMIKA : table physique `Lieu`, `LI_CleType`, GUID, Adresse Omika.
- `AdaptiveSiteRepository` route selon `DatabaseSchemaVersion`.
- API : `/sites`.
- DI : `ISiteRepository → AdaptiveSiteRepository`, `ISiteService → SiteService`.
- Suppression : archivage logique.
- Tests : `BatikSiteMapperTests`, `OmikaSiteMapperTests` (PASS).
## Document — VERIFIED
- Create / ReadOne / ReadList : implémentés et testés.
- Update : NOT_APPLICABLE (document immuable après création).
- Delete : SEMANTIC_DELETE (archivage via `Archive`).
## Intervention — VERIFIED
### CRUD (implémenté et testé unitairement)
| Opération | Statut | Implémentation | Tests |
|-----------|--------|----------------|-------|
| Create | IMPLEMENTED | `InterventionService.CreateAsync` → `AdaptiveInterventionRepository` → `Batik/OmikaInterventionRepository` | `BatikInterventionRepositoryTests`, `OmikaInterventionRepositoryTests`, `InterventionServiceTests`, `InterventionEndpointsTests` |
| ReadOne | IMPLEMENTED | `GetByIdAsync` → `GetDetailsAsync` | idem |
| ReadList/Search | IMPLEMENTED | `SearchAsync` | idem |
| Update | IMPLEMENTED | `UpdateAsync` | idem |
| Delete | SEMANTIC_DELETE | `ArchiveAsync` (archivage logique, jamais DELETE) | idem |
### Relations
| Relation | Statut | Détail |
|----------|--------|--------|
| EtatIntervention | VERIFIED (unitaire) | Chargée via `LoadEtatsInterventionAsync`, mappée en `ActionIntervention`. Testée dans `BatikInterventionRepositoryTests`. |
| InterventionCollaborateur | VERIFIED (unitaire) | `CollaborateurIds` persistés dans `InterventionCollaborateur` (DELETE + INSERT) sur Update. IDs invalides → `DomainValidationException` sans écriture partielle. Testé (`UpdateAsync_PersistsCollaborateurAndPersonneRelations`, `UpdateAsync_InvalidCollaborateurId_ThrowsControlledError`). |
| InterventionPersonne | VERIFIED (unitaire) | `ContactIds` persistés dans `InterventionPersonne` (DELETE + INSERT) sur Update. IDs invalides → `DomainValidationException` sans écriture partielle. Testé (`UpdateAsync_PersistsPersonneRelations`, `UpdateAsync_InvalidContactId_ThrowsControlledError`). |
### Intégration
| Cible | Statut | Détail |
|-------|--------|--------|
| BATIK_TEST | PASS | `HfSqlOleDbInterventionLifecycleIntegrationTests.Batik_CreateUpdateArchive_RollsBackAtomically` exécuté et PASS : CREATE → UPDATE → ARCHIVE → ROLLBACK dans une transaction externe unique. |
| OMIKA_TEST | PASS | `HfSqlOleDbInterventionLifecycleIntegrationTests.Omika_CreateUpdateArchive_RollsBackAtomically` exécuté et PASS : CREATE → UPDATE → ARCHIVE → ROLLBACK dans une transaction externe unique. |
Les tests `HfSqlOleDbInterventionLifecycleIntegrationTests` exécutent le cycle de vie complet contre les vraies bases BATIK_TEST/OMIKA_TEST via le provider OLE DB, puis annulent (rollback) pour ne laisser aucune trace. Ils s'ignorent uniquement si la config est absente ou le serveur injoignable.
### Transaction
| Opération | Statut | Détail |
|-----------|--------|--------|
| CreateTransaction | PASS | `CreateAsync(command, transaction, ct)` exécute l'INSERT racine et les relations dans UNE transaction (interne ou externe). Exercé en intégration. |
| UpdateTransaction | PASS | `UpdateAsync(command, transaction, ct)` exécute UPDATE + DELETE/INSERT relations dans UNE transaction. Exercé en intégration. |
| Rollback | PASS | Rollback externe prouvé en intégration (CREATE→UPDATE→ARCHIVE→ROLLBACK). |
| PartialFailureRollback | NOT_COVERED | Aucun test ne provoque une erreur après une première écriture pour démontrer le rollback interne. Non bloquant : Create/Update utilisent bien une transaction unique, l'intégration réelle passe, le rollback externe est prouvé, aucune perte silencieuse de relations. |
### Application
| Couche | Statut | Détail |
|--------|--------|--------|
| AdaptiveRepository | PASS | `AdaptiveInterventionRepository` délègue selon le schéma détecté. Testé (`AdaptiveInterventionRepositoryTests`). |
| Service | PASS | `InterventionService` orchestre requête → critère → repository → DTO. Testé (`InterventionServiceTests`). |
| API | PASS | `InterventionEndpoints` (GET/POST/PUT/DELETE). Testé (`InterventionEndpointsTests`). |
## Dossier — VERIFIED
### CRUD (implémenté et testé unitairement)
| Opération | Statut | Implémentation | Tests |
|-----------|--------|----------------|-------|
| Create | IMPLEMENTED | `DossierService.CreateAsync` → `AdaptiveDossierRepository` → `Batik/OmikaDossierRepository` | `BatikDossierRepositoryTests`, `OmikaDossierRepositoryTests`, `DossierServiceTests`, `DossierEndpointsTests` |
| ReadOne | IMPLEMENTED | `GetDetailsAsync` | idem |
| ReadList/Search | IMPLEMENTED | `SearchAsync` | idem |
| Update | IMPLEMENTED | `UpdateAsync` | idem |
| Delete | SEMANTIC_DELETE | `ArchiveAsync` (archivage logique, jamais DELETE) | idem |
### Intégration
| Cible | Statut | Détail |
|-------|--------|--------|
| BATIK_TEST | PASS | `HfSqlOleDbDossierLifecycleIntegrationTests.Batik_CreateUpdateArchive_RollsBackAtomically` exécuté et PASS : CREATE → UPDATE → ARCHIVE → ROLLBACK dans une transaction externe unique. |
| OMIKA_TEST | PASS | `HfSqlOleDbDossierLifecycleIntegrationTests.Omika_CreateUpdateArchive_RollsBackAtomically` exécuté et PASS : CREATE → UPDATE → ARCHIVE → ROLLBACK dans une transaction externe unique. |
Les tests `HfSqlOleDbDossierLifecycleIntegrationTests` exécutent le cycle de vie complet contre les vraies bases BATIK_TEST/OMIKA_TEST via le provider OLE DB, puis annulent (rollback) pour ne laisser aucune trace. Ils s'ignorent uniquement si la config est absente ou le serveur injoignable.
### Particularité Omika — DO_NumDossier (rubrique calculée)
Dans la base Omika, `DO_NumDossier` est une **rubrique calculée** : toute écriture (INSERT/UPDATE) lève l'erreur HFSQL `28000002` (« Opération interdite sur la rubrique <Dossier.DO_NumDossier> : il s'agit d'une rubrique calculée »). Le `OmikaDossierRepository` exclut donc `DO_NumDossier` des INSERT/UPDATE : la valeur est générée par la base elle-même. La lecture (SELECT) reste possible. Ce comportement a été découvert et corrigé lors de l'intégration réelle.
### Transaction
| Opération | Statut | Détail |
|-----------|--------|--------|
| CreateTransaction | PASS | `CreateAsync(command, transaction, ct)` exécute l'INSERT racine dans UNE transaction (interne ou externe). Exercé en intégration. |
| UpdateTransaction | PASS | `UpdateAsync(command, transaction, ct)` exécute l'UPDATE dans UNE transaction. Exercé en intégration. |
| Rollback | PASS | Rollback externe prouvé en intégration (CREATE→UPDATE→ARCHIVE→ROLLBACK). |
### Application
| Couche | Statut | Détail |
|--------|--------|--------|
| AdaptiveRepository | PASS | `AdaptiveDossierRepository` délègue selon le schéma détecté. Testé (`AdaptiveDossierRepositoryTests`). |
| Service | PASS | `DossierService` orchestre requête → critère → repository → DTO. Testé (`DossierServiceTests`). |
| API | PASS | `DossierEndpoints` (GET/POST/PUT/DELETE). Testé (`DossierEndpointsTests`). |
## Référentiels (REFERENCE_DATA) — lecture seule
Les référentiels sont exposés en **lecture seule uniquement**. Aucun CRUD administratif générique (Create/Update/Delete) n'est créé : conforme à la règle « ne crée pas automatiquement un endpoint pour chaque table ».
### ParametreMetier — READ_ONLY_VERIFIED (PUBLIC_READ_REFERENCE)
Seul référentiel exposé en lecture publique, via le mécanisme générique existant :
- Endpoint : `GET /reference-data/{key}` (`MapReferenceDataEndpoints`).
- Service : `IReferenceDataService → ReferenceDataService`.
- Repository : `IReferenceDataRepository → AdaptiveReferenceDataRepository` (route selon le schéma détecté).
- Implémentations : `BatikReferenceDataRepository` (filtre `PA_Code`) / `OmikaReferenceDataRepository` (filtre `PA_Categorie`).
- Retour : `ReferenceValueDto` (Key / LegacyId / Code / Label).
- DI : enregistré dans `ServiceCollectionExtensions` (Scoped).
### Autres référentiels — aucune exposition publique
| Entité | Classification | Justification |
|--------|----------------|---------------|
| Societe | INTERNAL_REFERENCE_ONLY | Aucun besoin public démontré (pas de sélecteur de société requis). |
| Equipe | INTERNAL_REFERENCE_ONLY | Pas d'identité publique canonique exploitable indépendamment ; aucun GUID fabriqué. |
| ParametreMetierEntete | INTERNAL_REFERENCE_ONLY | Référentiel historique/protégé, pas de CRUD public. |
| EtatIntervention | INTERNAL_REFERENCE_ONLY | Table d'historique des états d'une intervention, chargée en interne par Intervention ; les valeurs d'état proviennent de ParametreMetier. Pas de liste publique autonome. |
| Role | SCHEMA_SPECIFIC | Omika uniquement ; absent sous Batik (`SchemaCapabilities.SupportsRoles`). Lecture interne. |
| Etats | SCHEMA_SPECIFIC | Omika uniquement ; absent sous Batik. Lecture interne. |
| ModeleRapport | NOT_REQUIRED | Omika uniquement ; aucun besoin public démontré. |
Aucun nouveau code n'a été nécessaire pour ce lot : le seul référentiel public (ParametreMetier) était déjà implémenté et câblé. Les autres restent internes.
## Blocker
Aucun. L'intégration réelle contre BATIK_TEST/OMIKA_TEST avec rollback est couverte et PASS pour Intervention et Dossier. Dossier est VERIFIED (avec la particularité Omika `DO_NumDossier` rubrique calculée gérée).