The public site
The public site is what an anonymous visitor reads at the root of a tenant’s
host: the page the site settings name as the home, any published page by its
slug, and an honest empty state until an operator has published one. It writes
nothing of its own — it renders what the site and content modules publish,
composed from ui/page and ui/components the way the admin is, with a bar
where the admin has a sidebar. The module is
modules/web; this page states nothing that tree
does not.
The map
features/web in the recordWhat it promises
Entity |
None. The site owns no table and no entity; every field it shows is the site module’s |
Events |
None. |
Permissions |
None. Both routes are public and read-only. |
Service |
None. Nothing takes the site as a dependency; it is the surface. |
Routes and screens
-
GET /— the home: the published content whose slug is the settings'homeSlug. A fresh installation, with no home slug, says "Nothing published yet" and links to the admin; a home slug nothing published has says so too. Both answer 200, because a site with nothing on it is a state, not a failure. -
GET /{slug}— one published page. A draft, an archived page, a slug nobody has used and a path that is not a slug are the same 404, rendered as a page with a way back to the site, which is the content module’s rule for its own public read. -
Both are HTML documents served through
page.Servewithhttpx.Public(); neither is in the OpenAPI document, which lists JSON routes. Screens: the site is its own screen; there is no admin page for the module, because it has nothing to configure that the site settings do not hold.
Authorization
Neither route asks for a session or a permission. A host that resolves to no tenant serves no site and answers 404; a database that cannot be reached answers 503 rather than an empty site.
Events, jobs and subscriptions
-
Publishes nothing, runs no job, subscribes to nothing. When an operator changes the settings or publishes a page, the next request reads the change: the site renders on read and caches nothing.
What it needs
|
Interface |
Supplied by |
|
|
the site module’s service, from |
|
|
the content module’s service, from |
|
|
|
Module panics without the two services. Configuration: none; the site reads the tenant’s settings on every request.
Who uses it
-
An anonymous visitor at the tenant’s host. No module imports it and no module may: a product with a storefront of its own composes that instead, and the root belongs to one module, so two claiming it is a boot failure rather than a coin toss.
-
The reference application’s
startcommand prints its address beside the admin’s and the API documentation’s.
Verification
-
go test ./modules/web/…— the empty state and its link, the published home with the tenant’s theme and colour pinned, a page by slug, the 404 page with a way back for an unknown slug and a path that is not one, and a host that serves no site; over the two modules' fakes and a real connection. -
make e2e—e2e/site.spec.tsreads the empty state, signs in, publishes a page and names it the home through the JSON routes, and reads it at/with the navigation and the pinned theme. -
Not proven: the logo, which is rendered from a file id but not exercised by a test; and a tenant’s
primaryColorreaching the rendered Markdown’s links, which the prose sheet does through the accent token but no test renders in a browser.