Financials lives under Experimental while the Core port is verified. Access requires the experimental sidebar flag plus the financial permission/ACL layers below.
The section reads tenant-scoped Core tables for Xero actuals, native and HubSpot-synced opportunity pipeline, contract billing schedules, scheduled billing items, bank balances, targets, planned events, report recipients, and financial integration metadata.
The live Project Works integration is retired. Historical payment schedules, source labels, mappings, and disabled configuration records remain available for reference, but Core no longer connects to Project Works or runs its contract and resourcing syncs. Native Core contracts and payment schedules are the active planning source.
Forecast Readiness is the financial-admin checklist for deciding whether projected profit is dependable. It combines Xero and HubSpot freshness, contract schedule gaps, missing billable users, renewal matches, Xero contact matches, unclassified opportunities, expired active contracts, and overlapping renewal contracts (an old and a renewed contract both active with the same billing unit types, which would double-count the overlap) on one page. Missing schedules open as editable drafts that show the calculation source and total before anything is saved. The embedded table initially shows clear schedule and single-choice billable-item fixes; select Show all issues to include rows that need judgment. Each row's actions are grouped in its actions menu, and successful billable-item fixes disappear immediately while the refreshed checklist catches up. Specialized contract and integration pages remain available for roles without broader Financials access.
The Financials overview includes a Needs attention card for review work that is still outstanding. It links directly to HubSpot renewal matches and Xero contact matches. Use Financials → Contracts to match HubSpot renewal deals to the Core contracts they extend. If the Core contract is missing, upload the signed contract file from the renewal match; Core drafts the contract details and payment schedule for review, attaches the file to the new contract, and lets you rate the extraction. The same import also drafts the contracted service scope — services that are included, excluded, conditional, or require escalation — with the supporting contract language, so you can edit and approve it before the contract is created. Approved exclusions and escalation clauses then warn technicians on tickets when work looks out of scope; technicians can escalate to managers and billing admins or proceed with a recorded reason, and every response is kept in an audit trail. Use Financials → Settings → Xero matches to connect Core contracts to Xero contacts or ignore matches that do not apply. The Xero contact matching page shows the Core contract, candidate Xero contact details, recent invoice evidence, and confirmed links grouped by Xero contact; use the confirmed links section to change a wrong match or clear one contract at a time so it returns to review. Billing Health highlights missing schedules, low scheduled revenue, and missing billable users; financial admins can review and edit a proposed schedule before saving it, apply clear billable-item fixes, or ask Financial Assistant to help with the same checks. The reconciliation queue also surfaces ticket-driven per-contact billing reviews when contact activity, onboarding, or offboarding suggests a billable contact should be assigned, moved, or removed.
Access Model
Owners keep the coarse financial:* app permissions by default. Non-owner users need explicit financial_user_access rows for the relevant financials:* access keys. Platform admins and billing admins do not automatically receive CFO access.
Salary-like data has two stores. employee_sensitive_data and employee_sensitive_data_history hold named sensitive fields such as annual salary and loaded monthly cost; RLS requires sensitive_data:read or a matching sensitive_data_access grant. technician_compensation_history holds structured, effective-dated pay data used by resourcing and rate resolution; access is gated by owner-level financial:read, an explicit financials:compensation grant, or a matching salary grant for that person. Financial admins can grant salary access for all people or selected people from Financials → Settings → Team. The same page has a numbered capacity and compensation form with one save action; successful saves confirm that compensation reached salary history. Salary viewers can also see the exact people who can view each salary they can see. Only financial compensation access can create or edit structured compensation history.
Company-wide financial surfaces use financial_user_access:
| Access key | Unlocks |
|---|---|
financials:overview | Dashboard summaries, targets, non-sensitive account classifications, app settings, assistant overview tools |
financials:revenue | Revenue dashboard, HubSpot deals/opportunities, contract revenue schedules, T&M projections, renewal assumptions, renewal matching, Xero contact matching |
financials:expenses | Expense P&L detail and ordinary expense actuals |
financials:cash | Cash-flow views and aggregate bank balance summaries |
financials:bank_accounts | Bank-account-level balances, bank monthly activity, bank transactions, bank transaction lines |
financials:payroll | Payroll actuals and payroll forecast inputs |
financials:compensation | All resource compensation rollups and allocation-sensitive resource planning data |
financials:owner_draw | Owner draw account classifications and owner-draw account detail |
financials:admin is an override for other company-wide financial access keys, but it is still explicit. It does not replace sensitive_data_access for per-person salary grants.
Financials navigation and overview modules only show reports when the user has the full access-key combination for that report.
Pages And Tools
/financials requires overview, cash, bank-account, revenue, expense, payroll,
compensation, and sensitive-accounting access because its summary combines all
of those inputs. The overview forecast combines posted month-to-date revenue, remaining contract
schedules, weighted pipeline and renewal revenue, and variable revenue pacing
for T&M or other non-scheduled work. It rolls open HubSpot pipeline forward when
close dates slip, time-weights deals still expected this month, and explains the
forecast breakdown. When contract schedules imply more revenue than any recent
closed month supports — for example after a bulk schedule import — the forecast
caps projected revenue at the three-month actual average, unless posted MTD
revenue or supported pace is already higher, and says so in the breakdown.
This keeps one unusually strong prior month or an inflated unbilled schedule
from overstating projected profit.
Financial admins can set separate HubSpot forecast-category percentages for new deals and renewals from Financials → Settings → General. Renewal Commit starts at 100% so committed renewal revenue stays fully represented, while Best Case, Pipeline, and other categories can be tuned independently. Changes apply after the next HubSpot sync. The line-of-business renewal percentage on Projections remains a fallback only when a matched renewal has no usable HubSpot category.
Hourly (time-and-materials) contracts can be set to a dynamic value instead of a fixed total. Core estimates the contract's value from the hours already tracked plus the hours resourced ahead across the projects it covers, and updates it as work is logged and scheduled. In the forecast this appears as a separate, variable usage estimate — added to the revenue outlook and shown faintly in the breakdown, but never counted as committed revenue, so it cannot raise the recent-actuals cap. Forecast Readiness flags any dynamic contract whose hours have no resolvable bill rate, since those hours contribute nothing until a rate is set.
/financials/revenue, /financials/contracts, contract revenue schedules, opportunities, forecast probability, renewal probability, renewal matching, and Xero contact matching require financials:revenue.
/financials/readiness requires revenue and compensation access so it can flag
contracts missing operating units and staff included in forecasts who are
missing compensation or a complete operating-unit allocation.
/financials/profit is visible with financials:revenue. Revenue-only viewers
receive completed-month aggregate Profit by LOB totals without raw expense
accounts or individual compensation. Current-month detail and
compensation-backed forecasts require financials:expenses,
financials:payroll, financials:compensation, and
financials:accounting_sensitive as well.
/financials/net-income requires financials:revenue, financials:expenses,
financials:payroll, financials:compensation, and
financials:accounting_sensitive so its expense and net-income totals cannot
silently exclude restricted accounts, payroll actuals, or compensation-based
forecast inputs.
The Profit dashboard explains month-to-month fully loaded net income changes, including the largest revenue, expense, overhead, planned-event, and line-of-business drivers.
For the in-progress month, the company forecast is the accounting control total and Profit by LOB allocates it with cent-exact rounding. Daily forecast snapshots sum those same reconciled unit rows for every projected month. Line-of-business revenue, expenses, and net income therefore add back exactly to each saved company snapshot.
/financials/cash requires financials:cash, financials:bank_accounts,
financials:revenue, financials:expenses, financials:payroll,
financials:compensation, and financials:accounting_sensitive access because it
combines account-level cash with trailing and forecast P&L totals.
/financials/settings and all integration/admin mutations require financials:admin.
Financial questions go through Core AI (sidebar / header Core AI). Financial tools only appear when the workspace has experimental financials and the signed-in user has the matching financial access grants. Every tool runs as that user under RLS and re-checks can_access_financial_data before returning results — salary, compensation line items, and other sensitive settings stay withheld unless the grant allows, and tools return aggregates rather than inventing person-level pay. Contract import from a signed PDF remains a human UI flow under Contracts, not an AI auto-apply path.
Migration Notes
The admin-data export/import harness preserves curated financial-dashboard settings: LOBs, staff/resource rows, compensation history, allocations, contracts, billing health dismissals, targets, planned events, probabilities, report recipients, account classifications, run-rate settings, and owner-draw grants.
Source Xero and HubSpot mirror tables are intentionally re-synced after cutover. Forecast snapshots, sync snapshots, report logs, AI history, and old connection secrets are not imported.
Before any production import, run bun run financials:export-admin-data, store the export with the old-dashboard backup record, then run DRY_RUN=1 bun run financials:import-admin-data against Core. The non-dry-run production import must wait until the matching Core code and schemas are deployed and the SaaS owner explicitly approves the restore.
The internal production checklist lives in docs/financials/cutover-runbook.md. The deeper security/import reference lives in docs/financials/security-and-import.md.
The standalone financial-dashboard changelog history is preserved in docs/financials/CHANGELOG.md.