Metode · Sådan bygger vi systemer

Vi beviser, at koden virker.

De fleste bureauer håber, at deres kode virker. Vi kører matematisk verifikation, drift-detektion mellem spec og kode, og 8+ destruktive tests per funktion — før en eneste linje når produktion. Derfor får vores systemer ikke panik klokken tre om natten.

Pipeline · Spec → Allium → Plan → Impl → Playwright → TLA+
Verifikation
TLA+ formel · Allium drift · Playwright destruktiv
Stack
.NET · ASP.NET Core · React · Blazor · TypeScript · SQL Server · Postgres · SQLite · Docker Swarm · Azure · Semantic Kernel
Testdækning
1:1 funktionel + 8 destruktive per flade
AI-augmenteret
Claude Code · spec-register · auto-hooks
I drift
6 systemer live på live4.se · alle demo-åbne

"Vi bruger agile metoder" er det mest meningsløse, man kan sige om softwareudvikling i 2026. Alle siger det. Ingen kan vise, hvad det betyder. Det er ikke en proces — det er en plakat, man hænger på væggen efter et dagligt stand-up.

Vores metode kan revideres. Den efterlader artefakter — spec- filer, Allium-rapporter, TLA+-modeller, Playwright-rapporter — som du kan læse og argumentere imod. Den fanger race conditions, før de når produktion, drift mellem specifikation og implementering, før nogen undrer sig over, hvorfor kode og dokumentation ikke længere stemmer overens, og ulogiske tilstandsovergange, før en slutbruger finder dem for os.

Pipelinen er ingen hemmelighed. Den køres på hver ikke-triviel ændring i hvert system, vi ejer. Nedenfor står hvad hver fase gør, hvorfor den findes, og hvad det betyder i praksis.

Vi bygger ikke flere funktioner, end kunden har brug for. Det, der bygges, har bevisbar logik bag sig.

Pipelinen i seks faser.

Hver fase producerer artefakter, som kan læses af mennesker og verificeres af maskiner. Ingen fase-spring, ingen genveje. Faserne køres i rækkefølge på hver ikke-triviel ændring — uanset om det er et nyt felt i en formular eller en ny domænemodel.

Fase 01

Specifikation.

Vi skriver, hvad systemet skal gøre, før vi skriver hvordan. Én spec-fil per feature, gennemgået før der skrives en linje kode. Plus en afklaringsrunde, der fanger huller, som ellers ville være dukket op i produktion.

/specify · /clarify
Fase 02

Formel spec (Allium).

Specen formaliseres i Allium — et udspørgssprog for specifikationer. Inkonsistenser og tvetydigheder dukker op som åbne spørgsmål før implementering. Senere sammenlignes spec mod kode for drift-detektion.

/allium:elicit
Fase 03

Plan + opgaver.

Specen brydes ned til en plan og en opgaveliste med afhængighedsgraf. Derefter køres en analysefase, der auto-anvender alle anbefalede tiltag. Implementering starter mod en fuldt instrumenteret tegning, ikke en hash af idéer.

/plan · /tasks · /speckit.analyze
Fase 04

Implementering.

Kode skrives mod planen — ikke i abstrakt forstand, men opgave for opgave. Backend-first som princip, ikke slogan: al autorisation, audit, soft-delete og idempotens er enforced server-side. Frontend er et tyndt visningslag.

.NET · React · EF Core · SSE
Fase 05

Browsertests.

1:1 funktionel dækning — bygger du tolv funktioner, skriver du tolv tests. Plus otte destruktive tests per flade: XSS, SQL-injection, auth-bypass, race conditions, ugyldig input, grænseværdier. Alle i Playwright. Ingen "happy path".

Playwright · Funktionel + destruktiv
Fase 06

Formel verifikation (TLA+).

Tilstandsmaskiner modelleres i TLA+ og invarianter bevises matematisk. TLC-modeltjekkeren finder race conditions, deadlocks og tilstande, som ingen har tænkt på. Det, der kommer ud af den fase, er ikke en test, der "bestod" — det er et bevis.

TLA+ · TLC · Invarianter

Det de fleste gør. Det vi gør.

En ærlig sammenligning med det, vi møder, når vi overtager et system bygget af nogen andre. Ikke et angreb — kun en kalibrering af, hvad "produktionsklar" faktisk betyder.

Test

Manuel gennemklikning før release.

Almindeligt bureau. Nogen klikker gennem systemet, ser, at intet eksploderer, og trykker deploy. Edge cases opdages af kunden.

Manuelt · Ønsketænkning
Test

1:1 funktionel + 8 destruktive.

Os. Hver implementeret funktion har mindst én Playwright-test. Plus otte destruktive tests per flade, som forsøger at bryde systemet på de seks mest almindelige måder, det kan brydes på.

