Skip to main content
InternalMarkdown

ADR 0034. Documentation site: Docusaurus, OpenAPI, Scalar; internal first

Status​

Accepted.

Context​

Docs were plain Markdown in docs/, spec/ and per-service READMEs, with no site, link checking or API specification. Routes are hard-coded v1/... prefixes validated by hand-written TypeScript; there was no OpenAPI. Partners need integration guides and an API reference; founders need architecture, decisions and operations in one place, with honest implementation status.

Decision​

  1. Docusaurus (docs-site/, own package.json and lockfile) renders docs/ in place. No files move. markdown.format: 'detect' keeps .md as CommonMark; .mdx opts into MDX. Broken links and anchors fail the build. Links to files outside the site are rewritten to GitHub (docs-site/plugins/remark-repo-links.mjs).
  2. OpenAPI is the source of the API reference, generated code-first with @nestjs/swagger decorators (services/api/src/openapi/). Two documents: internal.json (every route; in docs-site/static-internal/, never copied into the public build) and partner.json (operations marked x-audience: partner). Both are committed under docs-site/static/openapi/; npm run openapi:check fails when they differ from the code. Unbuilt endpoints are not added to OpenAPI.
  3. Scalar renders both documents, self-hosted: the renderer is vendored from a pinned @scalar/api-reference at build time, not loaded from a CDN. Request testing and the client button are off and no proxy is configured, until a sandbox exists.
  4. Internal first, fail closed. Every page is internal unless its front matter says audience: public. The public build (DOCS_AUDIENCE=public) contains only those pages and the partner reference, and fails if a public page links to an internal page or into the repository. The internal site is hosted on Cloudflare Pages behind Cloudflare Access, which is already used for other hosts. CI deploys it on push to main; setup is in Contributing to the docs. The public build is not deployed yet.
  5. Status labels. Page front matter status: implemented | in-progress | proposed, optional demo: true and verified: <commit>; section-level > **Status: …** — evidence: … lines on mixed pages. A status must cite code or tests; a mockup alone never makes something implemented.
  6. Spec and glossary (spec/PLAYERPAL_AUTH_IDENTITY_SPEC.md, CONTEXT.md) are rendered on the internal site only, from copies made at build time. They stay where they are and the spec still wins on conflict.

Defaults chosen for open questions​

These were taken as defaults when the site was built and can be revisited:

QuestionDefault
Public site now or laterLater. No page is marked public.
Code-first or spec-first OpenAPICode-first
Sandbox for request testingNone yet; reference is read-only
PR previewsNone; local preview plus CI build
App locationdocs-site/ with its own lockfile
Publish the specNo; internal build only
Partner doc scopeIncludes routes behind the shared machine key (activity batches and uploads, link intents and results, aliases) because integrations call them today. Revisit before any public release: per-partner credentials do not exist for these routes yet.

Still undecided and not answered by this ADR: retention schedule and purpose limits, reward-partner scope, the canonical redemption state model, packaging and pricing. Pages describing them say so.

Amendment: shareable public site​

The site now serves partners, prospects and investors as well as the team. Public pages are .mdx under product/, developers/, analytics/, rewards/ and trust/, written to contributing/style.md: reader-facing status labels (Available / In development / Planned), evidence kept in MDX comments, no repository links or internals. The PlayerPal brand theme, a landing page, offline search and a social preview image are part of the build. npm run check:public scans the public build output for hostnames, infrastructure vendors, configuration keys, non-placeholder IDs, repository links and the internal OpenAPI document, and runs in CI.

Consequences​

  • A behaviour change updates its page and, for endpoints, the regenerated OpenAPI files in the same PR; CI checks the OpenAPI part and the KPI IDs.
  • The API gains decorators and hand-written JSON schemas that must track the hand-written validators until validation moves to a schema library.
  • Internal hosting needs a Cloudflare Access application before the docs image is added to build-push.yml and k8s/apps/.