Projects Tab — Feature Guide


What it's for
The Projects tab is the programme view: every project the team is running side-by-side, plus the team allocation matrix that splits people across them, the cross-project dependency declarations that propagate slips between them, and the scenario builder that lets the user model "what if" plans across the whole portfolio.
Five things live in one tab: register a new project, edit per-project settings inline, see a portfolio dashboard with per-project health, declare and watch cross-project blocking dependencies, and queue mutations into named scenarios for comparison. When the user adjusts scope on one project or moves a person to another, the engine immediately re-derives forecast dates, slack days, utilisation, and dependency violations across the whole portfolio.
The audience is programme managers, portfolio leads, and engineering directors. A single project's view is on the Dashboard; this is where multiple projects meet.
Programme model
A programme is a set of related projects plus a shared team and the allocations between them. Each programme contains:
- Projects — registered with a Jira board ID and a JQL filter that defines membership.
- Team members — pool of people with base capacity (hours per week, points per sprint) drawn from the Team & Capacity tab.
- Allocations — per (member × project) entries stored as percent of capacity:
hoursAllocPctandpointsAllocPct. Each unit is an independent percent (a member can be 50% on hours and 60% on points for the same project, intentionally). AbsolutehoursAllocated/pointsAllocatedare written alongside during the transition for legacy readers; percent is the source of truth and survives capacity changes without rebalancing. - Dependencies — declarative project A blocks project B statements.
- Draft mutations — a working set of pending what-if changes shown inline as before → after on each affected row, with per-mutation explanations and an
× Revertbutton per step. Mutations are not committed to Jira; they are local-only modelling.
Demo / regression mode loads a fixture programme containing eight projects: DEMO, DEMOHR, AUTH, PAY, MOB, DATA, plus internal AUTOLEVEL and NOSPR.
Toolbar / header
- + Add Project — opens the project registration form.
- (There is no global Save / Reset button.) Pending mutations are reverted individually with the
× Revertbutton next to each per-mutation explanation. Saved scenarios were removed; what remains is the live draft against the program store.
Add Project form

