Health

Experience

How the product behaves, key flows and every state a PM or engineer can meet. Behaviour over decoration.

If a screen doesn’t help find sellable upgrades, size sell hours, hide inactive projects, or refresh, it doesn’t belong.

01

Key flows

Three paths cover daily use. Product defines the jobs; this page defines the steps and states.

01 · Arrive

Open dashboard → cache load → worst-first list → filter or search.

02 · Inspect

Expand a card → Runtime / Security / Upgrade (sell hours) → copy or Slack.

03 · Refresh

Hit Refresh → phase strip → snapshot persists → list updates.

02

Flow · Arrive

First paint should answer “what is worst?” without a forced scan.

Step 1

Land on dashboard

Shared chrome: HealthLogo + quiet desktop tagline; work nav Overview · Opportunities · Dashboard · Settings; quiet Brand OS → /brand-os. One dark system. Operator UI English; report EN|NL on Upgrade.

Step 2

Read from cache

List loads from the last snapshot. Freshness lives on Refresh (hover/focus title), not a permanent header clock.

Step 3

Triage

Default sort is worst-first. Filters: All, Needs attention, Healthy, Hidden. Search by name.

Do

Show cached risk immediately so operators can act before Refresh.

Don’t

Don’t block the whole UI on a full GitHub scan on every visit.

03

Flow · Inspect

Expand is on-demand. Collapsed rows stay scannable.

Step 1

Scan the row

Identity, Runtime, Security, chevron. One severity rail on the card edge. Long-past-EOL stacks get a caption, not a wash.

Step 2

Expand

Chevron rotates in place. Panel opens with Runtime, Security, and Upgrade (when EOL applies). Motion is feedback only.

Step 3

Act

Tune rate, effort, portfolio weight (Auto or Custom), copy update report, or share to Slack. Hide sits on Dashboard cards and Opportunities rows (no expand); Unhide via Hidden filter. Method: /estimate-method.

04

Flow · Refresh

Scans are deliberate. Phase strip names the work in progress.

Step 1

Operator clicks Refresh

On the filter strip under the Dashboard title/lead, text-only, same height as search. Hover/focus shows last refreshed time and that a full org scan can take several minutes. Goes busy while scanning.

Step 2

Phases

Repos (GitHub) → Runtime (endoflife.date) → Alerts (Dependabot). Active phase blinks.

Step 3

Settle

Snapshot writes. List may reveal-in. Refresh briefly shows Updated, then settles. Absolute time stays on the Refresh title.

Phase strip (specimen)

ReposRuntimeAlerts

05

States

Every durable UI path needs an explicit state. Colour never carries meaning alone.

Unauthenticated

When

Auth configured and no valid session cookie.

UI

Redirect to /login (pages) or 401 JSON (APIs). Digest cron exempt.

Loading · repos

When

First load or empty cache while fetching the org list.

UI

Loading repositories from GitHub…

Loading · scan

When

Refresh is running runtime + security phases.

UI

Checking runtime and security… Sweep bar + phase strip.

Empty · filter

When

Search or filter matches nothing.

UI

“No projects match” + clear search when a query is set.

Error · fetch

When

API fails or returns non-JSON.

UI

Could not load dashboard + recovery hint (token / restart).

Partial · security

When

Dependabot or posture data unavailable.

UI

Security section explains unavailability; rest of card still usable.

Partial · runtime

When

EOL check unavailable or no runtimes detected.

UI

Runtime section says so plainly; Refresh to retry.

Success · copy / Slack

When

Clipboard or Slack share completes.

UI

Button label → Copied / Posted + one-shot confirm motion.

Restricted · Slack

When

Slack not configured or rate missing.

UI

Share disabled with clear title; never a silent no-op.

Long past EOL

When

EOL age is 2+ years past the milestone.

UI

Caption “Long past EOL” under the title, no field wash.

Healthy portfolio

When

Filter Healthy or clear security + supported runtimes.

UI

Same list chrome; healthy severity colour on status text only.

06

Interaction principles

Same bar as Brand, applied to behaviour.

Risk first

Default order and filters serve triage. Don’t sort the list alphabetically.

Deliberate refresh

Scans cost rate limit. Cache-first; Refresh is an operator choice.

Expand on demand

Detail is progressive. Collapsed rows stay one glance.

Still when idle

Motion only answers work the user caused. Honor prefers-reduced-motion.

Do

Design empty, loading, error, and partial before polish on the happy path.

Don’t

Don’t invent a fifth primary flow or decorative motion that delays status.