TL;DR
Tidsregistrering i et revisionsfirma handler ikke om timeren. Den handler om to ting: hvem der kan se hvilken klients timer, og om totalerne i rapporterne er rigtige. Da jeg byggede et system til ét revisionsfirma, fandt jeg fire fejl, som ingen skærm viste: rapporttotaler, der stille ville ende for lave, cirka 30 handlinger, der sagde “gemt”, uden at noget blev gemt, en fortrolig klient, hvis eksistens lækkede gennem rapporter og tagtællere, og en afvist registrering, som en senere godkendelse kunne skjule. Hver af dem kan testes på få minutter i ethvert værktøj, købt eller bygget.
Jeg er Denys, fullstack- og AI-ingeniør. Mellem maj og oktober 2026 gik et revisionsfirma fra et værktøj, hvor alle kunne åbne alle klienter, til et system, jeg byggede kun til firmaet, over 388 commits. Firmaet nævnes ikke ved navn. Denne tekst er til dem, der driver et firma og vælger dets værktøjer: hvad et revisionsfirma har brug for af tidsregistrering, de fire fejl jeg fandt, og hvordan du tjekker et hvilket som helst system for dem.
Hvad har et revisionsfirma brug for af tidsregistrering?
Et revisionsfirma sælger timer, så tidsregistreringen er det grundlag, hele forretningen hviler på. Firmaet, jeg byggede til, havde brug for:
- Timer mod klient, projekt og opgave. Hver registrering hører til ét opdrag, så timerne kan læses pr. klient, pr. projekt og pr. person.
- Ugentlige timesedler med godkendelse. Medarbejderne indsender ugen, projektadministratoren godkender eller afviser hver registrering, og kun godkendte timer tæller.
- Påmindelser. Den, hvis timeseddel stadig er tom før fristen, får en e-mail. Siden september 2026 minder den kun om manglende timer og springer folk med nul kapacitet over.
- Ressourceplanlægning. Hvem der arbejder på hvilket opdrag de kommende uger, holdt op mod hver persons kapacitet.
- Fortrolige klienter. Ejeren kan begrænse en klient med dens projekter, opgaver og tid til udvalgte medlemmer.
- Arkivér, slet aldrig. Et medlem, der forlader firmaet, deaktiveres og anonymiseres, og et afsluttet projekt arkiveres, så timesedlernes historik bevares.
Systemet udsteder ikke fakturaer. Projekters faktureringsform og timebudgetter ligger bag deres egen rettighed, og fakturering bliver i firmaets regnskabssystem.
Hvem skal se hvis timer i et revisionsfirma?
Før dette projekt kunne alle i firmaet åbne alle klienter og alles timer. For et revisionsfirma er det et fortrolighedsproblem, før det er et softwareproblem: ikke alle medlemmer skal se alle klienter, og ingen har brug for at se en kollegas uge, medmindre de godkender den.
Adgangsmodellen, firmaet bekræftede, ser sådan ud:
| Rolle | Ser | Kan godkende |
|---|---|---|
| Medarbejder | Kun egne timer | Intet |
| Projektadministrator | Timer for teamet på egne projekter | Teamets uger på de projekter |
| Ejer | Alle klienter, projekter og personer | Alt |
| Fortrolig klient | Kun synlig for de medlemmer, ejeren har valgt | — |
Ejeren former hver rolle i en matrix af afkrydsningsfelter, område mod handling, og hver regel ligger i databasen frem for i skærmene, så en side kan ikke vise noget, databasen afviser. Hvert felt blev testet mod en kopi af produktion før udgivelsen; hvordan, og hvad testen fandt, står i sådan tester du Supabase RLS.
Ét spørgsmål kunne matrixen ikke besvare, og det kom fra firmaet selv. I juni 2026 så et medlem med den mest begrænsede rolle andre medlemmer og deres projekter på ressourceskærmen, men forventede kun at se sig selv og én kollega. Skal et begrænset medlem se de personer, der er på de samme projekter? Reglen, vi nåede frem til: ja, kun på fælles projekter, og med andres kapacitet og fravær skjult.
Hvordan får man en adgangsmodel, som et firma reelt er enigt i? Jeg bad ikke klienten beskrive den ud fra hukommelsen. Jeg sendte et spørgeskema med 72 spørgsmål i 9 afsnit, hvor rettighedsgitrene allerede var udfyldt, som det levende system fungerede den 7. august 2026. Klienten rettede det, der var forkert, og hver ændret celle blev markeret. Folk er bedre til at rette virkeligheden end til at beskrive den.
Fejl 1: rapporttotalerne ville være endt for lave
Siden Timesedler har visningerne “Dette kvartal” og “Hittil i år” for hele firmaet. De indlæste alle tidsregistreringer i perioden i én forespørgsel. Database-API’et bag appen returnerer højst 1.000 rækker pr. forespørgsel, og når det stopper ved 1.000, rejser det ingen fejl. Det returnerer bare de første 1.000.
Supabase dokumenterer standarden: projekter returnerer højst 1.000 rækker, medmindre grænsen ændres i API-indstillingerne.
Så når firmaet passerede 1.000 registreringer i en periode, ville medlemmer og uger falde ud af visningen, og totalerne ville ende for lave uden noget på skærmen, der sagde det. Med cirka 70 registreringer om ugen var visningen “hittil i år” på vej til at passere 1.000 registreringer omkring midten af november 2026. Et kodeeftersyn den 24. september 2026 fandt det, før det skete. Rettelsen læser hver periode side for side, og hver rapporteksport henter nu data på samme måde.
Sådan tjekker du dit værktøj: vælg en lang periode, eksportér de rå registreringer, læg dem sammen selv, og sammenlign med rapportens total. Hvis de to adskiller sig, skærer rapporten rækker fra.
Fejl 2: “Gemt”, selv om intet blev gemt
Når databasen afviser en ændring på grund af en rettighed, eller fordi en regel kræver tofaktorlogin, kan den svare “0 rækker ændret” uden nogen fejl. Cirka 30 steder i appen, der opdaterer eller sletter poster, læste det svar som en succes og viste “gemt”. Brugeren går videre. Ændringen skete aldrig.
Rettelsen er at fejle lukket: en skrivning, der ikke rører nogen række, er en fejl og vises som en fejl, og en test tjekker nu, at hver skrivesti behandler det sådan.
Sådan tjekker du dit værktøj: log ind som medlem uden ret til at redigere noget, prøv at redigere det, og genindlæs siden. Hvis du så “gemt”, og den gamle værdi er tilbage, lyver værktøjet om gem.
Fejl 3: en fortrolig klient lækkede gennem rapporter
Nogle opdrag kendes kun af dem, der arbejder på dem. Siden 24. august 2026 kan ejeren begrænse en klient til navngivne medlemmer. Alle andre får intet tilbage for den klient, dens projekter, opgaver eller tid. Ejeren har altid adgang, og den adgang beregnes ud fra, hvem der har ejerrollen i dag, og er ikke gemt, så den følger rollen.
At skjule klienten på klientlisten var den nemme del. Lækagerne sad i sidedørene. En gennemgang den 8. september 2026 fandt, at:
- tre rapportfunktioner ignorerede begrænsningen, fordi de kører med rettigheder, der springer de almindelige adgangsregler over, så en fortrolig klients timer kunne dukke op i rapporter;
- tagtællere i administratorens tagoversigt talte den fortrolige klients projekter og opgaver med, hvilket afslørede, at opdraget fandtes, og cirka hvor stor den var;
- fejlmeddelelserne afslørede forskellen: at forsøge at ændre en rigtig, men skjult post gav “forbudt”, mens en opdigtet post gav “ikke fundet”, så enhver kunne undersøge, om en fortrolig klient fandtes.
Alle tre anvender nu samme tjek som hovedtabellerne, og en skjult post ser præcis ud som en manglende. At flytte et projekt eller en registrering ud af en fortrolig klient kræver også ejeren eller en særskilt rettighed, og hver sådan flytning logges.
Sådan tjekker du dit værktøj: begræns én klient til én enkelt person. Kør derefter som en anden alle rapporter, se på hver tæller og hvert filter, søg efter klientens navn, og åbn et direkte link til et af dens projekter. Du bør ikke finde noget spor af den, heller ikke i fejlmeddelelsen.
Fejl 4: en afvisning kunne skjules af en senere godkendelse
En uge kan have registreringer på flere projekter, så flere personer godkender den. Hvis én projektadministrator afviste en registrering, og en anden senere godkendte sin del, kunne den senere godkendelse afgøre hele ugen og dække over afvisningen. At flytte registreringer mellem opgaver eller genåbne en uge kunne skjule den på samme måde.
Den 24. september 2026 blev godkendelseslogikken ændret, så en uge forbliver afvist, så længe en afvist registrering stadig er aktiv, og en projektadministrator kun kan arkivere en afvist registrering, hvis vedkommende selv afviste den. En databaseprobe kører nu hvert af disse tilfælde, og hvert skal vise PASS.
Sådan tjekker du dit værktøj: brug to godkendere på én uge. Afvis én registrering som den første, godkend alt andet som den anden, og se, hvilken tilstand ugen ender i.
Køb eller byg tidsregistrering til et revisionsfirma?
Køb først. Toggl, BigTime, ZenWorkflow og lignende værktøjer dækker allerede timere, ugentlige godkendelser og klientfakturering, og du kan komme i gang med et af dem i denne uge. Et skræddersyet system giver mening, når firmaet har regler, produkterne ikke kan udtrykke, for eksempel fortrolige klienter, der kun er synlige for navngivne medlemmer, godkendelse fra flere projektadministratorer pr. uge eller roller, ejeren vil forme felt for felt.
Uanset hvilken vej du vælger, tager de fire tjek ovenfor en eftermiddag og fortæller dig mere end en funktionsliste. Hver produktside siger “granulære rettigheder”. Få viser, hvad der sker, når du fjerner et flueben.
Begrænsninger i denne rapport
- Ét firma. Adgangsmodellen, mængden på cirka 70 registreringer om ugen og spørgeskemaet stammer fra ét enkelt firma.
- Fejl 1 blev fanget, før den udløstes. Datoen midt i november er en fremskrivning ud fra firmaets registreringstakt, ikke en målt hændelse.
- Ingen fakturering. Systemet rummer timer, faktureringsform og timebudgetter, men fakturerer ikke klienter, så jeg kan ikke udtale mig om forløb fra tid til faktura.
Adgangsreglerne her er Postgres row-level security. To huller, som en rollematrix ikke fanger, er beskrevet for sig: en bruger, der tilhører to organisationer og en IF, der svigter åbent ved NULL. Selve opbygningen står i casen om tidsregistrering for et revisionsfirma, og den slags arbejde hører under interne værktøjer og dashboards.
Vælger eller bygger du tidsregistrering til dit firma?
Jeg udveksler gerne erfaringer om adgangsregler og godkendelser. Ingen salgstale.
Kontakt mig