SecuAAS Docs
ConformVault

API Desktop Agent

Endpoints pour le client desktop ConformVault — registration, heartbeat, sync, SSE, conflict reporting

API Desktop Agent

Disponible depuis filesecure v3.29.0 (avril 2026). Authentification par token de device (X-Device-Token).

L'API Desktop Agent permet au client ConformVault Desktop (Tauri) de synchroniser un dossier local avec le serveur. Elle est distincte de la Developer API (clé API publique) et de l'API interne (JWT user) — elle utilise un token long-vie scopé à un device, créé une seule fois lors de l'enregistrement.

Vue d'ensemble du flow

1. POST /api/v1/agent/register     [JWT user]    → device_token (cvdt_…)
2. POST /api/v1/agent/heartbeat    [X-Device-Token] → ping périodique (60s)
3. GET  /api/v1/agent/config       [X-Device-Token] → paramètres sync (interval, chunk size)
4. GET  /api/v1/files/delta        [X-Device-Token] → polling incrémental
5. GET  /api/v1/events/stream      [X-Device-Token] → SSE push temps réel
6. POST /api/v1/files/upload-init  [X-Device-Token] → resumable upload : init
   PUT  /api/v1/files/upload-part  [X-Device-Token] → resumable upload : chunk
   POST /api/v1/files/upload-complete [X-Device-Token] → resumable upload : finalisation
7. POST /api/v1/sync/conflict      [X-Device-Token] → reporter un conflit local

Registration

POST /api/v1/agent/register

Enregistre un nouveau device pour l'utilisateur courant et retourne un device_token long-vie.

Authentification : Authorization: Bearer <jwt-user>

Corps de requête :

{
  "device_name": "Olivier-MacBook",
  "platform": "darwin",
  "arch": "arm64",
  "app_version": "0.5.1",
  "capabilities": {
    "sync": true,
    "resumable_upload": true,
    "sse": true,
    "max_chunk_mb": 10
  }
}
ChampTypeDescription
device_namestringNom lisible du device (max 120 chars). Pré-rempli avec le hostname.
platformstringUne de : darwin, windows, linux.
archstringArchitecture CPU (x86_64, aarch64, etc.).
app_versionstringVersion du client desktop.
capabilitiesobject (optionnel)Capacités déclarées par le client. Stocké tel quel en JSONB côté serveur.

Réponse 201 :

{
  "device_id": "550e8400-e29b-41d4-a716-446655440000",
  "device_token": "cvdt_a1b2c3d4e5f6...",
  "expires_at": null,
  "created_at": "2026-04-28T10:00:00Z"
}

Important : Le device_token est retourné une seule fois. Le serveur stocke uniquement son hash SHA-256 et ne peut pas le récupérer. Le client doit le persister immédiatement (OS keychain recommandé).

Erreurs :

  • 400 Bad Requestdevice_name manquant ou plateforme invalide
  • 401 Unauthorized — JWT invalide ou expiré

Heartbeat

POST /api/v1/agent/heartbeat

Met à jour le last_seen_at du device. À appeler toutes les 60 secondes par défaut (configurable via agent/config).

Authentification : X-Device-Token: cvdt_…

Corps de requête :

{
  "app_version": "0.5.1",
  "sync_status": "idle"
}

Réponse 200 :

{
  "device_id": "550e8400-e29b-41d4-a716-446655440000",
  "last_seen_at": "2026-04-28T10:01:00Z",
  "paused": false,
  "server_time": "2026-04-28T10:01:01Z"
}

Erreurs :

  • 401 Unauthorized — Token de device invalide ou révoqué. Le client doit re-register.

Configuration distante

GET /api/v1/agent/config

