Impulse AI Docs
Intern dokumentasjon
skipLink.label

API-utvikling

Denne guiden dekker API-utvikling med Fastify, autentisering, tier-haandheving, AI-workloads og jobbkoer.

API-et bruker Fastify med OpenAPI-skjemavalidering og middleware-kjeding.

Mappestruktur

heading.anchorLabel
apps/api/src/
├── routes/ # Alle API-endepunkter
│ ├── impulses/ # CRUD + AI-analyse
│ ├── sessions/ # 5-stegs sesjoner
│ ├── check-ins/ # Sjekk-inn-vurdering
│ ├── insights/ # AI-innsikt + analytics
│ ├── dashboard/ # Home + journey dashboard
│ ├── profiles/ # Brukerprofiladministrasjon
│ ├── subscriptions/ # Abonnementsynkronisering
│ ├── webhooks/ # App Store + Google Play
│ ├── ai/ # AI rate limit + status
│ ├── quota/ # Kvoteinformasjon
│ └── feedback/ # Brukertilbakemelding
├── middleware/ # Auth, subscription, rate limiter
├── ai/ # AI-workloads
├── queues/ # BullMQ-jobbkoer
├── services/ # Forretningslogikk
├── state-machines/ # Robot3-tilstandsmaskiner
└── lib/ # Supabase, Redis, Sentry

Standardmonster for ruter

heading.anchorLabel
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'
import { authenticateJWT } from '../../middleware/auth.js'
import { requireSubscription } from '../../middleware/subscription.js'
export async function myRoutes(fastify: FastifyInstance) {
// Autentisering pa alle ruter i denne gruppen
fastify.addHook('preHandler', authenticateJWT)
fastify.post<{ Body: CreateItemBody }>(
'/',
{
schema: {
description: 'Opprett et nytt element',
tags: ['items'],
body: {
type: 'object',
required: ['content'],
properties: {
content: { type: 'string', minLength: 1 },
},
},
response: {
201: {
type: 'object',
properties: {
success: { type: 'boolean' },
data: { type: 'object', additionalProperties: true },
},
},
},
},
preHandler: [requireSubscription],
},
async (request, reply) => {
// 1. Ekstraher og valider input
const { content } = request.body
const userId = request.user.id
// 2. Utfor forretningslogikk
const item = await createItem(userId, content)
// 3. Returner strukturert respons
return reply.code(201).send({
success: true,
data: { item },
})
}
)
}

Autentisering

heading.anchorLabel

JWT-middleware

heading.anchorLabel

authenticateJWT verifiserer JWT-tokens fra Supabase Auth og legger brukerinfo pa request.user.

// Bruk i ruter:
fastify.addHook('preHandler', authenticateJWT)
// Tilgang til bruker i handler:
const userId = request.user.id

Dev API token (bypass)

heading.anchorLabel

For raskere testing uten ekte autentisering:

Terminal window
# Generer token
openssl rand -hex 32
# Legg til i apps/api/.env.local
# DEV_API_TOKEN=din-token
# Bruk i kall
curl -H "X-Dev-Token: din-token" http://localhost:3001/api/v1/impulses
# Velg bruker-tier
curl -H "X-Dev-Token: din-token" \
-H "X-Dev-User-Tier: trial" \
http://localhost:3001/api/v1/impulses

Abonnement og tier-haandheving

heading.anchorLabel

Abonnementsmodell

heading.anchorLabel
TierPrisAI-tilgangKvoter
trialGratis (3 dager)Full tilgang3 impulser + 7 sjekk-inn
foundation$6/mndFull tilgang30 sesjoner/mnd
mastery$12/mndFull tilgangUbegrenset
partnerGratisFull tilgang30 sesjoner/mnd

Subscription-middleware

heading.anchorLabel
import { requireSubscription } from '../../middleware/subscription.js'
// Krev aktiv abonnement
fastify.get('/protected', {
preHandler: [authenticateJWT, requireSubscription],
}, handler)

Middleware-en:

  1. Henter brukerens abonnementsprofil (Redis-cachet, 1 time TTL)
  2. Sjekker at status er active
  3. Returnerer 403 hvis abonnement mangler eller er utlopt
StatusBetydning
activeFull tilgang
expiredTrial utlopt, trenger abonnement
inactiveAbonnement kansellert
grace_periodBetalingsproblemer, midlertidig tilgang
billing_retryFaktureringsforsoket feiler

JSONB-serialiseringskonvensjon

heading.anchorLabel

API-et folger en todelt konvensjon for serialisering:

LagKonvensjonStabilitet
DB-kolonnersnake_caseStabil
JSONB-innholdcamelCaseDynamisk

JSONB-innhold fra AI-workloads endres ofte. Definer aldri JSONB-innhold i Fastify-skjemaer:

