Files
Omika/docs/phase5-diagnostic-center.md
2026-10-23 18:46:50 +02:00

5.7 KiB

Phase 5 — Diagnostic Center (architecture & décisions)

Outil SUPPORT uniquement (§13). PostgreSQL et OpenTelemetry ne sont jamais critiques pour Omika : Mobile → DiagnosticOutbox → POST /api/diagnostics → RemoteDiagnosticIngestionStore (JSONL durable) → ACK mobile reste inchangé (§4). L'import PostgreSQL et l'export OTLP sont asynchrones et optionnels.

Architecture retenue

APPLICATIONS OMIKA (Mobile / Desktop / API / Worker)
             │
             ▼
       IOmikaTelemetry
             │
             ▼
     SafeTelemetrySink
             │
             ▼
     PriorityTelemetryQueue (P0-P4)
             │
      ┌──────┴─────────┐
      ▼                ▼
 JSONL / Outbox    OpenTelemetry (OTLP HTTP, optional, kill-switch)
 durable Omika          │
      │                 ▼
      │        OpenTelemetry Collector (Windows Service)
      │                 │
      ▼                 ▼
 Diagnostic Import   Omika Telemetry Backend   ← transport finalisé Phase serveur
      │                 │
      └────────┬────────┘
               ▼
          PostgreSQL (omika_diagnostics)
               │
               ▼
       Omika Diagnostic Center (ASP.NET Core Web)

Projets créés (§12)

Projet Rôle
src/Omika.Diagnostics.Core Domain / models, abstractions repository, importer, whitelist sécurité
src/Omika.Diagnostics.Data Persistance PostgreSQL (Npgsql direct), source JSONL, checkpoint
src/Omika.Diagnostics.Worker Import asynchrone JSONL → PostgreSQL (BackgroundService, backoff)
src/Omika.Diagnostics.Web Diagnostic Center Web (Razor Pages) + auth support/admin

Choix d'accès données (§25)

Npgsql direct (pas d'ORM). Justification :

  • Sous-système simple : 2 tables, peu de patrons de requêtes.
  • Aucune « magie » (pas de mapping réflexif, pas d'EF Core) — SQL explicite et lisible.
  • Pooling intégré de Npgsql (§24) : jamais une connexion par événement.
  • Dapper réduirait le boilerplate mais ajoute une dépendance + réflexion inutile ici.
  • EF Core est surdimensionné pour 2 tables.

Version : Npgsql 10.0.3 (aligné .NET 10, présent dans le cache local du poste).

Données interdites (§19) et whitelist (§18)

Réutilise DiagnosticForbiddenData (Phase 4) : password, token, authorization, cookie, connectionstring, requestbody, responsebody, emailbody, smtp, imei, macaddress, advertisingid, signature, secret.

Les métadonnées metadata_json (JSONB) ne sont pas un stockage libre : DiagnosticMetadataPolicy n'autorise qu'une whitelist de clés low-cardinality (method, routeTemplate, statusCode, exceptionType, retryCount, …) et rejette toute clé/valeur interdite. Les champs d'identité métier (DeviceId, UserId, ClientId, CollaborateurId, EntityId) ne sont pas persistés dans PostgreSQL (confidentialité, §30/§31).

Importeur JSONL → PostgreSQL (§20-§23)

DiagnosticImporter.ImportOnceAsync() : lecture bornée (BatchSize, défaut 100) → mapping (whitelist) → INSERT ... ON CONFLICT (event_id) DO NOTHING (batch) → avancement du checkpoint uniquement après insertion réussie.

  • at-least-once : le checkpoint n'avance qu'après succès → doublons possibles, dédupliqués par event_id unique en base (§16).
  • fail-open (§22) : toute erreur PostgreSQL → résultat Retryable, JSONL intact, checkpoint non avancé, backoff exponentiel borné (aucune boucle CPU).
  • idempotent : relire un fichier déjà importé est sans effet (ON CONFLICT).

Checkpoint (§21)

import-checkpoint.json (curseur { fileName, lineIndex }), distinct du checkpoint du forwarder OpenTelemetry. Reprise après restart / PostgreSQL down / reboot sans réimporter tout l'historique. Les fichiers JSONL bruts ne sont jamais supprimés.

Rétention (§45)

Diagnostics:RetentionDays (défaut 60 jours), non hardcodé. La purge (DELETE ... WHERE timestamp_utc < now() - interval '60 days') est documentée mais non exécutée automatiquement (purge destructive → maintenance planifiée).

Métriques (§28-§31)

Table telemetry_metric_hourly : agrégats horaires (bucket_utc, metric_name, component, value, count, min/max, tags_json). Low-cardinality obligatoire (ExternalAttributePolicy) : jamais TraceId/SessionId/UserId/DeviceId/GUID métier en dimension. Utilisateurs actifs/jour = agrégation respectueuse de la confidentialité, jamais de surveillance individuelle (§31).

Traces (§32/§33/§39/§40)

X-Omika-TraceId reste l'identifiant applicatif de support (§33). La timeline Mobile → API → Worker se reconstruit par trace_id (ORDER BY timestamp_utc ASC), et par operation_id pour les synchronisations.

Configuration (générique, jamais de secret §26)

Observability:
  External:
    Enabled: false          # kill-switch : aucun OTLP, aucun réseau, aucun crash
    OtlpEndpoint: ""
  Remote:
    Directory: ""           # JSONL durable (frontière d'ACK Phase 4)

Diagnostics:
  ConnectionString: ""      # configuration / variable d'environnement UNIQUEMENT
  RetentionDays: 60
  Import:
    BatchSize: 100
    CheckpointFileName: "import-checkpoint.json"

Déploiement (Phase serveur, PAS dans cette phase)

  • Windows Server 2025 : PostgreSQL + OpenTelemetry Collector (Windows Service) + Omika.Diagnostics.Worker + Omika.Diagnostics.Web.
  • Aucune dépendance Linux / Docker / ClickHouse / SigNoz / Kubernetes.
  • Rien n'est à installer sur le serveur dans cette phase (§ « NE RIEN INSTALLER »).