Retourne les paramètres de sync poussés par le serveur (l'admin peut les ajuster par device).

Authentification : X-Device-Token: cvdt_…

Réponse 200 :

{
  "device_id": "550e8400-e29b-41d4-a716-446655440000",
  "paused": false,
  "selective_sync_paths": ["/Documents", "/Projects"],
  "bandwidth_cap_kbps": 8192,
  "sync_interval_secs": 30,
  "max_chunk_mb": 10
}
ChampDescription
pausedSync globalement en pause pour ce device.
selective_sync_pathsChemins relatifs à synchroniser uniquement (vide = tout).
bandwidth_cap_kbpsPlafond upload/download en kilobits/s (0 = illimité).
sync_interval_secsCadence du polling delta (min 5s, défaut 30s).
max_chunk_mbTaille de chunk recommandée pour les resumable uploads.

Delta sync

GET /api/v1/clients/:client_id/files/delta

Retourne les fichiers ajoutés / modifiés / supprimés depuis un timestamp donné, avec pagination keyset.

Authentification : X-Device-Token: cvdt_…

Paramètres query :

ParamètreTypeDescription
sincestring (RFC3339)Timestamp seuil (requis).
cursorstring (optionnel)Curseur opaque pour la page suivante.
limitintNombre max d'éléments (défaut 100, max 200).
include_deletedboolInclure les fichiers supprimés (défaut true).

Réponse 200 :

{
  "files": [
    {
      "id": "uuid",
      "name": "rapport.pdf",
      "size": 1048576,
      "encrypted_size": 1049000,
      "mime_type": "application/pdf",
      "version": 3,
      "checksum": "sha256:…",
      "folder_id": "uuid",
      "encrypted_metadata": "base64",
      "deleted_at": null,
      "updated_at": "2026-04-28T10:00:00Z",
      "created_at": "2026-04-15T08:00:00Z"
    }
  ],
  "next_cursor": "opaque-cursor-or-null",
  "has_more": true,
  "fetched_at": "2026-04-28T10:01:00Z"
}

Le client doit suivre le next_cursor jusqu'à has_more=false, puis utiliser fetched_at comme nouveau since au prochain round.

SSE — Stream d'événements temps réel

GET /api/v1/events/stream

Flux Server-Sent Events qui pousse les changements en temps réel (alternative au polling pour les clients connectés).

Authentification : X-Device-Token: cvdt_…

Headers :

  • Accept: text/event-stream
  • Last-Event-ID: <id> (optionnel, pour reprendre après déconnexion)

Format des événements :

event: file.created
data: {"file_id":"uuid","client_id":"uuid","name":"a.pdf","version":1}
id: 42

event: file.updated
data: {"file_id":"uuid","client_id":"uuid","version":3}
id: 43

event: file.deleted
data: {"file_id":"uuid","client_id":"uuid"}
id: 44

event: space.activity
data: {"space_id":"uuid","action":"document_uploaded","actor_id":"uuid"}
id: 45

Reconnexion : Le client doit reconnecter avec backoff exponentiel borné (1s → 60s) en cas de coupure, en envoyant Last-Event-ID pour reprendre.

Erreurs :

  • 401 — Token invalide → re-register
  • 503 — Service en surcharge (rare)

Resumable upload (3 étapes)

POST /api/v1/clients/:client_id/files/upload-init

Crée une session d'upload et retourne le plan de chunks.

Corps :

{
  "file_name": "rapport.pdf",
  "total_size": 52428800,
  "chunk_size": 5242880,
  "folder_id": "uuid (optionnel)",
  "mime_type": "application/pdf",
  "checksum": "sha256:…"
}

Réponse 200 :

{
  "session_id": "uuid",
  "chunk_size": 5242880,
  "total_chunks": 10
}

Le serveur peut renvoyer un chunk_size différent de la requête (clamp à max_chunk_mb).

PUT /api/v1/clients/:client_id/files/upload-part

Upload un chunk individuel.

Query params :

  • session_id : UUID retourné par upload-init
  • part : index du chunk, 0-based

Headers : Content-Type: application/octet-stream

Corps : bytes du chunk (taille = chunk_size, sauf le dernier chunk qui peut être plus petit).

Réponse 200 : {"part": 0}

Stratégie de retry : 5xx et 429 → backoff exponentiel jitter (cap 30s, max 5 retries). 4xx (autre que 429) → abort immédiat.

POST /api/v1/clients/:client_id/files/upload-complete

Finalise l'upload et crée l'enregistrement fichier.

Corps :

{
  "session_id": "uuid",
  "encrypted_file_key": "base64 (optionnel)",
  "checksum": "sha256:… (optionnel)"
}

Réponse 200 : payload du fichier créé (incluant id).

Conflict reporting

POST /api/v1/clients/:client_id/sync/conflict

Notifie le serveur qu'un conflit a été détecté localement et résolu (server-wins par défaut côté client).

Corps :

{
  "file_id": "uuid",
  "conflict_type": "edit_edit",
  "local_version": "v3-local",
  "server_version": "v3-server",
  "device_id": "uuid"
}

Types de conflit :

  • edit_edit — modifié des deux côtés
  • delete_edit — supprimé localement, modifié serveur
  • edit_delete — modifié localement, supprimé serveur

Réponse 200 : {"id": "uuid", "ok": true, "recorded_at": "..."}

Le serveur ne tranche pas — il enregistre la résolution dans le journal d'audit + l'activité du space.

SDKs officiels

Les trois SDKs implémentent ces endpoints :

SDKModuleVersion min
Gogithub.com/secuaas/conformvault-sdk-go/agentv0.7.0
Pythonconformvault.agent + conformvault.syncv0.8.0
TypeScript@secuaas/conformvault/agentv2.5.0

Exemple Go : examples/desktop-sync/main.go du repo conformvault-sdk-go. Exemple Python : examples/desktop_sync.py du repo conformvault-sdk-python.

Sécurité

  • Le device_token n'est jamais journalisé en clair côté serveur — seul son hash SHA-256 est stocké.
  • Un device peut être révoqué via DELETE /api/v1/devices/:id (interface utilisateur dans Settings → Devices).
  • Le X-Device-Token n'autorise que les endpoints /api/v1/agent/*, /api/v1/files/delta, /api/v1/files/upload-*, /api/v1/events/stream, /api/v1/sync/conflict. Les opérations sensibles (admin, users, billing) restent JWT-only.
  • Toutes les communications sont en TLS 1.2+ (cert Let's Encrypt via cert-manager k8s).

Observabilité

Les métriques Prometheus sont exposées sur /metrics :

  • conformvault_agent_register_total — compteur de registrations
  • conformvault_agent_heartbeat_total{device_id} — heartbeats par device
  • conformvault_files_delta_duration_seconds — histogramme du temps de réponse
  • conformvault_events_stream_clients — gauge des consumers SSE actifs
  • conformvault_upload_chunk_duration_seconds — histogramme par chunk
  • conformvault_sync_conflicts_total{conflict_type} — compteur de conflits par type

Le dashboard Grafana est disponible à https://grafana.secuaas.ovh/d/conformvault-api.

On this page