Doing the work
The plan and the contract are always two different documents.
Somebody reads the signed statement of work and re-types the milestones into a project tool. The payment triggers do not come across, because the project tool has no concept of one. And from that moment the thing being delivered and the thing that was sold are two separate objects that happen to agree for a while.
Conversion
One transaction, seven steps, and the ordering is explained.
It refuses unless the document is signed and has not already been converted. It copies the client, the contact, the deal, the currency and the engagement type, and snapshots the budget from the document's own figures.
Milestones are seeded before the document's status changes, deliberately — so the whole conversion rolls back if seeding fails, rather than leaving a converted document with an empty project.
Two different failure policies sit inside that single transaction, and both are intentional: a milestone failure rolls everything back; a failure to resolve a named consultant only logs, because it should not cost you the conversion.
- Discovery completetriggers billingwk 3€36,000
- Environment provisionedwk 5—
- Phase 1 livetriggers billingwk 11€96,000
- Phase 2 sign-offtriggers billingwk 18€108,000
- It prefers the schedule the client signed —
Copying the titles, the acceptance criteria, the dates, the billing amounts and which milestones trigger billing — and re-making the dependency chain as real edges. It falls back to the deliverables only for older documents, and logs when it does.
- A project composes several documents —
The original, and every change document that follows, each linked with its own kind — which is what lets the budget rise automatically when a change is signed.
- Reopening clears the end date —
With the reason recorded: so the margin calculation does not think the project ended and then travelled back in time.
Milestones
Dependencies with a real cycle check, and acceptance that bills.
Three kinds of dependency, and before an edge is created it walks forward from the other end to see whether it already reaches back — refusing a cycle by name. Three cheaper refusals fire first: a self-edge, one across projects, and a duplicate, which returns what exists rather than erroring.
Submitting for acceptance moves a not-yet-started milestone along automatically, so nobody has to remember to start it first — and supersedes any earlier submission rather than leaving two open, recording how many.
An accepted billing milestone drafts its invoice, keyed so a replayed event finds the existing one. A skip is recorded with its reason rather than silently doing nothing.
- Rejection has its own state —
A rejected milestone does not quietly return to in-progress — resubmitting is a deliberate act.
- Reordering is state-gated —
Only while a milestone is still ahead of you, and deleting only while it is untouched.
- Two different defaults, deliberately —
A milestone on the signed document is presumed to bill; one created on the project is presumed not to, unless it came from that schedule.
›Can the client accept a milestone themselves?
Not directly — acceptance is recorded by your team on their behalf, and the product calls that what it is. The statement of work is the one document the client signs directly.
›Is there a Gantt view?
No. Dependencies are validated and nothing draws or schedules from them.
›Can a project be created without a document?
Yes, and the audit row records that it was — the bypass is recorded rather than merely permitted.