A Publishing panel on app detail shows the app's tier (private → organization →
marketplace) and its marketplace review state from GET /apps/{slug}/publication. Private and
organization are the existing visibility edit; only the marketplace step is a request a platform admin
reviews. Each review state has exactly one next action.
Visible to every member of Acme Corp. Publish to the FuzeFront marketplace to let any FuzeFront user or organization discover and install it. A platform admin reviews each request.
A FuzeFront admin will review it. Until it's approved nothing changes: it stays visible to Acme Corp only. Once approved, it's listed publicly with Acme Corp as publisher.
App detail renders with no Publishing panel and no “Publish to
marketplace” control — never a button that only fails on click. Same when
fuzefront.apps.marketplace-publishing is OFF (503 feature_disabled, or the flag read
client-side first).
Data. AppPublication: tier (Visibility) drives the tier badge;
status ∈ none | pending | approved | rejected drives the panel; rejection.reason
is shown as text (escaped, never HTML). Names for requestedBy come from the creator/member lookup
where available; otherwise the date alone is shown.
Visibility of the panel. Rendered only when the flag is ON and GET /apps/{slug}/publication
returns 200 — the contract answers 404 to anyone who can merely read the app, so a 404 means “no panel”, not an
error. A 409 on submit is a race, not a failure: refetch and render (f3)/(f4).
Test hooks: [data-frame='06-publish-request'] · [data-panel='app-publication'] ·
[data-publication-status='none'] · [data-action='request-publication'] ·
[data-panel='publication-request-dialog'] · [data-input='publication-notes'] ·
[data-action='submit-publication-request'] · [data-publication-status='pending'] ·
[data-publication-status='approved'] · [data-publication-status='rejected'] ·
[data-field='rejection-reason'] · [data-error-code='ALREADY_PENDING'] ·
[data-error-code='ALREADY_PUBLISHED'] · [data-state='read-only'] · [data-http='403'].