Entities and fields
Mode: reference.
The persisted schema for each Tollgate governance entity. Field names are exactly
as stored. Enum values come from packages/methodology/src/constants.js. The
persisted shapes come from the resolvers in src/index.js.
Conventions
Section titled “Conventions”| Convention | Meaning |
|---|---|
accountId fields |
Store a Jira accountId (not a name). Display names are resolved from Jira only at render time. |
| Date / timestamp | ISO strings. “ISO date” means YYYY-MM-DD. “ISO timestamp” means a full datetime. |
| Nullable number | Empty / negative / non-numeric input normalises to null. |
| Sanitised text | Trimmed and length-capped (the cap is noted per field, e.g. ≤ 2000). |
| Storage | All governance data is stored privately per project in Tollgate’s own Forge storage, isolated to your site. See Roles and permissions. |
Work Package
Section titled “Work Package”| Field | Type | Allowed values / notes |
|---|---|---|
id |
string (UUID) | Generated if absent. |
projectKey |
string | Owning Jira project. |
name |
string | Required, ≤ 200 chars, unique per project. |
type |
string | null | Free text, ≤ 200 (for example Delivery, Infrastructure, Build, “Adoption / Change”). |
ownerAccountId |
string | null | Jira user. |
plannedStartDate |
ISO date | null | Baseline plan. |
plannedEndDate |
ISO date | null | Baseline plan. |
actualStartDate |
ISO date | null | |
actualEndDate |
ISO date | null | |
actualEnd |
ISO date | null | Alias mirror of actualEndDate. |
forecastStartDate |
ISO date | null | |
forecastEndDate |
ISO date | null | Used for schedule-variance derivation. |
status |
enum | Not Started, In Progress, Blocked, Complete. Default Not Started. |
rag |
enum | Red, Amber, Green, Blue, None. Default None. |
progress |
number | null | 0–100 in steps of 10, validated against status (Complete ⇒ 100, Not Started ⇒ 0 or null, In Progress/Blocked ⇒ 10–90). A contradiction is rejected, never rounded. |
budget |
number | null | The requested spend for the package — the freely editable field from the Add/Edit dialog. |
budgetPhasing |
array | null | Optional time-phased spread of budget: {period: 'YYYY-MM', amount} entries. One malformed entry invalidates the whole array. |
budgetBaseline |
number | null | Read-only on save — a frozen copy written by business-case approval. An ordinary work-package save always keeps the stored value. |
budgetForecast |
number | null | Non-negative. |
budgetActual |
number | null | Non-negative. |
commentary |
string | null | ≤ 2000. |
linkedIssueKeys |
string[] | Jira issue keys (upper-cased, typically Epics). |
sortOrder |
number | null | Manual display order for Register/Timeline. Null falls back to date-then-name. |
budgetBaselineLockedAt |
ISO timestamp | null | Legacy — carried forward unedited, never freshly set. Only tells a legacy-approved project which packages were part of the approved plan. |
plannedDatesBaselineLockedAt |
ISO timestamp | null | Legacy — as above. |
createdAt |
ISO timestamp | |
updatedAt |
ISO timestamp | |
updatedByAccountId |
string | Actor. |
Business Case (Charter)
Section titled “Business Case (Charter)”A single KVS (key-value store) object per project. Grouped below by concern.
Thesis core
Section titled “Thesis core”| Field | Type | Allowed values / notes |
|---|---|---|
projectKey |
string | |
businessProblem |
string | Sanitised. |
outcome |
string | Sanitised. (Legacy objectives surfaces here on read.) |
returnExpected |
string | The as-promised return (prose). |
scopeInBounds |
string | What it will deliver (in scope). |
scopeBoundaries |
string | Explicit exclusions (out of scope). |
theme |
string | Free-text investment theme (see defaults below). |
designPrinciples |
array | Normalised list. |
supportingLinks |
array | Each {id, label, url, type, pageId?, spaceKey?, templateKind?}. url must be http or https. type = confluence | link. |
decisionAuthority |
object | null | The sponsor: {accountId, displayName, avatarUrl}. |
projectManager |
object | null | {accountId, displayName, avatarUrl}. |
customerRep |
object | null | Single seat. |
supplierRep |
object | null | Single seat. |
steeringCommittee |
array | Members {id, accountId, displayName, role}. |
financialCase |
object | Shaped by normaliseAndComputeFinancialCase. mode ∈ attached, builtin, none (an invalid mode coerces to none, and a never-saved charter serves a fresh empty builtin model). Carries mode, attached, builtin (with recomputed computed metrics), boardPaperPageId, timestamps. |
planBaseline |
object | null | The frozen plan (per-package budget and planned-date baselines), written only by business-case approval (ADR-0010). |
updatedAt / updatedByAccountId |
ISO timestamp / string | Stamped on every save. |
Adoption & Change quartet (BCM at outset)
Section titled “Adoption & Change quartet (BCM at outset)”The four inputs gated at business-case submission. This is one of the product’s two deliberate hard content gates. The other is the lessons requirement on a Not-realised verdict.
| Field | Type | Allowed values / notes |
|---|---|---|
adoptionAffected |
string | Who/what is affected. |
adoptionKpi |
string | The adoption KPI (key performance indicator). |
adoptionOwner |
object | null | {accountId, displayName, avatarUrl}. |
changeSaturation |
enum | None, Low, Modest, High. Invalid/missing → Unknown. |
adoptionGap is derived, not stored. It is true when adoptionAffected
or adoptionKpi is empty, or when changeSaturation is absent or Unknown.
It is also true when the adoptionOwner seat is not actionable — no Jira
account and no usable external address.
Approval lifecycle
Section titled “Approval lifecycle”| Field | Type | Allowed values / notes |
|---|---|---|
approvalStatus |
enum | Exploring, Draft, Submitted, Approved, ClosingSubmitted, Closed, Archived, InRealisation, Realised, NotRealised, InMaintenance. Default Exploring. |
version |
number | Default 1. |
submittedAt |
ISO timestamp | null | Set on submit. |
approvedAt / approvedByAccountId |
ISO timestamp | null / string | null | Set on approve. |
approvalComment / approvalRationale |
string | |
returnNotes |
array | Each {id, section, ask, severity, addressed}. Sections and severities below. |
returnedAt |
ISO timestamp | null | |
archivedAt / archivedByAccountId / archiveReason / archivedFromStatus |
ISO timestamp | null / string | null / string / enum | null | Kill-with-dignity metadata. |
amendmentEnabledByChangeId |
string | null | The enabling change request recorded when the approved case was re-opened for amendment. |
amendmentNoChangeReason |
string | null | Legacy — retired 30 Jul 2026. Charters amended before then still carry it. Nothing writes it any more. |
terminalDisposition |
enum | archived (explored, not pursued) or killed (a stop decision on a running investment). Recorded at archive time. Older records read as archived. |
firstSteercoScheduledFor / firstSteercoHeldAt |
ISO timestamp | null | First steering committee. firstSteercoHeldAt is set by the first recorded steering minutes (or the explicit confirmation) and completes Initiation. |
Re-opening an approved case always records an enabling change request in
amendmentEnabledByChangeId. The amender either cites an approved change
awaiting application, or Tollgate raises one on their behalf. The raised
request needs a reason and routes to the sponsor for approval. The reopen
audit entry cites it. Approval of the amended case (version ≥ 2) stamps the
enabling change request with an applicationRecord.
Return-note sections: businessProblem, outcome, returnExpected,
adoption, sponsor, steeringCommittee, theme, general.
Return-note severities: Blocker, Significant, Minor.
Initiation / first-steerco scaffolding
Section titled “Initiation / first-steerco scaffolding”Set by dedicated resolvers, not the thesis form.
| Field | Type | Notes |
|---|---|---|
firstSteercoScheduledFor |
ISO date | null | |
firstSteercoAttendees |
array | Default []. |
firstSteercoHeldAt |
ISO timestamp | null |
Close-out (closeOut sub-object)
Section titled “Close-out (closeOut sub-object)”closeOut defaults to null. Top-level closure stamps closedAt /
closedByAccountId. The body carries:
| Field | Type | Allowed values / notes |
|---|---|---|
asBuiltOutcome |
string | ≤ 2000 — what was actually delivered, in the sponsor’s words. |
asBuiltReturn |
string | ≤ 2000 — with deltas vs the approved case. |
asBuiltReturnValue |
number | null | Optional revised numeric return. |
asBuiltEndDate |
ISO date | Optional. |
scopeDispositions |
map {[wpId]: {disposition, note}} |
disposition ∈ DeliveredAsChartered, DeliveredReduced, DeliveredExpanded, Dropped, Deferred. |
rioDispositions |
map {[riskId]: {disposition, note}} |
disposition ∈ Closed, TransferredToBau, Accepted, Pursued, Dropped. |
pendingDispositions |
{decisions: {...}, changes: {...}} |
disposition ∈ Adjudicated, Withdrawn, ApprovedAsShipped, DeferredToBau. |
lessons |
{worked, differently, nextSponsor} |
Three free-text fields (each ≤ 2000). |
bauHandover |
object | {state, ownerAccountId, ownerDisplayName, acknowledgedAt, acknowledgedByAccountId, escalatedAt, escalationReason}. state ∈ Pending, Acknowledged, Escalated (default Pending). |
commentary |
string | ≤ 2000. |
startedAt / submittedAt |
ISO timestamp | Lifecycle stamps. |
Close-out return notes (separate list): {id, section, ask, severity, addressed}. Sections ∈ asBuiltOutcome, asBuiltReturn, scopeDispositions,
rioDispositions, lessons, bauHandover, general.
Benefits Realisation
Section titled “Benefits Realisation”| Field | Type | Allowed values / notes |
|---|---|---|
returnRealised |
string | Prose, not numeric. The realised return as judged by the sponsor. |
realisationSummary |
string | |
realisationLessons |
string | Elevated on NotRealised. |
realisationConfidence |
enum | High, Modest, Low, Unknown (default Unknown). |
realisationDate |
ISO date | null | Plan field (“measured by” date). |
kpiResolution |
object | null | {resolvedAt, resolvedBy, resolvedValue, met, notes}. |
brOwner |
string | null | |
realisationReviews |
array | Append-only review log: {id, at, byAccountId, note, confidence}. |
realisationStartedAt |
ISO timestamp | null | |
realisationDecidedAt / realisationDecidedByAccountId |
ISO timestamp | null / string | null | |
maintenanceStartedAt / maintenanceRetiredAt |
ISO timestamp | null | |
lastRealisationReviewAt |
ISO timestamp | null |
The BR review cadence (brCadence) does not live on the Business Case. It is
an optional override on Project Status.
R·I·O item (Risk / Opportunity / Materialised)
Section titled “R·I·O item (Risk / Opportunity / Materialised)”The unified downside/upside register. Its user-facing name is Risks. The
direction field records whether an item is a Risk or an Opportunity.
| Field | Type | Allowed values / notes |
|---|---|---|
id |
string (UUID) | |
projectKey |
string | |
title |
string | ≤ 200. |
description |
string | ≤ 2000. |
ownerAccountId |
string | null | |
status |
enum | Open, Closed (anything not Closed → Open). |
direction |
enum | Risk, Opportunity. |
materialised |
boolean | Only meaningful when direction = Risk. Forced false for Opportunity. |
impact |
number | null | 1–5. |
likelihood |
number | null | 1–5. |
residualImpact |
number | null | 1–5. |
residualLikelihood |
number | null | 1–5. |
treatment |
enum | null | Risk: Mitigate, Avoid, Transfer, Accept. Opportunity: Pursue, Enhance, Share, Ignore. |
mitigation |
string | ≤ 2000. Treatment plan. Doubles as acceptance rationale. |
acceptedByAccountId / acceptedAt / acceptanceRationale |
string | null / ISO timestamp | null / string | Stamped on first transition to treatment = Accept. |
createdAt / updatedAt / updatedByAccountId |
ISO timestamp / ISO timestamp / string | null | |
imported |
boolean | Present (true) only on bulk-imported rows. |
Decision
Section titled “Decision”Append-only log. New entries are prepended.
| Field | Type | Allowed values / notes |
|---|---|---|
id |
string (UUID) | |
projectKey |
string | |
decision |
string | Required, ≤ 200. |
decisionNotes |
string | ≤ 2000. |
madeOn |
ISO date | null | Null until the decision is taken — adjudication stamps it. (Bulk-imported historical rows default to today.) |
madeByAccountId |
string | null | Defaults to the raiser. |
rationale |
string | ≤ 2000. On reject, holds the required reason. |
ownerAccountId |
string | null | |
approverAccountId |
string | null | The per-decision approval gate. Defaults to the sponsor when the raiser names no approver. |
approverSeat |
object | null | The nominated decision-maker’s seat — supports an external (non-Jira) approver, whose decision is then recorded as an attestation. |
minutesRef |
object | null | Provenance: the linked steering minutes the decision was taken in ({id, title, url, pageId?}), validated against the project’s own minutes list. |
riskId |
string | null | Provenance: seeded from a materialised risk. |
treatedRiskId |
string | null | Live back-link to the risk this decision treats. |
evidenceLinks |
array | Same shape as Business Case supportingLinks. |
status |
enum | Proposed, Approved, Rejected, Withdrawn. Created as Proposed. |
decidedAt |
ISO timestamp | null | Set on adjudication. |
decidedByAccountId |
string | null | Set on adjudication. |
createdAt / createdByAccountId |
ISO timestamp / string | |
updatedAt |
ISO timestamp | Added on adjudication. |
imported |
boolean | Present on bulk-imported rows. |
Adjudication rules: reject requires a reason. Only the creator can set
Withdrawn. Only the named approverAccountId can approve or reject
(self-approval allowed).
Legacy decisions with no approver fall back to edit permission.
Change (change request)
Section titled “Change (change request)”| Field | Type | Allowed values / notes |
|---|---|---|
id |
string (UUID) | |
projectKey |
string | |
summary |
string | Required, ≤ 200. |
reason |
string | ≤ 2000 — the requester’s justification. |
dimensions |
string[] | Subset of Scope, Budget, Schedule, Quality, Other (de-duped). Inferred when empty (scope prose → Scope, budget impact → Budget, schedule delta → Schedule. Quality/Other are never inferred). |
impactScheduleDays |
number | null | Signed day delta — the single truth for a schedule impact. |
impactBudget |
number | null | Signed (savings allowed). |
impactScope |
string | ≤ 2000 — scope impact as prose (scope doesn’t quantify). |
impactQualityOther |
string | ≤ 2000 — one combined prose field for Quality and Other. |
impactTimeline |
string | Legacy — the free-text schedule label. Stored records keep it. Nothing reads or writes it now. |
targetWorkPackageId |
string | null | Optional anchor to one work package. |
proposerAccountId |
string | null | Audit field. Defaults to the raiser. |
approverAccountId |
string | null | Named approver. |
approverSeat |
object | null | The nominated approver’s seat — supports an external (non-Jira) approver. |
status |
enum | Proposed, Approved, Rejected, Withdrawn. Created as Proposed. |
decidedAt |
ISO timestamp | null | Set on adjudication. |
decidedByAccountId |
string | null | Set on adjudication. |
decisionComment |
string | Set on adjudication (distinct from reason). A reject requires a reason. |
createdAt / createdByAccountId / updatedAt |
ISO timestamp / string / ISO timestamp | |
imported |
boolean | Present on bulk-imported rows. |
applicationRecord |
object | null | Server-authored evidence that an authorised amendment landed: { kind: 'charter' | 'baseline', ref, at, by } — ref is the charter version (v2) or the work-package id. Stripped from incoming payloads. Never user-settable. |
Derived change state
Section titled “Derived change state”status records the decision. The application of an approved change is
derived on top of it, never stored. The register renders the derived state as
a note under the status lozenge.
| Derived state | When |
|---|---|
Proposed |
Not yet decided. |
Rejected / Withdrawn |
Terminal decisions. |
Applied |
applicationRecord is present, or the change is approved and carries only Budget / Schedule deltas (the variation roll-up is the application — it happens at approval). |
AwaitingApplication |
Approved, carries an amendment dimension (Scope, Quality, Other, or no dimension at all), and no applicationRecord yet. |
A mixed change (a Budget delta and a Scope amendment) derives
AwaitingApplication — its delta applies at approval, but the amendment half
still awaits application. Only changes deriving AwaitingApplication are eligible to
enable a business-case amendment.
Project Status
Section titled “Project Status”A single KVS object per project.
| Field | Type | Allowed values / notes |
|---|---|---|
projectKey |
string | |
overallRag |
enum | Red, Amber, Green, Blue, None. Default None. Manual (not derived). |
phase |
string | Free text (no enum validation). Default Initiation. |
reportingCadence |
enum | Daily, Weekly, Monthly. Default Monthly. |
structuredCommentary |
object | null | {keyMessages, keyRisks, decisionsRequired}. |
projectMetrics |
any | null | Pass-through. |
costRagOverride |
enum | null | Red/Amber/Green/Blue/None, else null. Null = use the derived value. |
scheduleRagOverride |
enum | null | As above. |
scopeRagOverride |
enum | null | As above. |
riskRagOverride |
enum | null | As above. |
costRagOverrideReason / scheduleRagOverrideReason / scopeRagOverrideReason |
string | Standing PM commentary on the dimension card, editable with or without an override. Same cap and clearing behaviour as overallReason. |
outcomeConfidence |
enum | null | High, Modest, Low, Unknown. Read fallback Unknown. |
adoptionConfidence |
enum | null | As above. |
revisedForecast |
number | null | PM top-down EAC override. |
pmKeyMessage |
string | PM-authored steering key message. |
overallReason |
string | Optional one-line “why this rating” shown on the Overall card. ≤ 120 chars (STATUS_REASON_MAX, clamped on save). '' clears it. |
confidenceReason |
string | Optional one-line reason shown on the Confidence card. Same cap and clearing behaviour. |
lastUpdatedAt |
ISO timestamp | |
lastUpdatedByAccountId |
string | |
initiationStartedAt |
ISO timestamp | null | Set on charter approval. |
initiationCompletedAt |
ISO timestamp | null | Set on acknowledgement / first steerco held. |
initiationDismissals |
map | {[checklistItemId]: ISO timestamp}. |
brCadence |
enum | null | Monthly, Quarterly, Annual — per-project BR review override. |
Investment themes
Section titled “Investment themes”theme is free text on the Business Case. The default canonical set
(CANONICAL_THEMES) that admins may rename / disable / add to site-wide (bounded
by a cap of 12):
Cost Out, Revenue Growth, Productivity, Risk & Compliance,
Customer Experience, Strategic.