Skip to content

core: build resilient API client with token refresh and offline queue #47

Description

@EmeditWeb

Problem

The learner app targets users on unreliable mobile connectivity, but the API
client is not resilient. register.tsx swallows registration failures in an
empty catch with only a TODO (#44), stores do not persist (#38, #39), and
api.ts has no centralized 401 refresh-and-retry, no backoff for transient
network errors, and no offline request queue. A dropped connection during a
mutation is silently lost with no user feedback and no retry.

Before Starting

Read ALL of these before writing any code:

  • context/architecture-context.md
  • context/code-standards.md

What To Build

A resilient API client layer:

  1. An interceptor-based client with automatic 401 handling: refresh the token
    once, retry the original request, and hard-logout on refresh failure.
  2. Exponential backoff with jitter for idempotent requests on transient
    network/5xx errors, with a request-timeout ceiling.
  3. A durable offline mutation queue (secure/persisted storage) that captures
    writes made while offline and replays them on reconnect, with per-request
    idempotency keys to avoid duplicates.
  4. Consistent typed error surfacing so screens can show real feedback instead
    of swallowing errors.

Files To Touch

  • services/api.ts (interceptors, refresh, retry)
  • src/offline/* (mutation queue + replay)
  • app/register.tsx (real error handling)
  • services/auth.service.ts

Acceptance Criteria

  • 401s trigger a single refresh + retry; refresh failure logs out
  • Transient failures retried with exponential backoff + jitter
  • Offline mutations queued durably and replayed on reconnect
  • Idempotency keys prevent duplicate submissions on replay
  • register.tsx surfaces real errors; no empty catch blocks remain
  • Tests cover refresh, retry, and offline replay

Mandatory Checks Before Opening PR

  • All context/ files read and understood
  • npx expo export --platform web passes
  • No TypeScript errors
  • No hardcoded hex colors (constants/colors.ts only)
  • Icons from lucide-react-native only
  • Loading, error, and empty states handled
  • PR references this issue number

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions