docs: add comprehensive developer guide (mdBook)

Add a browsable mdBook developer guide under docs/dev-guide/ covering the
full PiCloud v1.1.9 surface for developers building on the platform:

- Guide: introduction, 10-minute quickstart, core concepts, writing scripts
- Tutorials: 5 end-to-end example apps (URL shortener, webhook receiver,
  TODO API with auth, scheduled report, file-upload service) + feature matrix
- SDK reference: kv/docs/files, pubsub/queue, http, email, users, secrets,
  invoke/retry/dead_letters, stdlib, ctx & events
- HTTP API reference: every /api/v1 endpoint, auth, and capability
- CLI reference: the `pic` client + the server admin recovery command
- Config: every PICLOUD_* env var, capabilities & roles
- Deployment: Docker Compose, bare binary, Caddy/TLS, production checklist
- Operations: security, best practices, troubleshooting

Every example was built and run against a live instance; SDK signatures,
endpoint paths, and env vars were verified against source. Build the site
with `mdbook serve docs/dev-guide`. A pointer is added to README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-20 13:54:23 +02:00
parent 51f14fa2b1
commit 05ea29fbd0
44 changed files with 3989 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
# Caddy & TLS
Caddy is the single entry point in front of PiCloud. The same topology serves dev and production — only
the upstream targets and TLS settings change.
## Routing topology
Caddy routes by path prefix (from `caddy/Caddyfile`):
| Path | Goes to |
|---|---|
| `/healthz`, `/version` | picloud (liveness + version) |
| `/api/v1/admin/*` | picloud (control plane) |
| `/api/v1/execute/*` | picloud (execute-by-id) |
| `/api/*` (anything else) | **404** — reserved for future API versions |
| `/admin/*` | the dashboard SPA |
| **everything else** | picloud's **user-route matcher** — your scripts' routes |
That final catch-all is what makes arbitrary user paths like `/hello` or `/r/abc123` work: Caddy
forwards them to picloud, which matches them against the [route table](../guide/concepts.md#routes-and-domains)
(or returns a JSON `404`). This is why your routes can't use the reserved prefixes `/api/`, `/admin/`,
`/healthz`, `/version` — Caddy would never forward them to the matcher.
## Security headers & body limit
The Caddyfile adds defense-in-depth headers and a hard body cap:
- `X-Content-Type-Options: nosniff` and `Referrer-Policy: no-referrer` on **every** response.
- A strict CSP, `X-Frame-Options: DENY`, `Cache-Control: no-store`, and a locked-down
`Permissions-Policy` on the **dashboard** and **admin API**.
- A **12 MB request-body ceiling** at the proxy (just above the orchestrator's 10 MiB user-route read).
- **User-route responses get no CSP on purpose** — your scripts own their own response headers. The
`?` (set-if-missing) operator means a script's own header wins over the default.
## Production: HTTPS with Let's Encrypt
Layer the production overlay, which swaps in `caddy/Caddyfile.prod` and exposes 80/443:
```sh
export PICLOUD_DOMAIN="picloud.example.com"
export PICLOUD_ADMIN_EMAIL="you@example.com"
export POSTGRES_PASSWORD="$(head -c 24 /dev/urandom | base64)"
export PICLOUD_SECRET_KEY="$(head -c 32 /dev/urandom | base64)"
export PICLOUD_ADMIN_USERNAME="admin"
export PICLOUD_ADMIN_PASSWORD="…"
export PICLOUD_PUBLIC_BASE_URL="https://picloud.example.com"
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
```
Caddy obtains and renews a certificate for `PICLOUD_DOMAIN` automatically (HTTP/TLS-ALPN challenge — the
host must be reachable on 80/443 from the internet). The prod overlay also:
- **removes the published Postgres port** (DB reachable only inside the compose network);
- adds **HSTS** to every response (on top of the dev headers);
- sets `restart: unless-stopped` on all services.
The prod Caddyfile reads `PICLOUD_DOMAIN` and `PICLOUD_ADMIN_EMAIL` from the environment, so set them
before `up`.
## Custom domains for your apps
PiCloud's app [domains](../reference/rest-api/apps.md#domains) are matched by picloud *after* Caddy
forwards the request — they're independent of Caddy's own host config. For multi-tenant setups
(`{tenant}.example.com`), point a wildcard DNS record + Caddy cert at the box, then let each app claim
its host pattern. The most-specific app claim wins; unclaimed hosts get a `404 no app claims host`.
## Adding a future API version
When `/api/v2/...` ships, add a `handle /api/v2/admin/* { … }` block before the catch-all `/api/*`
404, mirroring the v1 block. The v1 routes stay live through the deprecation window.