Projects Overview — v3 · interactive + decisions

The same three personas, now as a live, re-composing route plus three frames that drive the open §5 questions: the mixed-role case, the PM margin design call, and how the capability flags map to cards.

Source of truth: docs/projects-dashboard-role-differentiation.md §3 + §5 · v1 = static trio · v2 = + charts · v3 = + interaction & decisions
1 Employee / ContractorUnit: a ticket (mine) · Cost: none
2 PM / ManagerUnit: a project (I lead) · Cost: margin health badge
3 Finance / OwnerUnit: the portfolio · Cost: full $ + margin
Live role switcher — one route, three compositions
Projects · Overview
Caps canViewAllcanViewMargin · led projectscanViewCost
Tue · May 13 · 4 projects you lead
Morning, Dan — are your projects on track?
2
At risk
5
Decisions pending
3
Blockers
2
Over-allocated
Delivery health · projects I leadmargin = ratio only, no $
AT
Atlas Replatform
On track · sprint burn 0.96 · 0 blockers
Healthy
NW
Northwind CRM
Timeline slip 6d · critical path · scope +3
Thin
BE
Beacon Mobile
2 blockers · 1 key-person risk · burn 1.21
Underwater
VX
Vertex Data Pipeline
On track · sprint burn 1.02 · 1 blocker
Healthy
Decisions pending5
Approve Northwind scope change
+3 tickets · timeline impact
Today
Reassign Beacon offline sync
owner blocked 2d
Now
Sign off Atlas auth design
ready for review
Queued
Team allocationover-allocated by name
PK
Priya Kapoor
Beacon + Northwind
124%
JL
Jon Lee
Atlas + Vertex
108%
MC
Maya Chen
Atlas
82%
Sprint burndownactive sprint · all led projects
Ideal Actual remaining· tracking ~2 days behind
Cross-app radarkey-person risk · contract expiry
Priya Kapoor — sole owner of Beacon sync layer
key-person risk · no backup assigned
Risk
Contractor MSA — Vertex — expires in 18d
renewal not started
Expiring
Cost framing Margin health badge — ratio only, never $. Surfaces the existing can_view_margin tier (automatic for a lead PM) as a thresholded signal + trend. Raw margin_pct stays on the project Cost tab.
Mixed role — PM here, IC there (§5 Q3)
Projects · Overview Mixed · Sam Rivera
Caps canViewAll canViewMargin · 2 led projects canViewCost
Tue · May 13 · leads 2 · contributes to 1
Morning, Sam — your projects, and your work.
1
Led · at risk
3
Decisions pending
4
My open tasks
1
Blocked on me
Projects I lead PM treatment · margin badge
AT
Atlas Replatform
On track · 0 blockers · 2 decisions
Healthy
NW
Northwind CRM
Timeline slip 6d · scope +3 · 1 decision
Thin
My work IC treatment · no money
BE
Beacon Mobile — Review sync architecture
SYM-4801 · blocked on me · I'm a contributor here
Blocked
AT
Atlas Replatform — Pair on token rotation
SYM-4830 · in progress · due Thu
In progress
BE
Beacon Mobile — Spec offline conflict rules
SYM-4812 · todo · due Mon
Todo
Composition Additive by capability flag, not highest-role. Sam gets the PM block for the projects they lead and the IC block for the one they contribute to — same overview. Margin badge appears only on led projects; never on Beacon, where Sam is a contributor.
PM margin — threshold + ratio-vs-badge (§5 Q1)
Design decision · PM margin signal
Where the bar is setthe open wiring fork
Per-projectBudget.margin_alert_pctShips today
Atlas Replatformalert 20%
Northwind CRMalert 15%
Beacon Mobilealert 25%
Stored on each project's budget; band math already lives in cost.py. Editable by whoever edits the budget — not strictly finance, and there's no org-wide default.
Org default + overrideNet-new
🔒 Finance-owned default · PMs see pass/fail only
Healthy≥ 20%
Thin8–20%
Underwater< 8%
One finance-owned default beside OrgSecuritySettings; per-project margin_alert_pct overrides it. The only model that gives “finance owns the bar, PMs never see the number.”
What the PM seessame data, two treatments
A · Bare ratioleaks the number
Atlas31.4%
Northwind12.0%
Beacon−4.1%
A precise % is one step from cost: with visible hours, a sharp PM can back into a rate.
B · Health badgerecommended
Atlas Healthy
Northwind Thin
Beacon Underwater
A threshold on a non-invertible ratio is itself non-invertible — leaks strictly less, and reads as a delivery signal.
Recommendation Badge + trend on the overview; bare ratio stays on the Cost tab. Triage wants a thresholded signal, not a column to threshold in your head. Two team calls: badge vocabulary (Healthy / Thin / Underwater vs On track / At risk / Negative), and the threshold model — per-project (ships today) vs org default + override (net-new).
Router legend — capability flags → cards
How the route decides · flags → composition
Which cells each composition gets✓ shown · · removed
Cell / cardGateEmpPMFin
My week · My assignmentsalways·
Decisions · Radar · Org capacitycanViewAll·
Delivery health (led projects)canViewAll·
Margin signalcanViewMargin·badgefull $
Worst-margin $ · Burn · FXcanViewCost··
Portfolio margin herocanViewCost··
The three flagsresolved at app load · fail-closed
always Self surfaces — no flag. Every persona's floor. canViewAll = RBAC pr.rollup → cross-project cells (decisions, radar, capacity). canViewMargin = canViewCost OR is_lead → ratio, shown as a badge. Upgrades to full $ when canViewCost is also true. canViewCost = RBAC cost-margin.view / Owner → every absolute $. The clean binary.
Read it as Compose by flags, additively. The persona names are shorthand — the route reads the three booleans and assembles cards. That's why "mixed role" (②) needs no special case: it's just a different combination of the same flags.
Why interactive matters Toggling proves the thesis better than three static frames: it's one route reading flags, re-composing — not three pages. Note the cost framing in the footer steps none → badge → full $.
The decisions this drives ② resolves §5 Q3 (additive, not highest-role). ③ resolves §5 Q1 (badge over ratio, finance-owned threshold). ⑤ shows both are the same mechanism: flags → cards.