For arbeidsgivere
Bart van den Berg
Systemutvikler
Jeg er fullstack-utvikler i Bergen med frontend-utdanning fra Noroff og praktisk erfaring med å utvikle, drifte og videreutvikle en webapplikasjon som er i daglig bruk.
Hos Total Entreprenør AS har jeg bygget TotalTiming fra bunnen av: React-klient, Express-API, MySQL-database, tilgangsstyring og drift på egen server. Nå ser jeg etter en fast stilling som systemutvikler, der jeg kan jobbe i team og lære av erfarne utviklere. Resten av dette nettstedet hører til enkeltpersonforetaket mitt, men det er en fast stilling jeg er ute etter.

Teknisk case
TotalTiming
Utgangspunkt og bruk
Før TotalTiming førte vi timene på papir. Mange glemte å notere timene sine og måtte spørre sjefen om han husket når de hadde jobbet, og i en travel hverdag var det lett at også han glemte å skrive det ned. Ved månedsslutt sendte hver ansatt timelisten sin, og sjefen måtte kontrollere alle for hånd. Det var dette jeg bygget TotalTiming for å løse: nå føres timene fortløpende på mobil eller PC, godkjennes direkte i systemet, og regnskap henter de godkjente timene rett fra appen i stedet for fra innsendte timelister.
TotalTiming er et arbeidsstyringssystem for byggebransjen. Ansatte fører timer og fravær, tar ledige vakter og laster opp bilder, filer og notater til prosjektene. Prosjektledere godkjenner eller avviser timer, regnskap gjennomgår timer og rapporter, og administratorer styrer brukere, prosjekter og vakter.
Systemet er utviklet i jobben min hos Total Entreprenør AS og brukes daglig av 10 aktive brukere, både ansatte og administrasjon. Til sammen føres det over 400 timer i systemet hver måned, og daglig leder har flere ganger sagt at systemet er til stor hjelp i hverdagen.
Vaktsystemet «Ledige timer» ble lansert i oktober 2026. Neste steg er e-postvarsler, slik at ansatte får beskjed om ledige vakter uten at noen må følge opp manuelt.
Se skjermbilder av TotalTiming →Kildekoden er privat fordi den tilhører Total Entreprenør AS. Jeg går gjerne gjennom løsningen i et intervju.
Stack
- Klient
- React 19TypeScriptViteTailwind CSSTanStack QueryReact RouterZod
- API
- Node.js 20Express 5mysql2ZodJSON Web TokensbcryptMultersharp
- Data og drift
- MySQL 8.4DockerVPSCloudflare Tunnel
Arkitektur
- NettleserMobil og PC
- CloudflareHTTPS og tunnel (cloudflared)
VPS · Docker
- React-klientStatisk Vite-bygg
- Express APINode.js-container
- MySQL 8.4Container + private filer
Daglige sikkerhetskopier på serveren og på en egen maskin via SSH.
Sikkerhet og personvern
- Passord lagres som bcrypt-hasher. Tilgangstokens varer i 15 minutter, og fornyelsestokenet ligger i en httpOnly-cookie som bare sendes til /api/auth.
- Hver forespørsel sjekker brukeren mot databasen. Deaktiverte brukere og utloggede økter blir derfor avvist med en gang, ikke først når tokenet utløper.
- Rollene ansatt, regnskap og administrator sjekkes på serveren. Tilgang til prosjekter avgjøres av prosjektmedlemskap direkte i SQL-spørringene, så klienten kan aldri se mer enn brukeren har rett til.
- All input valideres med Zod, og alle databasekall bruker parametriserte spørringer.
- Opplastede filer lagres utenfor offentlig mappe med tilfeldige filnavn og kan bare hentes gjennom en innlogget, tilgangskontrollert rute. Filtyper og størrelser er begrenset.
- Bilder konverteres til WebP med sharp. Da forsvinner også metadata som GPS-posisjon fra mobilkameraet.
- Slettede prosjektnotater beholdes i 90 dager for gjenoppretting og revisjon, og skal deretter slettes permanent.
- Klienten sendes med sikkerhetsheadere, blant annet HSTS og en streng Content-Security-Policy, og API-et tillater bare kjente domener via CORS.
Testing
- Backend-tester skrevet med Node.js sin innebygde testløper. Databasen stubbes, og testoppsettet nekter å koble til en ekte database.
- Testene dekker blant annet øktsikkerhet og tilgangsstyring, prosjektmedlemskap, interne prosjekter, notater, filer, vakter, oppmøtepoeng og aktivitetslogg.
- Klienten har enhetstester for tidsberegning rundt vakter, i tillegg til TypeScript-bygg og ESLint.
- Tester, lint og bygg kjører automatisk med GitHub Actions på hver pull request og hver endring på main.
Drift og sikkerhetskopier
- Først driftet jeg TotalTiming selv fra en maskin hjemme, med Nginx foran. Maskinen var ikke energieffektiv, så det ble billigere å flytte løsningen til en VPS.
- Klient, API og MySQL kjører i Docker på én VPS. Jeg valgte det fremfor tre separate tjenester for å holde hostingkostnadene nede, fordi Docker er enkelt å jobbe med, og fordi jeg ville lære det. Ulempen er at alt står på én server, og derfor tas det også kopier utenfor serveren.
- Trafikken går gjennom Cloudflare Tunnel (cloudflared). Serveren åpner selv en utgående forbindelse til Cloudflare, så appen trenger ingen åpne porter mot internett, og Cloudflare håndterer HTTPS.
- Databaseendringer leveres som versjonerte SQL-migreringer med dokumentert fremgangsmåte, verifisering og rollback.
- Databasen sikkerhetskopieres hver dag både på serveren og til en egen maskin, med mysqldump over SSH. Kopiene på den egne maskinen slettes automatisk etter 30 dager.
- [PLACEHOLDER: hvor ofte gjenoppretting fra backup testes]
Tre problemer jeg måtte løse
Utlogging som faktisk stenger tilgangen
- Problemet
- Rene JWT-er er raske, men kan ikke trekkes tilbake før de utløper. En ansatt som slutter, eller en mistet telefon, skulle ikke beholde tilgang.
- Slik løste jeg det
- Hver bruker har et sessionVersion-felt som bakes inn i tokenene. Utlogging øker versjonen, og alle tokens med gammel versjon blir ugyldige på alle enheter.
- Hva det koster
- Det koster ett enkelt databaseoppslag per forespørsel, men gir umiddelbar tilbaketrekking uten å måtte drifte en egen øktlagring.
Samme person, ulik rolle på ulike prosjekter
- Problemet
- I byggebransjen kan samme person lede ett prosjekt og jobbe som vanlig ansatt på et annet. En global prosjektleder-rolle ville gitt for mye eller for lite tilgang.
- Slik løste jeg det
- Prosjektledelse og medlemskap lagres per prosjekt. Én felles funksjon lager SQL-betingelsen som avgjør hvilke prosjekter en bruker får se, og den brukes på tvers av API-et.
- Hva det koster
- Spørringene blir litt mer komplekse, men tilgangsregelen ligger ett sted og er dekket av tester.
Poeng som ikke kan telles dobbelt
- Problemet
- Oppmøte på vakter gir poeng, og registreringer kan bli korrigert i ettertid. Doble klikk eller nye forsøk etter nettverksfeil skulle ikke gi doble poeng.
- Slik løste jeg det
- Hver endring i oppmøte skrives som en ny rad i en poenglogg som bare tillater nye rader. Unike nøkler på bookingversjon og operasjons-ID gjør gjentatte forespørsler trygge, og databasetriggere hindrer sletting av historikk.
- Hva det koster
- Det krever transaksjoner og mer omhyggelig API-kode, men poengsummen kan alltid regnes ut og forklares fra historikken.
Erfaring og utdanning
Arbeid
Apr 2025 – nå
Utvikler · Total Entreprenør AS
Utvikler og drifter TotalTiming, og har laget og vedlikeholder bedriftens nettside.
Jun 2019 – sep 2023
Nattevakt og resepsjonist · Citybox Bergen
Gjestehenvendelser, bookinger og daglig drift, og opplæring av nye ansatte.
Mar 2016 – nov 2018
Kundeservice · Sellbytel, Barcelona
Kundeservice for internasjonale merkevarer som Salomon, Arc'teryx og Atomic.
2013 – 2016
Personlig trener og instruktør
Des 2009 – mai 2012
Soldat · 11 Luchtmobiele Brigade, Den nederlandske hæren
Utdanning
Aug 2026 – jun 2028
Cybersikkerhet, høyere fagskole (2 år) · Gokstad Akademiet
Pågår. Informasjonssikkerhet, etisk hacking, penetrasjonstesting og cyberforsvar.
Sep 2026
Networking Basics (22 timer) · Cisco Networking Academy via Gokstad Akademiet
Grunnleggende nettverk og nettverksprotokoller.
Sep 2026
Linux Essentials · Cisco Networking Academy
Grunnleggende Linux og kommandolinjen.
Mar 2023 – mar 2025
Frontend-utvikling (2 år) · Noroff School of Technology and Digital Media
React, TypeScript, REST API-er og universell utforming. Scrum Master i et teamprosjekt.
Ferdigheter
- Språk
- TypeScript
- JavaScript
- SQL
- HTML
- CSS
- Backend
- Node.js
- Express
- REST API-er
- MySQL
- JWT-autentisering
- Zod
- Frontend
- React
- Next.js
- Tailwind CSS
- TanStack Query
- React Router
- Universell utforming (WCAG)
- Drift og verktøy
- Docker
- Nginx
- Linux (Ubuntu)
- Fail2Ban
- Git og GitHub
- Netlify
- Figma
- Testing og CI
- Node.js test runner
- ESLint
- TypeScript
- GitHub Actions
- Metodikk
- Scrum (Scrum Master i studieprosjekt)
- Versjonerte databasemigreringer
- SEO
Litt om meg
Jeg er oppvokst i Nederland og har bodd og jobbet i Barcelona før jeg slo meg ned i Arna. Bakgrunnen fra militæret, kundeservice og byggebransjen har lært meg å jobbe strukturert og å forstå hva brukerne faktisk trenger.
På fritiden trener jeg, går på tur og er mye sammen med barna mine. Jeg liker å utvikle nye idéer og leke med ny teknologi, for eksempel å sette opp ti AI-agenter samtidig bare for å se hva som skjer. Jeg løser også oppgaver på Hack The Box, som henger godt sammen med cybersikkerhetsstudiet. Ellers slapper jeg av med serier og spill.
Språk: Nederlandsk (morsmål), engelsk (flytende) og norsk (B1/B2, brukes daglig på jobb).