Playwright · Reviewbar
Spec

Specen lever i et Confluence-dokument.

Almindeligt bureau. Specen skrives én gang, derefter glider den væk fra koden. Seks måneder senere kan ingen svare på, hvorfor det virker, som det gør.

Drift · Glemsel
Spec

Allium-drift mellem spec og kode.

Os. Spec og kode sammenlignes automatisk. Drift dukker op som åbne spørgsmål, ikke gæt. Specen er kildekode — versioneret, gennemgået, altid i sync.

Allium · Driftdetektion
Tilstand

Race conditions findes i produktion.

Almindeligt bureau. En tilstandsmaskine skitseres på whiteboard, derefter kodes den på stedet. Race conditions fanges af uheldige brugere en torsdag eftermiddag.

Whiteboard · Håb
Tilstand

TLA+ beviser invarianter.

Os. Tilstandsmaskiner modelleres formelt, invarianter bevises. TLC finder klyngen af tilstande, som logikken ikke håndterer — før det bliver en produktionshændelse.

TLA+ · Bevisbar

Stacken — hvad vi vælger, og hvorfor.

Få teknologivalg, truffet én gang, fordybet i ti år. Vi skifter ikke stack hver sprint. Vi skifter, når der er en faktisk grund — og så begrunder vi det skriftligt.

Backend

.NET · ASP.NET Core.

Moden, hurtig, gratis runtime med stærkt typesystem. EF Core med SaveChanges-interceptors, der fanger audit-trail centralt — ingen kode kan smutte forbi. Vi har skrevet .NET siden version 1.1.

.NET · EF Core · ASP.NET
Frontend

React · Blazor hvor det passer.

React som default for nye frontends — server components, suspense, native streaming. Blazor WASM til PWA, hvor C# ende-til-ende er det værd. Aldrig SPA-religion: vi vælger per system.

React · Blazor WASM · TypeScript
Database

SQLite. Også i produktion.

SQLite på NFS rummer flere projekter uden tenant_id-bøvl. Backups er filer, du kan zippe. Ingen driftsomkostninger til en separat databaseserver. Vi skifter til PostgreSQL den dag, belastningen kræver det — sjældent tidligere.

SQLite · WAL · NFS
AI

Selv-hostet LLM som fail-open.

Lokal model i Docker Swarm-klyngen. Er AI'en nede, fortsætter systemet med at virke uden blokeringer — auto-kategorisering bliver manuel, intet crasher. GDPR-venligt, fordi data aldrig forlader klyngen.

Lokal LLM · Semantic Kernel · RAG
Drift

Docker Swarm på Azure.

Vi ejer hele kæden: arkitektur, database, frontend, drift. Egen Swarm-klynge på live4.se. Ingen managed-tjenester med uklar prissætning. Du ved præcis, hvad der køres og hvor.

Docker Swarm · Azure · live4.se
Værktøjer

Claude Code · spec-register.

AI-augmenteret udvikling med deterministiske hooks. Spec-register som kilde for, hvad der bygges næste gang. Pipeline-hooks der blokerer feature-arbejde uden spec. AI'en følger en metode, vi har skrevet ned, gennemgået og versioneret.

Claude Code · Hooks · Subagents

Hele kompetencespændet.

Vi vælger få teknologier per system — men listen over det, vi behersker, er længere end som så. 25+ års leveringer giver et bredt grundlag at læne sig op ad, når problemet ikke passer standardløsningen.

Backend

.NET-økosystemet.

.NET 6–10 · C# · ASP.NET Core · .NET Aspire · EF Core · Dapper · MediatR · Quartz.NET · SignalR · gRPC · GraphQL · REST · Clean Architecture · CQRS · DDD · multi-tenant SaaS · microservices · Node.js

Frontend

Web og mobil.

TypeScript · JavaScript · React · React Native · Expo · Next.js · Vue · Svelte · Blazor WASM · Blazor Server · HTMX · Tailwind · Bootstrap · jQuery · HTML · CSS · WordPress · Android (Java) · iOS (Obj-C)

Databaser

Relationelt, dokument, søgning.

SQL Server · T-SQL · PostgreSQL · pgvector · pg_trgm · MySQL · MongoDB · Redis · SQLite · Elasticsearch · indeksoptimering · backup-strategier · execution plans · skemamigrationer

AI & formel verifikation

Agenter, RAG, bevisbar logik.

Semantic Kernel · Microsoft Agent Framework · Azure OpenAI · Ollama · lokale LLM'er · Claude Code · Cursor · GitHub Copilot · RAG · embeddings · hybridsøgning (pgvector + pg_trgm) · TLA+ · Allium · spec-drevet udvikling · custom skills

Cloud (Azure)

Tjenester vi bruger.

