Commit Graph
14 Commits
Author SHA1 Message Date
m 197c7db8a9 feat(mobile): boucle sync client↔serveur — outbox push + snapshot permissions
- api/types.ts : SyncOperation, SyncResult (sémantique `applied` = INDEX documentée),
  ResourcePermission (miroir docs/api-v1.md §6, consommé tel quel par saveResourcePermission)
- api/client.ts : syncOps (POST /sync/ops), getSyncPermissions (GET /sync/permissions?after=),
  hasAuthToken() ; INVALID_RESPONSE documenté dans docs/api-v1.md §1/§4
- services/db/repositories/pendingOps.ts : listQueuedOperations(limit) (batch FIFO due)
  + scheduleRetries(ids, retryAt) qui ne modifie JAMAIS attempts (erreur transitoire,
  contrairement à markPendingOperation('failed') qui incrémente + backoff)
- features/syncOutbox.ts (nouveau) :
  * pushPendingOps : batch ≤ SYNC_BATCH_SIZE (50) → ops [0, applied) passent 'completed' ;
    op à l'index applied refusée → 'failed' (backoff, dead-letter MAX_PENDING_ATTEMPTS) ;
    ops suivantes intactes (re-soumission) ; réseau/5xx → scheduleRetries (retried) sans
    dead-letter prématurée ; applied==0 && failed → rien commité, aucun compteur touché
  * refreshPermissions : delta monotone en mémoire lastPermissionCachedAt → `after`,
    upsert saveResourcePermission ; no-op sans token
- features/syncDevice.ts : le tick useSyncDevice() enchaîne SAF walk → pushPendingOps()
  → refreshPermissions(), tous deux gardés par hasAuthToken()
- tests/syncOutbox.test.ts : 12 cas (FIFO/limit, succès complet/partiel, applied=0,
  transitoire réseau + 5xx sans incrément, dead-letter après MAX_PENDING_ATTEMPTS,
  delta snapshot croisé) — npm run test:sync
- tests/e2e.live.test.ts : smoke real backend (register → push → relecture /files/folders →
  snapshot), skip si serveur down, SORTI de npm test via npm run test:e2e
- gates : npx tsc --noEmit + npm run test → 56/56 verts (24 db + 20 api + 12 sync)
2026-09-10 20:23:55 +02:00
m eddab392a2 test(mobile): blindage contrat API — suite apiClient + durcissement INVALID_RESPONSE
- tests/apiClient.test.ts (tsx/node:test, fetch stubbé) : paths/méthodes/query/body de tous les endpoints, multipart FormData sans Content-Type manuel, enveloppe {data,meta}, Bearer (présent/absent/fusion)
- cas hostiles : 2xx HTML/corps vide/JSON invalide/objet sans data/error → ApiError INVALID_RESPONSE (jamais de TypeError ni data indéfini) ; bare 5xx → HTTP_<status> ; fetch rejeté (dont AbortError) → NETWORK_ERROR ; [] toléré en data
- client.ts : parse d'enveloppe stricte dans request() (nouveau code client INVALID_RESPONSE)
- package.json : scripts test:api + test (db + api)
2026-09-10 20:16:27 +02:00
m caa6e6483c feat(api): /devices register + paseto v4 (middleware Bearer, bootstrap mobile du token) 2026-09-10 07:25:11 +02:00
m 8ff2339c8a better iterface 2026-09-10 06:46:22 +02:00
m 2ba837bcb0 from scratch 2026-09-09 18:23:01 +02:00
m 3d63dc1987 sse implémentaton 2026-07-29 19:08:22 +02:00
m 9c699446dc migrate mobile with new endpoints 2026-07-28 20:28:32 +02:00
m cd24ba5b0c display pdf files 2026-07-16 08:32:48 +02:00
m 333387ad98 add missing headers 2026-07-14 09:59:41 +02:00
m 76ceafa56c add backend auth 2026-07-14 09:47:55 +02:00
m 911592758a handle https tatus 2026-07-12 13:53:39 +02:00
m b6e38e930c refresh signed files 2026-07-11 23:09:35 +02:00
m 8e728c9042 upload file is working 2026-07-11 22:10:17 +02:00
m b1f7fe6959 init project 2026-07-11 20:12:00 +02:00