Skip to content

Send publishers to the publisher console and rewrite the publisher guide - #46

Merged
legendko merged 13 commits into
mainfrom
feat/publisher-console
Oct 16, 2026
Merged

legendko merged 13 commits into
mainfrom
feat/publisher-console

Conversation

@legendko

@legendko legendko commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

What changes

  • Onboarding page (/publishers/onboarding/): the email contact form at the end is replaced by the register block from the ticket's design.
    • Label "Liked the preview?", heading "Register to start step 1.", then the ticket's text.
    • Primary button "Register on the publisher console", outlined button "Read the publisher guide".
    • Both open in a new tab with noopener noreferrer.
  • New build setting FORA_PUBLISHER_CONSOLE_URL in website/astro.config.mjs.
    • Default https://console.fora-protocol.org/.
    • Validated with url and startsWith: 'https://', so a malformed or non-https override fails the build.
  • Removed: contact.mjs, contact.test.mjs, the form's markup, CSS and handler, and the copy of the request kept only for the enquiry. Nothing on the site posts to /v1/contact any more.
  • The two messages that pointed at the form now link to FORA_PUBLISHER_CONTACT_URL (mailto:publishers@fora-protocol.org):
    • the unknown-CDN card, with a "Write to us" button;
    • the note shown when no discovery document could be generated.
  • Fixed: the outlined (ghost) button never showed its border. The page reset every .btn border to transparent after brand.css had set it.
  • Publisher guide (/getting-started/publisher-onboarding/) is rewritten around the console flow.
    • The title is now "Publisher Onboarding"; the slug is unchanged.
    • Removed: the fora-cli commands (the tool exists nowhere), the ACME flow, publisher-held keys and the SDK catalog push. All of these are covered elsewhere, and a separate "Without a publisher console" section links to those pages.
  • Pages that pointed at the old guide:
    • the For Providers anchor now goes to the Content Sources SDK-push section;
    • the Content Attestation "Next Steps" bullet now goes to CatalogService API Push;
    • the home page card is updated.
  • docs/design-history.md: a new entry explains why the guide follows the console's served-manifest proof while the domain-verification RPCs stay in the contract.

The onboarding page is about to send publishers to the publisher console,
and the publisher guide will link to it too. Both read one setting,
FORA_PUBLISHER_CONSOLE_URL, so moving the console is a build value rather
than an edit in two places.

The default is the console's address on fora-protocol.org, which redirects
to wherever the console runs. Astro checks a value set in the build
environment against url and startsWith https, but never checks the default,
so a malformed or non-https override fails the build while the default stays
a literal https URL.
The page ended with an email form that posted the visitor's address, the
previewed page and their terms to the preview service's contact route.
It is replaced by a register block: a button to the publisher console,
read from FORA_PUBLISHER_CONSOLE_URL, and the existing link to the
publisher guide. Both open in a new tab with noopener and noreferrer, so
the preview stays open and its address, which carries the previewed page,
is not handed on.

The form's client and its tests, the copy of the request kept only for the
enquiry, and the submit handler go with it. They have to go together: the
handler bound to the form's markup when the script loaded, so removing
either one alone throws before a shared preview link gets to run.

The guide link also never showed its outline. The page reset every .btn
border to transparent after brand.css had given the ghost variant its
border, then restored only the width and style. The reset is gone;
brand.css already gives each variant its full border.
With the form gone, two messages pointed at nothing. The card for a CDN the
preview does not recognize told the visitor to leave their email below, and
the note for a domain with no generated discovery document said "Ask us".
Both now link to FORA_PUBLISHER_CONTACT_URL, which was declared for exactly
this and had gone unused.

cdnPresentation stays a pure mapping: it only labels the link, and the page
supplies the address, escaped into the card's markup. The discovery-document
note is built from nodes. A test pins that only the unrecognized outcome
offers the link and that the mapping never carries an address.
The guide described onboarding as an ACME challenge plus fora-cli commands
that generate, push, rotate and revoke signing keys, and told publishers to
push their catalog with the SDK. fora-cli exists nowhere, and the console
publishers now use does none of that. It generates the discovery file and
the edge package, proves the domain from the file it serves, and the
operator imports the catalog from the sitemap with a key the operator holds.

The new guide follows the console step by step, quoting its labels, and says
where it stops: Cloudflare and AWS CloudFront only, terms fixed after
registration, no automatic import without a sitemap. A short separate
section points a publisher without a console at the pages that already cover
the manifest, the edge function, catalog pushes and attestation, so nothing
the old guide said is lost or repeated here. The console link reads the same
build setting as the onboarding page. The title now matches the sidebar
label; the slug is unchanged.

For Providers linked into the guide's SDK-push section, which is gone. It
now links to the section of Content Sources that documents the push.
The home page card promised ACME verification, key provisioning and a
single CLI command, and Content Attestation sent readers to the publisher
guide to learn how to publish signing keys and push attestations. Neither
is in the guide any more. The card now describes the console flow, and the
attestation page links to the CatalogService push section, which covers how
a signed push carries attestations.
The publisher guide now follows the console, which never calls the
contract's domain-verification RPCs. Without a note, a reader holding the
proto and the guide side by side would take that for an omission. The entry
records that the served fora.json is the proof (domain control, payee and
contributor authorization in one fetch, re-read at every catalog push), why
the operator rather than the publisher holds the catalog key, and that the
RPCs and publisher-held pushes both remain in the contract.
Once deployed, the edge package answers /.well-known/fora.json itself,
from its settings: always on Cloudflare, whose route covers the whole
hostname, and on CloudFront when the cache behavior carrying the function
covers that path. The guide only ever spoke of the file, so a publisher who
edited it to change or withdraw the operator's authorization would change
nothing. Each network's section now says which copy the domain serves, and
Keys and your catalog says where a change has to go.

