On this page
Key takeaways
- Studios and agencies sell scope, and scope changes. The change order is the most important object in the business.
- Generic SaaS billing assumes a plan and a subscription; project work assumes an engagement and its amendments.
- Invoices should be an outcome of approved work, not a parallel translation of a deck.
- Clients need a reading room for decisions, not a social feed.
Aperture Collective is a forty-person studio. Its work runs on approved scope and the extras that appear after. Its software assumed subscriptions. The mismatch cost them hours every month, and it is the reason Meridian starts from the change order rather than the homepage.
How project firms actually make money
A subscription business has a plan, a price, and a renewal date. A project firm has a statement of work, a series of amendments, and a moment at which something is finally allowed to be invoiced.
In between sits the real business: a producer says yes to an extra on a call, a client nods in an email, and three weeks later finance is asked to turn a deck into line items.
| Subscription software | Project-shaped firm |
|---|---|
| Unit of value is a seat | Unit of value is an engagement |
| Price is a plan | Price is scope plus approved changes |
| Invoice is periodic | Invoice follows an approval |
| Account is one customer | Engagement is many people with different rights |
| Changes are upgrades | Changes are negotiated amendments |
Why the parallel spreadsheet appears
When the software cannot represent a change order, someone builds a spreadsheet that can. It tracks original scope, approved extras, and what has been billed. It is correct, and it lives outside every system. Finance cannot audit it; the client never sees it.
That spreadsheet is the requirements document — see our note on shadow spreadsheets. Its columns became Meridian's data model.
The four objects
Workspace
One per engagement, not one per generic account. It is a reading room for decisions, files, and approved scope. Clients see what they need to make a decision, and nothing that resembles a feed.
Change order
A first-class object with a proposer, a state, and an approver. It has a distinct life: proposed, reviewed, approved or declined. Approved extras become part of the scope of record.
Entitlements
Who can propose, approve, and see — written as roles that exist in the firm. A client can approve; a producer can propose; finance can see billing state. Nobody needs a permissions manual.
Invoice
An outcome of approved work. Meridian emits invoices only from an approved state, so finance stops translating and starts closing.
The rule that shaped the product
An invoice is not allowed to exist until the work it describes has been approved by someone entitled to approve it.
An invoice is not allowed to exist until the work it describes has been approved by someone entitled to approve it.
The reading room
Client portals often fail by imitating social software: activity streams, notifications, and comment threads that grow forever. The reading room is deliberately quieter. It distinguishes proposed from signed scope, so a client can tell at a glance what they have agreed to.
- Producers remain the authors. Clients remain reviewers.
- Approvals are explicit actions, not implied by silence.
- Scope shown to the client is scope of record, not a draft in someone's head.
- 01
Propose
A producer raises the change with a description and a price. It is visible to the client as proposed, not agreed.
- 02
Review
The client reads the change in the reading room, with the original scope beside it.
- 03
Approve or decline
An entitled person approves. Silence never counts as approval.
- 04
Fold into scope
The approved extra joins the scope of record. Nobody re-types it into a deck.
- 05
Bill
Finance closes from the same object; an approved change can emit a draft invoice.
Generic SaaS billing
- Plans and seats
- Invoices on a schedule
- One account, one customer
- Changes are upgrades
Meridian
- Engagements and amendments
- Invoices from approved work
- Roles: client, producer, finance
- Changes are negotiated objects
What we did not build
Meridian is not a full PSA or resource planner, not a portfolio site, and not a replacement for your accountant. It emits a single export into the accounting tool the firm already runs. Version 0.4 lets approved change orders become a draft invoice without a finance rewrite.
Modelling scope so it can change
A subscription product can get away with a table of plans. A project product cannot, because the thing being sold is a moving agreement. The data model has to represent three things at once: what was originally agreed, what has been proposed since, and what is currently in force.
| Object | Key fields | Invariant |
|---|---|---|
| Engagement | client, name, status, currency | Belongs to exactly one client organisation |
| Scope item | engagement, description, price, origin (original or change_order) | Price is immutable once part of scope of record |
| Change order | engagement, proposer, description, price delta, state | State moves only along allowed transitions |
| Approval | change order, approver, decision, decided_at | Approver must hold an approve entitlement |
| Invoice | engagement, line items, source (scope item ids) | Every line traces to an approved scope item |
CREATE TABLE scope_items (
id uuid PRIMARY KEY,
engagement_id uuid NOT NULL REFERENCES engagements(id),
description text NOT NULL,
price_minor bigint NOT NULL, -- integer minor units, never floats
origin text NOT NULL CHECK (origin IN ('original','change_order')),
change_order_id uuid REFERENCES change_orders(id),
approved_at timestamptz NOT NULL, -- only approved items exist here
CHECK ((origin = 'change_order') = (change_order_id IS NOT NULL))
);
CREATE TABLE invoice_lines (
id uuid PRIMARY KEY,
invoice_id uuid NOT NULL REFERENCES invoices(id),
scope_item_id uuid NOT NULL REFERENCES scope_items(id),
amount_minor bigint NOT NULL
);Money is integers
Store amounts in minor units as integers and keep the currency alongside them. Floating-point arithmetic is not safe for money, and the Money pattern [2] exists precisely because a bare number hides currency and rounding rules.
The change order as a state machine
A change order has a life, and each stage has rules about who can move it forward. Writing the transitions as a table — before writing any code — is the single most useful design step.
| From | To | Who can do it | Recorded |
|---|---|---|---|
| draft | proposed | Producer | Proposer, description, price delta |
| proposed | approved | Client approver | Approver, timestamp |
| proposed | declined | Client approver | Approver, reason |
| proposed | withdrawn | Producer | Reason |
| approved | superseded | Producer with client approval | Link to the replacing change order |
- No silent approvals. A state changes only through an explicit action by a person with the entitlement, never by elapsed time.
- Declines are data. A declined change order keeps its reason. It is often the most useful record in a later dispute.
- Supersession, not editing. If terms change after approval, create a new change order that supersedes the old one. Editing history is how disputes start.
Entitlements without a permissions manual
Role-based access works best when the roles are the ones that already exist in the firm. Three roles cover most engagements, and writing the matrix down forces the awkward conversations early.
| Action | Client | Producer | Finance |
|---|---|---|---|
| See approved scope | Yes | Yes | Yes |
| See proposed changes | Yes | Yes | Read only |
| Propose a change | No | Yes | No |
| Approve or decline | Yes (named approvers) | No | No |
| See internal notes | No | Yes | Yes |
| Issue an invoice | No | No | Yes, from approved state |
Keep an audit log of every state change and entitlement decision. An append-only audit table [1] is cheap to build and invaluable when a client says they never approved something.
Pricing extras without renegotiating the relationship
The commercial side of a change order is as important as the technical one. Firms lose money less through bad extras than through unbilled ones, so the process has to make billing the natural consequence of approval.
Habits that leak revenue
- Agreeing to extras verbally on a call
- Waiting until the end to tally the extras
- Pricing extras differently in every conversation
- Treating a declined change as a failure
Habits that protect both sides
- Writing every extra as a proposed change within a day
- Approving in a shared reading room
- Using a rate card so prices are predictable
- Recording declines with the reason
Designing the accounting export
Meridian does not replace the accountant, so its most important interface is an export. A good export is boring: one row per invoice line, stable identifiers, currency explicit, and an idempotency key so re-exporting never duplicates a posting. Design it as a contract with the finance tool, and version it like any API.
Export design checklist
- Every line carries a stable id so a re-export can be matched.
- Currency and minor units are explicit on each amount.
- Tax handling is left to the accounting system unless the firm says otherwise.
- An export log records who exported what and when.
- Failures are visible to finance, not just to engineers.
Closing
If your firm sells projects, the change order is your product's most important noun. Build around it, and finance, producers, and clients start reading from the same page.
References & further reading
- 1Audit Log — Martin Fowler, martinfowler.com
- 2Money — Martin Fowler, Patterns of Enterprise Application Architecture
- 3PostgreSQL Documentation: Constraints — PostgreSQL Global Development Group
The product behind this post
Meridian
Client workspaces and living billing for project-shaped firms.
From $190 per month
About the author
Product behaviour described here reflects what is implemented and tested; anything else is marked as planned. Code samples are illustrative.
All writing