Skip to content

Editing These Docs

This site is a workspace app like any other: apps/docs, built with VitePress. Documentation lives next to the code it describes and ships through the same pipeline.

Running it

bash
pnpm docs                                # from the repo root
pnpm --filter @playpals/docs dev         # equivalent

Opens on http://localhost:5173 with hot reload.

bash
pnpm --filter @playpals/docs build       # static site → .vitepress/dist
pnpm --filter @playpals/docs preview     # serve the built output

Structure

apps/docs/
├── .vitepress/
│   ├── config.ts              site config, nav, sidebar
│   ├── markdown/mermaid.ts    ```mermaid fence → <Mermaid> component
│   └── theme/
│       ├── index.ts           theme entry, registers <Mermaid>
│       ├── custom.css         PlayPalz brand colours
│       └── Mermaid.vue        client-side diagram rendering
├── public/                    logo, favicon
├── index.md                   home page
├── guide/  architecture/  services/  database/
├── api/    mobile/  infrastructure/  operations/
├── reference/  platform/
├── Dockerfile
└── nginx.conf

Adding a page

  1. Create the markdown file in the right directory.
  2. Add it to the sidebar in .vitepress/config.ts. A page not in the sidebar is unreachable.
  3. Link to it from related pages.

Links are root-relative and omit the .md extension (cleanUrls is on):

md
See [Realtime](/architecture/realtime).

The build fails on a dead link (ignoreDeadLinks: false), which is deliberate — a broken cross-reference is caught before it ships.

Diagrams

Mermaid works in a plain fenced block:

md
```mermaid
graph LR
    A[Client] --> B[api]
    B --> C[(PostgreSQL)]
```

A custom markdown-it rule replaces the fence with a <Mermaid> component that renders client-side and re-renders when the reader toggles light/dark. Sequence diagrams, ER diagrams, flowcharts, and Gantt charts are all used in these docs.

Callouts

md
::: tip
Helpful aside.
:::

::: warning
Something that will surprise you.
:::

::: danger
A defect, a security issue, or an irreversible action.
:::

::: info
Neutral context.
:::

Use warning for behaviour that differs from what a reader would reasonably expect, and danger for real defects, security gaps, and destructive commands. Do not use them for emphasis.

Status badges

html
<span class="pp-pill pp-pill--live">Shipped</span>
<span class="pp-pill pp-pill--partial">Partial</span>
<span class="pp-pill pp-pill--planned">Planned</span>

House style

Say what is true, including when it is unflattering. These docs name specific defects with file paths and suggested fixes. That is the point — a developer who hits the ogun /admin prefix bug at 2am should find it documented, not discover it.

Point at the code. apps/api/src/lib/roomAccess.ts is more useful than "the room access logic".

Explain why, not just what. The reader can read the code for what. Document the reasoning that is not in the code — why esu calls back into the API, why the socket ingress is separate, why anansi is a singleton.

Keep code excerpts short and real. Copy from the source rather than paraphrasing; a stale snippet is worse than none.

Line length ~100 characters, matching Prettier's 120 with margin.

Keeping it current

Update the docs in the same pull request as the change:

You changedUpdate
A routeThe relevant API Reference page
An environment variableEnvironment Variables
A socket eventSocket Events
The schemaDomain Models
A deployment manifestKubernetes
A service's behaviourThat service's page

If you fix one of the defects documented here, remove the callout in the same PR.

Deployment

The site builds to static HTML and is served by nginx on port 8080 in a distroless-style Alpine image, running as the non-root nginx user.

bash
./scripts/build-docs.sh [tag]
kubectl apply -f infra/k8s/docs-deployment.yaml     # first time only
kubectl rollout restart deployment/playpalz-docs
PropertyValue
Imageregistry.digitalocean.com/playpalzproduction/docs
Manifestinfra/k8s/docs-deployment.yaml
Replicas2
Port8080
Hostdocs.playpalz.gg
Resources10m CPU / 32Mi requested — the smallest workload in the cluster

./scripts/build-all.sh includes docs.

Restricting access

The docs describe internal architecture, known defects, and operational procedures. The ingress has commented-out basic-auth annotations ready to enable:

bash
htpasswd -c auth <username>
kubectl create secret generic docs-basic-auth --from-file=auth

Then uncomment the three auth-* annotations in infra/k8s/ingress.yaml and re-apply. Worth doing before the site is publicly reachable.

First-time setup

  1. Add a docs A record — dns.tf already contains it when manage_dns = true, otherwise create it manually pointing at the LoadBalancer IP.
  2. ./scripts/build-docs.sh
  3. kubectl apply -f infra/k8s/docs-deployment.yaml
  4. kubectl apply -f infra/k8s/ingress.yaml
  5. Watch kubectl get certificate until playpalz-docs-tls reports Ready.

Notes on the build

  • .dockerignore excludes **/*.md for the service images, with an explicit !apps/docs/**/*.md exception — without it the docs image would build an empty site.
  • nginx try_files $uri $uri.html is what makes cleanUrls work: VitePress emits getting-started.html but links to /getting-started.
  • Hashed assets get a one-year immutable cache; HTML must revalidate so a redeploy is picked up immediately.

Internal documentation — PlayPalz platform