Audit firm time tracking
Project and staff time tracking for an audit firm · Built from scratch, solo
Updated
Before
Clients, projects and hours lived in one place where everyone in the firm could see and change everything.
After
87
permission boxes proven against the database before every deploy; the 30 that did nothing were hidden.
- 1Person:Owner
Builds roles with checkboxes per area (clients, projects, time, reports) for view, create, edit and delete.
- 2Person:Staff member
Logs hours against a client, project and task, or books time off.
Software:Web appReminds anyone whose timesheet is still empty before the deadline.
- 3Person:Project admin
Approves or rejects the week's timesheet for their own project team.
- 4Software:Database
Shows each person only what their role allows: staff see their own hours, project admins their team, owners every client.
- 5Person:Owner
Reads hours by client, project and person on the dashboards and reports.
Always on
- Before, everyone in the firm could open every client and everyone's hours. Now the database refuses anything a role does not allow, even if a screen asks for it.
- Before each push, every role is tested against an isolated copy of the database.
Problem
An audit firm ran its clients, projects and staff hours in a tool where every person could open every client and everyone's time.
Diagnosis
Access control fails quietly when it lives in the screen, so every rule had to live in the database, proven by tests.
Options I weighed
Each role sees different data. Where do the access rules live?
Chosen
In the database itself, tested for every role before each deploy
The screen cannot leak what the database refuses. Cost: a test run on an isolated copy before each push.
Rejected
Only in the screens
A person could see or change data the screen meant to hide.
A record is no longer needed. Delete it or keep it?
Chosen
Archive and anonymise it
Timesheet history stays intact.
Rejected
Delete them
Deleting cascades away timesheet history.
Solution
A single-page web app on managed Postgres. Every access rule lives in the database and is proven by an automated role matrix before each deploy.
- App
- React
- Vite
- TanStack Router
- TanStack Query
- shadcn/ui
- Chart.js
- Data and security
- Supabase
- PostgreSQL row-level security
- Edge Functions (Deno)
- Hosting
- Cloudflare
- Quality
- GitHub Actions
- Role-matrix tests
- Vitest
- Property-based tests
- Accessibility tests
Related services
Figures: Automated role check, 2026-09-25