Time Tracking & Time Entry In-Product — Chat Prompts
If your B2B SaaS serves any time-based-billing, project-management, services, agency, consulting, legal, or freelancer use case — eventually customers will ask: "Can we track time inside [Product] instead of using a separate tool?" Toggl, Harvest, Clockify, Everhour — these are popular standalone tools, but customers prefer one-app workflow. The naive shape: "Hours" field on tasks. Works for a single freelancer; falls over the moment a team needs timesheets, approvals, project profitability, billable vs non-billable distinction, time off / PTO, or integrations with billing / payroll.
A real time-tracking system handles: timer + manual entry UX, project + task allocation, billable/non-billable, approval workflow, timesheet review, exports, integrations with accounting / billing / payroll, and reporting. Done well, time tracking becomes a sticky feature that compounds product value (customers' billing becomes dependent on your product). Done badly, customers use Toggl alongside and complain about double-entry forever.
This chat walks through implementing real time-tracking + time-entry: data model, UX patterns (timer vs manual), approval workflow, integrations, edge cases, and operational realities.
What you're building
- Time entry data model
- Two entry modes (timer + manual)
- Project / task / category allocation
- Billable / non-billable classification
- Daily / weekly timesheet UX
- Approval workflow (manager → approve → submit to billing)
- Reporting (per project, per person, per client)
- Exports + integrations (CSV, QuickBooks, Xero, payroll)
- Timezone handling
- Edge cases (overlapping timers, missing entries, edits to approved time)
1. Decide the scope
Help me decide what shape of time tracking to ship.
Three increasingly-deep shapes:
LEVEL 1: BASIC TIME LOG (the simplest start)
- Add hours to tasks
- Daily total view
- No approvals; no exports
- Pros: ships in 1-2 weeks
- Cons: not a complete time-tracking solution
LEVEL 2: FULL TIME TRACKING (timer + timesheets)
- Timer + manual entry both supported
- Daily / weekly timesheet
- Project + billable allocation
- Submission + approval workflow
- Reports + exports
- Pros: 6-12 weeks; stickiness
- Cons: lots of edge cases
LEVEL 3: BILLABLE-OPS-COMPLETE
- Level 2 + invoicing / billing integration
- Per-client rate cards
- Profitability reporting
- Time-off / PTO accounting
- Payroll integration
- Pros: enterprise-grade; replaces standalone tools
- Cons: 16-24+ weeks; ongoing complexity
DEFAULT FOR MOST B2B SaaS:
- Year 1: Level 1 (basic; if customers want it)
- Year 2: Level 2 (full tracking) when customer pull is clear
- Year 3+: Level 3 only if it fits your product positioning (agency / legal / consulting tool)
Don't pre-build Level 3 unless you're explicitly a billable-services SaaS.
Output: scope decision; explicit boundary.
Output: scope statement.
2. Design the data model
Schema for time tracking:
time_entries (
id uuid pk
workspace_id uuid not null
user_id uuid not null -- who logged the time
project_id uuid -- nullable; some entries don't tie to project
task_id uuid -- nullable
client_id uuid -- nullable; for billing
category text -- 'engineering', 'meeting', 'pto', 'admin', etc.
description text
starts_at timestamptz -- start time (or null for manual entry without exact time)
ends_at timestamptz -- nullable while timer running
duration_seconds int -- denormalized for query speed
date date -- date the work was performed (in user's timezone)
is_billable bool default false
billable_rate_cents int -- denormalized at entry time (rate at time of work)
status text -- 'draft', 'submitted', 'approved', 'rejected', 'invoiced'
approved_by uuid
approved_at timestamptz
invoice_id uuid -- nullable; if rolled into an invoice
created_at timestamptz
updated_at timestamptz
-- Audit: changes after approval require special handling
approved_locked bool default false
)
INDEXES:
- (workspace_id, user_id, date) — for timesheet queries
- (workspace_id, project_id, date) — for project reports
- (workspace_id, client_id, status='approved') — for invoicing
- (status='submitted') — for approval queue
active_timers (
user_id uuid pk -- only one active timer per user
workspace_id uuid
project_id uuid
task_id uuid
description text
started_at timestamptz
)
UNIQUE PER user_id (only one running timer at a time per user)
projects + tasks: assume already exist in your model
clients (
id uuid pk
workspace_id uuid
name text
default_rate_cents int -- default billable rate
rate_card jsonb -- per-role / per-task rates
)
approval_workflows (
workspace_id uuid pk
requires_approval bool default true
approver_role text -- 'manager', 'project_lead', 'admin'
auto_approve_below_hours numeric -- e.g., entries < 8 hours auto-approved
)
Implement:
1. Migrations for time_entries, active_timers, clients, approval_workflows
2. Indexes for hot queries
3. RLS / multi-tenancy
4. Validators (no overlapping timers, etc.)
Output: schema for tracking.
3. Implement timer + manual entry UX
Two entry modes:
A. TIMER MODE
- Click "Start" on a task
- Timer runs; visible across app (header bar)
- Click "Stop" → entry created
- Or: switch to another task → previous timer stops; new starts
UX:
- Persistent timer widget in header
- Project + task fields (selectable mid-timer)
- Description field
- One timer at a time per user (system enforced)
Implementation:
- POST /api/timers/start { project_id, task_id, description }
- DELETE /api/timers/stop → creates time_entry
- Real-time UI update via subscription / refresh
Anti-pattern:
- Multiple concurrent timers (confusing; double-counts)
B. MANUAL ENTRY MODE
- Click "Add time"
- Form: date, project, task, hours, description, billable
- Submit → creates time_entry with manual flag
UX:
- Date defaults to today
- Project / task last-selected memory
- "Time spent" input formats: hh:mm or decimal hours
- Backfill multiple days at once
Implementation:
- POST /api/time-entries { date, project_id, task_id, hours, description, billable }
Both modes:
- Auto-save drafts; not require submission
- Edit-in-place
- Bulk-edit support
Mobile:
- Timer always accessible (notification with current timer)
- Quick-entry form mobile-optimized
Implement:
1. Timer start/stop UI + endpoints
2. Manual entry form
3. One-timer-per-user enforcement
4. Persistent timer widget
5. Mobile timer
6. Edit / delete entries
Output: entry UX users use daily.
4. Build the timesheet (weekly review + submission)
Timesheet UX:
Page: /time/timesheets
Layout:
- Week selector (current week, prev / next)
- Day-by-day grid
- Per day: list of entries
- Summary: total hours, billable hours, % billable
- Per-project rollup
- Submit button
Per-week submission:
- Customer selects week
- Reviews entries
- Edits / adds missing
- Clicks "Submit for approval"
- Status: draft → submitted
Per-day quick entry:
- Click day → modal with all entries for that day
- Add / edit / delete
Edge cases:
- Past weeks: show but flag if not yet submitted
- Future weeks: don't allow entries (unless intentional pre-planning)
- Submitted weeks: read-only unless reverted
Approval-side UX (for managers):
Page: /time/approvals
- Queue of submitted timesheets
- Per submission: user, period, total hours, summary
- Click → detail view
- Approve / Reject (with reason)
- On approve: status → 'approved'; lock entries (unless admin overrides)
- On reject: notify user; allow re-submit
Auto-approval:
- Configurable per workspace
- Auto-approve below threshold (e.g., < 40 hours/week, no edge cases)
- Above threshold: manual review
Notifications:
- Submitted: notify approver
- Approved: notify user
- Rejected: notify user with reason
Implement:
1. Weekly timesheet UI
2. Submission flow
3. Approval queue UI
4. Notification triggers
5. Auto-approval logic
6. Lock-after-approval enforcement
Output: weekly review + approval workflow.
5. Build reports + exports
Reports needed:
Per-project:
- Total hours
- Billable hours
- Hours by user
- Trend over time
- Budget vs actual
Per-person:
- Total hours per period
- Billable %
- Project breakdown
- Manager view: team-wide
Per-client:
- Hours by project
- Billable + ready-to-invoice hours
- Trend over time
Per-category:
- Time on meetings vs admin vs deep work
- Trend analysis
Export formats:
- CSV (most common)
- Excel
- PDF report (formatted)
- API access (programmatic)
Filtering:
- Date range
- Project / client / user
- Status (draft / approved / invoiced)
- Billable / non-billable
Implement:
1. Per-project report
2. Per-person report
3. Per-client report
4. Date-range picker + filters
5. CSV / Excel / PDF exports
6. Schedule: weekly / monthly auto-export to admin
Output: reports for billing + management.
6. Integrations (the stickiness multiplier)
The killer feature: integrations with billing / accounting / payroll.
Integration targets:
ACCOUNTING:
- QuickBooks Online
- Xero
- Zoho Books
- Sage
- Wave
What syncs:
- Approved billable hours → invoice line items
- Per-client; per-project; per-rate
- Customer mapping (your client_id → their customer)
PAYROLL:
- Gusto, Rippling, ADP
- Approved hours → payroll period
- Hourly employees: hours fed in
- Salaried with overtime tracking
PROJECT BILLING:
- Direct invoice generation (if you have billing module)
- Or: send to external billing tool
CRM:
- Salesforce, HubSpot
- Customer engagement / project hours visible to sales
CALENDAR:
- Google / Outlook integration
- Auto-suggest entries based on calendar events
Implementation per integration:
- OAuth setup with vendor
- Mapping UI (your projects / clients to theirs)
- Sync schedule (daily; on-demand)
- Conflict resolution (which side wins on edit?)
- Audit log of syncs
Webhook outbound:
- Time-entry-created webhook for customer's automations
- Invoice-ready webhook
Implement:
1. QuickBooks / Xero integration as v1
2. Customer mapping UI
3. Scheduled sync
4. Manual force-sync
5. Conflict + error reporting
6. API + webhooks for customer DIY
Output: integrations that make customers stay.
7. Timezone + DST handling
Time entries cross timezones; DST shifts; international teams.
Rules:
A. Entry timezone:
- Capture in user's local timezone (IANA)
- Store starts_at + ends_at as UTC; date as local-date
- Display in viewer's timezone (or user's choice)
B. Date attribution:
- "Date of work" = local date when work started
- A timer starting 11:30pm and ending 1:30am: 2-hour entry on START date
- Or: split across days (some products do this; complex)
C. DST transitions:
- Spring-forward: 1am-3am skip; entries crossing this period adjust
- Fall-back: 1am-3am happens twice; mark explicitly
D. International team:
- Each user's local timezone
- Aggregate reports in workspace's timezone
- Or: per-report timezone choice
E. Travel:
- User in Tokyo for week; entries should still be in their workspace's primary tz?
- User choice: entry-tz follows them OR follows workspace
- Default: user-tz
Implementation:
- Always store IANA timezone with entry
- starts_at / ends_at in UTC
- date field in user's local time at entry creation
- Render in viewer's tz with appropriate notes
Anti-patterns:
- Storing local time without tz
- Using server tz
- Letting tz auto-change without notice
Output: tz handling that doesn't betray customers.
8. Edge cases + operational realities
Walk me through:
1. Active timer crashes (browser closed; no stop)
- On reconnect: detect orphaned timer
- Prompt: "Was this still running?" (yes / no / round to nearest 15min)
- Don't auto-stop without user input
2. Multiple devices (timer on phone + laptop)
- Single timer per user (system enforced)
- Stopping on one device stops everywhere
- Sync via subscription
3. Entry > 24 hours
- Validation: warn at 24+ hours
- Hard error at 168 hours (week)
- Likely a bug or forgot-to-stop scenario
4. Editing approved entries
- Lock by default (compliance)
- Admin override with audit log
- "Unlock" button rarely used
5. Forgot to log time (multi-day backfill)
- Allow up to 30 days back (configurable)
- Beyond: require admin permission
- Audit who backfilled what
6. Project deleted; entries reference it
- Soft-delete project (don't lose entries)
- Allow re-categorization to "Archived"
7. User leaves company
- Their entries preserved (audit + billing)
- Reassign approver responsibilities
8. Currency conversion (international clients)
- Per-client currency
- Rate cards in their currency
- Reports in workspace base currency (with FX conversion)
9. Overtime tracking
- Workspace setting: standard hours/week (e.g., 40)
- Above standard: flag as overtime
- Pay rate may differ (1.5x)
10. PTO / time off
- PTO tracked separately from billable
- Counts toward "total hours" but not "billable"
- Approval flow may differ
11. Public holidays
- Per-region holiday calendars
- Auto-fill (optional)
12. Entry with future date
- Allow (intentional pre-planning)
- Don't auto-submit until date passes
13. Bulk operations (delete / re-categorize / approve)
- Bulk select; bulk action
- Audit bulk actions
14. Mobile offline
- Local cache; sync on reconnect
- Conflict resolution if edits diverge
15. Client viewing time
- Some clients want visibility into hours billed
- Read-only client portal
- Per-project sharing toggle
For each: code change + UX impact + ops consideration.
Output: ops handling.
9. Recap
What you've built:
- Time-entries data model
- Timer + manual entry both
- Weekly timesheet + submission
- Approval workflow
- Reports per project / person / client
- Exports (CSV / Excel / PDF)
- Integrations: QuickBooks / Xero (v1), more later
- Timezone + DST handling
- Edge cases (forgot-to-stop, backfill, deletion, etc.)
What you're explicitly NOT building in v1:
- Native invoicing (use accounting integration)
- Native payroll (use payroll integration)
- Per-task time budgets (defer)
- AI-suggested time entries from calendar / activity (defer; nice-to-have)
- Productivity-pulse insights (defer; different category)
- Cross-tenant time-sharing (anti-pattern)
Ship Level 1 in 2 weeks. Level 2 in 8-12 weeks. Level 3 only if billable-services SaaS.
The biggest mistake teams make: shipping time tracking without integrations. Time is logged but doesn't flow to billing / payroll → customers maintain Toggl alongside.
The second mistake: approval flow without lock-after-approve. Customers edit time after billing → audit chaos.
The third mistake: forgetting timezone. International teams = wrong reports.
See Also
- Custom Fields & Schema Extensibility — pairs (custom-fields on time entries)
- Bulk Operations — pairs for bulk-edit
- Approval Workflows / Audit Logs — pairs
- Outbound Webhooks — pairs for customer integrations
- Inbound Webhooks — pairs for accounting-tool sync
- Reports & Scheduled Exports — pairs (export time data)
- Roles & Permissions — depended-upon
- Multi-Tenancy — depended-upon
- Timezone Handling — depended-upon
- Public API — exposes time data
- Activity Feed & Timeline — adjacent
- Quotas, Limits & Plan Enforcement — pairs
- Time-Tracking & Timesheet Tools (Reference) — competitive landscape
- Accounting & Bookkeeping Software (Reference) — integration targets
- HR & Payroll Tools (Reference) — integration targets
- Stripe (Reference) — billing integration