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,151 @@
# Environment variables
The `picloud` server is configured entirely through environment variables. This is the complete list,
grouped by area. Only `DATABASE_URL` and a master key are strictly required to boot.
## Required to boot
| Variable | Default | Purpose |
|---|---|---|
| `DATABASE_URL` | — | **Required.** Postgres connection string. |
| `PICLOUD_SECRET_KEY` | — | Master encryption key, base64 of 32 bytes. Required **unless** dev mode is acknowledged (below). Encrypts secrets and realtime keys at rest. |
On a **fresh** database you also need the [bootstrap admin](#bootstrap-admin) vars. After that, only
the two above are required.
## Dev mode
| Variable | Default | Purpose |
|---|---|---|
| `PICLOUD_DEV_MODE` | `false` | Enables local-dev conveniences (in-memory email sink). **Never in production.** |
| `PICLOUD_DEV_INSECURE_KEY` | — | Set to the literal `i-understand-this-is-insecure` to boot without `PICLOUD_SECRET_KEY`, using a deterministic, world-known dev key. `PICLOUD_DEV_MODE=true` **alone aborts** — you must also set this. Never in production. |
## Network & process
| Variable | Default | Purpose |
|---|---|---|
| `PICLOUD_BIND` | `0.0.0.0:8080` | HTTP listen address. (In Compose, picloud binds 8080 *inside* the network; Caddy publishes 8000.) |
| `PICLOUD_PUBLIC_BASE_URL` | `http://localhost:8000` | Public origin reported by `/version` and used to render URLs. |
| `PICLOUD_DB_MAX_CONNECTIONS` | `32` | Postgres pool size (matched to the execution cap). |
| `PICLOUD_MAX_CONCURRENT_EXECUTIONS` | `32` | Global cap on simultaneous script runs. Overflow → `503` + `Retry-After: 1`, no queue. |
| `PICLOUD_SESSION_TTL_HOURS` | `24` | Admin session sliding-window lifetime. |
| `RUST_LOG` | `info` | `tracing` filter, e.g. `info,picloud=debug`. |
| `PICLOUD_CONFIG_DIR` | platform default | Where the `pic` CLI stores credentials. |
## Bootstrap admin {#bootstrap-admin}
Read only on a fresh install (empty `admin_users`); ignored afterward. See
[Server admin commands](../cli/server-admin.md).
| Variable | Purpose |
|---|---|
| `PICLOUD_ADMIN_USERNAME` | first admin's username (seeded as `owner`) |
| `PICLOUD_ADMIN_PASSWORD_HASH` | preferred: Argon2id PHC string |
| `PICLOUD_ADMIN_PASSWORD` | fallback: raw password |
## Data-plane size caps
Exceeding any cap throws in the script. All in bytes.
| Variable | Default | Caps |
|---|---|---|
| `PICLOUD_KV_MAX_VALUE_BYTES` | `262144` (256 KiB) | `kv::...set` value |
| `PICLOUD_DOCS_MAX_VALUE_BYTES` | `262144` | `docs` document |
| `PICLOUD_PUBSUB_MAX_MESSAGE_BYTES` | `262144` | `pubsub::publish_durable` message |
| `PICLOUD_QUEUE_MAX_PAYLOAD_BYTES` | `262144` | `queue::enqueue` message |
| `PICLOUD_SECRET_MAX_VALUE_BYTES` | `262144` | `secrets::set` value |
| `PICLOUD_FILES_MAX_FILE_SIZE_BYTES` | `104857600` (100 MiB) | `files::...create/update` blob |
| `PICLOUD_EMAIL_MAX_MESSAGE_BYTES` | — | inbound/outbound email size |
| `PICLOUD_EMAIL_MAX_RECIPIENTS` | — | recipients per send |
| `PICLOUD_HTTP_MAX_REQUEST_BODY_BYTES` | — | outbound `http` request body |
| `PICLOUD_HTTP_MAX_RESPONSE_BODY_BYTES` | — | outbound `http` response body read |
## Sandbox ceilings
Upper bounds on per-script [sandbox overrides](../../guide/writing-scripts.md#sandbox-limits). An
override above the ceiling is rejected at deploy time. Defaults are the conservative built-ins.
| Variable | Default ceiling |
|---|---|
| `PICLOUD_SANDBOX_MAX_OPERATIONS` | 10,000,000 |
| `PICLOUD_SANDBOX_MAX_STRING_SIZE` | 1 MiB |
| `PICLOUD_SANDBOX_MAX_ARRAY_SIZE` | 100,000 |
| `PICLOUD_SANDBOX_MAX_MAP_SIZE` | 100,000 |
| `PICLOUD_SANDBOX_MAX_CALL_LEVELS` | 128 |
| `PICLOUD_SANDBOX_MAX_EXPR_DEPTH` | 128 |
Two related platform-level depth bounds (not per-script overridable):
| Variable | Default | Purpose |
|---|---|---|
| `PICLOUD_MAX_TRIGGER_DEPTH` | `8` | max trigger fan-out / `invoke` re-entry depth |
| `PICLOUD_MODULE_IMPORT_DEPTH_MAX` | `8` | max `import` chain depth |
## Outbound HTTP (`http` SDK)
| Variable | Default | Purpose |
|---|---|---|
| `PICLOUD_HTTP_ALLOW_PRIVATE` | `false` | **Dev/test only.** `true` disables the SSRF deny-list (allows requests to private/loopback IPs). Never production. |
## Email / SMTP
Configure a relay to make `email::send` work; without it, sends throw `NotConfigured` (or hit the dev
sink in dev mode).
| Variable | Purpose |
|---|---|
| `PICLOUD_SMTP_HOST` / `PICLOUD_SMTP_PORT` | relay address |
| `PICLOUD_SMTP_USER` / `PICLOUD_SMTP_PASSWORD` | relay auth |
| `PICLOUD_SMTP_TLS` | TLS mode |
| `PICLOUD_SMTP_TIMEOUT_SECS` | send timeout |
## Triggers, dispatcher & background workers
| Variable | Default | Purpose |
|---|---|---|
| `PICLOUD_DISPATCHER_ASYNC_EXEC_TIMEOUT_SEC` | `120` | per-message executor budget for async/triggered runs |
| `PICLOUD_DISPATCHER_TICK_INTERVAL_MS` | — | dispatcher poll interval |
| `PICLOUD_CRON_TICK_INTERVAL_MS` | — | cron scheduler resolution |
| `PICLOUD_QUEUE_RECLAIM_INTERVAL_MS` | — | how often expired claims are reclaimed |
| `PICLOUD_QUEUE_DEFAULT_VISIBILITY_TIMEOUT_SECS` | — | default queue claim lease |
| `PICLOUD_TRIGGER_RETRY_MAX_ATTEMPTS` | `3` | default trigger retry attempts |
| `PICLOUD_TRIGGER_RETRY_BACKOFF` | `exponential` | default backoff shape |
| `PICLOUD_TRIGGER_RETRY_BASE_MS` | `1000` | default backoff base |
| `PICLOUD_TRIGGER_RETRY_JITTER_PCT` | — | retry jitter |
| `PICLOUD_DEAD_LETTER_RETENTION_DAYS` | `30` | how long dead-letters are kept |
| `PICLOUD_ABANDONED_EXECUTIONS_RETENTION_DAYS` | — | sweep window for stale in-flight executions |
## Realtime, subscriber tokens & caches
| Variable | Default | Purpose |
|---|---|---|
| `PICLOUD_REALTIME_HEARTBEAT_SEC` | `30` | SSE heartbeat interval |
| `PICLOUD_REALTIME_BROADCAST_CAPACITY` | — | per-topic broadcast buffer |
| `PICLOUD_SUBSCRIBER_TOKEN_TTL_DEFAULT_SEC` / `_MIN_SEC` / `_MAX_SEC` | — | bounds for `pubsub::subscriber_token` TTLs |
| `PICLOUD_SCRIPT_CACHE_SIZE` / `PICLOUD_MODULE_CACHE_SIZE` | — | in-memory cache sizes |
## Files storage
| Variable | Default | Purpose |
|---|---|---|
| `PICLOUD_FILES_ROOT` | `./data` | filesystem root for `files` blobs |
| `PICLOUD_FILES_ORPHAN_SWEEP_INTERVAL_SEC` / `PICLOUD_FILES_ORPHAN_TMP_TTL_SEC` | — | cleanup of stale temp blobs |
## App-user token lifetimes (`users` SDK)
| Variable | Purpose |
|---|---|
| `PICLOUD_APP_USER_SESSION_TTL_HOURS` / `_ABSOLUTE_HOURS` | sliding & absolute session lifetime |
| `PICLOUD_APP_USER_VERIFICATION_TTL_HOURS` | email-verification token TTL |
| `PICLOUD_APP_USER_PASSWORD_RESET_TTL_HOURS` | password-reset token TTL |
| `PICLOUD_APP_USER_INVITATION_TTL_DAYS` | invitation TTL |
## `pic` CLI
| Variable | Purpose |
|---|---|
| `PICLOUD_URL` | default server URL for `pic` |
| `PICLOUD_TOKEN` | bearer token for `pic` (CI) |
> Values shown as "—" have an internal default that's safe to leave unset; consult the running
> instance or release notes if you need the exact number for capacity planning.