Move sub-surfaces into their sections: billing views get a pill row,
org types a header button. Replace inline IdP handoff copy with an SVG
icon and tooltip, add help icons to dense form rows, and delete the
registry-driven sidebar nav plumbing. Update specs and tests.
- Restructure operator sidebar into a flat task list with indented
children; fold plan topology into plan ladders
- Expand member catalog non-plan section to all published non-tier
products; require recurring Stripe-mapped prices for purchase
- Add operator domains placements and terminal-claims ledger; redirect
/domains to the FedWiki Sites Domains anchor
- Apply canonical vocabulary and chrome/form conventions; migrate seeded
FedWiki Sites display name
Implement the ux-first-run change: a state-derived setup checklist on
/operator/setup with a landing region that recedes once required steps
are done, and empty states that distinguish blocked from empty across
operator and member surfaces. Also add production deployment and
environment reference docs, plus a config-key completeness test.
- Add deployment-name branding to titles, mastheads, and OG tags
- Share one grant delivery-state query with lineage across grants
surfaces
- Show pool status/usage, org owners, and config readiness
- Make billing views projection-aware with recency and sync vocabulary
- Guard FedWiki creation without domains and render route-aware 404s
Replace domain claims with open invoices, show monthly recurring
revenue,
count team organizations, and add more informative trend captions.
Use standard bordered cards and add a README screenshot with reversible
sample-data tooling.
Replace the bare landing panel with a four-region overview: lookup, an
"At a glance" tile row, a unified activity timeline, and a System rail.
The tiles are chosen so each earns its place and each drills into a real
operator section, which makes the row double as navigation for an
operator who arrived without a destination. People carries no link
because there is no persons browse route by design -- persons are reached
by lookup. Grants and provisions share one tile: the headline counts
grants and the caption names the active provisions it was joined against,
so the ledger-versus-delivery distinction is visible on the page instead
of only in the SQL.
Every count degrades independently, like the activity feed already did. A
failed count renders an em dash and says so; it never renders zero, since
an operator reading "0 organizations" off a broken query would draw
exactly the wrong conclusion. This is the surface people reach for when
something is already wrong, so it has to render under partial failure.
The System rail reports every registered provider, not just the
provisioning ones the sidebar lists, and splits the outbox by what an
operator would do about each bucket -- only dead-lettered work, which has
exhausted its retries, gets the alarm.
Headings run H1 to H3 with no skipped levels; the H1-to-H6 pattern of the
older operator pages is deliberately not copied. The stat-tile hover and
focus affordance lives in app.css because Bootstrap cards are containers,
not controls, and it is suppressed under reduced-motion. No new JS, no
inline script, handler or style attribute.
The shell's title and brand no longer name a specific deployment: this is
general-purpose OSS and the operator surface is the first page a stranger
evaluating the project sees.
Covered by operator_overview_render_test.go, which renders the template
without a database and guards the outline, the CSP constraints, the
brand neutrality, the empty states, and the em-dash-not-zero rule.
Replace product-kind branching and direct position writes with enclosed
database functions driven by structural product shape.
Migrate grant and provision data, unify operator issuance, update
subscription and expiry flows, and add migration and integration proofs.
Add an explicit registry with capability hooks for migrations, routes,
workflows, config, and UI assets. Move FedWiki fully and Stripe's
separable
store, workflow, and webhook pieces under internal/integrations.
Drive startup wiring from declarations, including config validation,
secret
file pairs, CSRF exemptions, UI composition, and workflow startup. Move
integration DB roles and grants into their owning migration streams, and
route outbox writes through a shared enqueue helper.
The operator sidebar's Integration group is registry-driven
(OperatorPageData.IntegrationProviders, loaded from integration.providers).
Every operator MPA page builds its page data via buildOperatorPageData, which
populates that slice — except the landing/overview surface, rendered by the
separate OperatorHandler.renderLanding, which built OperatorPageData inline and
never set IntegrationProviders (OperatorHandler had no DB access at all). So
FedWiki showed in the sidebar on every operator page except the overview.
Extract loadIntegrationProvidersNav as a shared free function, give
OperatorHandler a Database field (wired in server.go), and have renderLanding
load the same nav and set CurrentPath. Latent since the M9
provider-extension-contract change made the Integration nav registry-driven.
Register FedWiki and Stripe providers at boot, persist provider
operations, and stamp owned resource keys.
Rename the FedWiki entitlement key from `sites` to `fedwiki_sites`
and drive the operator integration nav from provisioning providers.
Resolve lookup terms for person/org on the operator landing
surface. POST /operator/lookup calls identity.LookupPersons (email-exact
first, else name ILIKE) then falls back to org slug lookup.
Use 303 redirects for unique person/org matches; ambiguous or no-match
results are re-rendered inline on the landing page via renderLanding.
Delete internal/embeds/static/operator-tabs.js and its include in
operator.html. Replace data-switch-tab triggers with plain /operator
links.
Retire legacy GET /partials/operator/* pane loaders and remove the
tabstrip
branch in templates; collapse dispatch to BodyTemplate/landing. Simplify
GetOperatorPage to 301 legacy ?tab bookmarks and update tests/openspec.
Add GetPersonPage handler and operator_person_detail.html
Retire the legacy /partials/operator/users list and remove the
People tab/pane from operator.html. Update legacyTabRedirects so
tab=people redirects to /operator
Add operator_billing.html wrapper and four GetBilling*Page handlers.
Extract loadBilling*/loadSubscriptions*/loadInvoices*/loadPaymentsData
helpers used by both legacy partial endpoints and the new pages.
Register new /operator/billing/* routes and add legacyTabRedirects
entry.
Add a no-op renderBody stub in fedwiki_partials to satisfy template
parse.
Register GET /operator/org-types, /operator/products,
/operator/entitlement-sets and /operator/plan-ladders
Extract load*PageData helpers and reuse them in GetXPage handlers.
Update operator template nav to use ActiveCapability and direct routes,
adjust legacyTabRedirects, and mark tasks in openspec
Register GET /operator/fedwiki-sites and add GetFedWikiSitesPage.
Reuse the existing operator_sites.html partial and set page
ActiveCapability/IAPosition. Update nav template link and
legacyTabRedirects, and mark the task done in the openspec tasks list.
Strip grant create/revoke UI from operator_grants.html; extract
loadGrantsListData to centralize grants hydration. Add GetGrantsPage
handler and register GET /operator/grants, update legacyTabRedirects,
trim renderGrantsPage, and update the tasks checklist.
Introduce a renderBody template func to dispatch dynamic body partials
from operator.html (real implementation in NewOperatorPartialsHandler).
Add GetOrganizationsPage and GetOrganizationDetailPage to render MPA
pages by setting BodyTemplate/BodyData and ActiveCapability on the
OperatorPageData. Refactor enrollment hydration into
loadOrgEnrollmentData,
update templates to use /operator/organizations links and target
Add IA-position meta and OperatorPageData fields (Tab, ShowLanding,
IAPosition). Add .operator-ia-sidebar min-width to stabilize sidebar
label
layout. Add smoke test to render both landing and legacy tabstrip
branches.
Add openspec archive, design, proposal, spec and task docs for
operator-mpa-conversion.
Introduce SafeTemplates.Render to execute templates into a buffer and
prevent partial HTML on errors. Replace direct ExecuteTemplate calls in
partial handlers and add a make lint-templates target to catch bypasses.
Update operator sites template/view model to use OwnerOrgName. Guard the
FedWiki sync by skipping inserts when DefaultWorkspaceID is empty and
scope deletes to the configured default workspace only.