Skip to main content
Status: Superseded Date: 2026-02-10 Deciders: Core team
This ADR has been superseded. Mobile schemas are retained for API backward compatibility, but the React Native client was removed in favor of a native Swift iOS app.

Context

The mobile app consumes APIs implemented in apps/api. Zod schemas are already used across the monorepo (@reflection/schemas) to validate external inputs and define domain-level contracts. Mobile-specific concerns:
  • API response shapes can drift; TypeScript types alone do not protect runtime behavior.
  • Mobile should fail fast and explicitly when the backend returns unexpected payloads, rather than crashing later in UI rendering.
  • A single canonical place for schemas avoids parallel/duplicated contract definitions.
Constraints:
  • Keep dependency flow consistent with monorepo rules: apps depend on packages; packages must not depend on apps.
  • Avoid speculative complexity (0-user mode): no heavy codegen or schema frameworks unless needed.

Decision

Centralize mobile-facing DTO schemas in @reflection/schemas and validate API responses at the boundary in the mobile app:
  • Define mobile DTO schemas in a dedicated module and export them via a dedicated package export path: @reflection/schemas/mobile.
  • In the mobile app, parse API responses using shared Zod schemas so failures are explicit and testable.
  • Add schema-level tests to lock contract shape and avoid accidental breaking changes.

Alternatives considered

Alternative 1: TypeScript-only types (no runtime validation)

Keep response typing in TS but do not validate payloads at runtime. Pros:
  • Lowest overhead at runtime.
  • No additional parsing step.
Cons:
  • Does not protect against backend drift or unexpected data.
  • Failures occur downstream in UI code and are harder to debug.
Not chosen because runtime safety at the boundary is worth the small parsing overhead for mobile.

Alternative 2: Define schemas inside the mobile app only

Keep mobile DTO schemas local to the app. Pros:
  • Faster iteration without touching shared packages.
  • No need to coordinate releases across packages.
Cons:
  • Duplicates contract definitions across the repo.
  • Encourages divergence between server expectations and client assumptions.
Not chosen to keep a single canonical contract definition shared across apps.

Alternative 3: Generate types/schemas from an OpenAPI spec

Establish OpenAPI as the source of truth and generate client/server bindings. Pros:
  • Stronger tooling and automated drift detection.
  • Potentially improved docs and API discoverability.
Cons:
  • Adds tooling and workflow complexity.
  • Requires more upfront investment and maintenance.
Not chosen because it is not justified in 0-user mode; can be revisited if API surface area grows materially.

Consequences

Benefits:
  • Runtime validation at the boundary reduces undefined behavior in UI.
  • Shared schema package keeps contracts centralized and reviewable.
  • Easier to test and evolve contracts with clear ownership.
Costs:
  • Parsing overhead (generally small for payload sizes).
  • Requires maintaining a stable exported schema surface.
Risks:
  • Schema changes could become blocked by mobile release cadence. Mitigation: version contracts carefully; prefer additive evolution; keep DTOs small and explicit.