Files
orion/clients/terminal-android/app
Samir Boulahtit ac5f46cff3
Some checks failed
CI / ruff (push) Successful in 16s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled
feat(android-terminal): Phase E — offline queue + sync
Stamp / earn / enroll actions performed without connectivity now persist
in the existing pending_transactions Room table and drain via a
SyncWorker as soon as the network constraint is satisfied. Redemption
stays online-only (server needs the authoritative balance — queueing
would let cashiers redeem rewards customers have already spent).

Pieces:

- Hilt-Work plumbing: androidx.hilt:hilt-compiler KSP processor wired,
  RewardFlowApp now implements Configuration.Provider with the injected
  HiltWorkerFactory, AndroidManifest disables the WorkManager auto-init
  via the AndroidX startup tools:node="remove" pattern. Bumped Dagger
  to 2.55 so its compiler can read Kotlin 2.1 metadata — 2.51 crashed
  with "Unable to read Kotlin metadata due to unsupported metadata
  version" once we added @Inject lateinit var on the Application class.

- data/sync/SyncWorker.kt — @HiltWorker CoroutineWorker that drains the
  queue FIFO. Per row: HTTP error → permanent markFailed; IOException
  → Result.retry(); success → markSynced + sweep at end of run.

- data/repository/QueueRepository.kt — single entrypoint for "queue
  this offline action". queueStamp / queuePointsEarn / queueEnroll
  Moshi-serialize the request body and enqueueUniqueWork(KEEP) the
  worker under a NetworkType.CONNECTED constraint with 30s exponential
  backoff. scheduleSync() is idempotent.

- TerminalViewModel: runAction(block, queueOnNetworkFailure) — on
  IOException AND a queue lambda is provided, queue + emit
  ActionResult.Queued. HttpException paths still surface the server's
  message inline. Stamp / Earn / Enroll go through the queue path;
  redeem actions pass null. setStaffPinId records who initiated each
  queued row. init schedules a sync so anything left from a previous
  session drains on screen entry. pendingSyncCount is combined into
  state via Flow<Int> from the DAO; when it drops to 0 we refresh the
  recent-transactions feed so the UI shows what just synced.

- TerminalScreen: PendingSyncPill in the top bar (only visible when
  count > 0) gives the cashier feedback that a queued action is
  waiting + that the queue is draining live.

Cleartext + readable HTTP errors from yesterday remain in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:54:42 +02:00
..