Required fields:
- Project Key — short uppercase id (e.g., AUTH).
- Board ID — Jira board id; the engine fetches sprints and issues from this board.
- JQL Filter — Jira-Query-Language filter selecting the issues that belong to the project.
Optional settings:
- Name — human-readable (defaults to the key).
- Target Date — used to compute
slack = target − forecast. - Estimation Mode — Story Points or Time (hours).
- Sprint Mode — on by default; when off, the project is treated as a continuous backlog.
- Sprint Capacity — points / hours per sprint default.
- Sprint Length — 1 / 2 / 3 / 4 weeks.
- Velocity Lookback — number of sprints averaged for rolling velocity (3 / 5 / 8 / 10).
- Capacity Mode — Sprint limit, Per-user capacity, or Auto (velocity).
Add Project persists the new entry into the programme store and triggers a fetch.
Edit / Delete
Each project row has Edit and Delete buttons. Edit lets the user change any setting; only the project key is required so settings can be edited even when board ID or JQL are missing. Delete opens a ConfirmDialog; on confirm, the engine removes the project and cleans up its allocations and dependencies.
Per-mutation explanations
When mutations exist from inline edits (scope cell, target date, team +/−), each one renders as a row below the affected project showing a plain-language explanation of what changed and the cumulative delta vs the baseline. Each row carries a × Revert button that removes only that step from the draft. There is no global save or reset; reverting every mutation returns the view to the baseline.
Portfolio dashboard table
One row per project. Columns:
- Project — uppercase key + name. A red ⚠ dep badge appears when the project has an active dependency violation.
- Health — coloured pill: Healthy (green), At Risk (orange), Critical (red). Hovering shows the exact reason.
- Progress — bar + percentage of issues complete (done estimate ÷ total estimate).
- Forecast — projected completion date or Complete when no work remains.
- Target — editable inline; click to type or pick from the calendar widget. Pending mutations show as
before → afteron hover. - Slack — calendar days between forecast and target. Green when ≥ 0, red when negative.
- Scope — total estimate excluding done. Editable inline; entering a different number records an addScope or removeScope mutation depending on direction.
- Utilisation — % of active sprint capacity committed; green < 85, amber 85–100, red > 100.
- Team — count of active team members. + / − buttons append addHeadcount / removeHeadcount mutations.
- Alerts — N blockers · M warnings counts from the alerts engine; Clear when zero.
- Estimation — % of active issues with an estimate. Green ≥ 90; orange when ≥ 10% are unestimated.
- Actions — Edit, Delete.
When mutations are pending, affected cells render in a slightly orange background; hovering shows the before / after.
Programme rollup row
When at least two projects exist, a footer row sums the portfolio:
- Programme (N projects) — label.
- Health — Critical if any is critical, At Risk if any is at-risk, else Healthy.
- Average Progress.
- Total Scope — sum across projects, with unit suffix only if every project shares the same estimation mode.
- Total Team — count of unique active members across projects.
- Alerts — aggregate blockers and warnings.
Project drilldown
Clicking a project row inside the dashboard opens an inline detail view with stat cards (Progress, Forecast, Slack, Utilisation), a longer progress bar, an alerts section, and a data-quality block listing unestimated %, dependency violations, and the dependency name with day-delta.
A Projects breadcrumb at the top returns to the dashboard.
Mutation types
The scenario builder supports six mutation types. Three change allocation, three change work / deadline:
- moveCapacity {from, to, memberName, newPct} — move one head from the source project to the destination. Both projects' utilisation and remaining-work duration scale by the team-size ratio; both health values re-derive.
- addHeadcount {projectKey, name, hoursPerWeek, startOffset} — adds one headcount to the project; remaining work compresses by the team-size ratio.
- removeHeadcount {projectKey} — opposite direction; remaining work stretches.
- addScope {projectKey, points} — increases remaining points; forecast pushes out by
points ÷ avgVelocity × 14days; slack drops accordingly. - removeScope {projectKey, points} — opposite direction.
- shiftDeadline {projectKey, newDate} — moves the target date; slack re-derives, forecast unchanged.
After any mutation the engine re-derives health from (slackDays, errorCount, warningCount, utilization) so health and slack and forecast always agree.
Team Allocation Matrix
Below the project table, a members × projects grid. Internal projects (AUTOLEVEL, NOSPR) are hidden by MATRIX_HIDDEN_PROJECT_KEYS.

