@graphit/cli 0.1.18 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/dashboard.js.map +1 -1
- package/package.json +1 -1
- package/skills/graphit/SKILL.md +35 -22
- package/skills/graphit/cursor/graphit-data-sources.mdc +31 -0
- package/skills/graphit/cursor/graphit-presentations.mdc +56 -0
- package/skills/graphit/cursor/graphit-sql-reference.mdc +2 -0
- package/skills/graphit/graphit.mdc +7 -8
- package/skills/graphit/references/chart-patterns.md +2 -13
- package/skills/graphit/references/chart-selection.md +22 -17
- package/skills/graphit/references/dashboard-planning.md +10 -0
- package/skills/graphit/references/data-sources.md +25 -0
- package/skills/graphit/references/domain-lenses.md +2 -0
- package/skills/graphit/references/graphit-style.md +11 -0
- package/skills/graphit/references/kb-actions.md +43 -96
- package/skills/graphit/references/kb-discovery.md +78 -0
- package/skills/graphit/references/kb-structure.md +64 -0
- package/skills/graphit/references/kb-traversal.md +21 -40
- package/skills/graphit/references/presentations.md +142 -0
- package/skills/graphit/references/sql-reference.md +2 -0
- package/skills/graphit/references/kb-awareness.md +0 -90
- package/skills/graphit/references/kb-explanation.md +0 -50
- package/skills/graphit/references/kb-exploration.md +0 -63
- package/skills/graphit/references/kb-graph-structure.md +0 -55
|
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { apiClient } from "../api/client.js";
|
|
3
3
|
import { getFrontendUrl } from "../config.js";
|
|
4
4
|
import { output, errorOutput, getOutputFormat } from "../output/format.js";
|
|
5
|
-
const REQUIRED_ATTRS = ["data-graphit-id", "data-graphit-label", "data-graphit-
|
|
5
|
+
const REQUIRED_ATTRS = ["data-graphit-id", "data-graphit-label", "data-graphit-sql", "data-graphit-ds"];
|
|
6
6
|
const KNOWN_ATTRS = new Set([...REQUIRED_ATTRS, "data-graphit-highlight"]);
|
|
7
7
|
const TYPO_MAP = {
|
|
8
8
|
"data-graphit-entity": "data-graphit-id",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3E,MAAM,cAAc,GAAG,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/skills/graphit/SKILL.md
CHANGED
|
@@ -43,7 +43,7 @@ Your HTML must NEVER contain:
|
|
|
43
43
|
- `<img src="https://...">` - no external images
|
|
44
44
|
|
|
45
45
|
If you use ANY `src=` or `href=` pointing to a URL, the dashboard will be blank.
|
|
46
|
-
All CSS in `<style>`, all JS in `<script>`, all fonts from system stack. The iframe has a built-in runtime (`graphit.chart`, `graphit.table`, `graphit.kpi`) for standard visualizations - use it instead of importing libraries.
|
|
46
|
+
All CSS in `<style>`, all JS in `<script>`, all fonts from system stack. The iframe has a built-in runtime (`graphit.chart`, `graphit.table`, `graphit.kpi`, `graphit.presentation`) for standard visualizations - use it instead of importing libraries.
|
|
47
47
|
|
|
48
48
|
### 2. ALWAYS query through data sources
|
|
49
49
|
NEVER query the warehouse directly when a cached data source covers the table. Data sources return in ~100ms. Warehouse queries take ~10s and cost Snowflake credits.
|
|
@@ -59,13 +59,12 @@ NEVER query the warehouse directly when a cached data source covers the table. D
|
|
|
59
59
|
**Use the data source name in SQL** (e.g. `FROM MARKETING_UA_DS`), not the raw source table. The DS is a KB table - governance rules target it directly, and users recognize DS names from the platform.
|
|
60
60
|
|
|
61
61
|
### 3. EVERY element must have entity wrapping
|
|
62
|
-
Without `data-graphit-*` attributes, elements are invisible to the platform - no click info, no mentions, no KB provenance. Every chart, KPI card, table, and text section needs ALL
|
|
62
|
+
Without `data-graphit-*` attributes, elements are invisible to the platform - no click info, no mentions, no KB provenance. Every chart, KPI card, table, and text section needs ALL FOUR attributes:
|
|
63
63
|
|
|
64
64
|
```html
|
|
65
65
|
<div data-graphit-id="revenue-trend"
|
|
66
66
|
data-graphit-label="Revenue Trend"
|
|
67
|
-
data-graphit-
|
|
68
|
-
data-graphit-sql="SELECT region, SUM(revenue) FROM orders GROUP BY region"
|
|
67
|
+
data-graphit-sql="SELECT {{dim:REGION}} AS region, {{metric:REVENUE}} AS revenue FROM orders GROUP BY region"
|
|
69
68
|
data-graphit-ds="ds_abc123">
|
|
70
69
|
<!-- chart/KPI/table content here -->
|
|
71
70
|
</div>
|
|
@@ -75,11 +74,10 @@ Without `data-graphit-*` attributes, elements are invisible to the platform - no
|
|
|
75
74
|
|-----------|--------|---------|
|
|
76
75
|
| `data-graphit-id` | Unique kebab-case | `"spend-by-source"` |
|
|
77
76
|
| `data-graphit-label` | Human-readable name | `"Ad Spend by Source"` |
|
|
78
|
-
| `data-graphit-kb` | `type:NAME` comma-separated | `"metric:CPI,dimension:MEDIA_SOURCE,table:MARKETING_UA_DS"` |
|
|
79
77
|
| `data-graphit-sql` | Executable SQL (HTML-encode `<>&"`) | `"SELECT ..."` |
|
|
80
78
|
| `data-graphit-ds` | Data source ID from `graphit ds list` | `"ds_abc123"` |
|
|
81
79
|
|
|
82
|
-
KB
|
|
80
|
+
KB asset references are derived automatically from `{{metric:X}}` / `{{dim:X}}` templates in your SQL. The platform's governance compiler resolves these and displays KB asset chips in the entity details panel.
|
|
83
81
|
Missing any attribute = broken entity. Missing wrapping entirely = invisible to the platform.
|
|
84
82
|
|
|
85
83
|
**SQL must be complete and executable.** The platform runs `data-graphit-sql` against the data source when a user opens the entity's details panel. Write the full query from the `graphit.resolve()` call - never abbreviate, truncate, or use placeholders (`FROM ...`, `SELECT ...`, ellipsis). It MUST use the real DS table name and only columns that exist in the DS - never invented summary columns, CTE aliases, JS variable names, or prose. If the chart's resolve call uses a CTE, put the full WITH query. If JS builds SQL dynamically, store one representative executable variant (e.g. the default date range).
|
|
@@ -108,19 +106,32 @@ NEVER embed query results as static JS variables. The dashboard iframe provides
|
|
|
108
106
|
|
|
109
107
|
---
|
|
110
108
|
|
|
109
|
+
## How to Work (governs both workflows below)
|
|
110
|
+
|
|
111
|
+
You are a colleague building WITH the user, not a batch job that explores in silence and returns a finished product. Two habits make the difference: **short iterations** and **narration**.
|
|
112
|
+
|
|
113
|
+
**Short iterations.** Do one thing, show it, let the user react, then do the next: explore the KB and report what you found; validate one query and show the rows; build one section and show it. Each small step is a cheap chance for the user to redirect before you have built in the wrong direction. The opposite - exploring silently, deciding by yourself whether the data will work, then dropping a finished 600-line dashboard (or a bulk KB write) on the user - forces them to either accept a wrong result or send you back to the start.
|
|
114
|
+
|
|
115
|
+
**Always narrate.** The user cannot see your command output: the KB you listed, the SQL you ran, the rows that came back are invisible unless you surface them. So after each step, say what you found, what it means, and what you are about to do next. The one exception: if the user says "just build it" or "go", drop the running commentary and work straight through. Match the user's mode.
|
|
116
|
+
|
|
117
|
+
The difference in practice:
|
|
118
|
+
- **Weak (solo):** silently list the KB, silently run several queries, then save a complete dashboard and announce "Done - here's your dashboard."
|
|
119
|
+
- **Strong (collaborative):** "Found a **Marketing UA** data source with `{{metric:CPI}}` and `{{metric:ROAS}}` already defined. Starting with a spend-vs-installs trend - querying now." Then, after showing the rows: "Spend tracks installs except in March. Want that as the first graph, or should I look at ROAS first?"
|
|
120
|
+
|
|
121
|
+
The numbered steps in each workflow run *inside* this loop, not instead of it.
|
|
122
|
+
|
|
111
123
|
## Workflow: Dashboard Build
|
|
112
124
|
|
|
113
|
-
1. **Ask the
|
|
114
|
-
2. **
|
|
115
|
-
3. **
|
|
116
|
-
4. **
|
|
117
|
-
5. **
|
|
118
|
-
6. **Save
|
|
119
|
-
7. Give the user the dashboard URL so they can open it.
|
|
125
|
+
1. **Understand.** Ask what the dashboard should answer. Don't query until you know the goal - one clarifying question beats a wrong dashboard.
|
|
126
|
+
2. **Scope to the domain, then work down: domain -> data source -> assets.** Start narrow, not broad. Ask the user which business domain this dashboard is about (or infer it and confirm) - that scopes everything that follows. Then `graphit kb explore domain <NAME>` to see that domain's data sources and the metrics and dimensions defined on them. Reach for broad `graphit kb search` only as a fallback - when the domain is unclear or a concept spans domains. See `kb-discovery.md` and `kb-traversal.md`. Then tell the user what you found - the data source, the metrics and dimensions you'll use (by name), and the graphs you plan - before building.
|
|
127
|
+
3. **Pick the data source, and handle gaps.** Use the cached data source in that domain (~100ms, preferred over live warehouse at ~10s); use its name in SQL (`FROM MARKETING_UA_DS`). If that data source is missing something you need, first look for a connection to another data source you can join (`graphit kb list relationships`); only if the data genuinely does not exist yet, propose building a new data source rather than forcing a bad query.
|
|
128
|
+
4. **Validate each query, and show the result.** Write SQL with `{{metric:NAME}}` / `{{dim:NAME}}` reference syntax for KB assets, run it with `--verbose`, and for EVERY query show the user a compact result: the reference-syntax query, a small markdown table of rows, the row count, and the trust tier. If a query returns zero rows or nulls, say so and diagnose (wrong table? filter too narrow?).
|
|
129
|
+
5. **Get approval, then build.** Once the user is happy with the data and plan, assemble the HTML: `graphit.resolve()` for live data, `graphit.chart/table/kpi` for rendering, every entity wrapped (see HARD CONSTRAINTS), all CSS in `<style>`, all JS in `<script>`. For a large dashboard, add entities incrementally - build one, show it, add the next - rather than generating everything at once. Write to a local `.html` file.
|
|
130
|
+
6. **Save - prefer entity updates - then hand off.** New dashboard: `graphit dashboard update-html <id> --file <path>`. Changing an existing one: prefer `graphit dashboard update-entity <id> <entity_id>`, which updates a single entity without regenerating (and destroying) the rest. If the response contains `entity_sql_warnings`, an entity's `data-graphit-sql` is missing, matches no data source, or fails the DS schema - fix the flagged entities and save again before reporting done. Confirm the save succeeded, then give the user the dashboard URL.
|
|
120
131
|
|
|
121
132
|
## Workflow: KB Build / Onboarding
|
|
122
133
|
|
|
123
|
-
When the user wants to build or populate their KB (from files, schema descriptions, or scratch). Consult `kb-
|
|
134
|
+
When the user wants to build or populate their KB (from files, schema descriptions, or scratch). Consult `kb-structure.md` for the full graph model and structural Q&A, `kb-traversal.md` for tool selection, `kb-actions.md` for the CLI command matrix, `kb-discovery.md` for when to propose asset creation, and `parameterized-metrics.md` for template metrics.
|
|
124
135
|
|
|
125
136
|
**Step 1: Audit current KB state.** Before proposing anything, traverse the existing KB:
|
|
126
137
|
|
|
@@ -128,9 +139,9 @@ When the user wants to build or populate their KB (from files, schema descriptio
|
|
|
128
139
|
2. For each domain: `graphit kb explore domain <NAME>` - returns all tables and assets in that domain in one traversal (see `kb-traversal.md` depth guidelines)
|
|
129
140
|
3. `graphit kb list synonyms` and `graphit kb list relationships` - global assets not scoped to domains
|
|
130
141
|
|
|
131
|
-
Present a tree summary of what already exists, following the Domain > Table > Topic > Asset hierarchy from `kb-
|
|
142
|
+
Present a tree summary of what already exists, following the Domain > Table > Topic > Asset hierarchy from `kb-structure.md`.
|
|
132
143
|
|
|
133
|
-
**Step 2: Analyze input.** Read the user's files, schema, or description. Classify every concept by asset type. Use `kb-
|
|
144
|
+
**Step 2: Analyze input.** Read the user's files, schema, or description. Classify every concept by asset type. Use `kb-structure.md` for asset type definitions (what is a metric vs dimension vs rule). Use `kb-discovery.md` for signals (aggregation = metric, derived grouping = dimension, business constraint = rule, colloquial term = synonym).
|
|
134
145
|
|
|
135
146
|
**Step 3: Present a tree-structured plan.** Show what will be created, organized by the KB hierarchy. Mark existing assets with (exists) so the user sees what's new vs what's already there:
|
|
136
147
|
|
|
@@ -288,6 +299,8 @@ The `dataSourceId` is the ID from `graphit ds list`. The `target` parameter (CSS
|
|
|
288
299
|
|
|
289
300
|
**Error handling:** `graphit.resolve()` rejects on timeout (120s), bad SQL, or invalid data source ID. Wrap calls in try/catch and show a user-visible error message in the target element on failure. Verify SQL returns data via the CLI before embedding it in HTML.
|
|
290
301
|
|
|
302
|
+
**Rate limit:** 120 requests per minute per user per dashboard. Each `graphit.resolve()` call counts as one request. A dashboard with 6 KPIs/charts that refreshes on every filter change uses 6 requests per interaction - budget for ~20 filter changes per minute. If you hit the limit, the API returns a "Too many requests" error with a retry-after hint. Design dashboards to batch all queries in a single `Promise.all` so they count against the same time window rather than spreading across multiple refresh calls.
|
|
303
|
+
|
|
291
304
|
### First-paint loading state
|
|
292
305
|
|
|
293
306
|
The dashboard HTML paints before the SDK connects (iframe load + handshake), so the SDK's own spinner cannot cover the first moments. Bake this pure-CSS overlay into the HTML so every chart shows a spinner from the first frame; the SDK adopts it and removes it when that element's `graphit.resolve()` settles (success or error).
|
|
@@ -322,6 +335,7 @@ The iframe also provides optional convenience helpers if you want quick standard
|
|
|
322
335
|
| `graphit.chart(el, {type, data, x, y, ...})` | Bar, line, area, donut, scatter, stacked-bar, heatmap, funnel, gauge, sparkline |
|
|
323
336
|
| `graphit.table(el, {data, columns?, maxRows?})` | Styled HTML table. `columns` is a `string[]` of data keys (NOT objects), defaults to `Object.keys(data[0])` |
|
|
324
337
|
| `graphit.kpi(el, {value, label?, format?})` | KPI card with optional delta |
|
|
338
|
+
| `graphit.presentation(el)` | Full-screen slide deck. Returns builder: `.slide({bg, layout, html})` then `.start()`. See `presentations.md` |
|
|
325
339
|
|
|
326
340
|
These are shortcuts, not requirements. Use them when a standard chart is all you need. Hand-roll when you want full control over the visualization.
|
|
327
341
|
|
|
@@ -334,8 +348,7 @@ These are shortcuts, not requirements. Use them when a standard chart is all you
|
|
|
334
348
|
```html
|
|
335
349
|
<div data-graphit-id="spend-by-source"
|
|
336
350
|
data-graphit-label="Ad Spend by Source"
|
|
337
|
-
data-graphit-
|
|
338
|
-
data-graphit-sql="SELECT MEDIA_SOURCE, SUM(APPSFLYER_COST) as spend FROM MARKETING_UA_DS GROUP BY MEDIA_SOURCE ORDER BY spend DESC"
|
|
351
|
+
data-graphit-sql="SELECT {{dim:MEDIA_SOURCE_DIMENSION}} AS source, {{metric:CPI}} AS cpi FROM MARKETING_UA_DS GROUP BY source ORDER BY cpi DESC"
|
|
339
352
|
data-graphit-ds="ds_abc123">
|
|
340
353
|
<div id="spend-chart" class="gh-loading">
|
|
341
354
|
<div class="gh-loading-overlay"><svg class="gh-loading-spin" width="24" height="24" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="var(--graphit-border,#e5e5e5)" stroke-width="2.5"/><path d="M12 2a10 10 0 0 1 10 10" stroke="var(--graphit-accent,#4DB6AC)" stroke-width="2.5" stroke-linecap="round"/></svg></div>
|
|
@@ -366,10 +379,8 @@ Detailed knowledge lives in `references/`. Consult the relevant file when you ne
|
|
|
366
379
|
|------|-------------|
|
|
367
380
|
| `dashboard-planning.md` | Building a multi-chart dashboard. Covers framing the question, picking archetype, mandatory rules, metric contracts, anti-patterns. |
|
|
368
381
|
| `chart-selection.md` | Choosing chart types. Full dimension/measure defaults, perception ranking, cardinality guards, hard caps. |
|
|
369
|
-
| `kb-
|
|
370
|
-
| `kb-
|
|
371
|
-
| `kb-graph-structure.md` | KB graph model. 9 node types, 5 edge types, multi-membership semantics, domain cascade, tree rendering order. |
|
|
372
|
-
| `kb-explanation.md` | Structural Q&A. What are domains, topics, tables, relationships, memory. Why assets appear where they do. |
|
|
382
|
+
| `kb-discovery.md` | Starting a build (domain-first). Domain -> DS -> assets discovery, metric vs dimension, naming, formula syntax, when to propose asset creation, reuse over reinvention, cross-table referencing. |
|
|
383
|
+
| `kb-structure.md` | KB graph model + structural Q&A. Node types, edge types, the vertical home (domain -> DS -> assets) vs horizontal topics, tree order, and how to answer "what is a domain" / "why is X under Y". |
|
|
373
384
|
| `kb-traversal.md` | Graph queries. Tool selection guide (search vs explore vs read), common query patterns, depth guidelines. |
|
|
374
385
|
| `kb-actions.md` | Full CRUD matrix. Asset create/edit/delete, topic management, domain assignment cascade, navigation and discovery. |
|
|
375
386
|
| `parameterized-metrics.md` | Metric templates. ${PARAM:NAME} tokens, child variant auto-generation, editing templates, using variants in queries. |
|
|
@@ -378,3 +389,5 @@ Detailed knowledge lives in `references/`. Consult the relevant file when you ne
|
|
|
378
389
|
| `graphit-style.md` | Building the HTML. Design principles, typography scale, color system with usage rules, layout patterns (page structure, KPI cards, data tables). |
|
|
379
390
|
| `chart-patterns.md` | Custom chart implementations. Inline SVG/CSS code for: scatter/bubble, heatmap, funnel, gauge, sparkline, stacked bar, and the shared tooltip pattern. |
|
|
380
391
|
| `governance.md` | Query governance. Reference syntax, trust tiers, enforceable rules, override flow, governance commands. |
|
|
392
|
+
| `presentations.md` | Slide deck presentations. Builder API, layouts (center/split/full), backgrounds, navigation, live data inside slides. |
|
|
393
|
+
| `data-sources.md` | Building performant, cache-friendly data sources. Why source shape decides dashboard speed; pre-aggregate to query grain, narrow columns, keep high-cardinality dimensions out of the base. |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: false
|
|
3
|
+
description: "Graphit: Consult when creating or shaping a data source. A source's shape (set by its source SQL) decides dashboard speed and whether filter changes are cacheable: pre-aggregate to the query grain, narrow columns, keep high-cardinality dimensions out of the base."
|
|
4
|
+
globs: []
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Data Sources: Building for Speed
|
|
8
|
+
|
|
9
|
+
A data source's shape - set by its source SQL at creation - decides how fast every dashboard built on it will be, and whether filter changes feel instant. Get this right when you create the source; it can't be fixed later in the dashboard SQL.
|
|
10
|
+
|
|
11
|
+
## Why source shape decides dashboard speed
|
|
12
|
+
|
|
13
|
+
When you change a dashboard filter (e.g. switch country), Graphit answers from a cached, pre-aggregated result instead of re-scanning the whole source - but only when the source is small and already aggregated to the grain you query. Build the source as one row per the grain you'll chart (e.g. month x country x channel) with only the columns you use, and filter changes return in milliseconds. Pull in raw ungrouped rows, hundreds of columns, or thousands-of-values dimensions and the result is too big to cache - every filter change re-scans the entire source and is slow.
|
|
14
|
+
|
|
15
|
+
## Build it right (in the source SQL)
|
|
16
|
+
|
|
17
|
+
1. **Pre-aggregate to your query grain.** Use `GROUP BY` so the source has one row per the grain you'll chart (month x country x channel), not one row per raw event. The single biggest speed lever.
|
|
18
|
+
2. **Select only the columns you'll use.** Every column is downloaded and cached on each query; hundreds of columns slow every dashboard, even ones that touch a few.
|
|
19
|
+
3. **Keep high-cardinality dimensions out of the base.** Individual ad / campaign / adset names (thousands of values) explode aggregation cost and block filter-caching. If you need them, build a separate filtered drill-down source.
|
|
20
|
+
4. **Aim small.** A source whose typical query aggregates a few thousand rows is fast and cacheable; a 50M-row, 400-column raw source is slow no matter how the dashboard is written. The size guardrails (>100M rows / >5GB) are the ceiling, not the target.
|
|
21
|
+
|
|
22
|
+
## Quick check
|
|
23
|
+
|
|
24
|
+
| Lever | Build it right | Anti-pattern |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| Grain | `GROUP BY` to the grain you chart | One row per raw event |
|
|
27
|
+
| Columns | Only the columns dashboards use | 400+ columns "just in case" |
|
|
28
|
+
| Cardinality | Low-card dimensions in the base; ad/campaign names in a separate drill-down | Thousands-of-values dimensions in the base grain |
|
|
29
|
+
| Size | A few-thousand-row typical aggregation | Sitting at the 100M-row / 5GB ceiling |
|
|
30
|
+
|
|
31
|
+
Build the source small and pre-aggregated, and dashboards on it stay fast and filterable.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: false
|
|
3
|
+
description: "Graphit: Build full-screen slide deck presentations inside canvas dashboards using graphit.presentation(). Builder pattern with layouts, backgrounds, and keyboard navigation."
|
|
4
|
+
globs: []
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Presentations
|
|
8
|
+
|
|
9
|
+
Build slide deck presentations inside Graphit canvas dashboards using `graphit.presentation()`.
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
var deck = graphit.presentation('#my-deck');
|
|
15
|
+
deck.slide({ bg: 'dark', layout: 'center', html: '<h1>Title</h1>' });
|
|
16
|
+
deck.slide({ bg: 'white', layout: 'split', html: '<div>Left</div><div>Right</div>' });
|
|
17
|
+
deck.slide({ bg: 'paper', layout: 'full', html: '<div id="charts">...</div>' });
|
|
18
|
+
var ctrl = deck.start();
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Slide Config
|
|
22
|
+
|
|
23
|
+
| Field | Type | Default | Description |
|
|
24
|
+
|-------|------|---------|-------------|
|
|
25
|
+
| `layout` | `'center'` / `'split'` / `'full'` | `'center'` | Content arrangement |
|
|
26
|
+
| `bg` | `'paper'` / `'white'` / `'dark'` / `'teal'` / hex | `'paper'` | Fixed background |
|
|
27
|
+
| `html` | `string` | `''` | Raw HTML content |
|
|
28
|
+
|
|
29
|
+
## Layouts
|
|
30
|
+
|
|
31
|
+
- **center**: Centered horizontally/vertically. Title slides, CTAs.
|
|
32
|
+
- **split**: First two child elements become left/right panels. Text + image.
|
|
33
|
+
- **full**: Top-to-bottom flow. Tables, grids, live data.
|
|
34
|
+
|
|
35
|
+
## Backgrounds (fixed, not theme-aware)
|
|
36
|
+
|
|
37
|
+
| Name | Background | Text |
|
|
38
|
+
|------|-----------|------|
|
|
39
|
+
| `paper` | `#F7F6F2` | `#222224` |
|
|
40
|
+
| `white` | `#FFFFFF` | `#222224` |
|
|
41
|
+
| `dark` | `#222224` | `#F7F6F2` |
|
|
42
|
+
| `teal` | `#4DB6AC` | `#FFFFFF` |
|
|
43
|
+
|
|
44
|
+
## Navigation
|
|
45
|
+
|
|
46
|
+
Arrow keys, spacebar, Home/End. Prev/Next buttons bottom-right with slide counter.
|
|
47
|
+
|
|
48
|
+
## Live data works inside slides
|
|
49
|
+
|
|
50
|
+
`graphit.resolve()` + `graphit.chart/table/kpi` work inside slides. Entity wrapping (`data-graphit-*`) works normally.
|
|
51
|
+
|
|
52
|
+
## Anti-Patterns
|
|
53
|
+
|
|
54
|
+
- Don't use external fonts/images (CSP blocks). Embed as base64 or use system fonts.
|
|
55
|
+
- Don't put scrollable content on slides. Split into multiple slides.
|
|
56
|
+
- One `graphit.presentation()` per dashboard.
|
|
@@ -128,12 +128,14 @@ Canvas `graphit.resolve()` queries that follow these shapes serve from a semanti
|
|
|
128
128
|
- Literal dates (`>= '2026-01-01'`), never `CURRENT_DATE` expressions
|
|
129
129
|
- GROUP BY column names or ordinals; ORDER BY / LIMIT allowed (outer only)
|
|
130
130
|
- CTEs are fine when the CTE body follows the same rules
|
|
131
|
+
- Top-N rank queries: project the sort metric in SELECT (`SELECT dim, SUM(metric) AS rv ... ORDER BY rv DESC LIMIT N`), not only in ORDER BY
|
|
131
132
|
|
|
132
133
|
**Shapes that skip the cache** (fall back to normal execution, still correct):
|
|
133
134
|
- `COUNT(DISTINCT x)`, window functions, HAVING, QUALIFY
|
|
134
135
|
- OR / NOT in WHERE
|
|
135
136
|
- Ratio metrics (`SUM(a)/NULLIF(SUM(b),0)`) - compute client-side or use two resolves
|
|
136
137
|
- `CURRENT_DATE`-relative predicates
|
|
138
|
+
- Top-N with aggregate only in ORDER BY (`SELECT dim FROM t GROUP BY dim ORDER BY SUM(metric) DESC LIMIT N` - no decomposable aggregate in SELECT)
|
|
137
139
|
|
|
138
140
|
## Data Source Routing
|
|
139
141
|
|
|
@@ -28,13 +28,12 @@ Run `graphit ds list` FIRST. If a DS covers your table, use `graphit query "SQL"
|
|
|
28
28
|
**Use the DS name in SQL, not the source table name.** Write `FROM MARKETING_UA_DS`, not `FROM MARKETING_UA`. The DS name is what users see in the platform. DuckDB resolves both, but the DS name keeps SQL consistent with the UI.
|
|
29
29
|
|
|
30
30
|
### 3. EVERY element must have entity wrapping
|
|
31
|
-
Without `data-graphit-*` attributes, elements are invisible to the platform. Every chart, KPI card, table, and text section needs ALL
|
|
31
|
+
Without `data-graphit-*` attributes, elements are invisible to the platform. Every chart, KPI card, table, and text section needs ALL FOUR attributes:
|
|
32
32
|
|
|
33
33
|
```html
|
|
34
34
|
<div data-graphit-id="revenue-trend"
|
|
35
35
|
data-graphit-label="Revenue Trend"
|
|
36
|
-
data-graphit-
|
|
37
|
-
data-graphit-sql="SELECT region, SUM(revenue) FROM orders GROUP BY region"
|
|
36
|
+
data-graphit-sql="SELECT {{dim:REGION}} AS region, {{metric:REVENUE}} AS revenue FROM orders GROUP BY region"
|
|
38
37
|
data-graphit-ds="ds_abc123">
|
|
39
38
|
<!-- chart/KPI/table content here -->
|
|
40
39
|
</div>
|
|
@@ -44,11 +43,10 @@ Without `data-graphit-*` attributes, elements are invisible to the platform. Eve
|
|
|
44
43
|
|-----------|--------|---------|
|
|
45
44
|
| `data-graphit-id` | Unique kebab-case | `"spend-by-source"` |
|
|
46
45
|
| `data-graphit-label` | Human-readable name | `"Ad Spend by Source"` |
|
|
47
|
-
| `data-graphit-kb` | `type:NAME` comma-separated | `"metric:CPI,dimension:MEDIA_SOURCE,table:MARKETING_UA_DS"` |
|
|
48
46
|
| `data-graphit-sql` | Executable SQL (HTML-encode `<>&"`) | `"SELECT ..."` |
|
|
49
47
|
| `data-graphit-ds` | Data source ID from `graphit ds list` | `"ds_abc123"` |
|
|
50
48
|
|
|
51
|
-
KB
|
|
49
|
+
KB asset references are derived automatically from `{{metric:X}}` / `{{dim:X}}` templates in your SQL.
|
|
52
50
|
|
|
53
51
|
**SQL must be complete and executable.** The platform runs `data-graphit-sql` against the data source when a user opens the entity's details panel. Write the full query from the `graphit.resolve()` call - never abbreviate, truncate, or use placeholders (`FROM ...`, `SELECT ...`, ellipsis). It MUST use the real DS table name and only columns that exist in the DS - never invented summary columns, CTE aliases, JS variable names, or prose. If the chart's resolve call uses a CTE, put the full WITH query. If JS builds SQL dynamically, store one representative executable variant (e.g. the default date range).
|
|
54
52
|
|
|
@@ -109,7 +107,7 @@ You are the rendering layer - format and present every CLI result using markdown
|
|
|
109
107
|
|
|
110
108
|
## Workflow: KB Build / Onboarding
|
|
111
109
|
|
|
112
|
-
When the user wants to build or populate their KB from files, schemas, or scratch. Consult companion rules: graphit-kb-graph-structure (graph model), graphit-kb-traversal (tool selection), graphit-kb-actions (CLI commands), graphit-kb-awareness (when to propose assets), graphit-parameterized-metrics (template metrics).
|
|
110
|
+
When the user wants to build or populate their KB from files, schemas, or scratch. Consult companion rules: graphit-kb-graph-structure (graph model), graphit-kb-traversal (tool selection), graphit-kb-actions (CLI commands), graphit-kb-awareness (when to propose assets), graphit-parameterized-metrics (template metrics), graphit-data-sources (shaping sources for speed: pre-aggregate to grain, narrow columns, keep high-cardinality dimensions out of the base).
|
|
113
111
|
|
|
114
112
|
1. **Audit current KB state FIRST.** Traverse, don't just list: `graphit kb list domains`, then `graphit kb explore domain <NAME>` for each (returns full tree in one call). Add `graphit kb list synonyms` and `graphit kb list relationships` for globals. Present tree summary.
|
|
115
113
|
2. **Analyze input.** Read the user's files/schema. Classify every concept by asset type (see graphit-kb-explanation for definitions, graphit-kb-awareness for signals).
|
|
@@ -153,6 +151,8 @@ const result = await graphit.resolve({
|
|
|
153
151
|
|
|
154
152
|
**Error handling:** Rejects on timeout (120s), bad SQL, or invalid data source ID. Wrap in try/catch.
|
|
155
153
|
|
|
154
|
+
**Rate limit:** 120 requests/min per user per dashboard. A 6-chart dashboard uses 6 requests per filter change (~20 changes/min budget). Batch all queries in a single `Promise.all`.
|
|
155
|
+
|
|
156
156
|
### First-paint loading state
|
|
157
157
|
|
|
158
158
|
The HTML paints before the SDK connects, so bake a pure-CSS spinner overlay into the page; the SDK adopts it and removes it when that element's `graphit.resolve()` settles (success or error). Add once to the page `<style>`:
|
|
@@ -181,8 +181,7 @@ Add the overlay inside EVERY element you pass as `target:` - and ONLY those elem
|
|
|
181
181
|
```html
|
|
182
182
|
<div data-graphit-id="spend-by-source"
|
|
183
183
|
data-graphit-label="Ad Spend by Source"
|
|
184
|
-
data-graphit-
|
|
185
|
-
data-graphit-sql="SELECT MEDIA_SOURCE, SUM(APPSFLYER_COST) as spend FROM MARKETING_UA_DS GROUP BY MEDIA_SOURCE ORDER BY spend DESC"
|
|
184
|
+
data-graphit-sql="SELECT {{dim:MEDIA_SOURCE_DIMENSION}} AS source, {{metric:CPI}} AS cpi FROM MARKETING_UA_DS GROUP BY source ORDER BY cpi DESC"
|
|
186
185
|
data-graphit-ds="ds_abc123">
|
|
187
186
|
<div id="spend-chart" class="gh-loading">
|
|
188
187
|
<div class="gh-loading-overlay"><svg class="gh-loading-spin" width="24" height="24" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="var(--graphit-border,#e5e5e5)" stroke-width="2.5"/><path d="M12 2a10 10 0 0 1 10 10" stroke="var(--graphit-accent,#4DB6AC)" stroke-width="2.5" stroke-linecap="round"/></svg></div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Chart Patterns
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The chart types documented below are the native `graphit.chart()` types. Anything not listed here (treemap, sankey, maps, box) is hand-rolled SVG - see `chart-selection.md` for the native-vs-hand-rolled split. All data comes from `graphit.resolve()` - never embed static data.
|
|
4
4
|
|
|
5
5
|
**NEVER use `<canvas>`.** Canvas produces blurry charts inside the sandboxed iframe due to DPI scaling issues.
|
|
6
6
|
|
|
@@ -54,18 +54,7 @@ Templates are org-specific - they exist only when users have saved them. The age
|
|
|
54
54
|
|
|
55
55
|
## Color tokens
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|---|---|
|
|
59
|
-
| `var(--graphit-accent)` | Primary brand teal |
|
|
60
|
-
| `var(--graphit-success)` | Positive/good |
|
|
61
|
-
| `var(--graphit-warning)` | Caution |
|
|
62
|
-
| `var(--graphit-error)` | Negative/bad |
|
|
63
|
-
| `var(--graphit-fg)` | Primary text |
|
|
64
|
-
| `var(--graphit-fg-muted)` | Secondary text |
|
|
65
|
-
| `var(--graphit-fg-subtle)` | Labels, placeholders |
|
|
66
|
-
| `var(--graphit-border)` | Borders, grid lines |
|
|
67
|
-
| `var(--graphit-surface-raised)` | Card backgrounds |
|
|
68
|
-
| `var(--graphit-surface-sunken)` | Inset areas |
|
|
57
|
+
Use theme CSS variables for all structural colors so charts adapt to light and dark mode. The full token table and usage rules live in `graphit-style.md` - that is the single source; do not re-list tokens here. Chart series colors come from the runtime palette automatically.
|
|
69
58
|
|
|
70
59
|
## Tooltip pattern (for hand-rolled charts)
|
|
71
60
|
|
|
@@ -17,23 +17,26 @@ When ambiguous, propose 2-3 options and ask the user. Do not guess.
|
|
|
17
17
|
|
|
18
18
|
## Full Chart Type Table
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
|
23
|
-
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
| Correlation | scatter | 2 numeric |
|
|
33
|
-
| 3 variables | bubble | 3 numeric |
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
20
|
+
`graphit.chart()` renders only the **native** types below and throws `Unsupported graphit.chart type` on anything else. The iframe still lets you draw anything with inline SVG/CSS, so the **hand-rolled** shapes are fully buildable - just not through `graphit.chart()` (see `chart-patterns.md`). Never pass a hand-rolled type name to `graphit.chart()`.
|
|
21
|
+
|
|
22
|
+
| Data shape | Chart type | Render with | Columns |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| Time series | line / area | `graphit.chart` (native) | 1 temporal + 1 numeric |
|
|
25
|
+
| Categories | bar | `graphit.chart` (native) | 1 categorical + 1 numeric |
|
|
26
|
+
| Long category labels | horizontal-bar | `graphit.chart` (native) | 1 categorical + 1 numeric |
|
|
27
|
+
| Part-whole (max 5 slices) | donut / pie | `graphit.chart` (native) | 1 categorical + 1 numeric |
|
|
28
|
+
| Single metric | KPI card | `graphit.kpi` (native) | 1 numeric |
|
|
29
|
+
| Stages | funnel | `graphit.chart` (native) | 1 categorical + 1 numeric |
|
|
30
|
+
| Target / progress | gauge | `graphit.chart` (native) | 1 numeric |
|
|
31
|
+
| Matrix (unpivoted) | heatmap | `graphit.chart` (native) | 2 categorical + 1 numeric |
|
|
32
|
+
| Correlation | scatter | `graphit.chart` (native) | 2 numeric |
|
|
33
|
+
| 3 variables | bubble | `graphit.chart` (native) | 3 numeric |
|
|
34
|
+
| Inline trend | sparkline | `graphit.chart` (native) | 1 numeric series |
|
|
35
|
+
| Detail / raw data | table | `graphit.table` (native) | any columns |
|
|
36
|
+
| Hierarchy | treemap | hand-rolled SVG | 1 categorical + 1 numeric |
|
|
37
|
+
| Flows | sankey | hand-rolled SVG | 2 categorical + 1 numeric |
|
|
38
|
+
| Geographic | map | hand-rolled SVG | region or lat/lng + 1 numeric |
|
|
39
|
+
| Distribution | histogram / box | hand-rolled SVG | 1 numeric |
|
|
37
40
|
|
|
38
41
|
## Perception Ranking (Cleveland-McGill)
|
|
39
42
|
|
|
@@ -53,6 +56,8 @@ Position > length > angle > area > color.
|
|
|
53
56
|
| KPI vs target | big-number + sparkline | gauge (unbounded) |
|
|
54
57
|
| 2D matrix / cohort | heatmap | bar with 100+ |
|
|
55
58
|
|
|
59
|
+
The native `graphit.chart` first choices here are line, bar, stacked-bar, scatter, bubble, funnel, heatmap, gauge, and sparkline. Treemap, histogram, and box are hand-rolled SVG (see the table above) - draw them, don't pass them to `graphit.chart()`.
|
|
60
|
+
|
|
56
61
|
## Cardinality Guards
|
|
57
62
|
|
|
58
63
|
| Cardinality of categorical dim | Action |
|
|
@@ -82,6 +82,16 @@ Purpose before data. The first response should mirror the user's intent and ask
|
|
|
82
82
|
- User says "active users" - ask: what defines active? (logged in? performed action? within what window?)
|
|
83
83
|
- User mentions MQL/SQL - ask: how does your org define the handoff? (Same column can mean 13% or 40%)
|
|
84
84
|
|
|
85
|
+
## Performance
|
|
86
|
+
|
|
87
|
+
`graphit.resolve()` is rate-limited to 120 requests/min per user per dashboard. Each call counts as one request. Design for efficiency:
|
|
88
|
+
|
|
89
|
+
- **Single refresh function.** All queries in ONE `Promise.all` inside one `refresh()` function. Never scatter `graphit.resolve()` across independent event handlers or timeouts - that turns one user action into multiple bursts.
|
|
90
|
+
- **Count your queries per interaction.** 6 charts = 6 requests per filter change = 20 changes/min budget. 12 charts = 10 changes/min. If you have 10+ charts with 3+ filters, consider debouncing filter changes (300ms) so rapid clicks don't each trigger a full refresh.
|
|
91
|
+
- **Reuse trend data for KPIs.** If you already fetch a weekly time series (`SELECT week, SUM(spend) ...`), derive the KPI total and sparkline from that result set in JS instead of running a separate aggregate query. One query serves both the chart and the KPI card.
|
|
92
|
+
- **Avoid redundant refreshes.** If a filter only affects some charts, split into targeted refresh functions (`refreshKPIs()`, `refreshCharts()`) so unchanged sections don't re-query.
|
|
93
|
+
- **No polling.** Never `setInterval(refresh, ...)`. Data sources update on their own schedule - a dashboard that polls wastes the entire rate budget.
|
|
94
|
+
|
|
85
95
|
## Pre-Build Checklist
|
|
86
96
|
|
|
87
97
|
Before generating the HTML:
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Data Sources: Building for Speed
|
|
2
|
+
|
|
3
|
+
A data source's shape - set by its source SQL at creation - decides how fast every dashboard built on it will be, and whether filter changes feel instant. Get this right when you create the source; it can't be fixed later in the dashboard SQL.
|
|
4
|
+
|
|
5
|
+
## Why source shape decides dashboard speed
|
|
6
|
+
|
|
7
|
+
When you change a dashboard filter (e.g. switch country), Graphit answers from a cached, pre-aggregated result instead of re-scanning the whole source - but only when the source is small and already aggregated to the grain you query. Build the source as one row per the grain you'll chart (e.g. month x country x channel) with only the columns you use, and filter changes return in milliseconds. Pull in raw ungrouped rows, hundreds of columns, or thousands-of-values dimensions and the result is too big to cache - every filter change re-scans the entire source and is slow.
|
|
8
|
+
|
|
9
|
+
## Build it right (in the source SQL)
|
|
10
|
+
|
|
11
|
+
1. **Pre-aggregate to your query grain.** Use `GROUP BY` so the source has one row per the grain you'll chart (month x country x channel), not one row per raw event. The single biggest speed lever.
|
|
12
|
+
2. **Select only the columns you'll use.** Every column is downloaded and cached on each query; hundreds of columns slow every dashboard, even ones that touch a few.
|
|
13
|
+
3. **Keep high-cardinality dimensions out of the base.** Individual ad / campaign / adset names (thousands of values) explode aggregation cost and block filter-caching. If you need them, build a separate filtered drill-down source.
|
|
14
|
+
4. **Aim small.** A source whose typical query aggregates a few thousand rows is fast and cacheable; a 50M-row, 400-column raw source is slow no matter how the dashboard is written. The size guardrails (>100M rows / >5GB) are the ceiling, not the target.
|
|
15
|
+
|
|
16
|
+
## Quick check
|
|
17
|
+
|
|
18
|
+
| Lever | Build it right | Anti-pattern |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Grain | `GROUP BY` to the grain you chart | One row per raw event |
|
|
21
|
+
| Columns | Only the columns dashboards use | 400+ columns "just in case" |
|
|
22
|
+
| Cardinality | Low-card dimensions in the base; ad/campaign names in a separate drill-down | Thousands-of-values dimensions in the base grain |
|
|
23
|
+
| Size | A few-thousand-row typical aggregation | Sitting at the 100M-row / 5GB ceiling |
|
|
24
|
+
|
|
25
|
+
Build the source small and pre-aggregated, and dashboards on it stay fast and filterable.
|
|
@@ -4,6 +4,8 @@ Consult when the user's data signals match a specific business domain. Each lens
|
|
|
4
4
|
|
|
5
5
|
Detect the domain from column names and user intent. Apply universal planning rules first (see dashboard-planning.md), then layer domain-specific patterns.
|
|
6
6
|
|
|
7
|
+
Several high-value lens charts - **waterfall** (P&L / ARR bridges), **bullet** (KPI vs target), **Lorenz** (revenue concentration), and **histogram** (attainment distribution) - are NOT native `graphit.chart()` types, so `graphit.chart()` throws on those names. Build them as hand-rolled SVG (see `chart-selection.md` for the native-vs-hand-rolled split). The native lens charts (line, bar, stacked-bar, heatmap, funnel, KPI, sparkline) render through `graphit.chart` / `graphit.kpi`.
|
|
8
|
+
|
|
7
9
|
---
|
|
8
10
|
|
|
9
11
|
## Marketing & Attribution
|
|
@@ -37,6 +37,17 @@ NEVER use hardcoded hex colors. Use CSS custom properties that automatically ada
|
|
|
37
37
|
- **Warning:** `var(--graphit-warning)`
|
|
38
38
|
- **Danger / bad:** `var(--graphit-error)`
|
|
39
39
|
|
|
40
|
+
### Custom Colors
|
|
41
|
+
|
|
42
|
+
When the user explicitly requests specific colors or a custom color theme, ask for both light and dark mode variants. Write explicit CSS with `.dark` class overrides so the dashboard adapts to both modes:
|
|
43
|
+
|
|
44
|
+
```css
|
|
45
|
+
.revenue-card { background: #001f3f; color: #ffffff; }
|
|
46
|
+
.dark .revenue-card { background: #0a3d6b; color: #e0e0e0; }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
NEVER hardcode a structural color (background, color, border-color) without a `.dark` counterpart. Data/chart series colors (bar fills, line strokes) are exempt - they work in both modes.
|
|
50
|
+
|
|
40
51
|
### Multi-Series
|
|
41
52
|
Use `var(--graphit-accent)` as the primary series. For additional series, choose muted complementary colors that work on both light and dark backgrounds.
|
|
42
53
|
|