# Schéma de base de données — ARGOS (SQLite / EF Core 8) Référence tenue à jour au fil de l'implémentation des entités `App.Core/Entities/**`. Les types EF Core réels sont fixés dans `App.Infrastructure/Data/Configurations/*`. ## Équipe & authentification **Users** — Id PK · Username (UNIQUE) · PasswordHash (Argon2id) · FullName · Email? · Role (enum) · IsActive · CreatedAtUtc · LastLoginAtUtc? **TechnicianProfiles** (1:1 avec Users) — UserId PK/FK → Users · Skills? · PhoneNumber? **QualificationTypes** — Id PK · Code (ex "B1","BR") · Label · Category (enum Electrique/Mecanique/Autre) **TechnicianQualifications** — Id PK · TechnicianUserId FK → TechnicianProfiles · QualificationTypeId FK · ObtainedDate · ExpiryDate? · CertificateAttachmentId FK → Attachments? Index (TechnicianUserId, ExpiryDate) pour l'alerte habilitations expirantes. **TimeEntries** — Id PK · WorkOrderId FK → WorkOrders · TechnicianUserId FK → Users · StartedAtUtc · EndedAtUtc? · DurationMinutes · Source (enum Pc/AndroidSync) · Comment? · SyncDeviceId FK → SyncDevices? ## Machines **Machines** — Id PK · Reference (UNIQUE) · Designation · Location? · Criticality (enum) · CommissioningDate? · PhotoAttachmentId FK → Attachments? · IsActive (soft delete) · CreatedAtUtc · UpdatedAtUtc **MachineParts** — MachineId FK, PartId FK (PK composite) — nomenclature pièces/machine **MachineCounterReadings** — Id PK · MachineId FK · CounterType (texte libre) · Value (REAL) · RecordedAtUtc · Source (enum Pc/AndroidSync) Index (MachineId, CounterType, RecordedAtUtc DESC) ## Maintenance préventive **MaintenancePlans** (gammes) — Id PK · MachineId FK · Name · Description? · FrequencyType (enum) · **StartDate** (ancre avant 1ère exécution) · CustomIntervalDays? · DayOfWeek? · DayOfMonth? · MonthlyRuleOccurrence? · MonthlyRuleWeekday? · CounterType? · CounterThreshold? · LeadTimeDays? · LeadTimePercentForCounter? · RequiredQualificationTypeId FK? · LastExecutionDateUtc? · LastExecutionCounterValue? · IsActive · CreatedAtUtc **MaintenanceTasks** — Id PK · MaintenancePlanId FK · Order · Label · Description? · EstimatedDurationMinutes? **Tools** — Id PK · Name (référentiel réutilisable) **MaintenanceTaskTools** — MaintenanceTaskId FK, ToolId FK (PK composite) **MaintenanceTaskParts** — MaintenanceTaskId FK, PartId FK (PK composite) · QuantityRequired **WorkOrders** (OT) — Id PK · MachineId FK · MaintenancePlanId FK? (null = curatif) · Type (enum) · Status (enum) · Priority (enum) · ScheduledDate · DueDate? · CompletedAtUtc? · AssignedTechnicianUserId FK → Users? · **GeneratedForOccurrenceKey?** · Comment? · Source (enum) · CreatedAtUtc **Index unique filtré** : `(MaintenancePlanId, GeneratedForOccurrenceKey) WHERE MaintenancePlanId IS NOT NULL` — anti-doublon de génération, voir `MaintenanceSchedulingEngine`. **WorkOrderTaskResults** — Id PK · WorkOrderId FK · MaintenanceTaskId? (null = tâche ad-hoc curative) · IsCompleted · Comment? · PhotoAttachmentId FK → Attachments? · CompletedAtUtc? · CompletedByTechnicianUserId FK → Users? **WorkOrderPartsUsed** — Id PK · WorkOrderId FK · PartId FK · QuantityUsed · StockMovementId FK → StockMovements? ## Magasin / stock **Suppliers** — Id PK · Name · ContactName? · Phone? · Email? · Address? **Parts** — Id PK · Reference (UNIQUE) · Designation · QuantityInStock (dénormalisé) · AlertThreshold · Location? · PrimarySupplierId FK? · UnitPrice · PhotoAttachmentId FK? · IsActive **StockMovements** — Id PK · PartId FK · MovementType (enum In/Out) · Quantity · Reason? · WorkOrderId FK? · SupplierInvoiceId FK? · CreatedByUserId FK → Users · CreatedAtUtc Index (PartId, CreatedAtUtc) ## Facturation **SupplierInvoices** — Id PK · SupplierId FK? · InvoiceNumber? · InvoiceDate · Amount · AttachmentId FK → Attachments (NOT NULL) · LinkedWorkOrderId FK? · ImportedAtUtc **Invoices** — Id PK · DocumentType (enum Invoice/Quote) · Number (UNIQUE) · ClientName · ClientAddress? · IssueDate · DueDate? · VatRate · Status (enum) · TotalHT · TotalTTC · PdfAttachmentId FK? · LinkedWorkOrderId FK? · CreatedByUserId FK → Users · CreatedAtUtc **InvoiceLines** — Id PK · InvoiceId FK · Order · Designation · Quantity · UnitPrice · VatRateOverride? ## Sync réseau local (Android futur) **SyncDevices** — Id PK · DeviceName · DeviceIdentifier (UNIQUE) · PairedAtUtc · PairingPinHash · LastSyncAtUtc? · IsActive **SyncLogEntries** — Id PK · SyncDeviceId FK · Direction (enum Push/Pull) · EntityType · Status (enum) · ErrorMessage? · OccurredAtUtc ## Transverse **Attachments** — Id PK · FileName · ContentType · StoredRelativePath (relatif à LocalFolder) · SizeBytes · EntityType (enum `AttachmentOwnerType`) · EntityId (int) · UploadedAtUtc · UploadedByUserId FK → Users? ⚠️ Clé polymorphe (EntityType+EntityId) : pas de FK SQLite possible, intégrité gérée par `IAttachmentRepository` (choix assumé, voir `docs/ARCHITECTURE.md`). **AppSettings** — Key PK (texte) · Value (texte) — clé-valeur générique, typé côté `App.Core` via `ISettingsProvider`. Clés connues : `App.Core.Entities.Shared.AppSettingKeys`. **LicenseActivationCache** — Id PK · CompanyName · MaxUsers · MaxMachines · IssuedDate — cache d'affichage uniquement, jamais utilisé pour la vérification (voir §Licence). ## Licence & essai — hors SQLite - État d'essai (`InstallDateUtc`, `HardwareIdHash`, `LastRunTimestampUtc`) : fichier séparé chiffré DPAPI (`DataProtectionScope.LocalMachine`) dans `LocalFolder`, PAS en base — un reset de `app.db` ne doit jamais relancer un essai. - Licence activée : fichier `.lic` JSON signé Ed25519, copié tel quel dans `LocalFolder`, revérifié (signature + hardware match) à chaque démarrage. Modèles : `App.Core.Services.Licensing.{LicenseFile, TrialState, LicenseCheckResult}`. ## Notes d'implémentation - Mode SQLite **WAL** à activer dès la première migration (`PRAGMA journal_mode=WAL`) : App.UI (thread UI) et App.SyncServer (Kestrel local) écrivent potentiellement en même temps dans `app.db`. - Toutes les dates métier "pures" (échéances, dates de naissance de document) utilisent `DateOnly` ; les horodatages système utilisent `DateTime` en UTC (`...AtUtc`).