# Mobile Architecture Decisions

> How to write and maintain Architecture Decision Records (ADRs) for mobile teams, and the canonical set of decisions every mobile project must record. Use when starting a project or when an architectural change is being proposed.

- Skill: `almasumdev/mobile-architecture-decisions` (Agent Skill)
- Install (CLI): `npx skillmds@latest add almasumdev/mobile-architecture-decisions`
- Raw SKILL.md: https://api.skillmd.com/api/skills/almasumdev/mobile-architecture-decisions/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: almasumdev (https://skillmd.com/u/almasumdev)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/almasumdev/mobile-architecture-decisions

---


# Mobile Architecture Decisions

## Instructions

Most mobile architecture debates repeat across projects. Capture decisions in Architecture Decision Records (ADRs) so the agent and future contributors inherit context instead of re-arguing it.

### 1. ADR Format

Keep ADRs short, markdown, and numbered. One decision per file under `docs/adr/`.

```markdown
# ADR-0007: Use Coroutines + Flow for Android Domain Layer

## Status
Accepted 2026-04-19. Supersedes ADR-0003.

## Context
- We had RxJava in the legacy Android app; iOS uses Combine.
- New domain logic is being shared via KMP.

## Decision
Use Kotlin Coroutines and Flow in the shared domain and Android presentation.
Bridge to Swift via KMP suspend interop; do not introduce RxSwift on iOS.

## Consequences
+ One async primitive across Kotlin codebases.
+ Structured concurrency is a first-class feature.
- Swift side needs adapter helpers for Flow collection.
- RxJava usages in legacy modules must be migrated or frozen.
```

Lifecycle states: `Proposed`, `Accepted`, `Superseded by ADR-NNNN`, `Deprecated`. Never delete ADRs.

### 2. Canonical Mobile ADR Set

Every mobile project should have accepted ADRs covering at least:

1. **Stack choice** (see `mobile-tech-stack-selection`).
2. **Minimum OS versions** and the policy for dropping them.
3. **Architecture pattern** -- MVVM, MVI, TEA, Redux, Clean, etc.
4. **Navigation approach** -- coordinator, declarative router, stack-based.
5. **State management library** -- Riverpod, BLoC, Redux Toolkit, Compose state, SwiftUI state.
6. **Networking layer** -- URLSession, Retrofit, Ktor, Dio, fetch/axios, generated client.
7. **Persistence** -- SQLite wrapper, Room, Core Data, Drift, SQLDelight, Realm.
8. **DI strategy** -- constructor, Hilt, Koin, Riverpod, SwiftUI EnvironmentObject.
9. **Error model** -- sealed error types, Result, exceptions, typed failures.
10. **Observability stack** -- crash reporter, analytics, logging, performance.
11. **Feature flag system** -- config service, build-time flags, remote config.
12. **Release strategy** -- staged rollout percentages, kill switches, flavors.
13. **CI system and signing** -- GitHub Actions, Bitrise, Codemagic, Xcode Cloud.
14. **Privacy boundaries** -- what leaves the device and through which SDK.

### 3. How to Propose a New ADR

An ADR becomes mandatory when a decision:

- Affects more than one module or platform.
- Is expensive to reverse (migrations, data model, public API surface).
- Introduces a new runtime dependency.
- Changes the deployment or compliance surface.

Otherwise, a code comment or CODEOWNERS note is enough.

### 4. Decision Anti-Patterns

- **Whiteboard-only decisions.** Write them down, even a week late.
- **Implicit decisions.** "We are using X because it is already there" must still become an ADR if any of the triggers in Section 3 apply.
- **Mega-ADRs.** Split decisions so each can be superseded independently.
- **Vague consequences.** Name specific costs (binary size, startup time, team learning curve).

### 5. Example Matrix of Architectural Decisions per Stack

Use this to seed ADRs on day one. Adjust to the chosen stack.

| Concern | Native iOS | Native Android | Flutter | React Native | KMP |
| --- | --- | --- | --- | --- | --- |
| UI pattern | SwiftUI + MV | Compose + MVVM | Widgets + Riverpod/BLoC | RN + hooks + Redux/Zustand | Compose MP or native UI |
| Nav | NavigationStack | Navigation-Compose | go_router | React Navigation | expect/actual + platform nav |
| Async | async/await | Coroutines + Flow | Future / Stream | async/await + RxJS optional | Coroutines + Flow |
| Persistence | Core Data / SwiftData | Room | Drift / sqflite | WatermelonDB / SQLite | SQLDelight |
| DI | plain init + EnvironmentObject | Hilt / Koin | Riverpod / get_it | plain context / DI libs | Koin |
| HTTP | URLSession | Retrofit / Ktor | Dio | fetch / axios | Ktor |
| Errors | typed enums + Result | sealed class + Result | sealed unions (freezed) | discriminated unions | sealed class |

### 6. Keeping ADRs Alive

- Link the ADR index from the top of the README.
- Require an ADR reference in the PR template for any change touching the listed surfaces.
- Review ADRs quarterly; supersede anything that no longer matches reality.
- When onboarding, read the ADR index before reading code.

### 7. Example ADR Index Snippet

```markdown
# Architecture Decisions

| # | Title | Status |
| --- | --- | --- |
| 0001 | Mobile stack: KMP + native UI | Accepted |
| 0002 | Minimum iOS 15 / Android 24 | Accepted |
| 0003 | Compose MVVM with unidirectional data flow | Accepted |
| 0004 | Networking via Ktor shared client | Accepted |
| 0005 | SQLDelight for persistence | Accepted |
| 0006 | Crashlytics + Sentry for releases | Accepted |
| 0007 | Coroutines + Flow async model | Accepted |
```

## Checklist

- [ ] `docs/adr/` exists with the canonical ADR set for the project.
- [ ] Each ADR has Status, Context, Decision, Consequences, and a date.
- [ ] ADRs are numbered and never deleted, only superseded.
- [ ] PR template references ADR IDs for architectural changes.
- [ ] ADR index is linked from the README.
- [ ] Decisions that span platforms call out per-platform consequences.

