A production-oriented reference system for a mobile transaction feed. It shows how a mobile client, API gateway, identity service, feed service, notification service, SQLite persistence, and a transactional outbox fit together.
The repository is intentionally compact. The code demonstrates the system design decisions instead of hiding them behind framework setup.
- Mobile clients can remain resilient when upstream services fail.
- Idempotent commands make retries safe.
- Keyset pagination avoids unstable offset paging.
- A transaction and its integration event can commit atomically.
- An outbox worker can deliver events at least once without duplicating notifications.
- Client caches can serve stale data without pretending it is fresh.
- Version gates, feature flags, deep links, telemetry, auth, and rate limits belong in the design.
flowchart LR
App[Swift mobile client] -->|Bearer token| Gateway[API gateway :8100]
Gateway --> Identity[Identity :8101]
Gateway --> Feed[Feed :8102]
Gateway --> Notifications[Notifications :8103]
Feed --> DB[(SQLite)]
Feed --> Outbox[(Outbox table)]
Worker[Outbox worker] --> Outbox
Worker --> Notifications
Notifications --> DB
App --> Cache[(Disk feed cache)]
App --> Telemetry[Client telemetry]
The local cluster starts four HTTP listeners and one outbox worker. They share one SQLite file for a simple local demo. In production, each service can own its datastore and deployment boundary.
sequenceDiagram
participant App
participant Gateway
participant Feed
participant DB
participant Worker
participant Notifications
App->>Gateway: POST /v1/transactions + idempotency key
Gateway->>Gateway: Verify token and rate limit
Gateway->>Feed: Forward trusted user identity
Feed->>DB: BEGIN
Feed->>DB: Insert transaction
Feed->>DB: Insert outbox event
Feed->>DB: Store idempotent response
Feed->>DB: COMMIT
Feed-->>App: 201 transaction
Worker->>DB: Read pending outbox event
Worker->>Notifications: POST /internal/events
Notifications->>DB: INSERT OR IGNORE notification
Worker->>DB: Mark delivered
The Swift package uses strict concurrency and keeps dependencies directional:
SystemDomain
↑
SystemNetworking SystemSecurity SystemCache MobileTelemetry
↑ ↑ ↑ ↑
TransactionFeedFeature
↑
CLI and live E2E app
The feature repository provides:
- authenticated session handling
- retry and circuit breaker behavior
- disk and memory caches
- fresh and stale cache policies
- cache invalidation after writes
- keyset pagination
- notification polling
- telemetry events
- a SwiftUI-ready state store
Requirements:
- Swift 6.2 or later
- Python 3.11 or later
- No third-party packages
Run the complete verification suite:
make verifyRun the local cluster:
python3 services/cluster.pyIn another terminal:
swift run mobile-system-cliRun the live E2E scenario:
make e2eThe E2E scenario verifies login, remote config, idempotent creation, keyset pagination, outbox delivery, notifications, deep-link parsing, and telemetry.
Sources/
SystemDomain/ Core models, errors, version gate, deep links
SystemNetworking/ URLSession transport, retry, circuit breaker, gateway API
SystemSecurity/ Memory and file session vaults
SystemCache/ Actor-isolated feed caches
MobileTelemetry/ Telemetry contract and recorder
TransactionFeedFeature/ Repository and UI state store
MobileSystemCLI/ Runnable client demo
LiveE2E/ Assertions against the live cluster
services/
cluster.py Four local HTTP services and outbox worker
storage.py SQLite schema and atomic operations
test_cluster.py Service-level integration tests
scripts/
verify.sh Full verification
run_e2e.sh Live cluster plus Swift E2E
load_test.py Concurrent command load test
check_boundaries.py Dependency rule enforcement
docs/
diagrams/ Mermaid sources
adr/ Short architecture decisions
openapi.yaml Public gateway contract
examples/
SwiftUIIntegration/ Feed screen integration example
swift test
python3 -m unittest services/test_cluster.py
scripts/run_e2e.sh
scripts/coverage.shThe test suite covers domain validation, version gating, deep links, retry, circuit breaker state, request headers, auth storage, disk cache behavior, stale fallback, pagination state, idempotent server writes, keyset pagination, and outbox delivery.
The gateway is the only public backend surface. It verifies user tokens, applies rate limits, and forwards a trusted user identifier to internal services.
The feed service owns transaction creation and pagination. It stores the transaction, idempotent response, and outbox event in one SQLite transaction.
The notification service accepts integration events through an internal endpoint. Event IDs are unique, so repeated delivery is safe.
The mobile client retries only operations that are safe to repeat. A POST is retryable because it carries a stable idempotency key.
This is a reference implementation, not a claim that every system needs microservices.
- SQLite keeps the demo reproducible. A high-scale deployment would likely separate transactional storage, event transport, and notification storage.
- Polling keeps the client demo portable. Production may use push notifications, WebSockets, or server-sent events.
- HMAC tokens keep authentication dependency-free. Production should use a managed identity system and rotating asymmetric keys.
- The local cluster uses one process for easy execution. The services still communicate through HTTP and can be split into separate deployments.
More detail is in docs/system-design.md and docs/trade-offs.md.
make build
make test
make services-test
make e2e
make coverage
make boundaries
make loadMIT