Dashboard folder layout
A dashboard in PlotPress is a folder, and a self-contained workspace. The folder name is the dashboard’s URL slug. Connections, users, and pages all live inside it.
The repository
Section titled “The repository”plotpress/├── plotpress.yaml # server config (listen, auth, storage)└── dashboards/ ├── sales/ # → /dashboards/sales/ │ └── ... └── ops/ # → /dashboards/ops/ └── ...One server-level file. Everything else is a dashboard folder.
A single dashboard folder
Section titled “A single dashboard folder”dashboards/sales/├── dashboard.yaml # required, but tiny├── connections.yaml # data sources this dashboard reads├── users.yaml # roles + membership rules├── index.md # the landing page├── revenue.md # → /dashboards/sales/revenue├── customers.md # → /dashboards/sales/customers└── queries/ # OPTIONAL — only for the SQL fallback └── _shared.sqlFour conventions:
dashboard.yamlis required, but most dashboards only needtitleandconnection.connections.yamldeclares the data sources this dashboard can read. No inheritance from outside.users.yamldeclares the roles allowed on this dashboard.- Every
.mdfile is a page, named by its filename (index.mdis the folder root).
queries/ is optional. Plot blocks reference database views by default; queries/*.sql only exists when the database doesn’t expose a view that fits — see Connections for that fallback.
A minimal dashboard.yaml
Section titled “A minimal dashboard.yaml”title: Salesconnection: warehouse # default for views in this dashboardTwo fields. That’s the floor.
A page (revenue.md)
Section titled “A page (revenue.md)”---title: Revenue---
Revenue is recognised on invoice date. The warehouse refresh runs hourly;this page reflects the last completed refresh.
## Monthly revenue
```plot view=monthly_revenuePlot.barY(data, { x: "month", y: "revenue", fill: "currency" })```
## Top customers
```plot view=top_customers params.limit=20Plot.dot(data, { x: "deals", y: "revenue", r: "lifetime", tip: true })```monthly_revenue and top_customers are views in the warehouse. The dashboard’s connections.yaml decides which database those views live in; nothing else needs to be wired up.
Why one folder per dashboard
Section titled “Why one folder per dashboard”| Property | What you get |
|---|---|
| Diff-friendly | A PR that touches “sales” only touches dashboards/sales/. Reviewers see the unit. |
| Move-friendly | git mv dashboards/sales dashboards/finance/sales is the rename. The URL follows. |
| Self-contained | Connections and users are in the folder. Auditing “what can sales read?” is one cat. |
| Template-friendly | A new dashboard is cp -r dashboards/_template dashboards/new. |
| No hidden state | Delete the folder, the dashboard is gone — including its query surface area, which matters for security review. |
Recommended reading next
Section titled “Recommended reading next”- Configuration →
dashboard.yaml— every field, with defaults. - Configuration →
connections.yaml— connection schema. - Configuration →
users.yaml— role/membership schema. - Connections — driver-specific details (PostgreSQL, ClickHouse, MongoDB, S3, …).
- Plots — chart types with code and live previews.