# 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` 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` (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` : 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` 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).