Tillbaka till bloggen
·David Larsson

Vi byggde om ett affärskritiskt system från grunden – en skiva i taget

Rutnät av skivor där de flesta är klara och de sista återstår

Systemet hade vuxit i fyra år. Det fungerade, användarna litade på det och det gick releaser varje vecka. Men arkitekturen var byggd för en annan tid: alla kunder delade en databas och en installation, och deras data hölls isär av ett fält på varje rad.

Nu behövde varje bolag en egen instans och en egen databas. För dataisoleringen, för att kunna köra och skala varje bolag för sig, och för att integrationer ska kunna slås på per bolag i stället för för alla.

Det fanns också ett skäl som handlade om framtiden. Allt mer av koden skrivs i dag med AI-agenter, och i högt tempo. Den grund systemet stod på var byggd för en tid då utvecklare skrev varje rad själva. Vi ville ha en grund som tål att utvecklas snabbt med AI – utan att kvaliteten glider.

Det går att bygga om inifrån. Vi valde att börja om.

Varför inte bygga om inifrån?

En ombyggnad på plats betyder att gammal och ny kod lever sida vid sida i samma kodbas, ofta i åratal. Det gamla läcker in i det nya, och ingen vet riktigt vilket mönster som gäller.

Vi övervägde också att låta en proxy skicka trafik till den nya appen en funktion i taget. Det ger tidig nytta, men kräver en brygga för routing och inloggning mellan två system som ska driftas samtidigt.

Så vi gjorde tvärtom: ett helt nytt repo med målarkitekturen från dag ett. Den gamla koden lades i en egen mapp – läsbar som referens, men aldrig byggd, testad eller importerad.

Fem regler

Hela ombyggnaden vilade på ett kort beslutsdokument. Reglerna var få och gällde varje skiva:

  1. Gående skelett först. Den första skivan var inloggning och layout – tunn i funktion, men hela vägen genom stacken, ut i drift. Där sattes alla mönster.
  2. En skiva är hela vertikalen. Databasschema, datamigrering, API, gränssnitt och tester. Inget halvt.
  3. Ordningen följer datan. Det som inget annat beror på byggs först. Det som beror på allt byggs sist.
  4. Oförändrat gränssnitt. Varje skärm flyttas exakt som den ser ut. Ingen redesign under resans gång.
  5. Klar betyder bevisad. En skiva är inte klar förrän den migrerade datan automatiskt har jämförts med originalet – och stämmer.
Vertikala skivor
En skiva i taget – hela vägen från schema till UI
Skelett · 1Referensdata · 9Avtal · 3Planering · 2Order · 4Transaktioner · 4Rapporter · 3Driftsättning · pågår

26 skivor i sju nivåer, byggda i databeroendeordning. Varje skiva innehåller schema, datamigrering, API, gränssnitt och tester.

Varje kolumn är en skiva, byggd nedifrån och upp. Nästa skiva påbörjas när den förra är bevisad.

Regel fyra är den som oftast får folk att höja på ögonbrynen. Varför inte passa på att förbättra designen? Därför att en omskrivning redan är en stor risk. Lägger man en redesign ovanpå har man två risker samtidigt, och när något skaver vet ingen vilken av dem det beror på. Användarna ska kunna byta system utan att lära om. Förbättringarna kommer efteråt – på en plattform som tål dem.

Ordningen är beroendegrafen

Vi kartlade varje datamodell i det gamla systemet och vad den refererade till. Resultatet var en graf utan cirklar, så den gick att sortera från löven och inåt.

Först referensdata: produkter, platser, bolag, lager, artiklar. Enkla register, en modell per skiva, och eftersom de inte beror på varandra kunde flera byggas parallellt. Sedan avtal, planering och prognoser. Sedan orderkärnan – den tyngsta delen. Sist transaktioner, integrationer och rapporter, som läser från nästan allt.

Tidiga skivor var små och snabba. De första två veckorna efter skelettet blev tolv skivor klara. Det gav fart, men framför allt gav det en stabil grund: när orderkärnan byggdes fanns allt den refererade till redan på plats, migrerat och verifierat.

Tidslinje
Från första commit till komplett system
  1. Maj
    Beslut – grönt fält och vertikala skivor
  2. Juni v.1
    Arkitektur, beslutslogg och skivornas ordning
  3. Juni v.2
    Gående skelett – hela vägen ut i drift
  4. Juni v.2–4
    Referensdata, avtal och prognoser
    Tolv skivor på två veckor
  5. Juli
    Sommaruppehåll
  6. Augusti
    Orderkärnan, planering, lager och transaktioner
  7. September
    Integrationer, rapporter, dashboards och AI-åtkomst
  8. Nästa
    Driftsättning, bolag för bolag

En grund för att utvecklas snabbt med AI

