@duckcodeailabs/dql-cli 0.1.1 → 0.1.4
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/assets/notebook-browser/app.js +548 -0
- package/dist/assets/notebook-browser/index.html +83 -0
- package/dist/assets/notebook-browser/styles.css +336 -0
- package/dist/assets/templates/ecommerce/README.md +27 -0
- package/dist/assets/templates/ecommerce/blocks/repeat_rate.dql +26 -0
- package/dist/assets/templates/ecommerce/blocks/revenue_by_segment.dql +24 -0
- package/dist/assets/templates/ecommerce/dashboards/revenue_command_center.dql +25 -0
- package/dist/assets/templates/ecommerce/data/customers.csv +11 -0
- package/dist/assets/templates/ecommerce/data/funnel.csv +6 -0
- package/dist/assets/templates/ecommerce/data/orders.csv +16 -0
- package/dist/assets/templates/ecommerce/dql.config.json +13 -0
- package/dist/assets/templates/ecommerce/semantic-layer/dimensions/channel.yaml +4 -0
- package/dist/assets/templates/ecommerce/semantic-layer/metrics/gmv.yaml +4 -0
- package/dist/assets/templates/ecommerce/workbooks/.gitkeep +1 -0
- package/dist/assets/templates/saas/README.md +20 -0
- package/dist/assets/templates/saas/blocks/churn_pressure.dql +25 -0
- package/dist/assets/templates/saas/blocks/revenue_by_segment.dql +25 -0
- package/dist/assets/templates/saas/dashboards/growth_scorecard.dql +25 -0
- package/dist/assets/templates/saas/data/cohorts.csv +7 -0
- package/dist/assets/templates/saas/data/subscriptions.csv +13 -0
- package/dist/assets/templates/saas/dql.config.json +13 -0
- package/dist/assets/templates/saas/semantic-layer/metrics/mrr.yaml +4 -0
- package/dist/assets/templates/saas/workbooks/.gitkeep +1 -0
- package/dist/assets/templates/starter/README.md +54 -0
- package/dist/assets/templates/starter/blocks/revenue_by_segment.dql +29 -0
- package/dist/assets/templates/starter/blocks/revenue_trend_query_only.dql +20 -0
- package/dist/assets/templates/starter/dashboards/.gitkeep +1 -0
- package/dist/assets/templates/starter/data/revenue.csv +13 -0
- package/dist/assets/templates/starter/dql.config.json +13 -0
- package/dist/assets/templates/starter/semantic-layer/blocks/revenue_by_segment.yaml +11 -0
- package/dist/assets/templates/starter/semantic-layer/dimensions/segment_tier.yaml +6 -0
- package/dist/assets/templates/starter/semantic-layer/hierarchies/revenue_time.yaml +12 -0
- package/dist/assets/templates/starter/semantic-layer/metrics/revenue.yaml +7 -0
- package/dist/assets/templates/starter/workbooks/.gitkeep +1 -0
- package/dist/assets/templates/taxi/README.md +19 -0
- package/dist/assets/templates/taxi/blocks/airport_mix.dql +25 -0
- package/dist/assets/templates/taxi/blocks/revenue_by_segment.dql +24 -0
- package/dist/assets/templates/taxi/dashboards/city_operations.dql +25 -0
- package/dist/assets/templates/taxi/data/trips.csv +13 -0
- package/dist/assets/templates/taxi/dql.config.json +13 -0
- package/dist/assets/templates/taxi/semantic-layer/.gitkeep +1 -0
- package/dist/assets/templates/taxi/workbooks/.gitkeep +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +3 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/notebook.d.ts.map +1 -1
- package/dist/commands/notebook.js +8 -2
- package/dist/commands/notebook.js.map +1 -1
- package/dist/local-runtime.d.ts +6 -0
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +65 -9
- package/dist/local-runtime.js.map +1 -1
- package/dist/local-runtime.test.js +24 -1
- package/dist/local-runtime.test.js.map +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: dark;
|
|
3
|
+
--bg: #09111f;
|
|
4
|
+
--panel: #0f172a;
|
|
5
|
+
--panel-2: #111c31;
|
|
6
|
+
--border: #243248;
|
|
7
|
+
--text: #e5eefc;
|
|
8
|
+
--muted: #93a4bf;
|
|
9
|
+
--accent: #59c2ff;
|
|
10
|
+
--accent-2: #2563eb;
|
|
11
|
+
--danger: #ef4444;
|
|
12
|
+
--success: #22c55e;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
* {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
body {
|
|
20
|
+
margin: 0;
|
|
21
|
+
font-family: Inter, system-ui, sans-serif;
|
|
22
|
+
background: radial-gradient(circle at top, #10203c, var(--bg) 48%);
|
|
23
|
+
color: var(--text);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
button,
|
|
27
|
+
select,
|
|
28
|
+
input,
|
|
29
|
+
textarea {
|
|
30
|
+
font: inherit;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
button {
|
|
34
|
+
border: 1px solid var(--border);
|
|
35
|
+
background: var(--panel-2);
|
|
36
|
+
color: var(--text);
|
|
37
|
+
border-radius: 10px;
|
|
38
|
+
padding: 0.6rem 0.9rem;
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
button.primary {
|
|
43
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
|
44
|
+
color: #08111f;
|
|
45
|
+
border-color: transparent;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
button.secondary {
|
|
49
|
+
background: transparent;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.app-shell {
|
|
53
|
+
display: grid;
|
|
54
|
+
grid-template-columns: 300px 1fr;
|
|
55
|
+
min-height: 100vh;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.sidebar {
|
|
59
|
+
border-right: 1px solid var(--border);
|
|
60
|
+
background: rgba(9, 17, 31, 0.88);
|
|
61
|
+
padding: 1.25rem;
|
|
62
|
+
position: sticky;
|
|
63
|
+
top: 0;
|
|
64
|
+
height: 100vh;
|
|
65
|
+
overflow: auto;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.brand {
|
|
69
|
+
display: flex;
|
|
70
|
+
gap: 0.9rem;
|
|
71
|
+
align-items: center;
|
|
72
|
+
margin-bottom: 1.5rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.brand p,
|
|
76
|
+
.subtitle,
|
|
77
|
+
.status,
|
|
78
|
+
.field-help,
|
|
79
|
+
.cell-status {
|
|
80
|
+
color: var(--muted);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.brand-mark {
|
|
84
|
+
width: 48px;
|
|
85
|
+
height: 48px;
|
|
86
|
+
border-radius: 14px;
|
|
87
|
+
background: linear-gradient(135deg, var(--accent), #8b5cf6);
|
|
88
|
+
color: #05111f;
|
|
89
|
+
display: grid;
|
|
90
|
+
place-items: center;
|
|
91
|
+
font-weight: 700;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.section-title {
|
|
95
|
+
font-size: 0.82rem;
|
|
96
|
+
text-transform: uppercase;
|
|
97
|
+
letter-spacing: 0.08em;
|
|
98
|
+
color: var(--muted);
|
|
99
|
+
margin: 1.25rem 0 0.75rem;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.panel,
|
|
103
|
+
.cell,
|
|
104
|
+
.chart-editor,
|
|
105
|
+
.table-shell {
|
|
106
|
+
background: rgba(17, 28, 49, 0.82);
|
|
107
|
+
border: 1px solid var(--border);
|
|
108
|
+
border-radius: 16px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.panel {
|
|
112
|
+
padding: 0.85rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.panel.small {
|
|
116
|
+
margin-bottom: 0.8rem;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.main {
|
|
120
|
+
padding: 1.25rem 1.4rem 2rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.toolbar {
|
|
124
|
+
display: flex;
|
|
125
|
+
justify-content: space-between;
|
|
126
|
+
align-items: flex-start;
|
|
127
|
+
gap: 1rem;
|
|
128
|
+
margin-bottom: 1rem;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.toolbar h1 {
|
|
132
|
+
margin: 0 0 0.3rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.toolbar-actions,
|
|
136
|
+
.row-actions,
|
|
137
|
+
.cell-actions {
|
|
138
|
+
display: flex;
|
|
139
|
+
gap: 0.55rem;
|
|
140
|
+
flex-wrap: wrap;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.cells {
|
|
144
|
+
display: grid;
|
|
145
|
+
gap: 1rem;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.cell {
|
|
149
|
+
overflow: hidden;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.cell-header {
|
|
153
|
+
padding: 0.85rem 1rem;
|
|
154
|
+
border-bottom: 1px solid var(--border);
|
|
155
|
+
display: flex;
|
|
156
|
+
justify-content: space-between;
|
|
157
|
+
gap: 0.75rem;
|
|
158
|
+
align-items: center;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.cell-type {
|
|
162
|
+
display: inline-block;
|
|
163
|
+
min-width: 88px;
|
|
164
|
+
font-size: 0.76rem;
|
|
165
|
+
letter-spacing: 0.08em;
|
|
166
|
+
text-transform: uppercase;
|
|
167
|
+
color: var(--accent);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.cell-title,
|
|
171
|
+
select,
|
|
172
|
+
.field input {
|
|
173
|
+
width: 100%;
|
|
174
|
+
padding: 0.65rem 0.75rem;
|
|
175
|
+
border-radius: 10px;
|
|
176
|
+
border: 1px solid var(--border);
|
|
177
|
+
background: rgba(9, 17, 31, 0.8);
|
|
178
|
+
color: var(--text);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.cell-title {
|
|
182
|
+
margin-top: 0.35rem;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.cell-body {
|
|
186
|
+
padding: 1rem;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.cell-source {
|
|
190
|
+
width: 100%;
|
|
191
|
+
min-height: 200px;
|
|
192
|
+
padding: 0.85rem;
|
|
193
|
+
border-radius: 12px;
|
|
194
|
+
border: 1px solid var(--border);
|
|
195
|
+
background: #07101d;
|
|
196
|
+
color: var(--text);
|
|
197
|
+
resize: vertical;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.cell-output {
|
|
201
|
+
margin-top: 1rem;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.file-list {
|
|
205
|
+
list-style: none;
|
|
206
|
+
padding: 0;
|
|
207
|
+
margin: 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.file-list li {
|
|
211
|
+
padding: 0.42rem 0;
|
|
212
|
+
color: var(--muted);
|
|
213
|
+
border-bottom: 1px solid rgba(36, 50, 72, 0.35);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.field {
|
|
217
|
+
margin-top: 0.75rem;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.field-label {
|
|
221
|
+
display: block;
|
|
222
|
+
margin-top: 0.6rem;
|
|
223
|
+
margin-bottom: 0.35rem;
|
|
224
|
+
color: var(--muted);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.checkbox {
|
|
228
|
+
display: flex;
|
|
229
|
+
align-items: center;
|
|
230
|
+
gap: 0.5rem;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.chart-editor {
|
|
234
|
+
display: grid;
|
|
235
|
+
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
236
|
+
gap: 0.75rem;
|
|
237
|
+
padding: 0.9rem;
|
|
238
|
+
margin-bottom: 1rem;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.chart-card {
|
|
242
|
+
padding: 1rem;
|
|
243
|
+
background: linear-gradient(180deg, rgba(12, 21, 37, 0.98), rgba(17, 28, 49, 0.9));
|
|
244
|
+
border-radius: 14px;
|
|
245
|
+
border: 1px solid var(--border);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.kpi-value {
|
|
249
|
+
font-size: 2rem;
|
|
250
|
+
font-weight: 700;
|
|
251
|
+
margin-top: 0.5rem;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.bar-row {
|
|
255
|
+
display: grid;
|
|
256
|
+
grid-template-columns: 140px 1fr 90px;
|
|
257
|
+
gap: 0.75rem;
|
|
258
|
+
align-items: center;
|
|
259
|
+
margin-bottom: 0.5rem;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.bar-track {
|
|
263
|
+
height: 12px;
|
|
264
|
+
background: rgba(255, 255, 255, 0.06);
|
|
265
|
+
border-radius: 999px;
|
|
266
|
+
overflow: hidden;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.bar-fill {
|
|
270
|
+
height: 100%;
|
|
271
|
+
background: linear-gradient(90deg, var(--accent), #8b5cf6);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.table-shell {
|
|
275
|
+
overflow: auto;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
table {
|
|
279
|
+
width: 100%;
|
|
280
|
+
border-collapse: collapse;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
th,
|
|
284
|
+
td {
|
|
285
|
+
text-align: left;
|
|
286
|
+
padding: 0.7rem 0.85rem;
|
|
287
|
+
border-bottom: 1px solid rgba(36, 50, 72, 0.6);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
th {
|
|
291
|
+
color: var(--muted);
|
|
292
|
+
font-size: 0.85rem;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.markdown-preview {
|
|
296
|
+
padding: 1rem;
|
|
297
|
+
border: 1px solid var(--border);
|
|
298
|
+
border-radius: 12px;
|
|
299
|
+
background: rgba(7, 16, 29, 0.7);
|
|
300
|
+
line-height: 1.6;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.markdown-preview h1,
|
|
304
|
+
.markdown-preview h2,
|
|
305
|
+
.markdown-preview h3 {
|
|
306
|
+
margin-top: 0;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.status.ok {
|
|
310
|
+
color: var(--success);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.status.error {
|
|
314
|
+
color: var(--danger);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.hidden {
|
|
318
|
+
display: none;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@media (max-width: 1100px) {
|
|
322
|
+
.app-shell {
|
|
323
|
+
grid-template-columns: 1fr;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.sidebar {
|
|
327
|
+
position: static;
|
|
328
|
+
height: auto;
|
|
329
|
+
border-right: 0;
|
|
330
|
+
border-bottom: 1px solid var(--border);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.toolbar {
|
|
334
|
+
flex-direction: column;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
This template packages a realistic e-commerce analytics sandbox for DQL.
|
|
4
|
+
|
|
5
|
+
## Included assets
|
|
6
|
+
|
|
7
|
+
- `blocks/revenue_by_segment.dql` — channel revenue block
|
|
8
|
+
- `blocks/repeat_rate.dql` — repeat purchase mix block
|
|
9
|
+
- `dashboards/revenue_command_center.dql` — KPI + bar + table dashboard
|
|
10
|
+
- `data/orders.csv` — orders with channel, region, and repeat purchase flags
|
|
11
|
+
- `data/funnel.csv` — acquisition and checkout funnel snapshot
|
|
12
|
+
- `data/customers.csv` — customer dimension data
|
|
13
|
+
- `notebooks/welcome.dqlnb` — browser notebook walkthrough
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
dql doctor
|
|
19
|
+
dql notebook
|
|
20
|
+
dql preview blocks/revenue_by_segment.dql --open
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## What to explore
|
|
24
|
+
|
|
25
|
+
- Compare performance across paid, partner, organic, and lifecycle channels
|
|
26
|
+
- Track repeat order contribution by region and segment
|
|
27
|
+
- Use the notebook to iterate on funnel SQL before promoting it into reusable blocks
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
block "Repeat Revenue Mix" {
|
|
2
|
+
domain = "commerce"
|
|
3
|
+
type = "custom"
|
|
4
|
+
description = "Repeat versus first-time order revenue mix"
|
|
5
|
+
tags = ["commerce", "retention"]
|
|
6
|
+
owner = "template"
|
|
7
|
+
|
|
8
|
+
query = """
|
|
9
|
+
SELECT
|
|
10
|
+
CASE WHEN is_repeat THEN 'Repeat' ELSE 'First Order' END AS order_type,
|
|
11
|
+
ROUND(SUM(order_total), 2) AS revenue
|
|
12
|
+
FROM read_csv_auto('./data/orders.csv')
|
|
13
|
+
GROUP BY order_type
|
|
14
|
+
ORDER BY revenue DESC
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
visualization {
|
|
18
|
+
chart = "bar"
|
|
19
|
+
x = order_type
|
|
20
|
+
y = revenue
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
tests {
|
|
24
|
+
assert row_count > 0
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
block "GMV by Channel" {
|
|
2
|
+
domain = "commerce"
|
|
3
|
+
type = "custom"
|
|
4
|
+
description = "Gross merchandise value by acquisition channel"
|
|
5
|
+
tags = ["commerce", "gmv", "channel"]
|
|
6
|
+
owner = "template"
|
|
7
|
+
|
|
8
|
+
query = """
|
|
9
|
+
SELECT channel, ROUND(SUM(order_total), 2) AS revenue
|
|
10
|
+
FROM read_csv_auto('./data/orders.csv')
|
|
11
|
+
GROUP BY channel
|
|
12
|
+
ORDER BY revenue DESC
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
visualization {
|
|
16
|
+
chart = "bar"
|
|
17
|
+
x = channel
|
|
18
|
+
y = revenue
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
tests {
|
|
22
|
+
assert row_count > 0
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
dashboard "Revenue Command Center" {
|
|
2
|
+
chart.kpi(
|
|
3
|
+
SELECT ROUND(SUM(order_total), 2) AS gmv
|
|
4
|
+
FROM read_csv_auto('./data/orders.csv'),
|
|
5
|
+
metrics = ["gmv"],
|
|
6
|
+
title = "Gross Merchandise Value"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
chart.bar(
|
|
10
|
+
SELECT channel, ROUND(SUM(order_total), 2) AS revenue
|
|
11
|
+
FROM read_csv_auto('./data/orders.csv')
|
|
12
|
+
GROUP BY channel
|
|
13
|
+
ORDER BY revenue DESC,
|
|
14
|
+
x = channel,
|
|
15
|
+
y = revenue,
|
|
16
|
+
title = "Revenue by Channel"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
chart.table(
|
|
20
|
+
SELECT order_date, customer_id, channel, region, order_total, is_repeat
|
|
21
|
+
FROM read_csv_auto('./data/orders.csv')
|
|
22
|
+
ORDER BY order_total DESC,
|
|
23
|
+
title = "Top Orders"
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
customer_id,customer_name,segment,region,acquisition_channel,first_order_date,health_score
|
|
2
|
+
C-001,Northstar Health,Enterprise,North America,Paid Search,2025-01-03,92
|
|
3
|
+
C-002,Blue Pine Retail,Mid-Market,EMEA,Organic Search,2024-11-19,87
|
|
4
|
+
C-003,Maple & Co,SMB,North America,Lifecycle,2024-12-01,79
|
|
5
|
+
C-004,Harbor Commerce,Enterprise,APAC,Partner,2025-01-11,90
|
|
6
|
+
C-005,Studio Relay,Mid-Market,North America,Paid Social,2025-01-14,74
|
|
7
|
+
C-006,Rio Goods,SMB,LATAM,Organic Search,2024-10-08,82
|
|
8
|
+
C-007,Vertex Home,Enterprise,North America,Partner,2024-09-22,95
|
|
9
|
+
C-008,Atlas Europe,Mid-Market,EMEA,Paid Search,2025-02-02,71
|
|
10
|
+
C-009,North Loop,SMB,North America,Organic Search,2025-02-06,77
|
|
11
|
+
C-010,Pacific Devices,Enterprise,APAC,Lifecycle,2024-08-12,88
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
order_id,order_date,customer_id,segment,channel,region,order_total,gross_margin,is_repeat,payment_method
|
|
2
|
+
1001,2025-01-03,C-001,Enterprise,Paid Search,North America,12400,0.41,false,Card
|
|
3
|
+
1002,2025-01-05,C-002,Mid-Market,Organic Search,EMEA,8600,0.37,true,Card
|
|
4
|
+
1003,2025-01-08,C-003,SMB,Lifecycle,North America,2400,0.54,true,ACH
|
|
5
|
+
1004,2025-01-11,C-004,Enterprise,Partner,APAC,15200,0.46,false,Wire
|
|
6
|
+
1005,2025-01-14,C-005,Mid-Market,Paid Social,North America,5400,0.35,false,Card
|
|
7
|
+
1006,2025-01-18,C-006,SMB,Organic Search,LATAM,1800,0.51,true,Card
|
|
8
|
+
1007,2025-01-22,C-002,Mid-Market,Lifecycle,EMEA,9200,0.39,true,Card
|
|
9
|
+
1008,2025-01-27,C-007,Enterprise,Partner,North America,17600,0.48,true,Wire
|
|
10
|
+
1009,2025-02-02,C-008,Mid-Market,Paid Search,EMEA,7300,0.36,false,Card
|
|
11
|
+
1010,2025-02-06,C-009,SMB,Organic Search,North America,2100,0.56,false,ACH
|
|
12
|
+
1011,2025-02-10,C-010,Enterprise,Lifecycle,APAC,13800,0.43,true,Card
|
|
13
|
+
1012,2025-02-15,C-011,Mid-Market,Partner,LATAM,6900,0.34,false,Wire
|
|
14
|
+
1013,2025-02-18,C-012,Enterprise,Paid Social,North America,9800,0.38,false,Card
|
|
15
|
+
1014,2025-02-21,C-007,Enterprise,Lifecycle,North America,12100,0.45,true,Wire
|
|
16
|
+
1015,2025-02-25,C-013,SMB,Organic Search,EMEA,1700,0.53,true,Card
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
This template packages a SaaS KPI sandbox focused on MRR, retention, and expansion.
|
|
4
|
+
|
|
5
|
+
## Included assets
|
|
6
|
+
|
|
7
|
+
- `blocks/revenue_by_segment.dql` — MRR by plan tier
|
|
8
|
+
- `blocks/churn_pressure.dql` — at-risk and churned revenue view
|
|
9
|
+
- `dashboards/growth_scorecard.dql` — executive SaaS KPI dashboard
|
|
10
|
+
- `data/subscriptions.csv` — recurring revenue and expansion sample data
|
|
11
|
+
- `data/cohorts.csv` — cohort retention snapshot
|
|
12
|
+
- `notebooks/welcome.dqlnb` — browser notebook walkthrough
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
dql doctor
|
|
18
|
+
dql notebook
|
|
19
|
+
dql preview blocks/revenue_by_segment.dql --open
|
|
20
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
block "Churn Pressure by Segment" {
|
|
2
|
+
domain = "saas"
|
|
3
|
+
type = "custom"
|
|
4
|
+
description = "MRR currently flagged as at risk or churned"
|
|
5
|
+
tags = ["saas", "churn"]
|
|
6
|
+
owner = "template"
|
|
7
|
+
|
|
8
|
+
query = """
|
|
9
|
+
SELECT risk_bucket, ROUND(SUM(mrr), 2) AS at_risk_mrr
|
|
10
|
+
FROM read_csv_auto('./data/subscriptions.csv')
|
|
11
|
+
WHERE status != 'active' OR risk_bucket IN ('high', 'critical')
|
|
12
|
+
GROUP BY risk_bucket
|
|
13
|
+
ORDER BY at_risk_mrr DESC
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
visualization {
|
|
17
|
+
chart = "bar"
|
|
18
|
+
x = risk_bucket
|
|
19
|
+
y = at_risk_mrr
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
tests {
|
|
23
|
+
assert row_count > 0
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
block "MRR by Plan Tier" {
|
|
2
|
+
domain = "saas"
|
|
3
|
+
type = "custom"
|
|
4
|
+
description = "Monthly recurring revenue by plan tier"
|
|
5
|
+
tags = ["saas", "mrr"]
|
|
6
|
+
owner = "template"
|
|
7
|
+
|
|
8
|
+
query = """
|
|
9
|
+
SELECT plan_tier, ROUND(SUM(mrr), 2) AS revenue
|
|
10
|
+
FROM read_csv_auto('./data/subscriptions.csv')
|
|
11
|
+
WHERE status = 'active'
|
|
12
|
+
GROUP BY plan_tier
|
|
13
|
+
ORDER BY revenue DESC
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
visualization {
|
|
17
|
+
chart = "bar"
|
|
18
|
+
x = plan_tier
|
|
19
|
+
y = revenue
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
tests {
|
|
23
|
+
assert row_count > 0
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
dashboard "Growth Scorecard" {
|
|
2
|
+
chart.kpi(
|
|
3
|
+
SELECT ROUND(SUM(mrr), 2) AS active_mrr
|
|
4
|
+
FROM read_csv_auto('./data/subscriptions.csv')
|
|
5
|
+
WHERE status = 'active',
|
|
6
|
+
metrics = ["active_mrr"],
|
|
7
|
+
title = "Active MRR"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
chart.line(
|
|
11
|
+
SELECT cohort_month, retained_accounts
|
|
12
|
+
FROM read_csv_auto('./data/cohorts.csv')
|
|
13
|
+
ORDER BY cohort_month,
|
|
14
|
+
x = cohort_month,
|
|
15
|
+
y = retained_accounts,
|
|
16
|
+
title = "Retained Accounts by Cohort"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
chart.table(
|
|
20
|
+
SELECT account_name, owner_segment, plan_tier, status, mrr, expansion_mrr, risk_bucket
|
|
21
|
+
FROM read_csv_auto('./data/subscriptions.csv')
|
|
22
|
+
ORDER BY mrr DESC,
|
|
23
|
+
title = "Account Revenue Snapshot"
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
account_id,account_name,owner_segment,plan_tier,status,mrr,expansion_mrr,risk_bucket,renewal_month
|
|
2
|
+
A-100,Acme Cloud,Enterprise,Enterprise,active,48000,6200,low,2025-06
|
|
3
|
+
A-101,North Ridge,Mid-Market,Growth,active,18400,2400,medium,2025-05
|
|
4
|
+
A-102,Blue Orbit,SMB,Starter,active,3400,200,low,2025-04
|
|
5
|
+
A-103,Helio Systems,Enterprise,Enterprise,at_risk,52100,0,high,2025-03
|
|
6
|
+
A-104,Vector Health,Mid-Market,Growth,active,19600,1800,medium,2025-08
|
|
7
|
+
A-105,Studio Works,SMB,Starter,churned,2200,0,critical,2025-02
|
|
8
|
+
A-106,SignalWare,Enterprise,Enterprise,active,43500,4100,low,2025-07
|
|
9
|
+
A-107,Maple Commerce,Mid-Market,Growth,active,17100,1200,medium,2025-04
|
|
10
|
+
A-108,Linea Labs,SMB,Starter,active,2800,0,medium,2025-06
|
|
11
|
+
A-109,Quartz Energy,Enterprise,Enterprise,active,50300,7300,low,2025-09
|
|
12
|
+
A-110,Summit Bio,Mid-Market,Growth,at_risk,15800,0,high,2025-03
|
|
13
|
+
A-111,Glider Ops,SMB,Starter,active,2600,150,low,2025-05
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|