136 lines
5.7 KiB
Markdown
136 lines
5.7 KiB
Markdown
# 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
|
|
|
|
```text
|
|
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)
|
|
|
|
```yaml
|
|
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 »).
|