Systemarkitektur
Komplett oversikt over systemarkitekturen til Impulse AI. Dokumentet dekker alle lag fra monorepo-oppsett til AI-pipeline, og forklarer de viktigste arkitekturbeslutningene og hvorfor de ble tatt.
Plattformoversikt
heading.anchorLabelImpulse AI er en impuls-drevet transformasjonsplattform med tre hoveddistribusjonskanaler:
| Kanal | Teknologi | Deploy |
|---|---|---|
| iOS-app | SwiftUI + KMP shared | App Store |
| Android-app | Jetpack Compose + KMP shared | Google Play |
| API | Fastify (Node.js) | Railway |
| Database | Supabase (PostgreSQL) | Supabase Cloud |
Monorepo-struktur
heading.anchorLabelProsjektet bruker Turborepo med pnpm workspaces for a organisere alle applikasjoner og pakker i ett repository.
im/├── apps/│ ├── api/ # Fastify API-server (port 3001)│ ├── mobile-kmp/ # Kotlin Multiplatform mobilapp│ │ ├── shared/ # KMP delt modul (Kotlin)│ │ ├── iosApp/ # iOS-app (SwiftUI)│ │ └── androidApp/ # Android-app (Jetpack Compose)│ ├── console/ # Kontrollrom for ClawdBot (Next.js)│ ├── landing/ # Distribusjonsplattform (Next.js)│ └── docs/ # Starlight dokumentasjon├── packages/│ ├── shared/ # Delte TypeScript-typer og skjemaer│ ├── api-client/ # Typet API-klient│ ├── auth/ # Autentiseringsverktoy│ └── database/ # Supabase-migrasjoner + genererte typerFordeler med monorepo
heading.anchorLabel- En kildekode: Alle tjenester deler typer og kontrakter
- Atomiske endringer: Database-migrasjoner, API-endringer og klientoppdateringer i samme PR
- Delt verktoy: Lint, formatering og typesjekk konfigurert en gang
API-laget
heading.anchorLabelFastify-server
heading.anchorLabelAPI-serveren er bygget med Fastify og kjorer pa Railway. Den hhandterer all forretningslogikk, AI-integrasjon og databasetilgang.
apps/api/├── src/│ ├── routes/ # HTTP-endepunkter (REST)│ ├── services/ # Forretningslogikk│ ├── middleware/ # Auth, subscription, rate limiting│ ├── ai/ # AI-workloads og pipeline│ ├── queues/ # BullMQ bakgrunnsjobber│ ├── state-machines/ # Robot3 tilstandsmaskiner│ └── lib/ # Database, logging, utilitiesViktige moonstre:
- Route-moenster: Schema-validering + preHandler (auth, tier-sjekk) + handler
- Serialiseringskonvensjon: Database-kolonner bruker
snake_case, JSONB-innhold brukercamelCase - Tier-hhandheving: Middleware sjekker abonnement for operasjoner (trial, foundation, mastery, partner)
// Typisk route-moensterfastify.post('/path', { schema: { /* OpenAPI-skjema */ }, preHandler: [requireAuth, requireTier(['foundation', 'mastery'])],}, async (request, reply) => { // 1. Valider input // 2. Sjekk tillatelser // 3. Kjor forretningslogikk // 4. Returner strukturert respons})Bakgrunnsjobber (BullMQ)
heading.anchorLabelAsynkrone operasjoner som AI-klassifisering og embedding-generering kjorer via BullMQ-koer med Redis:
- Impulse-klassifisering: Analytisk + kreativ AI-analyse etter impulsfangst
- Embedding-generering: Voyage AI vektorer for semantisk sok
- Sesjonoppsummering: AI-generert oppsummering etter fullfort sesjon
- Innsikt-regenerering: Periodisk oppdatering av personlige innsikter
Database
heading.anchorLabelImpulse AI bruker Supabase som database-plattform, med PostgreSQL, innebygd autentisering og Row Level Security (RLS).
Se Databasearkitektur for fullstendig dokumentasjon av tabeller, JSONB-konvensjoner og migrasjonsarbeidsflyt.
Mobil (KMP)
heading.anchorLabelKotlin Multiplatform
heading.anchorLabelDen delte mobillogikken lever i apps/mobile-kmp/shared/ og inneholder:
shared/src/commonMain/kotlin/com/im/shared/├── domain/ # Domenemodeller (Impulse, Session, Insight)├── stores/ # FlowMVI stores (state management)├── data/ # API-klienter og repository-implementasjoner├── i18n/ # Moko streng-ressurser└── util/ # Delte verktoyKMP deler:
- Domenemodeller (Impulse, Session, CheckIn, etc.)
- API-klienter (Ktor-basert HTTP)
- Autentiseringshhandtering (AuthManager)
- State management (FlowMVI stores)
- Lokalisering (Moko Resources)
iOS-arkitektur (SwiftUI)
heading.anchorLabeliOS-appen folger en feature-basert mappestruktur med @Observable StoreWrappers som bro mellom KMP og SwiftUI:
iosApp/├── Features/ # Feature-moduler (en mappe per skjerm)│ ├── Home/ # Hjem-skjerm│ ├── Insights/ # Innsikter (2 dataprodukter)│ ├── Journey/ # Impuls-reise│ ├── Sessions/ # 5-stegs sesjoner│ ├── CheckIn/ # Sjekk-inn│ ├── Capture/ # Impulsfangst│ └── Navigation/ # Tab bar├── Stores/ # KMP StoreWrappers (@Observable)├── Components/ # Delte UI-komponenter├── Theme/ # Fargetokens, typografi└── Services/ # PlattformtjenesterState management
heading.anchorLabelAppen bruker FlowMVI i KMP for unidireksjonal tilstandshhandtering, med @Observable StoreWrappers pa iOS-siden:
┌─────────────────────────────────────────────────┐│ SwiftUI View ││ Leser @Observable StoreWrapper properties │└──────────────────────┬──────────────────────────┘ │ Intent-dispatch┌──────────────────────▼──────────────────────────┐│ @Observable StoreWrapper ││ • Abonnerer pa KMP state flow (via SKIE) ││ • Eksponerer Swift-vennlige properties ││ • Dispatcher intents til KMP store │└──────────────────────┬──────────────────────────┘ │ SKIE bridging┌──────────────────────▼──────────────────────────┐│ KMP FlowMVI Store ││ • Hhandterer state via reduce {} ││ • Kjorer async operasjoner (API-kall) ││ • Emitter actions for side effects │└─────────────────────────────────────────────────┘Dataflyt: State (KMP) -> View (SwiftUI) -> Intent (brukerhandling) -> Reducer (KMP) -> ny State
Kommunikasjonsmekanismer
heading.anchorLabelAppen bruker tre distinkte kommunikasjonsmonstre mellom lag:
| Mekanisme | Jobb | Retning | Eksempel |
|---|---|---|---|
| @Observable state | Reaktive UI-oppdateringer | Store -> View (automatisk) | Loading-spinnere, listedata |
| Callbacks | Navigasjons-sideeffekter | Store -> View (imperativt) | Apne fullScreenCover, dismiss view |
| AppEventBus | Kryss-store koordinering | Store -> Store (KMP-niva) | “Analyse ferdig” -> HomeStore refresher |
Kryss-domene events (AppEventBus)
heading.anchorLabelsealed interface AppEvent { data class ImpulseUpdated(val impulseId: String) : AppEvent data class SessionCompleted(val impulseId: String, val sessionType: String) : AppEvent data object UserLoggedOut : AppEvent // ...}
object AppEventBus { private val _events = MutableSharedFlow<AppEvent>( extraBufferCapacity = 20, onBufferOverflow = BufferOverflow.DROP_OLDEST ) val events: SharedFlow<AppEvent> = _events.asSharedFlow()}Derived View State (enum state machines)
heading.anchorLabelNar en SwiftUI view avhenger av flere @Observable stores, utledes visningstilstanden gjennom en computed enum — aldri gjennom if-else-kjeder i view body.
// Enum fanger ALLE mulige tilstanderenum FooContentState { case loading case empty case content case error(String)}
// Computed property -- ett eneste utledningspunktprivate var contentState: FooContentState { if store.isLoading && !store.hasData { return .loading } if !store.hasData { return .empty } return .content}
// Exhaustive switch -- kompilatoren sikrer fullstendighetswitch contentState {case .loading: ProgressView()case .empty: EmptyState()case .content: ContentView()case .error(let msg): ErrorView(msg)}AI-pipeline
heading.anchorLabelAI-integrasjonen bruker Anthropic Claude (via Vercel AI SDK) for tekst og Voyage AI for embedding-generering.
Se AI Pipeline for fullstendig dokumentasjon av workloads, modellvalg og prompter.
Overordnet flyt
heading.anchorLabelBrukerhandling ↓API-endepunkt (Fastify) ↓BullMQ koe (asynkron) ↓AI Workload (Anthropic Claude / Voyage AI) ↓Database-oppdatering (Supabase) ↓Klient-oppdatering (polling / SSE)Viktige arkitekturbeslutninger
heading.anchorLabelHvorfor KMP (Kotlin Multiplatform)?
heading.anchorLabel- Delt forretningslogikk: API-klienter, domenemodeller og state management skrives en gang
- Plattformnative UI: SwiftUI og Jetpack Compose gir best mulig brukeropplevelse
- SKIE bridging: Seker Kotlin/Swift interop for flows, sealed classes og coroutines
Hvorfor Fastify (ikke Next.js API routes)?
heading.anchorLabel- Ytelse: Fastify er vesentlig raskere enn Express/Next.js API routes
- Schema-validering: Innebygd JSON Schema-validering med OpenAPI-generering
- Plugin-okosystem: Strukturert plugin-system for middleware, auth, rate limiting
- Separat deploy: API deployes uavhengig av frontend pa Railway
Hvorfor Supabase?
heading.anchorLabel- PostgreSQL: Full relasjonsdatabase med pgvector for embedding-sok
- Innebygd auth: Supabase Auth med social login (Apple, Google)
- RLS: Row Level Security for finkornet tilgangskontroll
- Realtime: Innebygd stoette for sanntidsoppdateringer
- Migrasjoner: SQL-baserte migrasjoner med versjonskontroll
Hvorfor FlowMVI?
heading.anchorLabel- Predikerbar tilstandsflyt: Enveis dataflyt gjor state-endringer sporbare
- Kryssplattform: Samme forretningslogikk pa iOS og Android
- Typesikkerhet: Compile-time verifisering av State/Intent/Action-kontrakter
- Testbarhet: Pure reducers og isolerte sideeffekter
Hvorfor Vercel AI SDK?
heading.anchorLabel- Strukturerte outputs: Automatisk Zod-til-JSON-Schema konvertering med validering
- Prompt caching: Innebygd stotte for Anthropic prompt caching (kostnadsreduksjon)
- Provider-abstraksjon: Enkelt a bytte mellom AI-modeller
- Retry-logikk: Automatisk retry pa HTTP-feil (429, 500, 503)
Porter og miljoer
heading.anchorLabel| Tjeneste | Port | Miljo |
|---|---|---|
| API (Fastify) | 3001 | Railway (produksjon) |
| Console (Next.js) | 3004 | Vercel |
| Landing (Next.js) | 3003 | Vercel |
| Supabase Studio | 54323 | Lokal |
| PostgreSQL | 54332 | Lokal |
| Redis | 6380 | Lokal / Railway |