The package recognizes AI agents by the name they give, so the guide no
longer says it refuses every unlicensed agent. It points at Bot Detection
for the CDN protection that covers disguised scrapers, and warns that a
firewall refusing announced AI agents refuses paying ones too and keeps the
console's package check from passing.

Smaller corrections against the console: the file step checks on entry and
unlocks Next, and has no Check button; Verify checks the signatures against
the keys recorded with the transaction; Finish setup reads the served
document, not the file; the Exchange fee is capitalized as the console
writes it; the served document is called the discovery document throughout;
and the fora.json example is said to describe the standard fields, since
the payee travels in an ext entry it does not cover.
The entry presented resource_owner_id as if it were a manifest field. It is
a key in the Exchange entry's ext that the v1 contract does not define. It
called the proof continuous, while catalog pushes read the manifest through
a short-lived cache, so a removed contributor stops imports only once that
copy expires. And it placed the publisher's authorization in the file, when
an edge package in front of the well-known path serves the document from
its own settings.
Deployment Models said the provider must prove its domain with the ACME
challenge before any deployment model, while the design history records
that an Exchange can take the served fora.json as the proof instead; the
page now says both. For Providers gains a next step that sends web
publishers to the guide where their operator runs a console, and its FAQ no
longer claims bots cannot get past the edge function: an AI agent that
announces itself gets nothing without a signed URL, and a disguised scraper
is the CDN bot protection's job. The home page card scopes the console flow
to operators that run one, and the music demo links to the pages that cover
pushing a feed rather than to the console guide.
The unknown-CDN card and the missing-manifest note both link to the
publisher contact address, but the label lived in the CDN mapping and again
as a literal in the page, and the two links were built two ways: one from
nodes, one as an HTML string. The label is now exported once from the
mapping, and both links come from one helper that builds the anchor from
nodes. The rendered markup is unchanged.
main sends publishers from the onboarding preview to the publisher console
with a register block of its own, written without this branch. Both sides
replaced the contact form with the same markup and the same build setting,
FORA_PUBLISHER_CONSOLE_URL, and both removed the form's client and tests. They
differ in the block's copy and in the setting's default and comments. main's
default is the console's host on the vendor domain, which the org-reference
check rejects; it passed on main only because main also added an exception for
that host, which the next commit removes.

Resolution ledger:
- textual conflicts:
  - website/src/pages/publishers/onboarding.astro -> main's register block
    copy: its label, heading and paragraph. The buttons were identical on both
    sides. The rest of the file is this branch's, including the links to the
    publisher contact address on the unknown-CDN card and the missing-manifest
    note.
  - website/astro.config.mjs -> this branch's side of both hunks:
    FORA_PUBLISHER_CONSOLE_URL defaults to https://console.fora-protocol.org/,
    the redirect alias, and each comment names who reads its setting. main's
    JSON Schemas sidebar entry auto-merged.
  - website/src/content/docs/getting-started/publisher-onboarding.mdx -> this
    branch. main edited two passages that this branch's rewrite removes: the
    caller_id instruction in the SDK push steps and the key directory's media
    type. Both corrections already live on the pages the rewrite links to,
    the CatalogService push section and Content Attestation.
  - docs/design-history.md -> union: main's appended sections first, then this
    branch's "A publisher proves its domain with the manifest it serves" at
    the end.
- auto-merged, reviewed: deployment-models.mdx, for-providers.mdx,
  live-demo-music.mdx and content-attestation.mdx (disjoint hunks); the
  contact module and its tests, and the preview client's comment (the same
  change on both sides).
- kept from this branch, untouched by main: the unknown-CDN card and the
  missing-manifest note link to the publisher contact address. main had left
  them telling the visitor to leave an email below, and to ask, with no form
  on the page any more.
- website/routes.txt: main's, which the merged build reproduces unchanged.
The org-reference check let one host through, the publisher console's on the
vendor domain, so that the onboarding preview could link to it. The preview and
the publisher guide now link to the console's redirect alias on
fora-protocol.org, and nothing in the tree names that host any more, so the
exception only kept a hole in a check that is meant to have none. The check
again rejects the old org name everywhere, with no exceptions.
…e guide and the design history

A publisher may always push for its own domain. Only a third party has to be
listed in catalog_contributors, as the NOT_CATALOG_CONTRIBUTOR comment and the
providers page say. Two sentences on this branch were written before that rule
was stated, and read otherwise. The guide's list for running without a console
named only a contributor key the manifest authorizes. The design history
explained a publisher's own push by the manifest naming it as a contributor.
Both now say that the push path accepts the publisher's own key, because the
signer is that domain's publisher.
@legendko
legendko merged commit d633e8b into main Oct 16, 2026
2 checks passed
@legendko
legendko deleted the feat/publisher-console branch October 16, 2026 08:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant