Storage
PlotPress keeps two kinds of state strictly separate.
1. Workspaces (in git)
Section titled “1. Workspaces (in git)”Markdown, YAML, optional SQL fallback files. Lives in your repository, mounted into the container at /workspace. PlotPress treats this directory as read-only at runtime — the only way to change a dashboard is to change the files. This is the “config-as-code” surface.
2. Metadata (in SQLite)
Section titled “2. Metadata (in SQLite)”Everything that has to outlive a single request:
| Table | Purpose |
|---|---|
users | id, email, oidc subject, last seen |
sessions | session token → user, expiry |
email_otp_codes | for the built-in email OTP flow |
audit_log | one row per query execution |
query_cache | optional; keyed by (dashboard, view, params_hash, user_roles_hash) |
A single SQLite file (/var/lib/plotpress/plotpress.db) holds all of it. WAL mode is on; back up with litestream or a periodic snapshot.
Why SQLite first
Section titled “Why SQLite first”- Zero ops. No separate process, no migration runner to schedule, no connection pool to tune.
- Backup is a file copy. Litestream replicates to S3/R2 transparently.
- Plenty fast. Audit and session writes stay well under SQLite’s single-writer ceiling for any team that fits in one Helm release.
- Container-friendly. The default Helm chart mounts a single PVC; that’s the entire stateful surface.
When you’d want Postgres
Section titled “When you’d want Postgres”Postgres is on the roadmap, not in v1. It becomes worth the operational cost when:
- You need >1 replica of the backend.
- Audit log retention grows past a few GB and you want partitioning / parallel queries.
- You already run Postgres and want one fewer thing to back up.
The schema is intentionally portable. Migration will be a pgloader run plus a connection-string change.
What is never stored
Section titled “What is never stored”- Connection DSNs. Read from env at boot. Never written to SQLite.
- Source data. Query results live in memory, optionally in
query_cachewith a short TTL, never in a long-lived table. - Workspace content. It’s already in git. Duplicating it would only invite drift.