När det inte längre är en utvecklare som skriver varje rad ändras vad man ska optimera för. Förr valde man gärna det som var smidigast att skriva. Nu vinner det som stoppar fel – tidigt och automatiskt.

  • Dataintegritet före bekvämlighet. Vi gick från en dokumentdatabas till PostgreSQL med strikta scheman och regler i databasen själv. Det är mindre flexibelt att skriva mot, men felaktig data kommer inte in, oavsett vem – eller vad – som skrev koden.
  • Typer hela vägen. Med tRPC delar gränssnittet och servern samma typer, från databasen till skärmen. Ändras ett fält på ett ställe säger kompilatorn var det måste ändras på alla andra.
  • Tester, typer och linting som första granskare. De är de snabbaste granskarna vi har, och de säger om en ändring är rätt – inte känslan.
  • Struktur och dokumentation. En beslutslogg, en plan per skiva och tydliga mönster gör att både människor och agenter hittar rätt. Det är det som gör det möjligt att släppa ofta och att granska stora ändringar i högt tempo utan att tappa greppet.
Förr → Nu
Vad grunden är byggd för
Flexibel dokumentdatabas
PostgreSQL med strikta scheman och regler
Typerna tar slut vid API:t
Samma typer från databas till gränssnitt med tRPC
Tester när det finns tid
Tester och datakontroll i varje skiva
Kunskapen sitter hos den som skrev koden
Beslutslogg och plan per skiva som alla läser

Planen skrivs innan koden

Vi byggde med AI-agenter i flödet, och det är en stor del av förklaringen till tempot. Men agenterna fick inte börja från en tom prompt.

Varje skiva hade en egen planfil: omfattning, steg, acceptanskriterier, risker och hur varje steg verifieras. Ovanpå låg beslutsloggen – varför vi valde som vi gjorde – och en arbetsbeskrivning för agenterna: läs det som gäller för uppgiften, ta nästa öppna steg i planen, ett steg per commit, kör verifieringen, bocka av. Upptäcker du något som ändrar planen, skriv en notering i stället för att skriva om historiken.

Att flytta en funktion från en gammal stack till en ny, med originalet som facit bredvid, är precis den sortens välavgränsade arbete som agenter är bra på. Det som krävde erfarenhet var allt runt omkring: i vilken ordning, var gränserna går, vad som räknas som klart – och när facit inte stämmer.

I siffror
26
skivor klara
29
dokumenterade arkitekturbeslut
11veckor
aktiv utveckling
2
utvecklare

När facit har fel

Regel fem – klar betyder bevisad – höll i nitton skivor i rad. Varje migrering jämfördes rad för rad med det gamla systemet, och målet var noll avvikelser.

Sedan kom lagret. Där visade jämförelsen något ingen hade räknat med: det gamla systemets data var själv fel. Vissa värden var fysiskt omöjliga, en del rader pekade åt fel håll, och genom åren hade stora manuella justeringar lagts in för att få saldona att gå ihop med verkligheten.

En migrering som gav noll avvikelser skulle alltså ha kopierat felen.

Kontrollen fungerade perfekt. Den mätte bara fel sak.

Vi flyttade facit ett steg bakåt i kedjan – till de ursprungliga mätningarna som det gamla systemet självt hade läst. De fanns kvar för i stort sett alla rader. Lagret byggdes om från originalkällorna, och jämförelsen gjordes mot dem i stället.

Det viktiga var inte att vi släppte regeln, utan att vi inte gjorde det. Undantaget gäller bara när felet i det gamla är påvisat med siffror. Kan det inte visas är avvikelsen ett fel i migreringen – precis som förut.

Vad det kostar

Vägen har ett pris. Tre saker är värda att känna till innan man väljer den:

  • Ingen tidig produktionsnytta. Den nya plattformen ger värde först när ett bolag byter över. Fram till dess kör det gamla systemet vidare.
  • Dubbelt underhåll. En bugg som rättas i det gamla kan behöva rättas i det nya.
  • Skivor växer. En funktion drar gärna in allt den refererar till. Beroendeordningen är det som håller dem små.
Big bang → Skivor
Big bang eller skivor
Allt byts på en gång
En skiva i taget, klar när datan stämmer
Datan migreras i slutet
Varje skiva migrerar och verifierar sin egen data
Ny design samtidigt
Oförändrat gränssnitt – en risk i taget
Gamla koden lever kvar i den nya
Grönt fält, gamla koden som läsbar referens

Var vi är nu

De 26 skivor som bär verksamheten är klara. På vägen byggde vi också sådant som aldrig blev färdigt i det gamla systemet: nya integrationer, AI-åtkomst till datan via MCP och automatisk uppsättning av nya bolag med egen instans och egen databas.

Nästa steg är att byta över, bolag för bolag.

Det vi tar med oss:

  1. Bygg skelettet först. Då sätts mönstren en gång.
  2. Låt datan bestämma ordningen. Då finns alltid grunden på plats.
  3. Definiera klart som bevisat. Då vet alla när en skiva är färdig.
  4. Skriv planen innan agenten skriver koden. Då blir implementationen nästan mekanisk.
  5. Våga ifrågasätta facit. Men bara med siffror.

Står ni inför en omskrivning av ett system som inte får stå still? Hör av er – vi berättar gärna mer.