Contract-freeze · UX approval · app-registry 1.2.0

App Builder & Ownership · Approval Frames

Three capabilities from docs/planning/app-builder-and-ownership.md, in four flows: a Build your application card that starts a FuzeAgent session which develops and deploys an app into your personal workspace or the active org; an org-held, user-originated ownership block (the org owns the app, its creator is the contact while a member); and the marketplace publish request with its platform-admin review queue. All four ship dark behind default-OFF release flags. Approve per flow.

Flow 1 · Build entry · route /applications · BuildEntryFlow · fuzefront.apps.build-with-agent
Frame (a) · /applications

“Build your application” card

Sibling of the dashed Add card. Flag OFF ⇒ not rendered; flag resolving ⇒ treated as OFF; in-flight session ⇒ resume shortcut.

Flow 2 · Build session · route /applications/build[/:sessionId] · BuildSessionFlow · fuzefront.apps.build-with-agent
Frame (b) · /applications/build

Describe the app

Where (personal / active org), name, brief ≤ 4000. Validation and submitting states.

Frame (c) · /applications/build/:sessionId

Session in progress

launching → building → deploying → deployed, FuzeAgent deep link (same-origin only), cancel confirm, loading.

Frame (d) · /applications/build[/:sessionId]

Outcomes, failures & refusals

Deployed (tile appears), failed, cancelled, 502 launch failed, 503 builder_unavailable / feature_disabled, 403, 409, 429, 404.

Flow 3 · Creator ownership · app detail · AppOwnershipCard · fuzefront.apps.creator-ownership
Frame (e) · /apps/:appId

Owner & creator

Org as owner; creator name + contact while a member, “former member” with no contact after; personal; not recorded; flag OFF.

Flow 4 · Marketplace publish · app detail + /admin/marketplace-requests · MarketplacePublishFlow · fuzefront.apps.marketplace-publishing
Frame (f) · /apps/:appId

Publish to marketplace

Request with notes; pending; approved; rejected with reason + resubmit; 409 already pending / published; read-only.

Frame (g) · /admin/marketplace-requests

Admin review queue

Platform admins: approve, or reject with a required reason; 409 NOT_PENDING race; empty, loading, error, 403.

Build inventory

Approving a flow approves its component/package plan and its contract binding. Mirrored in manifest.json → build. Everything new lands in one package, @fuzefront/app-builder-ui; the shell only mounts it.

BuildEntryFlow

route /applications · flag fuzefront.apps.build-with-agent · approved: false
contract: @fuzefront/app-registry-client (REAL) — GET /build-sessions (resume shortcut) · paths: packages/app-builder-ui/src/entry/** + the one-line mount in frontend/src/pages/ApplicationsPage.tsx
BuildAppCardResumeBuildCard

BuildSessionFlow

route /applications/build, /applications/build/:sessionId · flag fuzefront.apps.build-with-agent · approved: false
contract: @fuzefront/app-registry-client (REAL) — POST /build-sessions, GET /build-sessions/{id}, POST /build-sessions/{id}/cancel
BuildAppFormBuildTargetPickerBriefFieldBuildSessionView BuildProgressStepperBuildStatusPillAgentSessionLink CancelBuildDialogBuildOutcomeBannerBuildErrorBanner

AppOwnershipCard

mounted in app detail (/apps/:appId) · flag fuzefront.apps.creator-ownership · approved: false
contract: @fuzefront/app-registry-client (REAL) — GET /apps/{slug} → App.organizationId, App.creator · AppCreator.contactEmail ANTICIPATED
AppOwnershipCardOwnerRowCreatorRowFormerMemberNotice

MarketplacePublishFlow

app detail (/apps/:appId) + /admin/marketplace-requests · flag fuzefront.apps.marketplace-publishing · approved: false
contract: @fuzefront/app-registry-client (REAL) — GET /apps/{slug}/publication, POST …/publication-requests[/approve|/reject] · queue listing ANTICIPATED (GET /publication-requests)
PublicationPanelPublicationTierBadgePublicationRequestDialog PublicationStatusBannerPublicationReviewQueueReviewQueueRow ApprovePublicationDialogRejectPublicationDialog

npm packages

  • @fuzefront/app-builder-ui (new — private, GitHub Packages, restricted)
  • @fuzefront/app-registry-client (existing — regenerate from 1.2.0)
  • @fuzefront/feature-flags (existing — the three release flags)

DS primitives needed (foundation PR, frontend-engineer)

  • Stepper — ordered progress with done/current/failed/cancelled
  • RadioCardGroup — choice cards (build target)
  • TextareaWithCounter — length-limited text (brief, notes, reason)
  • StatusPill / Dialog / DataTable — shared with app-management
● Awaiting approval — per flow (Flow 1 / 2 / 3 / 4)

Design system: @fuzefront/design-system (fuse-seam, tokens only). Plan: docs/planning/app-builder-and-ownership.md. Contract: services/app-registry-service/openapi.yaml (app-registry 1.2.0, merged in #1261).
Coordination with app-management. frontend/src/pages/ApplicationsPage.tsx is also claimed by app-management (whose flows are unapproved). build-entry claims that file too, so approving build-entry unblocks the card mount there; the card itself lives in packages/app-builder-ui/src/entry/**, keeping the page edit to one import + one element. Flows 3 and 4 mount inside app detail, which app-management/app-detail owns; they ship as self-contained components in this package and claim only their own package paths.
Commissioned by approval (contract amendments for contract-designer): AppCreator.contactEmail (flow 3) and GET /publication-requests?status=pending (flow 4).
Authz is fail-closed. Controls render only when the caller can use them; 403 is shown in place, only 401 re-authenticates. Approve per flow with the in-frame control, or reply @claude approve <flow> / @claude reject: <reason>.

Review · app-builder approve or reject each flow ↓
build-entrypendingApproveReject
build-sessionpendingApproveReject
creator-ownershippendingApproveReject
marketplace-publishpendingApproveReject