// FEIL -- vil brekke nar AI endrer output
ai_analysis: {
type: ['object', 'null'],
properties: { sessionCTA: { type: 'string' } }
}
// RIKTIG -- behandle som opak
ai_analysis: {
type: ['object', 'null'],
additionalProperties: true
}

AI-workload-utvikling

heading.anchorLabel
ai/
├── infrastructure/
│ ├── anthropic/ # Provider + modellkonfig
│ ├── access/ # AI-tilgangskontroll
│ ├── tracking/ # Brukssporing
│ ├── safety/ # Sikkerhetssjekker
│ └── voyage/ # Embedding-klient
├── impulses/
│ └── classification/ # Klassifiser impulser
├── sessions/
│ ├── step-guidance.ts # Steg-veiledning
│ └── session-summary.ts # Sesjonsoppsummering
├── check-ins/
│ └── assessment/ # Sjekk-inn-vurdering
├── insights/
│ ├── narrative.ts # Innsiktsnarrativ
│ ├── pulse.ts # Kort puls-innsikt
│ └── embedding-analytics.ts
└── shared/
├── prompt-builder.ts # Prompt-konstruksjon
├── conventions.ts # Felles konvensjoner
└── types.ts # Delte typer

Alle workloads bruker Sonnet 4.6 som standard. Tre tier-er bestemmer modellvalg:

TierModellWorkloads
fastSonnet (Haiku-safe)classify_analytical
balancedSonnet (ma vaere Sonnet)classify_enrichment, guidance, pulse, check_in_assess
qualitySonnet+summary, insight

Override via miljovaribler: AI_MODEL_FAST, AI_MODEL_BALANCED, AI_MODEL_QUALITY.

Jobbkoer (BullMQ)

heading.anchorLabel

Alle asynkrone AI-operasjoner bruker BullMQ med Redis.

1. POST-endepunkt oppretter ressurs + legger jobb i ko -> returnerer umiddelbart
2. Klient kobler til SSE-endepunkt for statusoppdateringer
3. Ko prosesserer jobb og sender oppdateringer
4. Klient mottar ferdig/feil via SSE
KoPrioritetBeskrivelse
impulseClassification1 (realtime)Klassifiser impulser
impulseAnalysis1 (realtime)Analyseanrikning
unifiedGuidance1 (realtime)Steg-veiledning i sesjoner
checkInAssessment1 (realtime)Sjekk-inn-vurdering
sessionSummary2 (near-realtime)Sesjonsoppsummering
insightsRegeneration5 (bakgrunn)Regenerer innsikter

Prioritetsniva

heading.anchorLabel
PrioritetTypeKontekst
1RealtimeBruker venter aktivt
2Near-realtimeBruker venter, men mindre akutt
5BakgrunnIngen bruker venter
10BatchKan ta timer

Tilstandsmaskiner (Robot3)

heading.anchorLabel

API-et bruker Robot3 for a haandtere statusoverganger.

apps/api/src/state-machines/
├── blockage-machine.ts # new -> clearing -> cleared
├── intention-machine.ts # new -> realizing -> realized
├── clearing-process-machine.ts # 5-stegs clearing
├── realization-process-machine.ts # 5-stegs realisering
└── integration-machine.ts # 5-stegs integrasjon

Hvert maskin-modul eksporterer:

createMachine() // Maskin-definisjon
canTransition(currentStatus, event): boolean // Kan vi ga til denne tilstanden?
getNextStatus(currentStatus, event): Status // Hva er neste tilstand?

Testing med dev-token

heading.anchorLabel
Terminal window
# Opprett impuls
curl -X POST http://localhost:3001/api/v1/impulses \
-H "X-Dev-Token: din-token" \
-H "Content-Type: application/json" \
-d '{"content": "Jeg kjenner motstand mot a ta kontakt"}'
# List impulser
curl http://localhost:3001/api/v1/impulses \
-H "X-Dev-Token: din-token"
# Hent dashboard
curl http://localhost:3001/api/v1/dashboard/home \
-H "X-Dev-Token: din-token"
# Sjekk kvoter
curl http://localhost:3001/api/v1/quota \
-H "X-Dev-Token: din-token"
BeskrivelseSti
API-serverapps/api/src/server.ts
Auth-middlewareapps/api/src/middleware/auth.ts
Subscription-middlewareapps/api/src/middleware/subscription.ts
Kvote-middlewareapps/api/src/middleware/quota.ts
AI-konfigapps/api/src/ai/infrastructure/anthropic/config.ts
Ko-infrastrukturapps/api/src/queues/index.ts
Tilstandsmaskinerapps/api/src/state-machines/
Tier-enforcementapps/api/src/helpers/tier-enforcement.ts