SMF·HARVEST
Can a prompt replace Harvest?
Time tracking — time tracking with invoicing
Exhibit tracking slip
Verdict
Harvest is a timer whose reason to exist is the next step: the hours become an invoice, the invoice gets paid, and neither is retyped. The tracking and the invoice document are a weekend. Getting paid is where the third parties arrive — a payment processor to accept a card, and an accounting system to reconcile it — which is why this stays a kinda rather than becoming a yes even though the code is small.
Exhibit A — The prompt
Received on31.07.2026Build a time tracker whose output is a correct invoice, with the double-billing problem solved properly.
Stack: your choice, Postgres, one command to run.
Model: Client, Project, Task, TimeEntry, Expense, Invoice, InvoiceLine.
Billing correctness is the whole build:
- A TimeEntry has a billable flag and an `invoice_id` that is null until invoiced. Invoicing selects unbilled billable entries in a date range and sets that id inside one transaction. There is no other way for an entry to become billed.
- An invoiced entry is immutable. Editing it requires voiding the invoice or writing an adjustment entry, and the UI must explain which.
- Rates resolve by specificity — person on project, then project, then person, then default — using the rate in force **on the entry's date**. Changing a rate today must never change the value of work already logged. Test this first.
- Expenses attach to a project with a receipt file, a category, and an optional markup percentage, and flow into the invoice as their own lines.
Invoice document: number from a configurable sequence with no gaps, issue and due dates, client billing details, line items grouped by project, task or person as chosen, subtotal, a tax line with a configurable rate, and a total. Render to PDF. Store the rendered PDF rather than regenerating it — a regenerated invoice can silently differ from the one the client received.
States: draft, sent, partially paid, paid, void. Payments are recorded manually with a date, amount and method; several payments can settle one invoice. Voiding never deletes: it releases the entries back to unbilled and records who voided it and when.
Reports: unbilled hours by client, ageing of unpaid invoices in 30/60/90-day buckets, and revenue by month from invoice dates.
Write tests for the invoicing transaction being atomic, for an entry never appearing on two invoices under concurrent invoicing, for historical rate resolution, and for void releasing entries exactly once.
Do not integrate a payment processor or an accounting system. Export a CSV your accountant can import.
Opening prefills the prompt — press enter to run it.
Exhibit B — What you lose
- B.1 accepting card payments on the invoice
- B.2 the QuickBooks, Xero and Stripe integrations that reconcile what was paid
- B.3 the mobile and desktop timers
- B.4 automatic payment reminders to the client
- B.5 team capacity and utilisation reporting
Prior art
Exhibit C — Why people still pay: invoicing and payment integrations
Because the value is in the last mile — a client clicking pay on the invoice — and that mile runs through a payment processor and an accounting system somebody has to maintain.
Questions
Why is double-billing the hard part rather than the PDF?
Because it is silent. A wrong-looking PDF gets noticed; the same three hours on two invoices does not, until a client notices for you. An `invoice_id` on the entry set inside one transaction is the whole fix, and it needs a test under concurrency.
Why store the rendered PDF instead of regenerating it?
Because your template, your address or your tax rate will change, and regenerating invoice 41 next year would produce a document the client never received. The stored file is the record.
Why must invoice numbers have no gaps?
Because in several jurisdictions a gapless sequence is a legal requirement for invoices, and in all of them a gap is the first thing an accountant asks about. Allocate the number at send, not at draft creation.
Can Harvest export everything I need?
Time entries, expenses, invoices and clients all export as CSV, and the API covers the rest. Invoice PDFs must be downloaded separately — the CSV has the numbers, not the documents you actually sent.
Related tools
Receipt