03 — Dashboards & Apps¶
Who this is for: anyone packaging certified blocks into a consumption surface for stakeholders.
What you'll do: create an App, compose a dashboard page from the three certified blocks you built in tutorial 02, and open it in the Apps view.
Time: 15 minutes.
Setup: continues from 02 — Authoring blocks — three certified blocks (
revenue_by_month,avg_order_value,daily_orders).
The mental model¶
- An App is a folder under
apps/with adql.app.jsonmanifest: name, domain, owners, tags, plus dashboard pages, attached notebooks, AI pins, and drafts. It's the unit a stakeholder opens. - A dashboard page (
.dqld) is layout-only: a grid that references blocks by id and pins a viz type per tile. The blocks own the SQL, governance, and tests — dashboards never copy business logic.
Everything is a file, so the whole surface is reviewable in a PR.
Step 1 — Create the App¶
dql app new revenue-ops --domain revenue --owner you@your-company.com
You should see
apps/revenue-ops/created with adql.app.jsonmanifest and a scaffoldeddashboards/overview.dqld.
Step 2 — Lay out the dashboard¶
Replace apps/revenue-ops/dashboards/overview.dqld with:
{
"version": 1,
"id": "overview",
"metadata": {
"title": "Revenue — Overview",
"description": "Monthly revenue trend, order volume, and AOV.",
"domain": "revenue",
"tags": ["revenue", "overview"]
},
"layout": {
"kind": "grid",
"cols": 12,
"rowHeight": 80,
"items": [
{ "i": "kpi-aov", "x": 0, "y": 0, "w": 4, "h": 2,
"title": "Avg Order Value",
"block": { "blockId": "avg_order_value" },
"viz": { "type": "single_value", "options": { "format": "currency" } } },
{ "i": "trend-revenue", "x": 4, "y": 0, "w": 8, "h": 4,
"title": "Revenue by month",
"block": { "blockId": "revenue_by_month" },
"viz": { "type": "line", "options": { "x": "month", "y": "revenue" } } },
{ "i": "orders-bar", "x": 0, "y": 4, "w": 12, "h": 4,
"title": "Orders per day",
"block": { "blockId": "daily_orders" },
"viz": { "type": "bar", "options": { "x": "day", "y": "orders" } } }
]
}
}
Save.
Step 3 — Build and check block resolution¶
dql app build
You should see
✓ Built 1 app(s), 1 dashboard(s). - revenue-ops: 1 dashboard(s)
Confirm every tile resolved to a real block:
node -e "
const m = require('./dql-manifest.json');
const d = m.dashboards['revenue-ops/overview'];
console.log({ blockIds: d.blockIds, unresolved: d.unresolvedRefs });
"
You should see
unresolved: []. Anything listed there means a tile references a block id that doesn't exist — fix the typo or certify the missing block, then rebuild.
Dashboard IDs are local to their App; the manifest qualifies them as
appId/dashboardId, so different Apps can each have an overview.
Step 4 — Open it in the Apps view¶
dql notebook
- Click Apps in the activity bar.
- Open Revenue — Ops. The
overviewpage is the App homepage.
You should see the grid render the three certified tiles. Tiles can be dragged and resized in Build mode; stakeholders use View mode.
You can also attach the welcome notebook to the App (read-only preview) from the App's Build panel — useful for analysis narratives that accompany the dashboard.
Step 5 — See the full lineage¶
dql lineage --app revenue-ops
You should see the complete chain:
app:revenue-ops ↑ contains dashboard:revenue-ops/overview ↑ contains block:revenue_by_month · block:avg_order_value · block:daily_orders ↑ reads_from dbt model: orders → staging → seeds
This is the graph the agent, the impact-analysis tooling, and dql verify
all share.
What you now have¶
✓ An App folder (apps/revenue-ops/) tracked in git
✓ A dashboard page composed purely from certified blocks
✓ unresolved: [] — every tile resolves against the manifest
✓ End-to-end lineage from dbt sources to the App