- Rows — every registered team member.
- Columns — every visible project.
- Capacity column — base capacity per member: hours/week and points/sprint.
- Status column — running percent totals across visible projects, Σ Hrs: X% / 100% and Σ Pts: Y% / 100%. When over 100% the row is red with an "over by N%" callout; both units fire over-allocation independently.
Cell editing
Each cell shows two stacked inputs:
- Percent input — the share of the member's capacity dedicated to that project (e.g., 50). The unit matches the project's estimation mode (
pointsAllocPctfor points-mode projects,hoursAllocPctfor time-mode). - Computed "= X pts/hrs" line — the absolute value the percent works out to at the member's current capacity. Also editable: type 8 in DEMO's "= X pts" box and the percent recomputes to 80% (assuming the member's
pointsPerSprintis 10).
Editing and blurring either field saves immediately to the program store. Storage is percent; the absolute is a derived editor. Toggling a project's estimation mode never loses data — both unit percents are persisted independently.
Over-allocation
The matrix does not clamp totals. Over-allocation is preserved verbatim and surfaced through the Status column's red text, so the cost of putting Sarah on five projects is visible rather than silently capped. Forecasts respect the actual loaded allocation, so the consequences of over-allocation show up in the per-project utilisation and forecast columns.
Capacity-change live update
Changing a member's hoursPerWeek or pointsPerSprint (in the Team & Capacity tab) immediately updates every "= X" display in this matrix and the Alloc popover, without re-entering any percents. A 60% allocation stays 60% across capacity changes — that's the intent the planner expressed, not the absolute number.
Critical Chain panel
A collapsible Critical Chain section sits below the project table and shows the longest, most-constrained path of work that determines the programme end date. It is the same engine documented in ALGORITHMS section 7 (Critical Chain) — chain confidence, per-resource summaries, feeding paths, due-date risks, epic grouping, and team-pool overflow. When in Program All mode the chain is computed across every registered project; otherwise it is filtered to the selected project. The panel can also auto-fire its AI box once per chain (see ALGORITHMS section 17 — Critical Chain AI Box) when an API key is configured.
Cross-Project Dependencies
A list and an Add form below the matrix.
Dependency violations
When at least one declared dependency has the upstream forecast past the downstream target, a red alert box lists each violation: PROJ_A is blocked by PROJ_B — upstream finishes N days after PROJ_A's target.
Declared dependencies
A list of every upstream → downstream statement with optional description and a Remove button.
Add dependency form
Three controls:
- Upstream (blocks) — dropdown of registered project keys.
- Downstream (blocked by) — dropdown.
- Description — optional human-readable reason.
Plus a + Add button.
Cascade rules
When a dependency violation fires:
- The downstream project gets a
_dependencyViolation = {blockedBy, upstreamEnd, daysBlocked}flag. - Its health is raised to At Risk if it was Healthy; left as Critical if already worse.
- If the upstream project itself has negative slack, the downstream's slack becomes
min(downstream, downstream + upstream)so the late chain propagates: a 10-day-late upstream eats 10 days off the downstream's slack.
Removing a dependency clears the violation flag in the next analysis pass.
Empty / loading / error states
- No projects registered — table is hidden; a hint reads Register a project to begin.
- Loading — sprints and issues stream in via
useMultiProjectData; a spinner is shown when the underlying fetch is in flight. - Demo mode — fixture loaded; the program registration is held in the app-data store under
pc_demo_program_v1(the in-memory demo cache, kept separate from the realpc_program_v1). Draft mutations are in-memory and reset on tab unmount.
Cross-cutting modes
- Estimation mode — when every project shares one mode, the rollup uses that unit; when they differ, the unit suffix is dropped from the rollup Total Scope cell to avoid mixing units.
- Sprint mode on/off — per-project; the Capacity Mode options shift accordingly.
- Programs / programAllMode —
programAllMode = trueaggregates every project at once; the Critical Chain panel and other views read this flag to know whether to filter by selected project.
How the numbers are computed
- Forecast —
today + (remaining ÷ avgVelocity) × sprintLengthDays. Velocity is the rolling average overvelocityLookbackrecent closed sprints; remaining is the sum of estimates on non-done issues. - Slack —
target − forecastin days. Complete projects get an arbitrarily large slack of 999 days. Negative when forecast is past target. - Health — Critical when slack < −14 days; At Risk when slack < 0 or utilisation > 120%; Healthy otherwise. Alerts do not influence health (they have their own column).
- Utilisation —
committed ÷ sprintCapacity × 100. After a moveCapacity / addHeadcount / removeHeadcount mutation, utilisation scales by the team-size ratio. - Cascade slack propagation — when upstream slack is negative, downstream slack =
min(downstream, downstream + upstream). See ALGORITHMS section 18 (Allocation in Scenarios and Cascades).
Effects on other parts of the app
- The Team Allocation Matrix here and the allocation popover in Team & Capacity write to the same store. Edits in either place propagate everywhere.
- Selecting a project in the main app's project picker filters every other tab to that project; selecting All projects sets
programAllMode = trueand the Critical Chain panel switches to programme-aware mode. - Mutations are not committed to Jira — they are local-only modelling. The current draft lives in component state; only the registered programme (projects + allocations + dependencies) is persisted to the app's Forge storage under
pc_program_v1(scoped to your Atlassian account, removed on uninstall). - The cascade rules feed the per-project warning badges shown across the Sprints and Critical Chain panels.
- Forecast and slack changes from mutations propagate to the Dashboard's Top Open Risks widget through the Deadline at risk detector.