InfraForge Docs

InfraNotes Project Finance · v0

Welcome

Select a document from the sidebar to read it.

Project Finance — Release 0 Canonical API

  • Jira: INFT-72
  • Source of truth: this file. Frozen contract for the Release 0 frontend cutover.
  • Owner: infranotes-project-finance
  • Gateway entitlements: business_financial, business_accounting
  • Tenant-aware: yes, enforced at the data layer via RLS
  • Idempotency-Key required on POST/PUT/PATCH/DELETE per gateway manifest

Authentication contract

  • Issuer: https://iam.staging.infranotes.io (staging)
  • Audience: infranotes-project-finance
  • JWKS: https://iam.staging.infranotes.io/.well-known/jwks.json
  • Trust profile: B (gateway-forwarded headers in production, direct JWT validation in local dev)
  • Canonical IAM roles[] are translated by mapCoreRoleToFinanceRole to PF native roles. Coverage:
IAM role-template PF role Project access scope
tenant_admin system_admin All projects
admin system_admin All projects
finance_manager project_manager Assigned projects (RLS)
manager project_manager Assigned projects (RLS)
accountant finance_analyst All projects (read-only)
analyst finance_analyst All projects (read-only)
user team_member Assigned projects (RLS)
premium team_member Assigned projects (RLS)
readonly client_viewer Assigned projects (RLS)

Read-model endpoints (canonical Release 0 surface)

These are the endpoints the frontend should consume to populate project-finance pages without browser-side multi-service stitching.

Project CRUD

  • POST /api/project-finance — create project (Idempotency-Key required)
  • GET /api/project-finance — list, paginated
  • GET /api/project-finance/{id} — single project
  • PUT /api/project-finance/{id} — update (Idempotency-Key required)
  • DELETE /api/project-finance/{id} — delete (Idempotency-Key required)

Project read models

  • GET /api/project-finance/{id}/command-center — command-center workspace data
  • GET /api/project-finance/{id}/billing — billing workspace, invoice resolution server-side
  • GET /api/project-finance/{id}/operations — operations workspace, team resolution server-side. Degrades gracefully when the upstream Infra_Notes available-users call fails: returns the read model with available_users: [], team members without name/email enrichment, degraded: true, and degraded_sources: ["infra_notes_available_team_users"], so the workspace stays usable while Infra_Notes service-to-service auth is being hardened (Profile B/C cutover). The degradation is logged at WARN with project_finance_id, tenant_id, and the upstream error.
  • GET /api/project-finance/{id}/activity — server-filtered activity feed (limit, offset)

Portfolio read models

  • GET /api/project-finance/portfolio/overview — portfolio overview
  • GET /api/project-finance/portfolio/dashboard — supports filters: status, billing_model, currency, client, team; includes dashboard source freshness metadata in freshness, degraded, and degraded_reasons
  • GET /api/project-finance/portfolio/capacity — capacity rollups
  • GET /api/project-finance/migration-validation/reconciliation — Release 5 reconciliation facts for portfolio controls and milestone billing validation

Dashboard read model freshness

  • GET /api/project-finance/project/{id}/dashboard and GET /api/project-finance/portfolio/dashboard expose first-class freshness metadata.
  • Freshness rows include source, state, observed_count, latest_at, and age_seconds.
  • state is fresh, stale, or missing; sources become stale after 72 hours.
  • degraded=true means one or more dashboard sources are stale or missing; use degraded_reasons for machine-readable details in <source>:<state> form.

Migration-validation reconciliation

  • GET /api/project-finance/migration-validation/reconciliation exposes data.facts for portfolio_projects and milestones.
  • Money facts include exact amount_minor, major-unit string amount, and currency.
  • Count facts include integer count.
  • Freshness uses the same fresh, stale, and missing semantics as dashboard freshness. Mixed-currency portfolio totals set degraded=true with portfolio_projects:mixed_currency.

Analytics (PF-owned)

  • GET /api/analytics/portfolio — owner: PF (post-INFT-80 manifest correction)
  • POST /api/analytics/projects/{id}/forecast
  • GET /api/analytics/projects/{id}/health

Compliance and export

  • GET /api/compliance/reports/audit-trail
  • GET /api/compliance/reports/gdpr
  • GET /api/compliance/reports/sox-404
  • POST /api/export

Frontend handoff guidance

  • The browser must not stitch project finance pages by calling Infra_Notes (invoices) and infranotes-financial-intelligence (budgets) directly. Use the read-model endpoints above.
  • The deprecated route families /api/phases/**, /api/team/**, /api/scope-changes/**, /api/audit-trail/**, /api/milestones/**, /api/cost-centers/**, /api/approvals/** are scheduled to sunset on 2026-07-31 per the gateway ownership manifest. Migrate consumers under /api/project-finance/** before that date.

Out of scope for Release 0

  • Vertical-specific overlays (per Jira INFT-72: not before generic project-finance core is excellent).
  • Vendor, payroll, asset, or core-ledger feature breadth — those stay in their own service tickets.
  • Frontend implementation. The PF role of this document is to freeze the contract; the FE migration off legacy paths happens under INFT-66.

Acceptance evidence

Evidence supporting the Release 0 acceptance gates is appended to TEST_LOG.md and the workspace RELEASE_0_HANDOFF_SUMMARY.md. Required gate checks:

  • canonical IAM roles accountant and analyst resolve to a defined PF role and pass RBAC checks (regression of finance_analyst undefined-role bug)
  • one authenticated happy path against a read-model endpoint via the gateway
  • one negative path: missing token returns 401
  • one negative path: missing Idempotency-Key on a write returns 428