overview
<!-- Status Legend -->
<div class="card">
<h2>Client Statuses at a Glance</h2>
<div class="subtitle">Every client has a <strong>Status</strong> (lifecycle phase) and a <strong>SubStatus</strong> (contract detail).</div>
<h3>Status (what stage the client is in)</h3>
<div style="display:flex;flex-wrap:wrap;gap:8px;margin:10px 0;">
<span class="status-badge status-onboarding">Onboarding</span>
<span class="status-badge status-active">Active — Multichannel service</span>
<span class="status-badge status-platform">Active — Platform Only</span>
<span class="status-badge status-suspended">Suspended</span>
<span class="status-badge status-inactive">Inactive</span>
<span class="status-badge status-onboarding">Reactivation Onboarding</span>
</div>
<h3>SubStatus (what contract type or situation)</h3>
<div style="display:flex;flex-wrap:wrap;gap:8px;margin:10px 0;">
<span class="substatus-mtc">MTC</span>
<span class="substatus-rolling">Rolling</span>
<span class="substatus-fixed">Fixed Term</span>
<span class="substatus-delayed">Delayed</span>
<span class="substatus-termnotice">Termination Notice</span>
<span class="substatus-termcredits">Termination (credits left)</span>
</div>
<h3>Which SubStatus goes with which Status?</h3>
<table>
<tr><th>Status</th><th>Possible SubStatuses</th></tr>
<tr><td><span class="status-badge status-onboarding">Onboarding</span></td><td>— (empty) or <span class="substatus-delayed">Delayed</span></td></tr>
<tr><td><span class="status-badge status-onboarding">Reactivation Onboarding</span></td><td>— (empty) or <span class="substatus-delayed">Delayed</span></td></tr>
<tr><td><span class="status-badge status-active">Active — Multichannel</span></td><td><span class="substatus-mtc">MTC</span>, <span class="substatus-rolling">Rolling</span>, <span class="substatus-fixed">Fixed Term</span>, <span class="substatus-termnotice">Termination Notice</span>, <span class="substatus-termcredits">Termination (credits left)</span></td></tr>
<tr><td><span class="status-badge status-platform">Active — Platform Only</span></td><td>— (empty) or <span class="substatus-termnotice">Termination Notice</span></td></tr>
<tr><td><span class="status-badge status-suspended">Suspended</span></td><td>— (empty)</td></tr>
<tr><td><span class="status-badge status-inactive">Inactive</span></td><td>— (empty)</td></tr>
</table>
</div>
<!-- Full Lifecycle Journey -->
<div class="card">
<h2>The Client Journey — End to End</h2>
<div class="subtitle">How a client moves through the system, from creation to termination.</div>
<pre class="mermaid">
flowchart TD CREATE["New Client Created via NewBookCampaign form"] CREATE --> ONBOARD["Onboarding - Status Onboarding, SubStatus empty"] ONBOARD --> DELAYED{"60 plus days without going live?"} DELAYED -->|Yes| DELAY["Delayed - flags for CS attention"] DELAYED -->|No| WAIT["Waiting for Go Live"] DELAY --> WAIT WAIT --> GOLIVE["Go Live - Ops clicks button, Requires Finance Approved"] GOLIVE --> MTC["Active MTC - minimum term contract"] GOLIVE --> FIXED["Active Fixed Term - fixed-length contract"] MTC --> ROLLING["Active Rolling - min term completed, month-to-month"] FIXED --> INACTIVE["Inactive"] ROLLING --> TERMINATE{"Termination initiated?"} TERMINATE -->|New term client| TERM_NOTICE["Termination Notice - notice period active"] TERMINATE -->|Old term client| TERM_CREDITS["Termination credits left - credits available"] TERM_NOTICE -->|Notice period ends| INACTIVE TERM_NOTICE -->|Cancelled| ROLLING TERM_CREDITS -->|Credits exhausted| INACTIVE ROLLING --> SUSPEND["Suspended - temporarily paused"] SUSPEND --> ROLLING ROLLING --> PLATFORM["Platform Only - downgraded to platform fee"] PLATFORM -->|Reactivated| MTC PLATFORM -->|Terminated| INACTIVE INACTIVE -->|Client rebooked| REACTIVATE["Reactivation Onboarding - client rebooked via NewBookCampaign"] REACTIVATE --> GOLIVE style CREATE fill:#dbeafe,stroke:#2563eb style ONBOARD fill:#fef3c7,stroke:#d97706 style GOLIVE fill:#d1fae5,stroke:#059669 style MTC fill:#dbeafe,stroke:#2563eb style ROLLING fill:#dbeafe,stroke:#2563eb style FIXED fill:#dbeafe,stroke:#2563eb style TERM_NOTICE fill:#fed7aa,stroke:#ea580c style TERM_CREDITS fill:#e5e7eb,stroke:#6b7280 style PLATFORM fill:#fce7f3,stroke:#be185d style SUSPEND fill:#fee2e2,stroke:#dc2626 style INACTIVE fill:#f1f5f9,stroke:#94a3b8 style REACTIVATE fill:#fef3c7,stroke:#d97706 style DELAY fill:#fed7aa,stroke:#ea580c
<!-- Common Actions -->
<div class="card">
<h2>Common Operations & What They Do</h2>
<div class="flow-steps">
<div class="flow-step">
<div class="step-num"></div>
<div class="step-body">
<h4>Create a New Client</h4>
<p>Use the <strong>New Book Campaign</strong> form. This sets the client to <span class="status-badge status-onboarding">Onboarding</span> and creates the first campaign. A contract and package are also created if the client is billable.</p>
</pre>
<div class="flow-step">
<div class="step-num"></div>
<div class="step-body">
<h4>Go Live</h4>
<p>Once the campaign setup is complete and Finance has approved, Ops clicks <strong>Go Live</strong>. The client moves from Onboarding to <span class="status-badge status-active">Active — Multichannel</span> with SubStatus <span class="substatus-mtc">MTC</span> or <span class="substatus-fixed">Fixed Term</span>.</p>
</pre>
<div class="flow-step">
<div class="step-num"></div>
<div class="step-body">
<h4>Terminate a Client</h4>
<p>From the client page, select <strong>Terminate</strong>. Choose a service end date. The client stays Active but moves to <span class="substatus-termnotice">Termination Notice</span> (new clients) or <span class="substatus-termcredits">Termination (credits left)</span> (legacy clients). The nightly job automatically moves them to Inactive when the date arrives.</p>
</pre>
<div class="flow-step">
<div class="step-num"></div>
<div class="step-body">
<h4>Suspend a Client</h4>
<p>Temporarily pauses the client. Status becomes <span class="status-badge status-suspended">Suspended</span>. Widget is disabled. Can be manually unsuspended.</p>
</pre>
<div class="flow-step">
<div class="step-num"></div>
<div class="step-body">
<h4>Cancel a Termination</h4>
<p>If a termination was initiated but the client changes their mind, <strong>Cancel Termination</strong> moves SubStatus back to <span class="substatus-rolling">Rolling</span>.</p>
</pre>
<div class="flow-step">
<div class="step-num"></div>
<div class="step-body">
<h4>Move to Platform Only</h4>
<p>Schedule a Platform Fee start date. On that date (during nightly processing), the client transitions to <span class="status-badge status-platform">Active — Platform Only</span> with a platform-fee package.</p>
</pre>
<div class="flow-step">
<div class="step-num"></div>
<div class="step-body">
<h4>Reactivate from Platform Only</h4>
<p>Finance can reactivate a Platform Only client back to <span class="status-badge status-active">Active — Multichannel</span> with a new package. SubStatus becomes <span class="substatus-rolling">Rolling</span> or <span class="substatus-mtc">MTC</span>.</p>
</pre>
</pre>
<!-- What Happens Nightly -->
<div class="card">
<h2>What Happens Automatically (Nightly Job)</h2>
<div class="subtitle">Every night at 1:12 AM, the system runs <code>_RecalculateCampaignsStatus</code> to handle time-based transitions.</div>
<table>
<tr><th>What changes</th><th>When</th></tr>
<tr><td>MTC → Rolling</td><td>Minimum contract term has passed</td></tr>
<tr><td>Fixed Term → Inactive</td><td>Fixed contract service end date reached</td></tr>
<tr><td>Termination Notice → Inactive</td><td>The termination service end date arrives</td></tr>
<tr><td>Termination (credits left) → Inactive</td><td>The delivery end date arrives (credits exhausted)</td></tr>
<tr><td>→ Platform Only</td><td>Scheduled Platform Fee date arrives</td></tr>
<tr><td>Onboarding → Delayed</td><td>60+ days in Onboarding without going live</td></tr>
<tr><td>Campaign deactivated</td><td>Scheduled deactivation date arrives</td></tr>
<tr><td>Finance Approved</td><td>All Xero invoices are paid/authorised</td></tr>
</table>
<div class="callout info">
<strong>💡 Tip:</strong> If a client looks stuck in a status, check whether a nightly job transition is pending (e.g. waiting for a date to arrive). The nightly job only runs once per day.
</pre>
<!-- Nightly Job Flow Diagram -->
<div class="card">
<h2>Nightly Job Flow Diagram</h2>
<div class="subtitle">Visual walkthrough of the automated nightly status recalculation process.</div>
<pre class="mermaid">
flowchart TD NIGHTLY["Nightly Job Runs at 1:12 AM"]
NIGHTLY --> CORR["Contract Corrections"]
CORR --> CB1["Fix MTC-FixedTerm mismatch"]
CORR --> CB2["Fix Fixed-MTC mismatch"]
NIGHTLY --> LIFE["Lifecycle Progression"]
LIFE --> LB1["MTC to Rolling when min term passed"]
LIFE --> LB2["Fixed Term to Inactive when service ended"]
NIGHTLY --> TERM["Termination Processing"]
TERM --> TB1["New term: TerminationDate becomes Inactive"]
TERM --> TB2["Old term: TerminationDate becomes credits left"]
TERM --> TB3["Old term: DeliveryEndDate becomes Inactive"]
NIGHTLY --> PFEE["Platform Fee"]
PFEE --> PB1["PlatformFeeDate becomes Platform Only"]
PFEE --> PB2["Platform Only plus TerminationDate becomes Inactive"]
NIGHTLY --> OTHR["Other Checks"]
OTHR --> OB1["Finance Approval via Xero"]
OTHR --> OB2["Remove BatchBilling when done"]
OTHR --> OB3["Onboarding 60 plus days becomes Delayed"]
OTHR --> OB4["DeactivationDate becomes Inactive"]
</pre>
</pre>
<div class="card">
<h2>Enum Definitions</h2>
<div class="subtitle">Source: <code>Services/Services/Enums/ClientNewStatusEnum.cs</code> and <code>ClientNewSubStatusEnum.cs</code></div>
<h3>ClientNewStatusEnum</h3>
<table>
<tr><th>Display Name</th><th>Enum Value</th><th>Int</th><th>Meaning</th></tr>
<tr><td>Active - Multichannel service</td><td><code>ActiveMultichannelService</code></td><td>0</td><td>Live client with active multichannel campaigns</td></tr>
<tr><td>Active - Platform Only</td><td><code>PlatformFeeOnly</code></td><td>1</td><td>Downgraded to platform-fee-only package</td></tr>
<tr><td>Inactive</td><td><code>Inactive</code></td><td>2</td><td>Terminated / fully deactivated</td></tr>
<tr><td>Onboarding</td><td><code>Onboarding</code></td><td>3</td><td>New client being set up</td></tr>
<tr><td>Suspended</td><td><code>Suspended</code></td><td>4</td><td>Temporarily paused</td></tr>
<tr><td>Reactivation Onboarding</td><td><code>ReactivationOnboarding</code></td><td>5</td><td>Previously inactive client being re-onboarded</td></tr>
</table>
<h3>ClientNewSubStatusEnum</h3>
<table>
<tr><th>Display Name</th><th>Enum Value</th><th>Int</th><th>Meaning</th></tr>
<tr><td>Delayed</td><td><code>Delayed</code></td><td>1</td><td>Onboarding >60 days without going live</td></tr>
<tr><td>MTC</td><td><code>MTC</code></td><td>2</td><td>Minimum Term Contract — within minimum commitment period</td></tr>
<tr><td>Rolling</td><td><code>Rolling</code></td><td>3</td><td>Past minimum term, month-to-month</td></tr>
<tr><td>Fixed Term</td><td><code>FixedTerm</code></td><td>4</td><td>Fixed-length contract</td></tr>
<tr><td>Termination Notice</td><td><code>TerminatioNotice</code></td><td>5</td><td>Notice period served, waiting for ServiceEndDate</td></tr>
<tr><td>(empty)</td><td><code>Empty</code></td><td>6</td><td>No substatus applicable</td></tr>
<tr><td>Termination (credits left)</td><td><code>TerminationCreditsLeft</code></td><td>7</td><td>Old-term client: ServiceEndDate reached but credits remain</td></tr>
</table>
</div>
<!-- NewBookCampaign -->
<div class="card">
<h2>Client Creation: NewBookCampaign</h2>
<div class="subtitle">Primary path — <code>ClientsController.NewBookCampaign</code> (POST)</div>
<pre class="mermaid">
flowchart TD START["POST NewBookCampaign"] --> GET["GetClientById"] GET -->|not found| NEW["Create New Client"] GET -->|found| CHK{"Inactive or TerminationCreditsLeft?"} NEW --> SN["Status Onboarding, SubStatus empty"] NEW --> FL["newClient true"] CHK -->|Yes| RA["Status ReactivationOnboarding"] CHK -->|No| EX["Keep Status, clear dates"] SN --> POP["Populate Client fields"] RA --> POP EX --> POP FL --> POP POP --> SAV["_clientService.AddOrUpdateClient"] SAV -->|newClient| SET["Create default ClientSettings"] SAV --> CP{"DontCreateCampaign?"} CP -->|No| NC["Create Campaign Onboarding"] NC --> SC["_campaignService.AddOrUpdate"] SC --> EX2{"DontCreateCampaign?"} EX2 -->|No| NE["Create CampaignExtended"] POP --> BL{"model.Billable?"} BL -->|Yes| CT{"DontCreateContract?"} CT -->|No| SCT["_contractService.AddOrUpdate"] BL -->|Yes| PK{"DontCreatePackage?"} PK -->|No| SPK["_clientMultichanelFeeService.Insert"] BL -->|Yes and GenerateInvoice| INV["_invoiceService.AddSetupFee"] SC --> PH["Sync Planhat"] PH --> RET["Return JSON with IDs"]
<h3>Campaign Status Mapping</h3>
<table>
<tr><th>Scenario</th><th>Client Status</th><th>Client SubStatus</th><th>Campaign Status</th></tr>
<tr><td>New client</td><td><code>Onboarding</code></td><td><code>""</code> (Empty)</td><td><code>New_Status_Onboarding</code></td></tr>
<tr><td>Reactivating inactive client</td><td><code>ReactivationOnboarding</code></td><td><code>""</code> (Empty)</td><td><code>New_Status_Reactivation_Onboarding</code></td></tr>
<tr><td>Existing client (adding campaign)</td><td>Unchanged</td><td>Unchanged</td><td><code>New_Status_Reactivation_Onboarding</code> (resets FinanceApproved)</td></tr>
</table>
</div>
<!-- GoLive -->
<div class="card">
<h2>Go Live (Campaign Activation)</h2>
<div class="subtitle"><code>CampaignController.GoLive</code> → <code>CampaignService.CampaignGoLive</code></div>
<pre class="mermaid">
flowchart TD A["Campaign in Onboarding or Reactivation"] --> B{"FinanceApproved?"} B -->|No| REJECT["Error not Finance Approved"] B -->|Yes| C["Set Campaign Active, DeliveryDate Now"] C --> D{"Other active campaigns exist?"} D -->|No| E["Client ActiveMultichannel, SubStatus MTC or FixedTerm"] D -->|Yes| F{"Client in Onboarding, Reactivation, or Inactive?"} F -->|Yes| E F -->|No| G["Preserve existing Status, log warning"] E --> H["Set MonthlyInvoiceDate"] G --> H H --> I["Create monthly invoice if billable"] I --> J["Send notifications, sync Planhat"]
<div class="callout">
<strong>Multi-campaign protection:</strong> If the client already has other active campaigns, GoLive will NOT overwrite the existing Status/SubStatus. The lifecycle is governed by the original contract.
</pre>
<!-- User-Triggered Actions -->
<div class="card">
<h2>User-Triggered Status Transitions</h2>
<div class="subtitle">All POST actions in <code>ClientsController.cs</code></div>
<h3>Terminate Client</h3>
<pre class="mermaid">
flowchart LR A["Active Client"] -->|Terminate| B{"ContractualStatus?"} B -->|NetNew or MigratedLegacy| C["ActiveMultichannel, Termination Notice, set TerminationDate"] B -->|ProtectedLegacy or ExceptionClients| D["ActiveMultichannel, Termination credits left, set both dates"] C --> E["AddTerminateSuspendClient log"] D --> E E --> F["Send ClientTerminationNotification"] F --> G["Planhat CreateChurn"]
<h3>Platform Fee Suspend — Back to Active</h3>
<pre class="mermaid">
flowchart TD A["Client on PlatformFeeOnly"] --> B["Select new Package"] B --> C["Update ClientMultiChanelFee"] C --> D["ActiveMultichannel, SubStatus MTC"] D --> E["Send SuspensionNotification"] E --> F["Log BackToActive"]
<h3>Other Actions</h3>
<table>
<tr><th>Action</th><th>Precondition</th><th>Result</th></tr>
<tr><td>Suspend Client</td><td>—</td><td>Status → Suspended, SubStatus → ""</td></tr>
<tr><td>Terminate Immediately</td><td>—</td><td>Status → Inactive, SubStatus → ""</td></tr>
<tr><td>Cancel Termination</td><td>ActiveMultichannel + Termination Notice</td><td>SubStatus → Rolling</td></tr>
<tr><td>Platform Fee Schedule</td><td>—</td><td>Sets PlatformFeeDate (nightly job executes)</td></tr>
<tr><td>Platform Fee Terminate</td><td>PlatformFeeOnly</td><td>Status → Inactive</td></tr>
<tr><td>Reactivate from Platform Only</td><td>PlatformFeeOnly</td><td>Status → ActiveMultichannelService, SubStatus → Rolling</td></tr>
<tr><td>Reactivate Legacy Client</td><td>—</td><td>Status → ActiveMultichannelService, SubStatus → TerminationCreditsLeft</td></tr>
</table>
</div>
<!-- Nightly Job -->
<div class="card">
<h2>Nightly _RecalculateCampaignsStatus</h2>
<div class="subtitle">Hangfire recurring job, daily at 01:12 AM. Source: <code>HangFireJobServiceDB.cs</code></div>
<pre class="mermaid">
flowchart TD subgraph CORRECT [Blocks 1 and 2: Contract Type Corrections] B1["B1: SubStatus is FixedTerm but Contract is MTC - Correct to MTC"] B2["B2: SubStatus is MTC but Contract is Fixed - Correct to FixedTerm"] end subgraph LIFE [Blocks 3 and 4: Lifecycle Progression] B3["B3: MTC to Rolling when min DeliveryDate plus MinimumTermMonths reached"] B4["B4: Fixed Term Expiry when max DeliveryDate plus MinimumTermMonths reached"] end subgraph TERM [Blocks 5, 6, 7: Termination Processing] B5["B5: TerminationDate reached for NetNew or MigratedLegacy becomes Inactive"] B6["B6: TerminationDate reached for ProtectedLegacy or ExceptionClients becomes TerminationCreditsLeft"] B7["B7: DeliveryEndDate reached becomes Inactive"] end subgraph PFEE [Blocks 8 and 9: Platform Fee] B8["B8: PlatformFeeDate reached becomes PlatformFeeOnly with platform package"] B9["B9: PlatformFeeOnly plus TerminationNotice plus TerminationDate reached becomes Inactive"] end subgraph OTHR [Blocks 10 to 13: Other] B10["B10: Finance Approval - invoices AUTHORISED or PAID in Xero"] B11["B11: Remove BatchBilling when delivery duration passed"] B12["B12: 60 plus days since last campaign in Onboarding becomes Delayed"] B13["B13: Campaign DeactivationDate reached becomes Inactive"] end B1 --> B2 --> B3 --> B4 --> B5 --> B6 --> B7 --> B8 --> B9 --> B10 --> B11 --> B12 --> B13
<!-- State Machine -->
<div class="card">
<h2>Complete Lifecycle State Machine</h2>
<pre class="mermaid">
stateDiagram-v2 [*] --> Onboarding : NewBookCampaign (new client)
Onboarding --> Onboarding_Delayed : 60 plus days (nightly)
Onboarding_Delayed --> Onboarding : manual edit
Onboarding --> Active_MTC : GoLive MTC contract
Onboarding --> Active_FixedTerm : GoLive Fixed contract
ReactOnboarding --> ReactOnboarding_Delayed : 60 plus days (nightly)
ReactOnboarding_Delayed --> ReactOnboarding : manual edit
ReactOnboarding --> Active_MTC : GoLive MTC contract
ReactOnboarding --> Active_FixedTerm : GoLive Fixed contract
Active_MTC --> Active_Rolling : Min term passed (nightly)
Active_MTC --> Suspended : Suspend (user)
Active_MTC --> Inactive : Terminate Immediately (user)
Active_MTC --> PFO_Empty : PlatformFeeDate reached
Active_FixedTerm --> Inactive : Service end reached (nightly)
Active_FixedTerm --> Suspended : Suspend (user)
Active_FixedTerm --> PFO_Empty : PlatformFeeDate reached
Active_Rolling --> Active_TerminationNotice : Terminate new term (user)
Active_Rolling --> Suspended : Suspend (user)
Active_Rolling --> Inactive : Terminate Immediately (user)
Active_Rolling --> PFO_Empty : PlatformFeeDate reached
Active_TerminationNotice --> Active_Rolling : Cancel Termination (user)
Active_TerminationNotice --> Inactive : TerminationDate reached
Active_TerminationNotice --> Suspended : Suspend (user)
Active_TerminationNotice --> PFO_Empty : PlatformFeeDate reached
Active_TermCreditsLeft --> Inactive : DeliveryEndDate reached
Active_TermCreditsLeft --> Suspended : Suspend (user)
Active_TermCreditsLeft --> PFO_Empty : PlatformFeeDate reached
Active_Rolling --> Active_TermCreditsLeft : Terminate old term (user)
Active_MTC --> Active_TermCreditsLeft : Terminate old term (user)
Active_FixedTerm --> Active_TermCreditsLeft : Terminate old term (user)
Suspended --> Active_MTC : Unsuspend (manual)
Suspended --> Active_FixedTerm : Unsuspend (manual)
Suspended --> Active_Rolling : Unsuspend (manual)
Suspended --> Active_TerminationNotice : Unsuspend (manual)
Suspended --> Active_TermCreditsLeft : Unsuspend (manual)
PFO_Empty --> PFO_TermNotice : Terminate Platform Only (user)
PFO_Empty --> Active_MTC : PlatformFeeSuspend (user)
PFO_Empty --> Active_Rolling : ReactivateFromPlatformOnly (user)
PFO_TermNotice --> Inactive : TerminationDate reached
Inactive --> ReactOnboarding : NewBookCampaign (reactivate)
Inactive --> Active_TermCreditsLeft : ReactivateLegacyClient (user)
note right of Active_TermCreditsLeft
Old term clients only
(ProtectedLegacy / ExceptionClients)
end note
note right of Active_TerminationNotice
New term clients only
(NetNew / MigratedLegacy)
end note
</pre>
</div>
<!-- Key Data Fields -->
<div class="card">
<h2>Key Data Fields</h2>
<table>
<tr><th>Entity</th><th>Field</th><th>Type</th><th>Purpose</th></tr>
<tr><td>Client</td><td><code>Status</code></td><td>string</td><td>Major lifecycle phase (friendly name from ClientNewStatusEnum)</td></tr>
<tr><td>Client</td><td><code>SubStatus</code></td><td>string</td><td>Contract/operational detail (friendly name from ClientNewSubStatusEnum)</td></tr>
<tr><td>Client</td><td><code>TerminationDate</code></td><td>DateTime?</td><td>When service ends (notice period expiration)</td></tr>
<tr><td>Client</td><td><code>DeliveryEndDate</code></td><td>DateTime?</td><td>Old-term clients: final date credits can be used</td></tr>
<tr><td>Client</td><td><code>PlatformFeeDate</code></td><td>DateTime?</td><td>Scheduled date to transition to PlatformFeeOnly</td></tr>
<tr><td>Client</td><td><code>ClientContractualStatus</code></td><td>int</td><td>NetNew(0), MigratedLegacy(1), ProtectedLegacy(2), ExceptionClients(3)</td></tr>
<tr><td>Client</td><td><code>ContractTermType</code></td><td>string</td><td>"MTC" or "Fixed"</td></tr>
<tr><td>Campaign</td><td><code>Status</code></td><td>string</td><td>New_Status_Onboarding, New_Status_Reactivation_Onboarding, New_Status_Active, New_Status_Inactive</td></tr>
<tr><td>Campaign</td><td><code>DeliveryDate</code></td><td>DateTime?</td><td>Go-live date</td></tr>
<tr><td>Campaign</td><td><code>DeactivationDate</code></td><td>DateTime?</td><td>Scheduled campaign deactivation</td></tr>
<tr><td>CampaignExtended</td><td><code>FinanceApproved</code></td><td>bool?</td><td>Finance sign-off (required for GoLive)</td></tr>
<tr><td>Contract</td><td><code>MinimumTermMonths</code></td><td>int</td><td>Minimum commitment before rolling</td></tr>
</table>
</div>
<!-- Appendix: Quick Reference -->
<div class="card">
<h2>Quick Reference: All Status Transitions</h2>
<table>
<tr><th>From</th><th>To</th><th>Trigger</th><th>Method</th></tr>
<tr><td>(new)</td><td>Onboarding / ""</td><td>New client created</td><td><code>NewBookCampaign</code></td></tr>
<tr><td>Inactive / ""</td><td>ReactivationOnboarding / ""</td><td>Inactive client reactivated</td><td><code>NewBookCampaign</code></td></tr>
<tr><td>TerminationCreditsLeft</td><td>ReactivationOnboarding / ""</td><td>Previous term client rebooked</td><td><code>NewBookCampaign</code></td></tr>
<tr><td>Onboarding / ""</td><td>Active / MTC</td><td>Campaign goes live (MTC)</td><td><code>GoLive</code></td></tr>
<tr><td>Onboarding / ""</td><td>Active / FixedTerm</td><td>Campaign goes live (Fixed)</td><td><code>GoLive</code></td></tr>
<tr><td>ReactivationOnboarding / ""</td><td>Active / MTC</td><td>Reactivation goes live (MTC)</td><td><code>GoLive</code></td></tr>
<tr><td>ReactivationOnboarding / ""</td><td>Active / FixedTerm</td><td>Reactivation goes live (Fixed)</td><td><code>GoLive</code></td></tr>
<tr><td>Onboarding / ""</td><td>Onboarding / Delayed</td><td>60+ days without going live</td><td>Nightly Block 12</td></tr>
<tr><td>Active / MTC</td><td>Active / Rolling</td><td>Min term period passed</td><td>Nightly Block 3</td></tr>
<tr><td>Active / FixedTerm</td><td>Inactive / ""</td><td>Service end date passed</td><td>Nightly Block 4</td></tr>
<tr><td>Active / *</td><td>Active / Termination Notice</td><td>User terminates (new term)</td><td><code>TerminateClient</code></td></tr>
<tr><td>Active / *</td><td>Active / TerminationCreditsLeft</td><td>User terminates (old term)</td><td><code>TerminateClient</code></td></tr>
<tr><td>Active / Termination Notice</td><td>Active / Rolling</td><td>User cancels termination</td><td><code>CancelTermination</code></td></tr>
<tr><td>Active / Termination Notice</td><td>Inactive / ""</td><td>TerminationDate reached (new term)</td><td>Nightly Block 5</td></tr>
<tr><td>Active / TerminationCreditsLeft</td><td>Inactive / ""</td><td>DeliveryEndDate reached (old term)</td><td>Nightly Block 7</td></tr>
<tr><td>Active / *</td><td>Suspended / ""</td><td>User suspends</td><td><code>SuspendClient</code></td></tr>
<tr><td>Active / *</td><td>Inactive / ""</td><td>User terminates immediately</td><td><code>TerminateImmediatelyClient</code></td></tr>
<tr><td>Active / *</td><td>PlatformFeeOnly / ""</td><td>PlatformFeeDate reached</td><td>Nightly Block 8</td></tr>
<tr><td>PlatformFeeOnly / ""</td><td>Active / MTC</td><td>Finance reactivation</td><td><code>PlatformFeeSuspend</code></td></tr>
<tr><td>PlatformFeeOnly / ""</td><td>Active / Rolling</td><td>Finance reactivation</td><td><code>ReactivateFromPlatformOnly</code></td></tr>
<tr><td>PlatformFeeOnly / ""</td><td>Inactive / ""</td><td>Platform terminate</td><td><code>PlatformFeeSuspend</code> (Terminate=true)</td></tr>
<tr><td>PlatformFeeOnly / Termination Notice</td><td>Inactive / ""</td><td>TerminationDate reached</td><td>Nightly Block 9</td></tr>
<tr><td>Inactive / ""</td><td>Active / TerminationCreditsLeft</td><td>Legacy reactivation</td><td><code>ReactivateLegacyClient</code></td></tr>
</table>
</div>
<!-- Active vs Deprecated -->
<div class="card">
<h2>Active vs Deprecated Code Paths</h2>
<table>
<tr><th>Method</th><th>Controller</th><th>Status</th></tr>
<tr><td><code>NewBookCampaign</code></td><td>ClientsController</td><td>✅ Active — primary client/campaign creation</td></tr>
<tr><td><code>GoLive</code></td><td>CampaignController</td><td>✅ Active — Onboarding → Active transition</td></tr>
<tr><td><code>TerminateClient</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>SuspendClient</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>TerminateImmediatelyClient</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>CancelTermination</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>PlatformFeeClient</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>PlatformFeeSuspend</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>ReactivateFromPlatformOnly</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>ReactivateLegacyClient</code></td><td>ClientsController</td><td>✅ Active</td></tr>
<tr><td><code>_RecalculateCampaignsStatus</code></td><td>HangFireJobServiceDB</td><td>✅ Active — nightly Hangfire job</td></tr>
<tr><td><code>EditNew</code></td><td>ClientsController</td><td>⚠️ Deprecated</td></tr>
<tr><td><code>BookCampaign</code></td><td>ClientsController</td><td>❌ Fully commented out</td></tr>
</table>
</pre>