Hopp til hovedinnhold
Aktiv· Teknisk lead· april 2026

Flowment

Operativsystem for fraktavtaler med pris-motor, fakturakontroll og provisjonsoppgjør for to produktmodeller.

Åpne
Next.js 15SupabaseTypeScriptTailwind CSSTrigger.devHetzner + CoolifyTurborepoCloudflare

Bedrifter som sender mye gods har sjelden bare én transportavtale. De har en for pakker, en for paller, en for ekspress, og hver er forhandlet separat med Bring, PostNord eller Porterbuddy. Når fakturaen kommer i slutten av måneden, stemmer den ofte ikke med det som ble lovet. Volumet ble feilberegnet, en tilleggsavgift dukket opp, en rabattgrense ble bommet på med to sendinger. Noen må kontrollere det, sending for sending, mot avtalt pris, og deretter viderefakturere frakt til sluttkunden dersom det er der den hører hjemme.

Flowment er plattformen som gjør den jobben. Klienten, Flowment AS, leverer den i to modeller: et administrasjonslag oppå kundens egne transportavtaler, og videresalg av Flowments egne fremforhandlede avtaler til kunder som ikke har volum til å forhandle selv. Begge modellene må regne provisjon til partnere, generere fakturagrunnlag, kontrollere avvik mot fakturaen fra transportøren, og fordele margin mellom Flowment og distributørene.

Det jeg bygde

Kjernen er en pris-motor som ligger som egen pakke (packages/domain). Den tar inn en sendingsspesifikasjon (vekt, dimensjon, fra-/til-sone, tjeneste) og en avtalekontekst, og returnerer prisen ledd for ledd: grunnpris, drivstofftillegg, øvrige tillegg, rabatter. Samme motor brukes både i sanntid når en kunde priser en sending, og i batch når månedens fakturagrunnlag genereres. Pris-tabellene importeres fra transportørenes prislister, som kommer i alt fra PDF til Excel til CSV med kolonner som flytter seg fra år til år.

Nattlig kjører en jobb i Trigger.dev som matcher hver linje på transportør-fakturaen mot Flowments egen beregning for samme sending. Avvik over en terskel havner i en kø som operatørene gjennomgår morgenen etter, og som etter hvert blir input til reforhandling. Det er den jobben som rettferdiggjør hele systemet for sluttkunden. En faktura med tusen linjer kontrolleres ikke for hånd.

Multi-tenancy var ikke noe å bomme på. RLS-policyer i Postgres er deny-by-default på alle tabeller, og hver rolle har eksplisitte SELECT-policyer koblet til tenant og rolle. Over det igjen verifiserer domenelaget rollen mot konteksten før resultater settes sammen. Dobbel sjekk, men de to lagene oppdager forskjellige feilkilder: RLS fanger glemte WHERE-klausuler, domenelaget fanger feil bruk av interne API-er. Hver policy har en isolasjonstest som verifiserer at en bruker i tenant A ikke får se en eneste rad fra tenant B, kjørt mot en ekte Postgres i CI.

Resten er orkestrering. Next.js 15 med App Router og Server Components som standard, Server Actions for mutasjoner, Supabase som database og auth-leverandør. Integrasjoner mot PowerOffice for regnskap, og mot Bring, PostNord og Porterbuddy for pris- og sporingsdata. Penger lagres som numeric(14,2) i Postgres og håndteres som Decimal gjennom hele koden, aldri som number. Det er den typen disiplin som ikke er morsom å rydde opp i etterpå.

Selvhosting fremfor Vercel ble valgt etter en runde med tall. Hetzner Helsinki, Coolify som orkestrering, Cloudflare foran, Infisical self-hosted for secrets. Kostnadsforskjellen mot Vercel Pro blir merkbar når man legger til edge functions, image optimization og båndbredde for et system som dette. Avveiingen er at vi eier oppetiden og sertifikatene selv nå, med en manual approve-gate i Coolify mot prod.

Det som overrasket

Coolify-bygget. Lokalt bygger pnpm via Turborepo og respekterer ^build-avhengigheter mellom pakker. Coolifys Dockerfile bygger bare @flowment/web direkte, uten å bygge avhengighetspakkene først. Det betyr at hvis en pakke eksporterer fra dist/ i stedet for src/, ser webserveren tomme moduler i prod selv om alt er grønt i CI. Lekkasjen er nå dokumentert som en pre-merge-sjekk, og pakkene eksporterer fra src/ til situasjonen rettes ordentlig. CI bygger nå også en variant som er lik prod-bygget for å fange differansen tidlig.

Systemet er under bygging. Pris-, margin- og provisjonsmotor er på plass. Faktureringsmotor er i spec-fasen. Kunde- og partnerportal utvikles parallelt.