InfraNotes Project Finance · v0
Welcome
Select a document from the sidebar to read it.
Release 3 Dev 2 Handoff: Project Controls
Routes
GET /api/project-finance/{id}/command-centerGET /api/project-finance/portfolio/overview
No new route or query parameter was added. Both existing read models now include control_summary.
Responses use the existing Project Finance JSON DTO shape; control_summary is embedded in the command-center and portfolio read-model payloads.
Command Center control_summary
Fields:
total_budget,burn_amount,committed_amount,total_revenue,forecast_variance_amountburn_percent,margin_percent,commitment_percent,forecast_variance_percentbilling_risk:unknown,low,medium, orhighunbilled_milestones,overdue_unbilled_milestonescurrency,last_updated
Billing risk rules:
unknown: project has no milestones.high: at least one non-billed/non-cancelled milestone is past due.medium: project has unbilled milestones but none overdue.low: every active milestone is billed.
Portfolio control_summary
Fields:
total_budget,burn_amount,committed_amount,total_revenue,forecast_variance_amountburn_percent,margin_percent,commitment_percent,forecast_variance_percentproject_count,currency,last_updated,mixed_currency_warning
Mixed-currency projects are skipped from single-currency portfolio totals and set mixed_currency_warning=true.
Empty And Degraded States
- Missing money fields are treated as zero in the project currency.
- Empty portfolio returns zero-valued USD control totals.
control_summaryis expected to be present on service-built responses; frontend should still toleratenullfor older backend versions.- Freshness is exposed through
control_summary.last_updated; there is no separate freshness collection for PF control facts in this slice.
Manual-Test Seed
Use the opt-in seed command after selecting the tenant and user that should own manual-test data:
DATABASE_URL="$DATABASE_URL" \
RELEASE3_SEED_TENANT_ID="<tenant-uuid>" \
RELEASE3_SEED_USER_ID="<user-uuid>" \
make seed-release3-control-facts
Optional overrides:
RELEASE3_SEED_PROJECT_ID: use a specific UUID instead of the deterministic per-tenant fixture ID.RELEASE3_SEED_PROJECT_NAME: defaults toRelease 3 Project Controls Fixture.RELEASE3_SEED_TIMEOUT: defaults to15s.
The command is idempotent and tenant-scoped. It sets transaction-local RLS context, upserts one project, two milestones, and one active budget commitment, then prints the seeded project, milestone, and commitment IDs. Expected manual-test state:
- Portfolio overview contains at least one project in
control_summary.project_count. - Command center for the printed project ID shows non-zero budget, burn, commitment, revenue, and forecast-variance fields.
- Command center
control_summary.billing_riskishigh, with two unbilled milestones and one overdue unbilled milestone.
Playwright hint: select the printed project ID from /business/project-finance, then assert /business/project-finance/{id} renders the control cards with non-zero money values and a high billing-risk state.
Verified Follow-Ups
- PF approval self-approval is already fixed and covered by model, service, repository, and handler tests. No code change was made for that item.
- No production/staging seed migration was added because fixture ownership must be explicit per tenant. Use
make seed-release3-control-factsfor staging/manual tenants.