Published in openvibe-contracts v0.107.0 (docs/adr/ADR-053-website-host-boundary.md), rendered as is.

ADR-053: The Website/Host boundary — OpenVibe.Website authors, OpenVibe.Host serves

Status: Proposed 2026-10-05 (plan track T19), for the owner's review. Builds on ADR-014 (developer projects and tenancy), ADR-006 (Media object, location and namespace model), ADR-036 (Run is an execution authority, not a Host detail) and ADR-048 (one authority per resource; a control operation is a call to the owning authority). Records the boundary T19 needs; the plan lists no Website ADR.

Evidence

Decision

  1. Website owns authoring; Host owns serving. OpenVibe.Website owns the authoring record a person edits and publishes: its projects (the authoring workspaces), pages (the page tree and content), revisions (the source history a build is made from), builds (the artifact and manifest a revision produces), Media asset pointers (references to media.object@1 objects, ADR-006 — pointers, never a second copy of the bytes) and the intended domains (the hostname(s) the authoring project targets, and the DNS instructions shown to its owner). OpenVibe.Host owns the site, the deploy and its activation, domain binding, DNS verification and TLS, and the actual serving of the bytes.
  2. Host is the one site/deploy authority, and it already is. Every create, read, change, activate, roll back, delete, domain and config operation is the Host route named in Evidence: GET/POST /projects/:id/sites (server/http/api.js:123, :127), POST /sites/:id/deploys (:197), POST /deploys/:id/activate (:207), POST /sites/:id/domains (:224), GET/PUT/DELETE /sites/:id/config (:237/:241/:245) among them. Website calls Host's own API under its own principal and grants; it does not reach into Host's tables. Whether Host also exposes the common control contract (common.resource-control-request@1, ADR-048) and what its OVRN resource names (ovrn:host:<prj>:site/<id>) are is open (below).
  3. Website keeps no duplicate host_sites / host_deploys rows. It may hold at most a rebuildable read model of what it shows (a site id, an active deploy id), never the row of record, and never a second active_deploy_id pointer: the one serving pointer stays host_sites.active_deploy_id, exposed as [email protected]_deploy_id (contracts/host/site.v1.json). A Website publish means "upload a build, then activate it" through Host; the answer is Host's host.deploy@1.
  4. A Website build is not a Host deploy. A revision and a build are authoring facts; a deploy is Host's immutable, content-addressed record of an uploaded output. Website's build manifest names the files and hashes it intends to publish; Host re-validates and stores them, and only a Host deploy can be served, activated or rolled back. The same rule applies to the CI path: POST /sites/:id/source/deploys (:265) always lands as the site's preview (server/http/api.js noActivate), and Website approves it through POST /deploys/:id/activate like any other deploy.
  5. Domains stay Host's rows. Website owns the intended hostname and shows its owner the TXT instructions; Host owns the host_domains row, POST /sites/:id/domains, the daily re-check and POST /domains/:id/verify, the certificate and the serving (host.domain@1). A domain is bound to a Host site (site_id), not to a Website authoring project. Whether Website keeps any domain row of its own, or reads Host's host.domains, is open (below).
  6. Media bytes stay Media's; Website holds pointers. An authoring asset is a pointer to a media.object@1 object (ADR-006); a deploy's served bytes are Host's host_blobs / host_deploy_files (or, per T12, objects on Media with replication and backup). Website never becomes a second object store.
  7. Website is not OpenVibe.Sites, and it is not a new serving stack. It composes Host + Codes + Actor + Run + Media (plan line 783); it never mounts a second Host API, a second host.* namespace or its own tenant vhosts.

Authority boundaries

| Concern | OpenVibe.Website (authoring) | OpenVibe.Host (serving) | |---|---|---| | Project | the authoring workspace (files, settings, collaborators) it owns | host.project@1 (contracts/host/project.v1.json): the Host tenancy keyed by Network prj_ (network_project_id), quota (GET/PUT /projects/:id/quota, :83/:87) and members (:92/:97) | | Pages | the page tree and content the editor reads/writes | none: a page is not a Host row; it becomes files in a deploy | | Revisions | the source history a build is made from (from the editor or a Codes repository) | none: deploys are immutable content-addressed outputs, not revisions | | Builds | the artifact and manifest a revision produces | a deploy is the uploaded output: POST /sites/:id/deploys (:197), or POST /sites/:id/source/deploys (:265, always preview) | | Media assets | pointers to media.object@1 objects (ADR-006) | the deploy's files (host_deploy_files, host_blobs); Host serves what it holds | | Domains | the intended hostname(s) and the DNS instructions shown to the owner | the served domain: host.domain@1, GET/POST /sites/:id/domains (:220/:224), POST /domains/:id/verify (:228), DELETE /domains/:id (:233); TLS by the operator | | Site | no row; it reads Host's site | host.site@1: GET/POST /projects/:id/sites (:123/:127), GET/DELETE /sites/:id (:132/:136); the one serving pointer host_sites.active_deploy_id | | Deploy / activation | asks Host and shows the answer; keeps no deploy row | GET /sites/:id/deploys (:139), GET /deploys/:id (:199), /log (:203), POST /deploys/:id/activate (:207), POST /sites/:id/rollback (:212), DELETE /deploys/:id (:217) | | Site config | none | GET/PUT/DELETE /sites/:id/config (:237/:241/:245): headers, redirects, SPA fallback (host.site.config) | | Git source | the project's code home (Codes, T19) | GET/PUT/DELETE /sites/:id/source (:253/:257/:261): the repo and branch the project's CI deploys from; Host never clones, fetches or builds it | | Takedown / serve | none | staff takedowns (:105-:120) and serving of the active deploy |

Open questions for the owner

  1. The authoring contracts. Whether Website's projects, pages, revisions and builds are new website.* contracts (and their shapes), or whether pages/revisions map onto Codes' repository objects, is open. Nothing exists today: no website.* id, no namespace and no service manifest.
  2. The Website project versus the Host project. Whether a Website authoring project is a distinct row that links a Network prj_ to a Host host.project@1, or is the Host project itself with authoring data beside it, is open. The plan's rule (T19, line 778) is only that the product keeps its own authority for genuinely unique domain data.
  3. Domains. Whether Website keeps a domain row of its own (the intended hostname and its approval state) or reads Host's host.domains directly is open; what is fixed is that the binding, verification, certificate and serving are Host's.
  4. The build artifact. Whether a build's output is stored as an authoring artifact (and where), or exists only as the Host deploy it is uploaded into, is open. T12 says Host keeps "objects on Media with replication and backup", so this may be Media, not Website.
  5. A Website service manifest. Whether Website registers as a service (a manifests/services/website.json with a capability and namespace) before its authoring contracts, or ships as a product that only calls Host, is open.
  6. Host's control contract and OVRNs. ADR-048 never mentions Host; this ADR records the call as Host's own API under Website's principal and grants. Whether Host also exposes the common control contract (common.resource-control-request@1, ADR-048), and what its OVRN resource names look like (ovrn:host:<prj>:site/<id>), is open.
  7. The serving zone and TLS. The Website product manifest promises yourname.openvibe.website (manifests/products/openvibe.website.json), but Host's manifest owns only openvibe.host. Which zone serves Website tenant sites and who issues their TLS certificates is open.

What this ADR does not claim

Out of scope

Consequences