App Service · Functions · Container Apps · Service Bus · Event Grid · SQL · Storage · Key Vault · API Management · Entra ID · Monitor · App Insights

Containere & infra

Drift, virt, netværk.

Docker · Docker Swarm · Docker Compose · Kubernetes · Linux (Ubuntu/Debian) · Windows Server · Active Directory · DNS · IIS · Nginx · virtualisering · GPU-farm

CI/CD & test

Pipelines og kvalitetsporte.

Azure DevOps · GitHub Actions · BitBucket · Bicep (IaC) · xUnit · NUnit · Playwright · Testcontainers · k6-stresstest · kodegennemgang · pull requests · Git/GitHub

Sikkerhed & identitet

Auth, GDPR, tilgængelighed.

OAuth2 · OpenID Connect · JWT · WebAuthn · Passkeys · GDPR · Zero Trust · audit-trail · soft-delete · idempotency-keys · WCAG 2.1 AA

Integrationer & data

Betaling, kommunikation, data governance.

Stripe · Swish · Twilio · Mailjet · Google APIs · Fortnox · SCORM · OpenTelemetry · Prometheus · Grafana · data governance · datakatalog · metadatahåndtering · begrebsmodellering · datakvalitet

Den lange forklaring.

For den, der vil have det tekniske dyb — her er, hvad hver fase faktisk producerer, hvorfor den findes, og hvordan den hænger sammen med den næste. Overordnet: pipelinen er en kæde af artefakter, hvor hver fase tager et dokument fra den foregående fase og producerer et nyt dokument, som den næste fase kan læse. Ingen mundtlige overdragelser. Ingen "jeg tror, vi talte om det på onsdagsmødet".

Allium — drift som datapunkt.

Allium er et udspørgssprog: du skriver en specifikation, så køres en elicitering, der finder huller, tvetydigheder og inkonsistenser. Den producerer åbne spørgsmål, som skal besvares, før vi går videre. Senere køres en destillering, der sammenligner den færdige kode mod specen — drift vises som tre kategorier: specificeret-men-ikke-implementeret, implementeret-men-ikke-specificeret, og adfærdsdrift. Hver post får en individuel beslutning: fiks nu, defer (spor i spec) eller dismiss med begrundelse. Ingen gruppebeslutninger om at "tage det senere" — hvert fund har en ejer og en dato.

TLA+ — beviser, ikke tests.

En test, der består, viser, at én eksekvering virkede. Den siger intet om de eksekveringer, du ikke testede. TLA+ modellerer systemet som et tilstandsrum og kører en udtømmende gennemgang — TLC-modeltjekkeren prøver hver mulig sekvens af hændelser og finder de tilstande, hvor invarianter brydes. For sagsbehandling: kan en sag være både lukket og i gang samtidig? For SSE: hvad sker der, hvis klienten reconnecter midt i en opdatering? For idempotens: hvad sker der, hvis samme idempotency-key ses i to requests samtidig? TLC svarer matematisk, ikke sandsynlighedsbaseret.

Destruktive tests — seks kategorier.

Funktionelle tests verificerer, at det heldige mønster virker. Destruktive tests verificerer, at systemet ikke falder, når nogen forsøger at bryde det. Vi kører mindst otte destruktive scenarier per flade, fordelt over seks kategorier.

Input-validering bombarderer felter med for lange strenge, ugyldige tegn, null og tomme værdier. Autorisation forsøger at læse og skrive ressourcer, som brugeren ikke ejer. Injection-kategorien fodrer XSS i tekstfelter og SQL-injection i søgeparametre. Race conditions tvinger to klienter til at ændre samme ressource i samme sekund. Grænseværdier tester maksimumlængder, maksantal og paginering på sidste side. Tilstandskorruption sender ændringer i forkert rækkefølge eller mod allerede slettede ressourcer.

Intet af dette er teoretisk. Hver kategori har fanget rigtige bugs i produktionssystemer, vi har bygget — før de blev frigivet.

AI-augmenteret udvikling — uden AI-religion.

Claude Code bruges som værktøj, ikke som erstatning. Pipelinen ovenfor er ikke AI-genereret — den er dokumenteret, versioneret og enforced via deterministiske hooks. Hookene blokerer feature-arbejde uden spec, kræver afklaring før plan, kører Allium-elicitering før implementering, og nægter at frigive en feature uden både Playwright- og TLA+-validering. AI'en følger metoden — den opfinder den ikke. Resultatet: AI-hastighed med menneskelig gennemgang af arkitekturbeslutninger.

Denne metode tager længere tid i den første uge. Den sparer måneder, når systemet er et år gammelt.

Vi er ikke det rette valg til alt.

Vi vender tilbage med en vurdering — og hvis det ikke er os, I har brug for, siger vi det direkte.

Skriv en linje til os om, hvad I prøver at bygge.

Skriv til os