Architecture Overview
Running Days is built as a Turborepo monorepo with clear separation between applications and shared packages.
System Architecture
graph TB
subgraph "Client Layer"
iOS[iOS App<br/>Swift/SwiftUI]
Web[Web Dashboard<br/>SvelteKit]
end
subgraph "API Layer"
API[Fastify API<br/>Port 3000]
end
subgraph "Data Layer"
DB[(SQLite/PostgreSQL<br/>Drizzle ORM)]
end
subgraph "External"
Apple[Apple Health<br/>via Health Auto Export]
AppleAuth[Apple Sign-In]
end
iOS --> API
Web --> API
Apple --> API
AppleAuth --> API
API --> DBPackage Structure
The monorepo uses pnpm workspaces with Turborepo for build orchestration.
Applications (apps/)
| App | Purpose | Tech Stack |
|---|---|---|
api | REST API backend | Fastify 5, TypeScript |
web | Cloud SaaS dashboard | SvelteKit 2, Svelte 5 |
oss | Self-hosted version | SvelteKit (single-user) |
ios | Native iOS app | Swift, SwiftUI |
Packages (packages/)
| Package | Purpose | Dependencies |
|---|---|---|
types | Shared TypeScript types | None (zero deps) |
utils | Date formatters, utilities | types |
database | Drizzle ORM schema | types |
business-logic | Goals, streaks, achievements | types, utils |
observability | Logging, metrics, audit | types |
ui | Shared Svelte components | utils |
Data Flow
Workout Import Flow
sequenceDiagram
participant iOS as iOS App
participant HAE as Health Auto Export
participant API as Fastify API
participant DB as Database
iOS->>HAE: Configure webhook
HAE->>API: POST /api/webhook
API->>API: Validate token
API->>API: Parse workouts
API->>DB: Upsert workouts
API->>DB: Update daily stats
API-->>HAE: 200 OKAuthentication Flow
sequenceDiagram
participant User
participant Web as Web App
participant API as Fastify API
participant Apple as Apple Sign-In
User->>Web: Click "Sign in with Apple"
Web->>API: GET /api/v1/auth/apple
API->>Apple: PKCE + nonce
Apple-->>User: Apple login UI
User->>Apple: Authenticate
Apple->>API: POST /api/v1/auth/apple/callback
API->>API: Validate identity token
API-->>Web: Set httpOnly cookiesKey Design Decisions
1. Monorepo Structure
Using Turborepo with pnpm workspaces enables:
- Shared code without publishing to npm
- Coordinated builds with caching
- Single lockfile for dependencies
2. Zero-Dependency Types Package
The @running-days/types package has no external dependencies, making it safe to import anywhere without bundling concerns.
3. Server-Only Database Access
Database code is restricted to .server.ts files in SvelteKit, preventing accidental client-side database imports.
4. OKLCH Color System
The design system uses OKLCH colors for perceptual uniformity. Adjusting lightness gives predictable visual results across all hues.
Port Assignments
| Service | Port |
|---|---|
| API | 3000 |
| Web Dashboard | 3001 (Docker) / 5173 (dev) |
| Grafana | 3002 |
| Loki | 3100 |