Site
A site is what a tenant shows the public: a name and a tagline, a home page, a
colour scheme and a navigation. The module owns that data and none of the
rendering — a theme reads a title, a navigation and a colour and decides what
to do with them — so a deployment can replace the theme without touching what a
tenant configured. There is one site per tenant, and it has settings from the
moment the tenant exists: reading them before anybody has saved anything
answers the defaults, not a 404. The module is
modules/site; this page states nothing that tree
does not.
The map
features/site in the recordWhat it promises
Entity |
|
Events |
|
Permissions |
|
Service |
|
Routes and screens
| Method | Path | Does | Authorization | Publishes |
|---|---|---|---|---|
|
|
Read this tenant’s settings |
|
— |
|
|
Save this tenant’s settings |
|
|
|
|
Read this settings as a visitor sees it |
public |
— |
-
GET /api/v1/site/settingsandPUT /api/v1/site/settings— the two routesrest.Singleton.Mountregisters (kit/rest/singleton.go, declared inmodule.go). There is no list, noPOSTand noDELETE, because a tenant has one site whether or not anybody has saved it. The read answers the defaults rather than a 404; thePUTreplaces the whole row,crud.Resetdrops whatever a body claims about its id and timestamps, and a valueValidaterefuses is a 422. -
GET /api/v1/site/settings/public— the public face, behindhttpx.Public(): the title, the navigation and the theme and nothing else, an empty navigation rather than a null, and a 404 at a host that resolves to no tenant. -
Commands: none.
-
Screens: the singleton has a
Writepermission, soMountregisters it as a resource and the admin generates its seven pages under/admin/site/settings: the list shows the one row, the detail and the edit form read and save it throughSettingsandSave, and creating or deleting through them answers with a conflict, "a tenant has one settings, and it is neither created nor removed". The navigation entry "Site" is shown to anyone withsite:manage. Hand-written pages: none — there is no HTML in the module, so the theme can be replaced.
Authorization
| Authorization | Who passes | Routes |
|---|---|---|
|
a member of the tenant |
|
none: public |
anyone |
|
Events, jobs and subscriptions
| Event | Published by | Handled by |
|---|---|---|
|
|
|
-
Publishes:
site.settings_updated, fromSaveininternal/service.go, throughevents.Publishinside the caller’s transaction; theSingleton’s `Eventfield declares it on thePUTso the boot gate can check it. -
Jobs: none, written out as a decision in
module.go: nothing about a site happens because time passed. -
Subscriptions: none.
What it needs
|
Interface |
Supplied by |
none |
|
|
Configuration: none.
Who uses it
-
No module takes its contracts: nothing in the public repository or its private consumers imports
modules/site/contracts, and no client storefront reads the site settings. The event’s payload is written for whatever renders the public site; nothing subscribes to it yet. -
The admin and the native shell reach it through
httpx.Resource, not throughcontracts/.
Verification
-
go test ./modules/site/…— the fake and the real service pass one conformance suite (conformance.go): the defaults for a tenant that has configured nothing, a save that reads back in the order it was written, silence on an identical save, one event on a change, andcrud.ErrInvalidfor a colour, a theme, a link, a bound or a slug that is not one. The internal tests (internal/service_test.go) prove what the fake cannot: one row per tenant whatever a body says about its id, the event in the caller’s transaction with a trimmed title, and a rollback that leaves neither. The module tests (module_test.go) mount the routes: read andPUTand nothing else, a lower-cased colour, a 422, a public face that carries the title, navigation and theme and none of the tagline, home slug, colour or timestamps, a 403 on an anonymous read of the settings, a navigation that cannot leave the site, and lengths counted in characters. -
No browser journey:
make e2erunse2e/admin-tasks.spec.ts, which does not touch the site. -
Not proven: the generated screens over the singleton, because no test mounts the admin over
site; a subscriber tosite.settings_updated, because none exists; the public route at a host that resolves to no tenant.