# The web surfaces Four websites sit around this project. They look similar from the outside and they are not interchangeable: each has a different origin, a different thing serving it, and a different reason it may not be merged with the others. An agent asked to "work on the dashboard" or "the site" has to say which one, and the answer changes what language it is written in and which host it runs on. Written down because the distinction was previously only implicit — spread across [ops-dashboard](../plan/ops-dashboard.md), [policy-dashboard](../plan/policy-dashboard.md) and [agent-sites](../plan/agent-sites.md) — and one of the four was not recorded anywhere. ## Surface 1 — the marketing site, `did.bot` A static site. Marketing and launch pages, the prose documentation from `docs/`, and the compiled Rust API documentation. Built from `site/` and published to an object store behind a CDN; nothing about it is served by this project's own binaries, and it holds no state. It is the only one of the four whose audience is people who have not yet decided anything. ## Surface 2 — the policy site, `policy.did.bot` A static page with no backend, and **it may not be served by the server it governs.** The operator signs in against their own personal data server as a public OAuth client and writes policy records with their own key. The reason is in [policy-dashboard](../plan/policy-dashboard.md) and it is worth repeating here, because it is the constraint most likely to be accidentally violated by someone consolidating pages: if the server this policy governs also served this page, a compromised server would serve modified JavaScript, the operator would sign the attacker's policy with their own key, and every downstream check would pass. Hosting it elsewhere removes that path. It is served at `policy.did.bot`. `policy-site/` is the page, and `infra/policy-site/` gives it its own bucket and CloudFront distribution, apart from `did.bot`'s, so a mistake in one site's deploy cannot reach the other. The page uses no cookies: it keeps its OAuth session in IndexedDB, which is scoped by origin. So the cookie-scoping problem in [agent-sites](../plan/agent-sites.md), where a cookie set by one host under a shared domain is sent to its siblings, cannot touch that session. ## Surface 3 — the per-server homepage and operations dashboard, served by the PDS **Served by this project's own binary**, out of `didbot-serve`, about the server serving it. Live state — agents, sessions, grants, refusals — and it carries the emergency stop. This is the one that has to interoperate with Rust. It is not a static site built elsewhere and copied in: it is served by the running server, reads that server's own state, and its front end talks to Rust either through the server's routes or through wasm compiled from this workspace. Anything built for it belongs in this repository, in `didbot-serve` and the asset directory beside it. Two consequences that catch people out: - It owns no policy. Everything it can change is operational. Policy is written from surface 2, into the owner's own repository, and only read here. - It can lie. A compromised server serves this page and also supplies its numbers, so anything security-relevant has to be checkable against the owner's own records instead. [ops-dashboard](../plan/ops-dashboard.md) makes saying so a deliverable of the page rather than a footnote. There is one of these per deployment, not one for the project. ## Surface 4 — `vibescrobble.com`, another repository A consumer of what this project publishes, developed separately and not in this tree. It reads data served from personal data servers — this project's among them — over the ordinary public interfaces. It is named here so that nobody looks for it in this repository, and so that a change to a public interface is understood to have a reader outside this codebase. It gets no special access and no private endpoint; if it needs something, that something is a public capability and belongs in a lexicon. ## Which one is being asked for | If the work is… | It is surface | It lives in | |---|---|---| | Marketing, docs, API reference | 1 | `site/`, static | | Editing policy as the operator | 2 | `policy-site/` and `infra/policy-site/`, static | | Watching or stopping a running server | 3 | `didbot-serve`, this repo | | Reading published records elsewhere | 4 | another repository | Surfaces 1 and 2 are static and may be built with whatever a static site is best built with. Surface 3 is part of the server and follows this workspace's conventions. Surface 4 is somebody else's build entirely.