Firm settings
The firm settings page is where admins set the rules of the road for everyone in the firm. Only users with the admin role can open the page, others get an Admin access required notice.
You'll find it at /admin/firm. Each setting takes effect on Save (you'll see Save changes enabled the moment any field is dirty, and a Saved banner appears on success). Most settings affect new entries only, flipping a toggle doesn't retroactively change time already logged.
Identity
- Firm name. Editable.
- Slug. Read-only. Used in URLs and Vault paths; you can't change it from the UI.
Client visibility
Controls which clients accountants can see and log time against.
- Assigned only, accountants see only clients they've been explicitly assigned to (via the client assignments table).
- Firm-wide, every accountant sees every client.
Managers and admins always see every client regardless of the mode. The setting only affects accountants.
Rounding (minutes)
A free-form number from 0 to 60. The helper text suggests "0 = no rounding. Common: 6 (.1 hr), 15 (.25 hr)."
When set above 0, the saved duration_seconds is rounded up to the nearest N-minute boundary at stop time (for timer entries) and at save time (for manual entries). The raw, unrounded duration is preserved in original_duration_seconds so audits can always recover the exact clock time. Reports show the rounded duration.
Time zone
Picked from a short dropdown of US zones plus UTC. Used for grouping entries by day in the dashboard tiles and in reports, "today's hours" means today in the firm's zone, not in UTC.
Require project on every entry
Toggle (require_project in the database).
When on, the backend rejects POST /v1/timer/start and the manual-entry create path with 400 "firm requires a project on every entry" if projectId is null. The web Start timer modal and the desktop client also flip the project field's label from Project (optional) to Project, with a red asterisk.
Require notes when stopping a timer
Toggle (require_notes_on_stop).
When on, the backend rejects POST /v1/timer/{id}/stop and the manual-entry create path with 400 "firm requires notes…" if the row has no notes and the stop call doesn't supply them. The web Stop modal surfaces this inline so the user can fill in notes before the request lands.
Long-running threshold (hours)
A number input from 1 to 48, stored as seconds in the database (long_running_threshold_seconds; default 28800 = 8 hours). When a timer stops with a duration above this, the entry gets flagged_long_running = true and shows a LONG tag in lists.
This one is enforced today, it's wired up end-to-end. Lower it to catch forgotten timers earlier, raise it for tax-season firms with genuinely long days.
Idle prompt threshold (minutes)
A number input from 1 to 60, stored as seconds in the database (idle_threshold_seconds; default 600 = 10 minutes, bounded server-side to 60..3600). The desktop app polls the user's idle time every 10 seconds while a timer is running and pops the Timer was running while you were away prompt once inactivity crosses this threshold.
This one is also enforced today: the desktop client reads it from /api/v1/users/me on startup and on every refresh, so a saved change takes effect on the next sync without a restart. Useful tuning:
- Lower (1, 5 min) for quick-turn bookkeeping work where you don't want idle minutes to accumulate.
- Higher (20, 30 min) for client calls, deep review sessions, and any work where thinking time is legitimately part of the entry.