Gå til innholdet

tech-architecture

Dette dokumentet er auto-synket fra kildefilene i boligassistent-repoet. Endringer her vil overskrives ved neste sync. Rediger kildefilen direkte.

Monorepo gir felles typer, delt konfigurasjon og effektiv bygging. pnpm er raskere og mer diskeffektiv enn npm/yarn. Turborepo cacher builds og kjører tasks parallelt.

React er en moden, fleksibel UI-plattform med stort økosystem. Vite gir rask utvikling og hot reload. shadcn/ui gir ferdige, tilpassbare komponenter uten lock-in — komponentene kopieres inn i prosjektet og eies fullt ut.

Enkel og veldokumentert Node.js-ramme. Gir full kontroll over routing, middleware og API-design uten magi. Passer for et prosjekt der utvikleren ønsker å forstå hva som skjer.

Express 5 — breaking changes fra v4 (kjente gotchas):

Express 5 er en major versjon med breaking changes. De viktigste for dette prosjektet:

  • Routing wildcards: path-to-regexp v8 tillater ikke bare /*. Bruk eksplisitt path-prefix (app.use('/prefix', handler)) eller navngitt wildcard (/*splat). Se engineering-standards.md seksjon 9 for detaljer.
  • Auth.js-montering: app.use('/api/auth', ExpressAuth(config))ikke '/api/auth/*'. app.use med prefix-path håndterer sub-ruter automatisk.
  • Async handlers: Express 5 håndterer async route handlers native — ingen express-async-errors-pakke nødvendig.
  • server.close() callback: Er sync — ikke async. Bruk Promise-chaining inne i callback.

PostgreSQL er den mest fullverdige åpen kildekode-databasen og støtter pgvector som utvidelse — viktig for semantisk søk. Drizzle ORM gir typesikker spørring, migrations og full SQL-kontroll uten overhead fra tyngre ORM-er som Prisma.

Nødvendig for AI-kontekstbygging. Lagrer vektor-embeddings av entiteter (rom, avvik, møbler) slik at AI-assistenten kan finne semantisk relevante data til et brukerspørsmål via cosine similarity-søk. Alternativet ville vært ekstern vector store (Pinecone, Weaviate), men pgvector holder alt i én database.

Gir fleksibel autentisering med e-post/passord og potensielt sosiale logins uten ekstern avhengighet. Self-hosted betyr full kontroll over brukerdata. OAuth-providere kan legges til uten arkitekturendring.

S3-kompatibel objektlagring som kjører i Docker — ingen ekstern avhengighet i MVP. Kan erstattes av AWS S3 eller Cloudflare R2 uten kodeendringer (identisk API).

Anthropic Claude er best egnet for kontekstuell rådgivning, strukturert output og reasoning over kompleks boligdata. Støtter lange kontekstvinduer som trengs for å sende inn romdata, manualinnhold og designretning i samme prompt.

Brukes for romvisualisering. Ikke i MVP, men arkitekturelt planlagt. Generering av bilder basert på stilbeskrivelser og rombeskrivelser.

Gir nettbasert produktsøk uten avhengighet til Google. Brukes av AI-assistenten til å finne konkrete møbler og produkter basert på stil og funksjon. Ikke i MVP.


boligassistent/
├── apps/
│ ├── api/ — Express.js backend
│ │ ├── src/
│ │ │ ├── routes/ — HTTP route handlers (tynne)
│ │ │ ├── services/ — Forretningslogikk
│ │ │ ├── db/ — Drizzle-klient og migrasjoner
│ │ │ ├── ai/ — Claude og DALL-E integrasjoner
│ │ │ └── ingestion/ — Ingestion Engine (PDF-parsing, ekstraksjon, jobbkø)
│ │ └── Dockerfile
│ └── web/ — React + Vite frontend
│ ├── src/
│ │ ├── components/
│ │ ├── pages/
│ │ ├── hooks/
│ │ └── lib/
│ └── Dockerfile
├── packages/
│ ├── types/ — Delte TypeScript-typer
│ ├── auth/ — Auth.js-konfigurasjon
│ └── db/ — Drizzle-skjema og migrations
├── docker-compose.yml
├── turbo.json
└── pnpm-workspace.yaml

En AI-assistent som gir generiske råd er lite nyttig. For å gi kontekstuell rådgivning om én spesifikk bolig trenger Claude tilgang til riktige data om den boligen.

Løsning: Strukturert kontekstbygging + pgvector RAG

Section titled “Løsning: Strukturert kontekstbygging + pgvector RAG”

Steg 1 — Strukturert kontekst (alltid med) Når brukeren stiller et spørsmål, bygges en strukturert kontekstblokk:

Eiendom: Hellebakken 9, enebolig, byggeår 1975
Valgt rom: Stue (34 m², 1. etasje)
Designretning interiør: nordisk, naturlig, varm
LayoutIntent stue: salong + arbeidshjørne, behov for mykt lys

Steg 2 — Semantisk søk (pgvector) Brukerens spørsmål embeddes og søkes mot:

  • Rom-beskrivelser
  • Issue-tekster
  • Observation-tekster
  • Manualinnhold (chunked)
  • DesignDirection-tekster

De mest relevante entitetene inkluderes i konteksten.

Steg 3 — Prompt til Claude Kontekstblokk + relevante data + brukerens spørsmål sendes til Claude API. Claude svarer basert på faktiske data om boligen, ikke generiske råd.

  • Entiteter embeddes ved opprettelse og oppdatering
  • Embedding-modell: text-embedding-3-small (OpenAI) eller tilsvarende
  • Embeddings lagres i embedding vector(1536) kolonne på relevante tabeller


Gjør det mulig å onboarde en ny bolig på 5–10 minutter ved å laste opp salgsoppgave og/eller takstrapport. AI ekstraherer strukturerte data, bruker godkjenner, systemet lagrer.

Kritisk prinsipp: AI fyller aldri databasen direkte. Flyten er alltid: AI foreslår → bruker godkjenner → system lagrer.

1. Upload — Bruker laster opp PDF → lagres i MinIO → Document opprettet
2. Queue — ExtractionJob opprettes med status=queued
3. Parse — pdf-parse ekstraherer tekst fra PDF (side-for-side)
4. Extract — Claude API med structured output identifiserer fakta:
rom, arealer, systemer, avvik, tilstandsgrader
5. Structure — Fakta mappes til entitets-felt via field_path
6. Store — ExtractedFact-rader lagres med status=pending
7. Review — Bruker ser gjennom fakta, godkjenner/endrer/forkaster
8. Persist — Godkjente fakta skrives til de ordinære tabellene
KomponentValgBegrunnelse
PDF-tekstekstraksjonpdf-parse (MIT)Enkel, veldokumentert, ingen ekstern avhengighet
Jobbkøpg-boss (MIT)Bruker eksisterende PostgreSQL, ingen ny infrastruktur
AI-ekstraksjonClaude API med tool use / structured outputGir typesikre JSON-responser
Gjennomgangs-UIReact + shadcn/uiInline redigering, diff-visning, godkjennknapper

Pipelinen sender dokumenttekst i bolker og ber Claude returnere strukturert JSON:

// Forenklet eksempel på extraction-prompt
const systemPrompt = `
Du er en ekspert på norske takstrapporter og salgsoppgaver.
Ekstraher strukturerte data og returner dem som JSON etter dette skjemaet: [schema]
For hvert faktum, oppgi: verdi, sidenummer, tekstutdrag, confidence (0.0-1.0).
Sett lav confidence på usikre tolkninger.
`

En takstrapport på 60 sider ≈ 80 000 tokens → ~$0.25 per dokument (Sonnet 4.6). Onboarding med 2–3 dokumenter totalt ≈ $0.50–0.75 (engangsbeløp).


docker-compose.yml inneholder:
- PostgreSQL 16 + pgvector
- MinIO
- API (Express.js)
- Web (Vite dev / statisk bygg)
- Caddy eller Nginx for reverse proxy med HTTPS

Tilgjengelig fra nett og telefon via lokal IP eller domene med TLS. Anbefalt: sett opp Tailscale eller Cloudflare Tunnel for sikker tilgang utenfra uten å åpne porter i hjemmeruter.

Arkitekturen er container-basert og kan flyttes til:

  • Fly.io, Railway, Render (enkelt)
  • AWS / GCP / Azure (mer komplekst)

Ingen arkitekturendringer er nødvendig — kun miljøvariabler og CI/CD.