<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Marcus Jenshaug</title>
    <link>https://marcusjenshaug.no</link>
    <description>Fullstack-utvikler i Redi AS. Jeg bygger webapplikasjoner med Next.js, TypeScript og Supabase, og deler det jeg lærer underveis.</description>
    <language>nb-NO</language>
    <atom:link href="https://marcusjenshaug.no/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Søknadsbasen: verktøyet jeg ikke fant, så bygget selv</title>
      <link>https://marcusjenshaug.no/blogg/soeknadsbasen-verktoeyet-jeg-ikke-fant-sa-bygget-selv</link>
      <guid isPermaLink="true">https://marcusjenshaug.no/blogg/soeknadsbasen-verktoeyet-jeg-ikke-fant-sa-bygget-selv</guid>
      <pubDate>Fri, 24 Apr 2026 09:39:52 GMT</pubDate>
      <description>Et CV-verktøy og jobbsøker-tracker som startet som frustrasjon over eksisterende løsninger, og ble til et lite produkt jeg faktisk bruker selv.</description>
      <content:encoded><![CDATA[Søknadsbasen startet med irritasjon.

Jeg har søkt jobb et par ganger, og hver gang har jeg endt opp med samme rot: en mappe med halvferdige CV-filer, et regneark med søknadsstatus som er utdatert etter tre dager, og en liste med kontakter jeg ikke klarer å holde orden på. Det finnes mange verktøy for dette, men de fleste er enten for enkle til å være nyttige, eller så fulle av features at de krever en onboarding-prosess bare for å sende én søknad.

Jeg ville ha noe midt imellom. Noe jeg faktisk ville åpne.

Så jeg bygget det selv.

## Problemet med eksisterende verktøy

De fleste jobbsøker-verktøy tenker på jobbsøking som en liste. Du legger inn en stilling, setter en status, kanskje noterer litt. Det er greit for de første ukene. Etter en måned med aktiv søking har du femti rader i den listen, og du har mistet konteksten på de fleste.

Det jeg manglet var en måte å tenke på jobbsøking som noe mer strukturert, en pågående prosess med faser, ikke bare et register over hva du har sendt inn.

Det jeg endte opp med å kalle "jobbsøk-sesjoner" var egentlig dette: at en jobbsøk-periode er sitt eget objekt i systemet. Den har en start, den har et mål, den har tilhørende søknader, og den har et utfall. Det lar deg se på én søknad i konteksten av hele perioden den tilhørte, ikke løsrevet fra alt annet.

Det høres kanskje komplisert ut, men det er intuitivt når du bruker det. Det er bare riktig abstraksjonsnivå for problemet.

## Å bygge for deg selv er en annen øvelse

Jeg er vant til å bygge for klienter, eller for brukere jeg aldri møter. Det er en type disiplin: du må gjøre ting eksplisitt, du må skrive onboarding, du må hjelpe noen som ikke kan koden til å forstå hva knappen gjør.

Å bygge for meg selv åpnet for snarveier som var fristende og farlige på samme tid.

Den positive varianten: jeg trengte ikke bygge alt. Jeg trengte ikke en admin-panel for å redigere data, jeg kunne bare gå i databasen. Jeg trengte ikke en fancy onboarding-flyt, jeg visste allerede hvordan ting funket. Det sparte meg for mye tid på ting som ikke mattered.

Den negative varianten: jeg la for mye implisitt kunnskap inn i produktet. Funksjonalitet som gir mening for meg, men som ikke ville gitt mening for noen andre. Det er ikke et problem nå, men det er en begrensning hvis jeg noen gang vil la andre bruke det.

Leksjonen: bygg for deg selv med klar bevissthet om hva du ofrer av bredde. Det er et bevisst valg, ikke en bug.

## CV-byggeren er den vanskeligste delen

En jobbsøker-tracker er egentlig bare en database med et grensesnitt. Det er ikke trivielt, men det er logisk.

En CV-bygger er noe helt annet.

CV-er har meninger om alt. Font-valg sender signaler om bransje og senioritet. Layout-hierarki påvirker hva rekrutterer ser i de første tre sekundene. Hva du inkluderer og hva du utelater er redaksjonelle valg, ikke bare innfylling av felter.

Jeg brukte mye mer tid på CV-delen enn jeg trodde. Ikke på teknisk implementasjon, men på å tenke gjennom hva et CV-verktøy faktisk skal hjelpe deg med. Er det å gjøre CV-en pyntelig? Er det å hjelpe deg velge hva du skal ta med? Er det å generere tekst?

Jeg landet på at det viktigste var kontroll og forutsigbarhet. Eksportert PDF skal se ut akkurat som forhåndsvisningen. Endringer skal reflekteres med én gang. Du skal aldri lure på om det du ser er det rekrutterer ser.

Det er lavere ambisjon enn "AI-generert CV tilpasset stillingen", men det er noe jeg faktisk stoler på.

## Tekniske valg jeg er fornøyd med

Next.js og Supabase er defaultene mine nå, og de funket greit her også. Det er ikke spennende å skrive om, men det er poenget: default-valg som funker lar deg bruke energien på produktet, ikke på infrastruktur.

To valg jeg er spesielt fornøyd med:

Å modellere jobbsøk-sesjoner som første-klasses modell i skjemaet, ikke bare som et tag eller en status på søknaden. Det ga meg query-muligheter jeg ikke hadde tenkt over da jeg designet det, og det gjorde det naturlig å vise aggregert statistikk per sesjon.

Å la PDF-generering skje server-side. Jeg vurderte client-side PDF-generering lenge fordi det er enklere å sette opp. Men server-side gir konsistent rendering uavhengig av nettleser, og det er verdt kompleksiteten for noe som er kjernen i produktet.

## Det jeg undervurderte

Filhåndtering er alltid mer komplisert enn det ser ut. Jeg ville la brukere laste opp profilbilde til CV-en, og jeg estimerte en halvtime på oppsett. Det tok en dag og tre omskrivinger, og jeg er fortsatt ikke hundre prosent fornøyd med flyten.

Det er ikke noe uvanlig i seg selv. Det som overrasket meg var at jeg undervurderte det selv etter å ha gjort det før. Noe med filhåndtering lar seg ikke fullt lære bort, det er noe du må møte på nytt i konteksten av akkurat dette prosjektet.

Jeg undervurderte også hvor mye tid jeg ville bruke på å designe selve CV-malen. Teknisk er det ikke vanskelig. Estetisk er det uendelig justerbart. Jeg satte meg en hard stopp-regel etter tredje iterasjon: dette er godt nok, ikke bra nok til å distrahere.

## Hva jeg skulle gjort annerledes

Laget mer av admin-panelet tidligere. Jeg redigerte direkte i Supabase i starten, akkurat som jeg lærte av Klink-prosjektet, og glemte leksjonen likevel.

Bestemt meg for PDF-bibliotek på dag én. Jeg byttet mellom tre alternativer og mistet tid på hver overgang. Neste gang setter jeg meg ned og evaluerer ordentlig en gang, ikke itererer gjennom dem i produksjon.

Vært tydeligere på hva produktet ikke er. Uten den grensen er scope åpen i begge ender, og det er dyrt.

## Hvorfor det var verdt det

Søknadsbasen er ikke et stort produkt. Det er et lite verktøy som hjelper én person, meg, å holde orden på noe som ellers skaper friksjon.

Men det var den første gangen jeg bygget noe jeg faktisk brukte aktivt mens jeg bygget det. Det gir en annen type feedback enn å se på analytics eller lese brukerrapporter. Du merker på kroppen når noe ikke funker bra nok, fordi du er frustrert av det selv.

Det er en luksus de fleste produktutviklere ikke har, å være sin egen mest kravstore bruker. Jeg prøver å ta vare på den leksjonen i andre prosjekter også: forstå brukerens frustrasjon så godt at du kjenner den selv.

Søknadsbasen lever på søknadsbasen.no. Den er ikke klar for allmenheten ennå, men det er dit det går.]]></content:encoded>
      <category>solodev</category><category>nextjs</category><category>supabase</category><category>produktutvikling</category><category>jobbsøking</category>
    </item>
    <item>
      <title>To og et halvt år som eneste utvikler</title>
      <link>https://marcusjenshaug.no/blogg/to-og-et-halvt-ar-som-eneste-utvikler</link>
      <guid isPermaLink="true">https://marcusjenshaug.no/blogg/to-og-et-halvt-ar-som-eneste-utvikler</guid>
      <pubDate>Mon, 20 Apr 2026 16:50:00 GMT</pubDate>
      <description>En retrospektiv etter å ha bygget Eiendomsavtaler.no fra første linje kode. Fra innleid konsulent til grunnleggers-utvikler, gjennom tre tekniske generasjoner.</description>
      <content:encoded><![CDATA[Jeg kom inn i Eiendomsavtaler.no høsten 2023 , først som innleid konsulent gjennom mitt eget byrå, [Spiderweb AS](/prosjekter/spiderweb). Det fantes ingen teknisk plattform ennå. Jobben var å bygge den. I januar 2025 ble jeg fast ansatt, og samme år la jeg ned Spiderweb for å fokusere fullt på Eiendomsavtaler. Jeg var eneste utvikler. Alt fra arkitektur til produksjon, fra sikkerhet til overvåkning, lå hos meg.

I mai 2026 gir jeg det fra meg. Plattformen er i stabil drift, har vært det lenge, og det er ingen dramatisk grunn til at jeg slutter , jeg skal videre til Redi AS og bygge andre ting. Men overgangen er en god anledning til å skrive ned det jeg faktisk har lært. Ikke på LinkedIn-format med "drev vekst og optimaliserte ytelse", men det som sitter i kroppen etter to og et halvt år.

## Tre generasjoner på to og et halvt år

Det første du må vite er at jeg bygget plattformen gjennom tre tekniske generasjoner.

**Generasjon 1** var en WordPress-installasjon. Advanced Custom Fields for strukturerte skjemaer, WP User Frontend for opplasting, WP Statistics for sporing , plugin-stacken man ender opp med når man trenger å komme fort i gang og validere at produktet har en rolle i markedet. Jeg valgte det bevisst. Et MVP skal leveres, ikke være arkitektonisk imponerende.

**Generasjon 2** var min første Next.js-app , en investor-plattform, et sideprosjekt innenfor samme organisasjon. Jeg skrev den mens jeg fortsatt driftet WordPress-siden. Den var i praksis min læringsarena: første gangen jeg jobbet med App Router, server components, server actions. Den lever fortsatt, men ble aldri produkt-hovedkanalen.

**Generasjon 5** (ja, vi hoppet over 3 og 4 , mer om det under) er den som kjører i dag. Full rewrite til TypeScript, Next.js, PostgreSQL. Ingen WordPress igjen. Dette er det jeg overleverer.

## Hvorfor versjonstellingen hopper

Versjonene 3 og 4 er ikke rewrites , de er arkitekturutkast som aldri ble deployet. Jeg prøvde først en tyngre tilnærming med et separat backend-API og Next.js som ren frontend. Det var overdimensjonert for et team på én. Så prøvde jeg en arkitektur med mer spesialiserte moduler. Også overdimensjonert.

Det jeg landet på i Versjon 5 var kjedelig: én Next.js-app med server actions, PostgreSQL som primærdatabase, bildebehandling via sharp, type-validering med zod. Ingen microservices, ingen separate API-er, ingen eventing bus jeg ville brukt tre måneder på å sette opp riktig.

Den viktigste leksjonen fra de forkastede versjonene var at **kompleksitet straffer seg eksponentielt når du er alene**. Hver abstraksjon du legger til er en ting bare du kjenner, bare du kan feilsøke, bare du kan endre. Og om to år er ikke engang du sikker på at du husker hvorfor.

## Hvorfor jeg tok det

Eneste-utvikler-jobber er polariserende i bransjen. Halvparten advarer deg: ingen pair programming, ingen kode-gjennomgang, ingen å sparre med, fullt ansvar når ting feiler klokka tre på natta. Den andre halvparten snakker om eierskap, fart og fravær av komitéer.

Begge sider har rett. Ingen av sidene forbereder deg på hva det faktisk er å gjøre det.

Grunnen til at jeg sa ja var ikke romantikken rundt "bygge alt selv". Det var at jeg ville vite om jeg *kunne*. Jeg hadde jobbet i team i flere år, og jeg hadde alltid hatt en følelse av at når noe gikk bra, var det fordi teamet var godt. Jeg visste ikke hva som var meg og hva som var dem. Å være eneste utvikler er den eneste måten å finne ut av det på.

## Det jeg undervurderte

De første månedene gikk på tekniske avgjørelser. Rammeverk, hosting, database, auth, overvåkning. Jeg hadde en arkitektur jeg var fornøyd med på papiret, og jeg fikk den til å kjøre.

Det jeg ikke hadde planlagt for var *alt det andre*. En eneste-utvikler er ikke bare utvikleren. Du er også:

- Sikkerhetsansvarlig som må følge med på CVE-er
- DevOps-ingeniøren som eier deploy-pipelinen
- Databaseadministratoren som må svare "hvorfor er det tregt nå?"
- Supporten når noe ikke funker for en kunde klokka 16:30 fredag
- Tech-lead-en som må si nei til features som er kule men unødvendige
- Product-en som oversetter "kan vi ikke ha en knapp som..." til noe faktisk utviklbart

Det siste er det jeg ble dårligst forberedt på. Kode er overraskende lite av jobben når du er alene. Mye mer av dagen går til kommunikasjon, prioritering og å forklare hvorfor ting tar den tiden de tar.

## WordPress hadde noen av svarene

Noe av det jeg synes var mest overraskende underveis var hvor mye WordPress faktisk hadde rett om. Jeg hadde utviklet i WordPress før, og jeg visste at stacken har dårlig rykte blant mer "moderne" utviklere. Men det løser reelle problemer veldig effektivt:

- **Strukturerte skjemaer uten å skrive dem** (ACF)
- **Brukergenerert innhold med moderering** (WP User Frontend)
- **Analyse uten tredjeparts-trackere** (WP Statistics)

Da jeg bygget v5, måtte jeg re-implementere hver av disse. Og det er *mye* kode for noe som før fyltes ut på femten minutter i et admin-panel. Det jeg vant var typesikkerhet, bedre performance, og kontroll over hele stacken. Det jeg tapte var utviklings-hastighet på ting som WordPress bare hadde løst.

Konklusjonen min etter migreringen er ikke "WordPress er dårlig" eller "egen-bygget er bedre". Det er at **valg av rammeverk er en kalibreringsøvelse, ikke et prinsipp**. WordPress var riktig valg for den fasen plattformen var i. Det er ikke riktig for denne fasen. Neste fase får vise om v5 fortsatt er det riktige valget.

## Å være sin egen kode-reviewer

Den tyngste enkelt-øvelsen i å være alene er å vurdere sitt eget arbeid nøkternt. Det er kjent, det er skrevet mye om, og likevel var det vanskeligere enn jeg trodde.

Når du er i et team, får du motstand. Noen spør "hvorfor gjorde du det sånn?", og du må forsvare valget , og noen ganger innser du midt i forsvaret at du ikke har et godt svar. Uten den motparten forsvinner forsvaret også. Du skriver kode, du merger den, du glemmer hvorfor.

Det jeg landet på var to enkle ting:

**Å skrive små commits med tydelige meldinger.** Ikke fordi noen skulle lese dem senere , ingen skulle , men fordi jeg som skrev dem, tvang meg selv til å formulere *hva* jeg hadde gjort og *hvorfor*. Jeg kom i det minste halvveis til en begrunnelse.

**Å la det ligge over natten før merge når det var stort.** Kveldsgløden etter at noe endelig funker er den verste reviewer. Morgen-meg er en strengere kollega enn kveld-meg.

Ingen av disse erstatter en ekte pair. Men de to sammen gjorde at jeg tok færre dumme snarveier enn jeg ellers ville gjort.

## Om å bygge for én klient du aldri møter

Eiendomsavtaler.no har reelle brukere. Megler-profesjonelle, eiendomsaktører, folk som bruker plattformen for å lande faktiske avtaler. Jeg har aldri møtt noen av dem ansikt til ansikt. Det jeg visste om dem, visste jeg gjennom forretningssiden , folk som oversatte behov til meg og tok mine tekniske svar tilbake til dem.

Det formet hvordan jeg jobbet. Jeg måtte bli flinkere til å stille spørsmål som ikke forutsatte at jeg hadde sett problemet selv. "Hva prøver brukeren å gjøre når dette feiler?" i stedet for "hva er feilen?". Det første gir deg kontekst. Det andre gir deg en stack trace.

Når du jobber alene uten direkte brukerkontakt, er forretningssiden din eneste bro til virkeligheten. Jeg lærte å respektere den rollen mye mer enn jeg gjorde før.

## Performance-arbeidet jeg lærte mest av

En av de mest lærerike øvelsene i v5 var ytelses-arbeidet. Jeg førte en enkel audit-fil i repoet der jeg noterte hvilke sider som trakk ned, hva som forårsaket det, og hva jeg gjorde for å fikse det. Ingenting avansert , bare en markdown-fil som vokste over tid.

Det jeg lærte av den øvelsen var at de fleste performance-problemer er kjedelige. Det er sjelden at løsningen er "bytt til en raskere runtime" eller "implementer en cache-strategi". Oftere er det at et bilde ikke er lazy-loaded, en database-spørring henter mer enn nødvendig, eller en komponent rendres klient-side fordi utvikleren (altså jeg) glemte å sjekke om den kunne kjøre server-side.

Kjedelig fix, stor gevinst. Den typen arbeid belønnes ikke av det tekniske miljøet , ingen holder foredrag om "jeg la til `sizes`-attributten på `<Image>`" , men det er det som faktisk utgjør forskjellen i Core Web Vitals.

## Hvorfor enkle løsninger vant

Jeg begynte prosjektet med en arkitektonisk ambisjon som var litt for stor for problemet. Microservices her, event-drevet der, queue for de tunge jobbene, Kubernetes en gang i fremtiden. Ingen av det var teknisk feil , det var bare feil *størrelse*.

Det jeg endte med var mye nærmere kjedelig. En monolitt med klare grenser mellom moduler. En primærdatabase med replika. En cache-lag på de åpenbare stedene. CI/CD som er rett-frem nok til at jeg kan gjøre endringer i den uten å være redd for å brekke den. Overvåkning som gir meg to-tre metrics jeg faktisk følger med på, ikke tjue jeg ignorerer.

Grunnen til at dette funket er ikke at jeg hadde rett i mine valg. Det er at jeg var eneste utvikler, og kompleksitet straffer seg eksponentielt når du er alene.

Hvis jeg bygget den samme plattformen i dag, ville jeg begynt enda enklere.

## Det som var verdt det

Det jeg tar med meg videre er ikke at jeg klarte det , det var aldri spørsmålet. Det jeg tar med meg er at jeg nå har en kalibrering på hva som faktisk koster tid når du eier hele stacken. Jeg vet hva "vi må bare få det ut" betyr for en real-world deploy, ikke bare for en sprint. Jeg vet hva det kveles av når en arkitektur er for stor for teamet som skal drifte den. Jeg vet hva du vinner ved å bytte fra et ferdig rammeverk, og hva du taper.

Den kalibreringen er vanskelig å få på annen måte. Det koster deg to og et halvt år, en del helger og noen kvelder du skulle ønske du kunne hatt tilbake. Men den sitter når du får den.

## Hva som skjer nå

Plattformen lever videre uten meg , overleveringen har vært ryddig, dokumentasjonen er der, og det nye teamet har fått tilgang til alt som trengs. Jeg går videre til [Redi AS](https://redi.as) og fullstack-utvikling i et multi-tenant produkt, der jeg er én utvikler blant flere. Det blir en annen jobb på måter jeg nok fortsatt undervurderer.

Men jeg tror det blir enklere å være en del av et team når man vet hva man faktisk bidrar med , og hva man trenger fra de andre.

Du finner plattformen på [eiendomsavtaler.no](https://eiendomsavtaler.no).]]></content:encoded>
      <category>arkitektur</category><category>solo-utvikling</category><category>retrospektiv</category><category>plattform</category><category>wordpress</category><category>nextjs</category>
    </item>
    <item>
      <title>Hva jeg lærte av å bygge Klink alene</title>
      <link>https://marcusjenshaug.no/blogg/hva-jeg-laerte-av-a-bygge-klink-alene</link>
      <guid isPermaLink="true">https://marcusjenshaug.no/blogg/hva-jeg-laerte-av-a-bygge-klink-alene</guid>
      <pubDate>Thu, 02 Apr 2026 04:23:00 GMT</pubDate>
      <description>Et drikkespill-webapp som skulle være en helgeprosjekt, og ble til en skole i scope, arkitektur og det å levere noe ferdig.</description>
      <content:encoded><![CDATA[Klink skulle være en helgeprosjekt. Én kveld på sofaen med en idé om et norsk drikkespill i nettleseren, et domene som var ledig (klinkn.no , klink.no var tatt), og en forestilling om at jeg kunne levere noe "raskt". Et halvt år senere er appen i produksjon, har PWA-støtte, en Hot Seat-timer, egne spillpakker og et easter egg som aktiveres av ti trykk på logoen.

Her er det jeg lærte underveis. Ingen av det er særlig originalt , men det er ting jeg nå faktisk vet, ikke bare nikker gjenkjennende til når andre skriver det.

## Scope er den viktigste avgjørelsen

Den første tabben jeg gjorde var å tenke: "det er bare et drikkespill, dette er enkelt". Det er det ikke. Selv et "enkelt" produkt har hundrevis av mikroavgjørelser , hvordan spillernavn interpoleres inn i kort, hvordan du håndterer en spiller som dropper ut midtveis, hvordan du deler et spill via QR-kode uten å lage brukere.

Det jeg gjorde riktig var å låse meg tidlig til noen bevisste begrensninger:

- **Ingen brukerkontoer.** Spillertilstand bor i sessionStorage. Du åpner appen, legger til spillere, spiller, lukker fanen. Ingen DB-skriving per økt, ingen auth, ingen GDPR-båndbredde.
- **Ingen multiplayer.** Én enhet, delt mellom spillerne , akkurat som et fysisk kortspill.
- **Ett språk.** Norsk. Klink er et norsk konsept for en norsk kontekst. i18n er et ork jeg ikke trenger nå.

Hver av disse avgjørelsene eliminerte ukevis med arbeid. Den viktigste ferdigheten på et soloprosjekt er ikke å bygge fort , det er å si nei til ting som ikke hører hjemme enda.

## Server-first er stort sett riktig, men ikke alltid

Jeg jobber server-first som default: Next.js App Router, server components, data på serveren, klientkomponenter kun når det trengs. Det er nesten alltid riktig valg.

Klink er et av de sjeldne tilfellene der det ikke er riktig for alt. Kort-logikken (shuffle, neste kort, interpolere navn) kjører helt i klienten med React Context, fordi:

1. Spillet skal føles umiddelbart. Ingen latency mellom "trykk neste" og "nytt kort vises".
2. Det skal funke offline. PWA-støtte betyr at appen må kunne kjøre uten nettverk.
3. Det er ikke sensitivt. Hvem som får hvilket kort kan lekke til klienten , det er klienten.

Det jeg bruker serveren til er å hente spillpakker og kort fra Supabase, og det er ISR-cachet med lang revalidation-tid. Jeg liker denne delingen: kunnskap på serveren, oppførsel på klienten.

## Fisher-Yates, og hvorfor Math.random er nok

Et drikkespill krever at kortene stokkes. Første versjon brukte `array.sort(() => Math.random() - 0.5)`, som er en klassisk antipattern , den er ikke uniform, og noen kort havner statistisk oftere tidlig eller sent i bunken.

Jeg byttet til [Fisher-Yates](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle):

```typescript
function shuffle(array) {
  const result = [...array];
  for (let i = result.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [result[i], result[j]] = [result[j], result[i]];
  }
  return result;
}
```

Jeg vurderte kort å bruke `crypto.getRandomValues()` for å få kryptografisk tilfeldighet. Så minnet jeg meg selv på at dette er et drikkespill. `Math.random()` gir biased bits i det fjerde desimalet. Ingen kommer til å merke det.

Et prinsipp jeg prøver å huske: løsningen skal være så robust som problemet krever, ikke som problemet kunne tenkes å kreve.

## Designet er forskjellen

Klink er ikke det eneste norske drikkespillet på nett. Det finnes et som heter Børst som er bygget godt og har vært der lenge. Jeg brukte tid på å velge en visuell identitet som ikke kunne forveksles:

- Lime og mørkegrønn som dominerende farger (Børst er blå/oransje)
- Sans-serif med karakter, ikke generisk
- Glass-morphism med hvite container-kort på fargede bakgrunner
- Et easter egg , "Athina-modus" , som aktiveres ved 10 trykk på logoen og bytter hele appen til leopard + rosa. Jo flere slike småting, jo mer personlighet.

Det er et paradoks her. Den tekniske delen av Klink er solid håndverk men ikke imponerende , Next.js og Supabase gjør 90% av jobben. Designavgjørelsene er det folk husker. Det lærte meg å bry meg mer om detaljer jeg tidligere ville delegert.

## Deploy-flyten som faktisk holder

På Eiendomsavtaler.no bygget jeg en CI/CD-pipeline med steg, tester, staging, godkjenninger, alt. Det var riktig der.

På Klink har jeg: `git push origin master`. Vercel merger til produksjon hvis build passerer. Det er det. Ingen staging. Ingen manual approval. Ingen "post-deploy smoke test".

Dette er ikke latskap , det er riktig størrelse for problemet. Klink har én utvikler, ingen SLA, ingen kunder som blør penger hvis siden er nede i ti minutter. Kompleksiteten i en CI-pipeline må stå i forhold til kostnaden av en feil.

## Hva jeg skulle gjort annerledes

1. **Skrevet database-schemaet på papir først.** Jeg endret spillpakker- og kort-tabellene fire ganger fordi jeg ikke hadde tenkt gjennom relasjonene. Supabase-migrasjoner er greie å rulle ut, men det eter tid.
2. **Laget et admin-panel tidligere.** Jeg redigerte kort direkte i Supabase-dashboardet i månedsvis. Et enkelt skjema hadde spart meg for timer.
3. **Ikke ventet med PWA-oppsett til slutten.** next-pwa er forholdsvis greit, men service workers har egne regler for caching som krasjer med Next.js ISR hvis du ikke tenker over det. Enklere å sette det opp fra dag én.

## Hvorfor det var verdt det

Klink har ikke tusenvis av brukere. Det er ikke et forretningsbygg. Men det var den første appen jeg leverte fra idé til produksjon helt alene , uten team, uten kunder, uten noen å skylde på hvis noe ikke var bra nok.

Det lærte meg at jeg kan levere et helt produkt selv. Det er en annen type selvtillit enn å levere godt innenfor et team. Begge er viktige, men den første får du bare ved å gjøre noe ferdig helt alene.

Appen finner du på [klinkn.no](https://klinkn.no). Koden ligger [på GitHub](https://github.com/MarcusJenshaug1/klink). Koden inneholder en overraskelse eller to.]]></content:encoded>
      <category>nextjs</category><category>supabase</category><category>pwa</category><category>sideprosjekt</category>
    </item>
  </channel>
</rss>