Revenue Recognition and Billing for Enterprise Projects
Intro
Kitaboo runs client contracts that do not bill the same way as each other - fixed bid, time and materials, licensing and rate card, in three currencies, recognised on three different bases. Grabodo built the platform that holds all of it together, with approvals, masking and an audit trail underneath.
Kitaboo is an enterprise project management and billing platform built on Next.js 14 and Supabase, covering the path from a signed client to recognised revenue. Grabodo built it around a schema of more than forty tables, with row-level security on every one of them.
The Background
Not every client contract bills the same way. Some are fixed bid, some are time and materials, some are licensing, some run against a rate card - and the same client can hold more than one at once, in a foreign currency, reported in another. Spreadsheets can produce an invoice from any one of those. What they cannot do is produce a defensible revenue figure across all of them at the end of a month.
The Challenge
Revenue recognition was the hard requirement. Licensing income has to be deferred and released monthly. Customisation work accrues as unbilled revenue before it is invoiced. Professional services accrue as unbilled hours. Each behaves differently, and all three have to reconcile to the same ledger.
On top of that the platform had to survive an audit. That meant no silent edits, a real approval chain, and control over who can see which fields - client financial data that some roles need and others must not have.
The Solution
Invoicing runs as an explicit three-stage workflow - an invoice request form, then a draft invoice, then the final invoice - with two-level maker-checker approval between stages, so no single person can raise and approve the same document. Invoice numbers are generated by the system rather than typed.
Currency is handled as a chain rather than a field: foreign currency converts to USD and then to INR, with FX rates captured against the invoice so a historical document still explains its own numbers. Around that sit a rate card builder covering five rate types, milestone tracking with locking, effort logging for time and materials work, and payment tracking for full and partial settlement.
Compliance is built into the schema. Row-level security covers every table, access is role-based, sensitive fields are masked by default with every unmask written to its own audit log, and a complete audit trail plus session monitoring sits underneath the lot.
The Solution
- 01A three-stage invoice workflow - invoice request form, draft invoice, final invoice - with two-level maker-checker approval between stages, so the person who raises a document cannot be the person who approves it.
- 02Three revenue recognition models running side by side: licensing deferred and released monthly, customisation accrued as unbilled revenue, and professional services accrued as unbilled hours.
- 03Four project types in one model - fixed bid, time and materials, licensing and rate card - so a client holding several contracts is still a single client record.
- 04A currency chain rather than a currency field: foreign currency to USD to INR, with FX rates captured against the invoice so historical documents keep explaining their own numbers.
- 05A client master covering the full lifecycle - multi-address billing and shipping, contacts with CC email lists, a rate card builder spanning five rate types, document storage and an audit history timeline.
- 06Project controls built for delivery as well as billing - milestone tracking with locking, task management for customisation work, effort logging for time and materials, and reusable rate templates.
- 07Compliance designed into the schema: row-level security on every table, role-based access control, field-level masking with every unmask written to its own audit log, plus session monitoring and a full audit trail.
- 08Finance reporting that answers collection questions - invoice aging across five buckets, revenue by client, project metrics, days sales outstanding and collection efficiency.
The Results
- 01Four contract types and three recognition models resolve to one revenue figure, produced by the system rather than assembled by hand at month end.
- 02The billing process became auditable end to end - no stage of an invoice can move without an approver, and no sensitive field can be revealed without leaving a record.
- 03Historical invoices remain explainable years later, because the FX rates that produced them are stored with the document instead of looked up again.
The Achievement
- A 40+ table schema with row-level security policies on every table.
- Three-stage invoicing with two-level maker-checker approval built end to end.
- Three distinct revenue recognition models implemented against a single ledger.
- Field-level data masking with dedicated unmask audit logging.
- Multi-currency support through a foreign currency to USD to INR conversion chain.
- 29 application screens and 68 components on Next.js 14 with AlignUI and Tailwind v4.