Restrict line item edits to draft invoices, auto-create drafts on clock-out,
and add sendReminderAt scheduling with dashboard due reminders.
Co-authored-by: Cursor <cursoragent@cursor.com>
Prevents Turbopack from statically analyzing better-auth's kysely adapter,
which imports symbols removed in kysely 0.29. Also fixes @typescript-eslint
consistent-type-imports warning on the Db type alias.
https://claude.ai/code/session_014126WHVRT8mftmqkU6dajG
- Remove "Time Clock" from sidebar navigation
- Redirect /dashboard/time-clock to /dashboard/invoices
- Add InvoiceTimerCard to invoice detail page (shown for non-paid invoices)
- Timer started from an invoice is explicitly linked to that invoice at clock-in
- On clock-out, time is added directly to the linked invoice as a line item
- Active timer widget on dashboard now shows which invoice is being tracked
- Backend: clockIn accepts invoiceId; clockOut prefers explicit invoiceId over
searching for the latest draft invoice for the client
https://claude.ai/code/session_014126WHVRT8mftmqkU6dajG
- Clock out and manual entry creation now auto-add a line item to the
client's latest draft/sent invoice and return invoice info
- Time clock page shows invoice badge on each entry with a link
- Toast after clock-out/create includes "View Invoice" action when linked
- MCP time_clock_in now accepts optional startedAt for backdating
- MCP time_clock_out description updated to document invoice linking
- Migration 0012: widen beenvoice_verification_token.value to text to
fix varchar(255) overflow during Authentik PKCE OAuth flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New beenvoice_time_entry DB table with migration (startedAt/endedAt, hours, rate, clientId)
- tRPC router with clockIn, clockOut, getRunning, getAll, getSummary, create, update, delete
- Dashboard page at /dashboard/time-clock with live elapsed timer, entry list, and manual entry form
- 5 MCP tools: time_clock_in, time_clock_out, time_get_running, time_entries_list, time_entries_create
- Sidebar navigation entry
Timer state is stored in PostgreSQL (endedAt IS NULL = running), suitable for serverless/Coolify deployment.