319 lines
17 KiB
Markdown
319 lines
17 KiB
Markdown
# Architecture de la solution Omika
|
|
|
|
Ce document décrit la structure initiale de la solution .NET **Omika**, son
|
|
organisation en projets, les dépendances entre eux, et les conventions retenues
|
|
pour la suite (migration HFSQL, application mobile, API, futur Windows).
|
|
|
|
> **Portée** : phase d'architecture. Les modèles métier détaillés et la connexion
|
|
> HFSQL réelle ne sont **pas** encore développés (voir les sections dédiées).
|
|
|
|
---
|
|
|
|
## 1. Vue d'ensemble
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────────────┐
|
|
│ Omika.App │
|
|
│ Application Avalonia (code partagé UI / ViewModels) │
|
|
│ Cibles : Android · iOS · Windows (desktop) │
|
|
└───────────────┬─────────────────────────────┬──────────────┘
|
|
│ │
|
|
▼ ▼
|
|
Omika.App.Desktop Omika.App.Android
|
|
Omika.App.iOS (hôtes plateformes)
|
|
(hôtes plateformes)
|
|
│
|
|
│ ProjectReference
|
|
▼
|
|
┌─────────────────────────────────────────────┐ ┌──────────────────────────────┐
|
|
│ Omika.Core │ │ Omika.Api │
|
|
│ Modèles · Interfaces · Constantes · │◄───────│ API ASP.NET Core │
|
|
│ Logique métier (indépendant UI/API) │ │ Endpoints / DI / OpenAPI │
|
|
└──────────────────┬──────────────────────────┘ └──────────────┬───────────────┘
|
|
│ ProjectReference │ ProjectReference
|
|
▼ ▼
|
|
┌─────────────────────────────────────────────┐ ┌──────────────────────────────┐
|
|
│ Omika.Data │ │ Omika.Tests │
|
|
│ Connexion HFSQL · Repositories · Mapping │ │ Tests unitaires (xUnit) │
|
|
│ Migration Batik/OMIKA │ └──────────────────────────────┘
|
|
└─────────────────────────────────────────────┘
|
|
```
|
|
|
|
## 2. Projets créés
|
|
|
|
| Projet | Type | Rôle |
|
|
|-----------------------|-----------------------------------|------|
|
|
| `Omika.App` | Bibliothèque Avalonia (net10.0) | Code UI partagé (Views, ViewModels, Services). Cible commune aux hôtes Android / iOS / Windows. |
|
|
| `Omika.App.Desktop` | Exécutable Avalonia (net10.0) | Hôte desktop Windows/Linux/macOS. Point d'entrée pour le futur client Windows. |
|
|
| `Omika.App.Android` | Exécutable Avalonia (net10.0-android) | Hôte Android (APK/AAB). |
|
|
| `Omika.App.iOS` | Exécutable Avalonia (net10.0-ios) | Hôte iOS (simulateur/appareil). **La compilation d'un .app pour iOS exige macOS + Xcode.** |
|
|
| `Omika.Api` | API ASP.NET Core (net10.0) | Expose les fonctionnalités métier et données via HTTP + OpenAPI. |
|
|
| `Omika.Core` | Bibliothèque (net10.0) | Modèles communs, interfaces, constantes, types partagés, logique métier. Aucune dépendance UI/API. |
|
|
| `Omika.Data` | Bibliothèque (net10.0) | Accès aux données HFSQL : options de connexion, contrats, repositories, mapping de tables, migration Batik/OMIKA. |
|
|
| `Omika.Tests` | xUnit (net10.0) | Tests unitaires des éléments critiques (Result, validation HFSQL, mapping de tables). |
|
|
|
|
## 3. Dépendances entre projets
|
|
|
|
```
|
|
Omika.App.Desktop ──► Omika.App ──► Omika.Core
|
|
Omika.App.Android ──► Omika.App ──► Omika.Core
|
|
Omika.App.iOS ──► Omika.App ──► Omika.Core
|
|
|
|
Omika.Api ──► Omika.Core
|
|
──► Omika.Data
|
|
|
|
Omika.Data ──► Omika.Core
|
|
|
|
Omika.Tests ──► Omika.Core
|
|
──► Omika.Data
|
|
```
|
|
|
|
- **Omika.Core** n'a aucune dépendance : c'est le noyau partagé.
|
|
- **Omika.Data** dépend de **Omika.Core** (interfaces, constantes, types).
|
|
- **Omika.Api** dépend de **Omika.Core** et **Omika.Data**.
|
|
- **Omika.App** et ses hôtes dépendent de **Omika.Core** (les appels à l'API se feront
|
|
via HTTP, pas par référence directe au projet Data).
|
|
- **Omika.Tests** référence **Omika.Core** et **Omika.Data**.
|
|
|
|
## 4. Gestion des packages
|
|
|
|
Le fichier racine **`Directory.Packages.props`** active la gestion centralisée
|
|
des packages (CPM). Toutes les versions NuGet y sont déclarées une seule fois ;
|
|
les fichiers `.csproj` référencent les packages **sans version**.
|
|
|
|
| Groupe | Package |
|
|
|------------------|---------|
|
|
| Avalonia | `Avalonia`, `Avalonia.Themes.Fluent`, `Avalonia.Fonts.Inter`, `Avalonia.Desktop`, `Avalonia.Android`, `Avalonia.iOS` |
|
|
| Diagnostique | `AvaloniaUI.DiagnosticsSupport` |
|
|
| Android | `Xamarin.AndroidX.Core.SplashScreen` |
|
|
| MVVM | `CommunityToolkit.Mvvm` |
|
|
| API | `Microsoft.AspNetCore.OpenApi` |
|
|
| Configuration | `Microsoft.Extensions.Options.ConfigurationExtensions` |
|
|
| Tests | `xunit`, `xunit.runner.visualstudio`, `Microsoft.NET.Test.Sdk`, `coverlet.collector` |
|
|
|
|
## 5. Structure des dossiers
|
|
|
|
```
|
|
Omika.slnx → solution (format .slnx)
|
|
Directory.Packages.props → versions centralisées des packages NuGet
|
|
docs/architecture-solution.md → ce document
|
|
docs/schema-compatibilite-batik-omika.json
|
|
→ dictionnaire machine-readable du schéma (tables, rubriques, liens)
|
|
analyse-sources.md → analyse WINDEV existante
|
|
BATIK.md / OMIKA.md → documentation historique
|
|
tools/generate_models.py → générateur des modèles physiques HFSQL (Batik/Omika)
|
|
src/
|
|
Omika.Core/
|
|
Constants/ → constantes applicatives et base de données
|
|
Interfaces/ → contrats (IRepository, IUnitOfWork)
|
|
Abstractions/ → types partagés (Result)
|
|
Runtime/ → version active de la base (BATIK/OMIKA), contexte global
|
|
Models/ → (vide pour l'instant) futurs modèles métier
|
|
Omika.Data/
|
|
Configuration/ → HfsqlOptions + validation
|
|
Connection/ → contrats et squelette de connexion HFSQL
|
|
Repositories/ → base commune des repositories
|
|
Mapping/ → référentiel de tables + mapping Batik/OMIKA
|
|
HfSql/Metadata/ → attributs de mapping HFSQL (Table, Column, PrimaryKey, CompositeKey, LegacyField)
|
|
HfSql/Models/ → modèles physiques générés (Batik/ et Omika/) — 106 classes
|
|
Migrations/ → service de migration Batik → OMIKA
|
|
Omika.Api/
|
|
Endpoints/ → endpoints HTTP (santé, futur métier)
|
|
Omika.App/
|
|
Views/ → MainWindow (desktop) et MainView (partagé)
|
|
ViewModels/ → MainViewModel, ViewModelBase
|
|
Omika.App.Desktop/
|
|
Omika.App.Android/
|
|
Omika.App.iOS/
|
|
tests/
|
|
Omika.Tests/ → tests xUnit (47 tests)
|
|
```
|
|
|
|
## 6. Conventions et règles
|
|
|
|
1. **Séparation des responsabilités** : l'UI (App) et l'API ne contiennent aucune
|
|
logique métier ; celle-ci vit dans **Omika.Core**.
|
|
2. **Accès aux données** : uniquement via **Omika.Data**, derrière les interfaces
|
|
`IRepository<TEntity,TId>` et `IUnitOfWork` définies dans **Omika.Core**.
|
|
3. **Pas de dépendance directe App → Data** : l'application mobile consommera
|
|
l'API (HTTP). Si un accès direct est nécessaire (hors ligne), il passera par
|
|
une façade dédiée à ajouter ultérieurement.
|
|
4. **Configuration** : les options de connexion HFSQL sont typées
|
|
(`HfsqlOptions`, section `"Hfsql"`), validées avant usage, et remplaçables
|
|
par la configuration .NET standard (appsettings / user-secrets / variables
|
|
d'environnement).
|
|
5. **Résultats d'opération** : les services renvoient `Result` / `Result<T>`
|
|
(Omika.Core) plutôt que de lever des exceptions pour les cas métier.
|
|
|
|
## 7. État de la couche HFSQL (phase d'architecture)
|
|
|
|
À ce stade, **aucune connexion HFSQL réelle n'est ouverte**. La couche fournit :
|
|
|
|
- `HfsqlOptions` et `HfsqlOptionsValidator` : préparation et validation des
|
|
paramètres (serveur, port 4900, base, groupes de protection ProtectionStd /
|
|
ProtectionPlus, comptes techniques) ;
|
|
- `IHfsqlConnection` / `HfsqlConnection` : contrat + implémentation squelette
|
|
(`OpenAsync` lève volontairement `NotImplementedException`) ;
|
|
- `RepositoryBase<TEntity,TId>` : base commune prête à câbler le provider HFSQL ;
|
|
- `LegacyTableMap` : référentiel des 58 tables OMIKA et des tables de l'ancienne
|
|
version (48 tables, e.g. `Intervention_Collaborateur` supprimée) ;
|
|
- `TableAttribute` : association future entité → table HFSQL ;
|
|
- `IMigrationService` / `MigrationService` : contrat de compatibilité Batik →
|
|
OMIKA (conversion de clés numériques vers textuelles, suivi ElementModifie /
|
|
ElementSupprime), non implémenté.
|
|
|
|
### 7.1 Modèles physiques générés (Batik / Omika)
|
|
|
|
Le dictionnaire machine-readable **`docs/schema-compatibilite-batik-omika.json`**
|
|
décrit le schéma WINDEV (tables, rubriques, types HFSQL, liens, marquage zombie).
|
|
Le générateur **`tools/generate_models.py`** produit à partir de ce fichier les
|
|
**106 modèles physiques** dans `Omika.Data/HfSql/Models` :
|
|
|
|
| Dossier | Contenu |
|
|
|---|---|
|
|
| `HfSql/Models/Batik/` | Modèles physiques de l'ancienne base (Isis_BO, 48 tables) |
|
|
| `HfSql/Models/Omika/` | Modèles physiques de la nouvelle base (OMIKA, 58 tables) |
|
|
|
|
Chaque classe `XxxRow` porte les attributs de mapping suivants :
|
|
|
|
- `[HfSqlTable]` : nom de la table, nom du fichier disque (`.fic`), groupes de
|
|
protection, versions de schéma concernées (Batik et/ou Omika) ;
|
|
- `[HfSqlColumn]` : nom physique de la rubrique, type HFSQL, longueur,
|
|
valeur par défaut, marquage « zombie » ou « Omika uniquement » ;
|
|
- `[HfSqlPrimaryKey]` / `[HfSqlCompositeKey]` : clé primaire (automatique ou composée) ;
|
|
- `[HfSqlLegacyField]` : rubrique historique à migrer, avec éventuellement la
|
|
rubrique de remplacement (`ReplacementColumn`).
|
|
|
|
Ces modèles sont **purement descriptifs** (attributs) : aucune requête n'est
|
|
exécutée. Ils constituent le socle du futur provider HFSQL et du mapping
|
|
table → entité.
|
|
|
|
Pour régénérer les modèles après modification du dictionnaire :
|
|
|
|
```powershell
|
|
python .\tools\generate_models.py
|
|
```
|
|
|
|
**Prochaine étape HFSQL** : choisir et brancher le provider HFSQL (.NET), puis
|
|
définir les entités du domaine en s'appuyant sur ces modèles physiques.
|
|
|
|
|
|
## 8. Sélection de base (BATIK / OMIKA)
|
|
|
|
Le mécanisme de sélection de la base est centralisé dans **`Omika.Core.Runtime`**
|
|
et **`Omika.Core.Compatibility`**, en distinguant deux notions :
|
|
|
|
- **`DatabaseSchemaSelection`** (`Omika.Core.Runtime`) — enum de la **sélection
|
|
demandée par la configuration** :
|
|
- `Auto` (0) : détection automatique de la base réelle (valeur par défaut sûre) ;
|
|
- `Batik` (1) : forcer l'ancienne base ;
|
|
- `Omika` (2) : forcer la nouvelle base.
|
|
- **`DatabaseSchemaVersion`** (`Omika.Core.Compatibility`) — enum de la
|
|
**provenance / version réellement détectée** d'une donnée :
|
|
- `Unknown` (0) : état non déterminé ;
|
|
- `Batik` (1) : ancienne version ;
|
|
- `Omika` (2) : nouvelle version.
|
|
Ce type ne doit pas être confondu avec `DatabaseSchemaSelection` : l'un décrit
|
|
la sélection demandée au démarrage (configuration), l'autre la version
|
|
réellement détectée du schéma dont provient une donnée.
|
|
- **`DatabaseSchemaSelectionParser`** — analyse une chaîne de configuration
|
|
(« Auto », « Batik » ou « Omika », insensible à la casse et aux espaces).
|
|
Il retourne un `Result<DatabaseSchemaSelection>` et refuse toute valeur
|
|
inconnue avec un message d'erreur explicite.
|
|
- **`ApplicationRuntimeContext`** — contexte global de l'application :
|
|
- `ConfigurationKey` : clé conventionnelle `"Omika:DatabaseVersion"` ;
|
|
- `Configure(...)` : définit la sélection demandée au démarrage (accepte
|
|
l'enum ou une chaîne de configuration) ;
|
|
- `SetDetectedVersion(...)` : fournit la version réellement détectée
|
|
(Batik / Omika) et la **valide** contre la sélection demandée ;
|
|
- `ValidateDetectedVersion(...)` : valide une version détectée sans modifier
|
|
le contexte global ;
|
|
- `Current` : accès au contexte actif (propriétés `Selection`,
|
|
`DetectedVersion`, `IsBatik`, `IsOmika`) ;
|
|
- `FromConfiguration(...)` : crée un contexte isolé sans toucher au global
|
|
(utile pour les tests et les traitements par lot) ;
|
|
- `Reset()` : réinitialise le contexte global.
|
|
|
|
**Sélection demandée ≠ version active**
|
|
|
|
Une valeur de configuration n'est **jamais** présentée comme version réellement
|
|
active : seule la base **détectée et validée** (`DetectedVersion`) détermine la
|
|
base utilisée. Tant que `SetDetectedVersion` n'a pas été appelé, la version
|
|
détectée reste `Unknown`, même si une sélection forcée (`Batik` / `Omika`) est
|
|
configurée.
|
|
|
|
**Comment changer la sélection demandée ?**
|
|
|
|
| Méthode | Exemple |
|
|
|---|---|
|
|
| **Fichier de configuration** (recommandé pour l'API) | Modifier la clé `"Omika:DatabaseVersion"` dans `appsettings.json` (valeur `"Auto"`, `"Batik"` ou `"Omika"`) |
|
|
| **Variable d'environnement** | `Omika__DatabaseVersion=Batik` (la convention .NET `__` est lue automatiquement) |
|
|
| **Au démarrage du code** | `ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Batik)` ou `Configure("Auto")` |
|
|
|
|
Une valeur inconnue lève une erreur explicite au démarrage. En mode `Auto`,
|
|
toute version réelle détectée (Batik ou Omika) est acceptée. En mode forcé, la
|
|
version détectée doit correspondre à la sélection demandée ; dans le cas
|
|
contraire, `SetDetectedVersion` retourne un échec explicite et **aucune version
|
|
active n'est affirmée** (la version détectée reste `Unknown`).
|
|
|
|
## 9. État des modèles métier
|
|
|
|
Les **modèles physiques HFSQL** (rubriques brutes du schéma WINDEV) vivent dans
|
|
`Omika.Data/HfSql/Models` (voir § 7.1). `Omika.Core/Models`, qui accueillera les
|
|
**entités du domaine**, est volontairement vide. La prochaine phase devra :
|
|
|
|
1. s'appuyer sur l'inventaire machine-readable du schéma (déjà produit) et sur
|
|
les modèles physiques pour définir les entités du domaine (Client, Dossier,
|
|
Intervention, RDV, …) ;
|
|
2. distinguer les propriétés utiles au domaine des rubriques « zombie »
|
|
(conservées pour la lecture d'une base existante, à ne pas utiliser comme
|
|
référence dans le nouveau domaine) ;
|
|
3. définir les DTO exposés par l'API et consommés par l'application.
|
|
|
|
|
|
## 10. Commandes utiles
|
|
|
|
```powershell
|
|
# Restaurer les packages
|
|
dotnet restore .\Omika.slnx
|
|
|
|
# Compiler toute la solution (hôtes desktop + API + bibliothèques + tests)
|
|
dotnet build .\Omika.slnx
|
|
|
|
# Compiler uniquement l'API
|
|
dotnet build .\src\Omika.Api\Omika.Api.csproj
|
|
|
|
# Compiler le client desktop (Windows)
|
|
dotnet build .\src\Omika.App.Desktop\Omika.App.Desktop.csproj
|
|
|
|
# Compiler l'hôte Android (APK)
|
|
dotnet build .\src\Omika.App.Android\Omika.App.Android.csproj
|
|
|
|
# Compiler l'hôte iOS (simulateur) — nécessite macOS + Xcode
|
|
dotnet build .\src\Omika.App.iOS\Omika.App.iOS.csproj
|
|
|
|
# Lancer les tests unitaires
|
|
dotnet test .\tests\Omika.Tests\Omika.Tests.csproj
|
|
|
|
# Lancer l'API en développement
|
|
dotnet run --project .\src\Omika.Api\Omika.Api.csproj
|
|
# → http://localhost:5xxx/health (état de la solution)
|
|
|
|
# Lancer le client desktop
|
|
dotnet run --project .\src\Omika.App.Desktop\Omika.App.Desktop.csproj
|
|
```
|
|
|
|
## 11. Prochaines étapes
|
|
|
|
- [ ] Choisir et intégrer le provider HFSQL (.NET) dans `Omika.Data`.
|
|
- [ ] Enrichir le dictionnaire `docs/schema-compatibilite-batik-omika.json`
|
|
(liens, règles de migration) et régénérer les modèles physiques.
|
|
- [ ] Définir les entités métier dans `Omika.Core/Models`.
|
|
- [ ] Implémenter les endpoints métier de `Omika.Api`.
|
|
- [ ] Brancher l'application Avalonia sur l'API (client HTTP) et préparer la
|
|
navigation mobile.
|
|
- [ ] Ajouter un projet `Omika.App.Windows` si un client Windows dédié est requis
|
|
(le desktop actuel en tient déjà lieu).
|
|
|
|
|