← All frames · Frame 04 · flow catalog · route /catalog

Catalog — loading, empty, filtered-empty, error, forbidden

States are contract, not decoration. A catalog that only draws the populated case produces a UI that only handles the populated case. Five states below; each is a distinct thing the API can hand us, and each tells the developer what to do next.

(a) Loading · GET /catalog in flight

Skeletons preserve the populated layout so nothing jumps on arrival. aria-busy="true" on the results region; no spinner-only screen.

(b) Empty · 200 with zero specs — nothing has been harvested yet
📭

No specs have been published yet

The catalog is built from specs that repos publish on merge. Nothing has arrived yet — this is a cold start, not a failure.

Distinct from (c): this is zero specs in the registry. Copy points at the one-step CI action that fixes it, rather than leaving a dead end.

(c) Filtered empty · specs exist, this query matches none
FuzeBI ✕ billing ✕
🔍

No specs match “webhook subscriptions”

22 specs are in the catalog — your filters exclude all of them.

(d) Error · harvest failed / catalog unavailable — degrade honestly
⚠

The catalog could not be refreshed

The last harvest run failed at 08:12 UTC (502 from 3 of 22 sources). You are seeing the last known-good catalog from 2026-09-07 22:40 UTC — it may be out of date, and newly published specs will be missing.

Harvest status
stale catalog Every result below is served from cache and carries the same stale badge — we never present cached data as fresh.
app-registry-service FuzeFront stale cached · 14h old

Total failure (no cache at all) renders the same callout with the list replaced by [data-empty='catalog-unavailable'] and no stale rows.

(e) Forbidden · 403 from Permit — signed in, but not a Developer yet
🔒

Your account doesn't have developer access yet

Reading the catalog needs DevPortalCatalog:read, granted by the Developer role on the platform root organization. Provisioning normally happens on first sign-in; if it hasn't completed, or the capability is still flag-gated for your account, it lands here. We do not silently show a partial catalog — this fails closed.

Test hooks: [data-frame='04-catalog-states'] · [data-state='loading'] · [data-state='empty'] · [data-empty='no-specs'] · [data-state='empty-filtered'] · [data-empty='no-results'] · [data-state='error'] · [data-error='harvest-failed'] · [data-catalog='stale'] · [data-state='forbidden'] · [data-http='403'] · [data-action='retry'] · [data-action='clear-filters'].

Review · devportal approve or reject each flow ↓
homependingApproveReject
catalogpendingApproveReject
spec-viewerpendingApproveReject
playgroundpendingApproveReject
my-accesspendingApproveReject