Databasearkitektur
Fullstendig dokumentasjon av databasearkitekturen til Impulse AI. Bygget pa Supabase (PostgreSQL) med pgvector for semantisk sok, Row Level Security for tilgangskontroll, og SQL-baserte migrasjoner.
Kjernemodell
heading.anchorLabelImpulse AI sin datamodell er sentrert rundt impulser — transformasjonstriggende tanker og folelser som klassifiseres som enten contraction (sammentrekning) eller expansion (utvidelse).
profiles (brukerprofil + abonnement) ↓impulses (kjernetransformasjon, contraction/expansion) ├── sessions (5-stegs prosessering) ├── notes (refleksjoner og takknemlighet) └── check_ins (sjekk-inn med AI-vurdering)
areas (livsomrader: relasjoner, karriere, helse, ...)layers (transformasjonslag: fysisk, emosjonell, mental, spirituell)analytics_insights (AI-genererte monstre og fremgang)Tabelloversikt
heading.anchorLabelPrimaertabeller
heading.anchorLabel| Tabell | Beskrivelse | Nøkkelkolonner |
|---|---|---|
profiles | Brukerprofil med abonnementsinformasjon | id, email, subscription_tier, subscription_status |
impulses | Kjernedata — transformasjonstrigger | id, user_id, content, classification, processual_status |
sessions | 5-stegs transformasjonssesjon | id, impulse_id, classification, status, current_step |
notes | Brukernotater (refleksjon, takknemlighet) | id, user_id, content, note_type, impulse_id |
check_ins | Sjekk-inn med AI-vurdering | id, user_id, content, classification, ai_assessment |
areas | Livsomrader (system-definerte) | id, name, is_system |
layers | Transformasjonslag (4 nivaer) | id, name, sort_order |
Stottetabeller
heading.anchorLabel| Tabell | Beskrivelse |
|---|---|
analytics_insights | AI-genererte monstre (pattern, progress, guidance, synchronicity, shift) |
analytics_dashboard_cache | Cachet analytikk (1 times TTL) |
ai_usage | Sporing av AI-tokenforbruk per bruker |
ai_rate_limits | Manedlige AI-bruksgrenser per tier |
subscription_config | Konfigurerer kvoter per abonnementstier |
iap_subscriptions | In-App Purchase abonnementer (iOS/Android) |
iap_transactions | Transaksjonshistorikk |
iap_webhook_events | Webhook-logg fra App Store / Google Play |
Impulsmodellen
heading.anchorLabelImpulser er hjertet i applikasjonen. Hver impuls er binaert klassifisert som enten contraction eller expansion.
CREATE TYPE impulse_classification AS ENUM ('contraction', 'expansion');
CREATE TABLE impulses ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, user_id uuid NOT NULL, content text NOT NULL, classification impulse_classification NOT NULL, -- Alltid satt, aldri NULL processual_status processual_status DEFAULT 'captured', ai_analysis jsonb, -- AI-anriket innhold embedding vector(512), -- Voyage AI semantisk vektor -- ... timestamps, areas, layers);Klassifisering
heading.anchorLabel- Contraction: Begrensende, fryktbaserte impulser. Prosesseres gjennom Clearing-sesjoner.
- Expansion: Vekstorienterte, apnende impulser. Prosesseres gjennom Realization-sesjoner.
Prosessuell status (Kanban)
heading.anchorLabelImpulser folger en enkel kanban-flyt:
| Status | Beskrivelse |
|---|---|
captured | Fanget, ikke prosessert enna |
transforming | Under aktiv prosessering (sesjon pagar) |
transformed | Ferdig prosessert |
AI-analyse (JSONB)
heading.anchorLabelEtter fangst berikes impulser asynkront med AI-analyse:
{ "contentValidity": "valid", // valid | low_confidence | gibberish "validityConfidence": 0.95, "title": "Frykt for a ikke vaere nok", "summary": "Du opplever en frykt for at...", "areas": [ { "id": "area-uuid", "name": "relationships", "relevanceScore": 0.92 } ], "layers": { "primary": { "layer": "emotional", "confidence": 0.88, "reasoning": "Frykt oppleves primaert som emosjonell respons", "perspective": "Hjertet ditt vet sannheten du laerer" }, "secondary": { /* valgfri */ } }, "processedAt": "2026-02-14T10:30:00.000Z"}Sesjonsmodellen
heading.anchorLabelSesjoner folger The Impulse AI Way — en 5-stegs prosess som er identisk i struktur for bade contraction og expansion, men med ulike AI-prompts per steg.
CREATE TYPE session_status AS ENUM ('created', 'active', 'completed', 'abandoned');CREATE TYPE session_type AS ENUM ('contraction', 'expansion');
CREATE TABLE sessions ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, user_id uuid NOT NULL, impulse_id uuid NOT NULL REFERENCES impulses(id), classification session_type NOT NULL, status session_status DEFAULT 'created', current_step integer CHECK (current_step >= 1 AND current_step <= 5),
-- AI-generert veiledning per steg step_1_guidance text, -- FEEL (Kjenn i kroppen) step_1_ai_status ai_workload_status DEFAULT 'pending', step_2_guidance text, -- OWN (Erkjenn energi-investeringen) step_3_guidance text, -- SHIFT (Tilstand definerer virkelighet) step_4_guidance text, -- ENVISION (Se for deg ny tilstand) step_5_guidance text, -- RELEASE (Loskoble og affirmer)
-- Oppsummering summary_document jsonb, -- AI-generert oppsummering user_reflection text, -- Brukerens refleksjon reflection_conclusion text, -- AI-generert konklusjon
-- Embedding for semantisk sok embedding vector(512), embedding_model text DEFAULT 'voyage-3-lite',
-- Kostnadssporing total_input_tokens integer DEFAULT 0, total_output_tokens integer DEFAULT 0, total_cost numeric(10,6) DEFAULT 0);De 5 stegene
heading.anchorLabel| Steg | Engelsk | Norsk | Formaal |
|---|---|---|---|
| 1 | FEEL | Kjenn i kroppen | Somatisk bevissthet |
| 2 | OWN | Erkjenn energi-investeringen | Erkjennelse av investering |
| 3 | SHIFT | Tilstand definerer virkelighet | Tilstand skaper virkelighet |
| 4 | ENVISION | Se for deg ny tilstand | Visualisering og forankring |
| 5 | RELEASE | Loskoble og affirmer | Slipp og bekreft |
Summary Document (JSONB)
heading.anchorLabelEtter fullfort sesjon genererer AI en oppsummering:
{ "title": "Fra frykt til frihet", "summary": "I denne sesjonen gikk du fra sammentrekning til apning...", "startingPoint": "En dyp frykt for fiasko i karrieren", "newUnderstanding": "Jeg innsa at min verdi ikke bestemmes av ytre suksess", "breakthroughs": [ "Frykt er ikke sannhet, bare en gammel beskyttelsesmekanisme", "Jeg har valg i hvordan jeg responderer pa usikkerhet" ], "nextSteps": [ "Legg merke til nar frykten oppstar og pust inn i den", "Skriv dagbok om oyeblikk der du folte deg ubetinget akseptert" ], "process": [ { "stepNumber": 1, "stepTitle": "Kjenn (Kjenn i kroppen)", "keyInsight": "Kjente frykt i brystet og halsen", "userInputs": ["Stramhet i brystet, restriksjon i halsen"] } ], "reflection": "Denne sesjonen markerte et vendepunkt...", "generatedAt": "2026-02-14T14:45:00.000Z"}Sjekk-inn
heading.anchorLabelSjekk-inn lar brukere logge hva de gjor akkurat na, med AI-vurdering basert pa BE->DO->RECEIVE-filosofien.
CREATE TABLE check_ins ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, user_id uuid NOT NULL, content text NOT NULL CHECK (char_length(content) >= 1 AND char_length(content) <= 500), classification text CHECK (classification IN ('contraction', 'expansion', 'neutral')), ai_assessment jsonb, ai_assessment_status text DEFAULT 'idle', embedding vector(512), -- ...);Sjekk-inn kan konverteres til impulser via source_check_in_id-koblingen pa impulses-tabellen.
Omrader og lag
heading.anchorLabelAreas (livsomrader)
heading.anchorLabelDynamiske livsdomener som AI tilordner impulser til:
CREATE TABLE areas ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, name text NOT NULL UNIQUE, display_name text, is_system boolean DEFAULT false, sort_order integer);Eksempler: relasjoner, karriere, helse, spiritualitet, kreativitet, okonomi.
Layers (transformasjonslag)
heading.anchorLabelFire hierarkiske dimensjoner av opplevelse:
| sort_order | Lag | Beskrivelse |
|---|---|---|
| 1 | Physical | Kroppslige opplevelser og sensasjoner |
| 2 | Emotional | Folelser og emosjonelle reaksjoner |
| 3 | Mental | Tankemonster og overbevisninger |
| 4 | Spiritual | Dypere mening og forbindelse |
Impulser tilordnes primaeert og sekundaert lag med AI confidence score (0.00-1.00).
Notater
heading.anchorLabelCREATE TABLE notes ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, user_id uuid NOT NULL, content text NOT NULL, note_type note_type DEFAULT 'reflection', -- gratitude | reflection impulse_id uuid REFERENCES impulses(id), -- valgfri kobling session_id uuid, -- valgfri sesjonskobling session_step smallint CHECK (session_step >= 1 AND session_step <= 5), archived_at timestamptz -- soft delete);Notater kan vaere fritstaende, koblet til en impuls, eller koblet til et spesifikt steg i en sesjon.
Brukerprofiler og abonnement
heading.anchorLabelCREATE TABLE profiles ( id uuid PRIMARY KEY, -- refererer til auth.users.id email text NOT NULL, display_name text, subscription_tier text DEFAULT 'trial', -- trial | foundation | mastery | partner subscription_status text DEFAULT 'inactive', -- active | inactive | cancelled | past_due trial_started_at timestamptz, trial_ends_at timestamptz, trial_converted boolean DEFAULT false, preferred_language text, -- en | no -- ...);Abonnementstier
heading.anchorLabel| Tier | Beskrivelse | AI-tilgang |
|---|---|---|
trial | 7-dagers gratis provperiode | Full tilgang |
foundation | Foundation-abonnement ($6/mnd) | Full tilgang, 30 sesjoner/mnd |
mastery | Mastery-abonnement ($12/mnd) | Full tilgang, ubegrenset |
partner | Gratis for samarbeidspartnere | Samme som foundation |
Kvoter konfigureres via subscription_config-tabellen og sjekkes gjennom check_impulse_quota()-funksjonen.
Semantisk sok (pgvector)
heading.anchorLabelImpulser, sesjoner og sjekk-inn har 512-dimensjonale embedding-vektorer generert av Voyage AI (voyage-3-lite).
Likhetsfunksjoner
heading.anchorLabelDatabasen har flere spesialiserte PostgreSQL-funksjoner for semantisk sok:
| Funksjon | Beskrivelse |
|---|---|
find_similar_impulses() | Finn impulser lignende en embedding-vektor |
find_similar_to_impulse() | Finn impulser lignende en gitt impuls (etter ID) |
find_similar_sessions() | Finn sesjoner lignende en embedding-vektor |
find_sessions_similar_to_impulse() | Finn sesjoner lignende en impuls |
find_similar_check_ins() | Finn sjekk-inn lignende en embedding-vektor |
Alle funksjoner bruker cosine similarity (1 - (a <=> b)) med konfigurerbar terskel (standard 0.7) og maks antall resultater.
JSONB-konvensjoner
heading.anchorLabelHvorfor JSONB-innhold er “opaque”
heading.anchorLabelJSONB-innhold fra AI-workloads endrer seg ofte nar prompts forbedres. Definer aldri JSONB-innhold i Fastify-skjemaer:
// FEIL -- vil brekke nar AI endrer outputai_analysis: { type: 'object', properties: { sessionCTA: { ... } } }
// RIKTIG -- behandle som ugjennomsiktigai_analysis: { type: ['object', 'null'], additionalProperties: true }JSONB-felter i databasen
heading.anchorLabel| Tabell | Kolonne | Innhold |
|---|---|---|
impulses | ai_analysis | AI-klassifisering, tittel, sammendrag, omrader, lag |
sessions | summary_document | Oppsummering med gjennombrudd, neste steg, prosess |
check_ins | ai_assessment | BE->DO->RECEIVE-vurdering og coach-forslag |
analytics_insights | data_points | Stottende data for innsikter |
analytics_dashboard_cache | summary, timeline, themes | Cachet analytikk |
Migrasjonsarbeidsflyt
heading.anchorLabelMigrasjoner forvaltes gjennom Supabase CLI:
# 1. Opprett ny migrasjonpnpm db:migrate:new navn_pa_migrasjon
# 2. Rediger SQL-filen# packages/database/supabase/migrations/[timestamp]_navn_pa_migrasjon.sql
# 3. Test lokaltpnpm db:reset
# 4. Generer TypeScript-typerpnpm db:types
# 5. Verifiser typer# packages/database/types/database.tsSupabase-spesifikasjoner
heading.anchorLabelAktiverte extensions
heading.anchorLabel| Extension | Formaal |
|---|---|
vector | pgvector for embedding-sok |
uuid-ossp | UUID-generering |
pgcrypto | Kryptografiske funksjoner |
pg_graphql | GraphQL-stotte |
pg_net | HTTP-kall fra databasen |
supabase_vault | Sikker hemmelighetslagring |
Enums
heading.anchorLabel| Enum | Verdier | Brukt av |
|---|---|---|
impulse_classification | contraction, expansion | impulses.classification |
processual_status | captured, transforming, transformed | impulses.processual_status |
session_status | created, active, completed, abandoned | sessions.status |
session_type | contraction, expansion | sessions.classification |
note_type | gratitude, reflection | notes.note_type |
ai_workload_status | idle, pending, processing, complete, failed | Flere tabeller |
content_validity | valid, low_confidence, gibberish | impulses.content_validity |
Database-funksjoner
heading.anchorLabel| Funksjon | Beskrivelse |
|---|---|
create_user_profile() | Trigger: Oppretter profil nar ny auth-bruker opprettes (3-dagers trial) |
check_impulse_quota() | Sjekker om bruker har gjenvaeerende kvoter for impulsfangst og sjekk-inn |
check_impulse_deletable() | Returnerer true hvis impuls ikke har relaterte sesjoner |
delete_impulse_safe() | Sikker sletting med eierskap- og relasjonssjekk |
expire_trials() | Planlagt funksjon for a markere utlopte trials |