@friedbotstudio/create-baseline 0.6.0 → 0.7.0

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.
Files changed (52) hide show
  1. package/README.md +14 -10
  2. package/bin/cli.js +16 -12
  3. package/obj/template/.claude/commands/init-project-doctor.md +74 -0
  4. package/obj/template/.claude/hooks/lib/resume_writer.py +14 -1
  5. package/obj/template/.claude/hooks/track_guard.sh +11 -1
  6. package/obj/template/.claude/manifest.json +29 -97
  7. package/obj/template/.claude/schemas/workflow-track.v1.json +64 -0
  8. package/obj/template/.claude/skills/audit-baseline/audit.sh +2 -2
  9. package/obj/template/.claude/skills/chore/SKILL.md +2 -2
  10. package/obj/template/.claude/skills/harness/SKILL.md +15 -6
  11. package/obj/template/.claude/skills/intake/SKILL.md +1 -1
  12. package/obj/template/.claude/skills/swarm-plan/SKILL.md +2 -0
  13. package/obj/template/.claude/skills/tdd/SKILL.md +2 -2
  14. package/obj/template/.claude/skills/triage/SKILL.md +29 -6
  15. package/obj/template/.claude/skills/triage/seed-tasklist.mjs +107 -0
  16. package/obj/template/.claude/workflows.jsonl +6 -0
  17. package/obj/template/CLAUDE.md +8 -14
  18. package/obj/template/docs/init/seed.md +148 -3
  19. package/package.json +1 -1
  20. package/src/.claude/workflows.template.jsonl +6 -0
  21. package/src/CLAUDE.template.md +8 -14
  22. package/src/cli/install.js +5 -1
  23. package/src/cli/merge.js +28 -1
  24. package/src/cli/track-tasklist-materializer.js +223 -0
  25. package/src/cli/tui/upgrade.js +14 -8
  26. package/src/cli/upgrade-tiers.js +22 -0
  27. package/src/cli/workflow-migrator.js +40 -0
  28. package/src/cli/workflows-validator-invariants.js +417 -0
  29. package/src/cli/workflows-validator-predicates.js +19 -0
  30. package/src/cli/workflows-validator.js +156 -0
  31. package/src/seed.template.md +148 -3
  32. package/obj/template/.claude/skills/google-analytics/SKILL.md +0 -129
  33. package/obj/template/.claude/skills/google-analytics/references/audiences.md +0 -389
  34. package/obj/template/.claude/skills/google-analytics/references/bigquery.md +0 -470
  35. package/obj/template/.claude/skills/google-analytics/references/custom-dimensions.md +0 -355
  36. package/obj/template/.claude/skills/google-analytics/references/custom-events.md +0 -383
  37. package/obj/template/.claude/skills/google-analytics/references/data-management.md +0 -416
  38. package/obj/template/.claude/skills/google-analytics/references/debugview.md +0 -364
  39. package/obj/template/.claude/skills/google-analytics/references/events-fundamentals.md +0 -398
  40. package/obj/template/.claude/skills/google-analytics/references/gtag.md +0 -502
  41. package/obj/template/.claude/skills/google-analytics/references/gtm-integration.md +0 -483
  42. package/obj/template/.claude/skills/google-analytics/references/measurement-protocol.md +0 -519
  43. package/obj/template/.claude/skills/google-analytics/references/privacy.md +0 -441
  44. package/obj/template/.claude/skills/google-analytics/references/recommended-events.md +0 -464
  45. package/obj/template/.claude/skills/google-analytics/references/reporting.md +0 -397
  46. package/obj/template/.claude/skills/google-analytics/references/setup.md +0 -344
  47. package/obj/template/.claude/skills/google-analytics/references/user-tracking.md +0 -417
  48. package/obj/template/.claude/skills/optimize-seo/SKILL.md +0 -313
  49. package/obj/template/.claude/skills/optimize-seo/scripts/pagespeed.mjs +0 -197
  50. package/obj/template/.claude/skills/pagespeed-insights/LICENSE.md +0 -37
  51. package/obj/template/.claude/skills/pagespeed-insights/SKILL.md +0 -446
  52. package/obj/template/.claude/skills/pagespeed-insights/reference.md +0 -50
@@ -1,470 +0,0 @@
1
- # GA4 BigQuery Export and Analysis
2
-
3
- Complete guide to GA4 BigQuery export including setup, schema, SQL query patterns, and data analysis.
4
-
5
- ## Overview
6
-
7
- GA4 BigQuery export provides raw, event-level data access for advanced analysis, custom reporting, machine learning, and long-term data warehousing. Unlike GA4 reports, BigQuery data is unsampled and allows SQL-based analysis.
8
-
9
- ## Why Use BigQuery
10
-
11
- | Benefit | Description |
12
- |---------|-------------|
13
- | Unsampled data | No sampling thresholds |
14
- | Raw event data | Access every parameter |
15
- | SQL analysis | Complex queries and joins |
16
- | Data integration | Combine with other sources |
17
- | Long-term storage | Beyond GA4 retention |
18
- | Custom attribution | Build custom models |
19
- | Machine learning | Train on GA4 data |
20
-
21
- ## BigQuery Export Setup
22
-
23
- ### Prerequisites
24
-
25
- - GA4 property (standard or 360)
26
- - Google Cloud project
27
- - BigQuery API enabled
28
- - Editor permissions on GA4 property
29
-
30
- ### Setup Steps
31
-
32
- **Step 1: Create/Select Google Cloud Project**
33
-
34
- 1. Go to console.cloud.google.com
35
- 2. Create new project or select existing
36
- 3. Enable BigQuery API
37
-
38
- **Step 2: Link GA4 to BigQuery**
39
-
40
- 1. GA4 Admin -> Product Links -> BigQuery Links
41
- 2. Click "Link"
42
- 3. Choose Google Cloud project
43
- 4. Select dataset location (US, EU, etc.)
44
- 5. Configure export:
45
- - Daily: Complete export once per day
46
- - Streaming: Real-time (360 only)
47
- 6. Include advertising IDs (optional)
48
- 7. Confirm setup
49
-
50
- ### Export Options
51
-
52
- | Option | Description | Availability |
53
- |--------|-------------|--------------|
54
- | Daily Export | Once per day (~9 AM property timezone) | Standard GA4 |
55
- | Streaming Export | Near real-time | GA4 360 only |
56
- | Include Advertising IDs | For Ads integration | Optional |
57
-
58
- ### Data Availability
59
-
60
- - Daily tables: ~24 hours after day ends
61
- - Intraday tables: ~3 updates per day
62
- - Streaming: Minutes after collection (360)
63
-
64
- ## Table Structure
65
-
66
- ### Table Naming
67
-
68
- ```
69
- project.dataset.events_YYYYMMDD # Daily export
70
- project.dataset.events_intraday_YYYYMMDD # Intraday
71
- project.dataset.events_* # Wildcard all dates
72
- ```
73
-
74
- ### Key Schema Fields
75
-
76
- #### Event Fields
77
-
78
- | Field | Type | Description |
79
- |-------|------|-------------|
80
- | event_date | STRING | YYYYMMDD format |
81
- | event_timestamp | INTEGER | Microseconds since epoch |
82
- | event_name | STRING | Event name |
83
- | event_params | RECORD (REPEATED) | Event parameters |
84
- | event_value_in_usd | FLOAT | Event value |
85
-
86
- #### User Fields
87
-
88
- | Field | Type | Description |
89
- |-------|------|-------------|
90
- | user_id | STRING | User ID if set |
91
- | user_pseudo_id | STRING | Anonymous ID |
92
- | user_properties | RECORD (REPEATED) | User properties |
93
- | user_first_touch_timestamp | INTEGER | First visit |
94
-
95
- #### Device Fields
96
-
97
- | Field | Type | Description |
98
- |-------|------|-------------|
99
- | device.category | STRING | desktop, mobile, tablet |
100
- | device.operating_system | STRING | Windows, iOS, Android |
101
- | device.browser | STRING | Chrome, Safari |
102
-
103
- #### Geo Fields
104
-
105
- | Field | Type | Description |
106
- |-------|------|-------------|
107
- | geo.country | STRING | Country name |
108
- | geo.region | STRING | State/region |
109
- | geo.city | STRING | City name |
110
-
111
- #### Traffic Source Fields
112
-
113
- | Field | Type | Description |
114
- |-------|------|-------------|
115
- | traffic_source.source | STRING | google, direct |
116
- | traffic_source.medium | STRING | organic, cpc |
117
- | traffic_source.name | STRING | Campaign name |
118
-
119
- #### E-commerce Fields
120
-
121
- | Field | Type | Description |
122
- |-------|------|-------------|
123
- | ecommerce.transaction_id | STRING | Transaction ID |
124
- | ecommerce.purchase_revenue_in_usd | FLOAT | Purchase revenue |
125
- | items | RECORD (REPEATED) | Items array |
126
-
127
- ## SQL Query Patterns
128
-
129
- ### Query 1: Event Count by Name
130
-
131
- ```sql
132
- SELECT
133
- event_name,
134
- COUNT(*) as event_count
135
- FROM
136
- `project.dataset.events_*`
137
- WHERE
138
- _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
139
- GROUP BY
140
- event_name
141
- ORDER BY
142
- event_count DESC
143
- ```
144
-
145
- ### Query 2: Extract Event Parameters
146
-
147
- ```sql
148
- SELECT
149
- event_date,
150
- event_name,
151
- user_pseudo_id,
152
- (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location') as page_location,
153
- (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_title') as page_title
154
- FROM
155
- `project.dataset.events_*`
156
- WHERE
157
- _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
158
- AND event_name = 'page_view'
159
- LIMIT 1000
160
- ```
161
-
162
- ### Query 3: Purchase Analysis
163
-
164
- ```sql
165
- SELECT
166
- event_date,
167
- COUNT(DISTINCT user_pseudo_id) as purchasers,
168
- COUNT(DISTINCT ecommerce.transaction_id) as transactions,
169
- SUM(ecommerce.purchase_revenue_in_usd) as total_revenue,
170
- AVG(ecommerce.purchase_revenue_in_usd) as avg_order_value
171
- FROM
172
- `project.dataset.events_*`
173
- WHERE
174
- _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
175
- AND event_name = 'purchase'
176
- AND ecommerce.transaction_id IS NOT NULL
177
- GROUP BY
178
- event_date
179
- ORDER BY
180
- event_date
181
- ```
182
-
183
- ### Query 4: UNNEST Items Array
184
-
185
- ```sql
186
- SELECT
187
- event_date,
188
- item.item_name,
189
- item.item_category,
190
- SUM(item.quantity) as total_quantity,
191
- SUM(item.item_revenue_in_usd) as total_revenue
192
- FROM
193
- `project.dataset.events_*`,
194
- UNNEST(items) as item
195
- WHERE
196
- _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
197
- AND event_name = 'purchase'
198
- GROUP BY
199
- event_date,
200
- item.item_name,
201
- item.item_category
202
- ORDER BY
203
- total_revenue DESC
204
- ```
205
-
206
- ### Query 5: User Journey Analysis
207
-
208
- ```sql
209
- WITH user_events AS (
210
- SELECT
211
- user_pseudo_id,
212
- event_timestamp,
213
- event_name,
214
- (SELECT value.string_value FROM UNNEST(event_params)
215
- WHERE key = 'page_location') as page_location
216
- FROM
217
- `project.dataset.events_*`
218
- WHERE
219
- _TABLE_SUFFIX = '20250115'
220
- )
221
- SELECT
222
- user_pseudo_id,
223
- ARRAY_AGG(
224
- STRUCT(event_name, page_location, event_timestamp)
225
- ORDER BY event_timestamp
226
- ) as event_sequence
227
- FROM
228
- user_events
229
- GROUP BY
230
- user_pseudo_id
231
- LIMIT 100
232
- ```
233
-
234
- ### Query 6: Session Attribution
235
-
236
- ```sql
237
- SELECT
238
- event_date,
239
- traffic_source.source,
240
- traffic_source.medium,
241
- traffic_source.name as campaign,
242
- COUNT(DISTINCT user_pseudo_id) as users,
243
- COUNT(DISTINCT CONCAT(user_pseudo_id,
244
- (SELECT value.int_value FROM UNNEST(event_params)
245
- WHERE key = 'ga_session_id'))) as sessions
246
- FROM
247
- `project.dataset.events_*`
248
- WHERE
249
- _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
250
- GROUP BY
251
- event_date,
252
- traffic_source.source,
253
- traffic_source.medium,
254
- traffic_source.name
255
- ORDER BY
256
- sessions DESC
257
- ```
258
-
259
- ### Helper Functions
260
-
261
- ```sql
262
- -- Reusable functions for parameter extraction
263
- CREATE TEMP FUNCTION GetParamString(params ANY TYPE, target_key STRING)
264
- RETURNS STRING
265
- AS (
266
- (SELECT value.string_value FROM UNNEST(params) WHERE key = target_key)
267
- );
268
-
269
- CREATE TEMP FUNCTION GetParamInt(params ANY TYPE, target_key STRING)
270
- RETURNS INT64
271
- AS (
272
- (SELECT value.int_value FROM UNNEST(params) WHERE key = target_key)
273
- );
274
-
275
- -- Usage
276
- SELECT
277
- event_date,
278
- GetParamString(event_params, 'page_location') as page_location,
279
- GetParamInt(event_params, 'engagement_time_msec') as engagement_time
280
- FROM
281
- `project.dataset.events_*`
282
- WHERE
283
- _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
284
- ```
285
-
286
- ## Query Optimisation
287
-
288
- ### Best Practices
289
-
290
- **1. Use _TABLE_SUFFIX Filtering:**
291
- ```sql
292
- -- Good
293
- WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
294
-
295
- -- Bad (scans all partitions)
296
- WHERE event_date BETWEEN '20250101' AND '20250131'
297
- ```
298
-
299
- **2. Filter on Clustered Columns:**
300
- ```sql
301
- -- Tables clustered by event_name and event_timestamp
302
- WHERE event_name IN ('page_view', 'purchase')
303
- ```
304
-
305
- **3. Select Specific Columns:**
306
- ```sql
307
- -- Good
308
- SELECT event_name, user_pseudo_id, event_timestamp
309
-
310
- -- Bad (high cost)
311
- SELECT *
312
- ```
313
-
314
- **4. Limit UNNEST Operations:**
315
- ```sql
316
- -- Good: Inline UNNEST
317
- (SELECT value.string_value FROM UNNEST(event_params)
318
- WHERE key = 'page_location')
319
-
320
- -- Avoid: Full UNNEST in FROM
321
- FROM table, UNNEST(event_params) as param
322
- WHERE param.key = 'page_location'
323
- ```
324
-
325
- **5. Use LIMIT During Development:**
326
- ```sql
327
- LIMIT 1000 -- Test query first
328
- ```
329
-
330
- ## Cost Management
331
-
332
- ### BigQuery Pricing
333
-
334
- | Type | Cost |
335
- |------|------|
336
- | Storage | ~$0.02/GB/month |
337
- | Queries | ~$5/TB scanned |
338
- | Streaming inserts | ~$0.05/GB (360 only) |
339
-
340
- ### Free Tier
341
-
342
- - 10 GB storage free/month
343
- - 1 TB queries free/month
344
-
345
- ### Reducing Costs
346
-
347
- 1. Partition by date using _TABLE_SUFFIX
348
- 2. Select only needed columns
349
- 3. Use LIMIT for testing
350
- 4. Create materialised views for frequent queries
351
- 5. Set up cost alerts in Google Cloud
352
-
353
- ## Data Retention
354
-
355
- ### GA4 vs BigQuery
356
-
357
- | Platform | Retention |
358
- |----------|-----------|
359
- | GA4 Standard | 2 or 14 months |
360
- | BigQuery | Unlimited (until deleted) |
361
-
362
- ### Setting Table Expiration
363
-
364
- ```sql
365
- ALTER TABLE `project.dataset.events_20250101`
366
- SET OPTIONS (
367
- expiration_timestamp=TIMESTAMP "2026-01-01 00:00:00 UTC"
368
- )
369
- ```
370
-
371
- ## Common Use Cases
372
-
373
- ### 1. Unsampled Reporting
374
-
375
- GA4 UI may sample large datasets. BigQuery provides complete data.
376
-
377
- ### 2. Custom Attribution
378
-
379
- - Access full user journey
380
- - Build custom attribution models
381
- - Credit touchpoints as needed
382
-
383
- ### 3. Data Integration
384
-
385
- - Join GA4 with CRM data
386
- - Combine with product catalogue
387
- - Enrich with external sources
388
-
389
- ### 4. Machine Learning
390
-
391
- - Export to ML tools
392
- - Predict churn, LTV, conversions
393
- - Train custom models
394
-
395
- ### 5. Long-term Analysis
396
-
397
- - Historical analysis beyond GA4 limits
398
- - Year-over-year comparisons
399
- - Trend analysis
400
-
401
- ## Troubleshooting
402
-
403
- ### No Data in Tables
404
-
405
- **Causes:**
406
- - Link just created (wait 24 hours)
407
- - Export paused
408
- - Wrong project/dataset
409
-
410
- **Solutions:**
411
- 1. Wait for first export
412
- 2. Check BigQuery Links status
413
- 3. Verify project configuration
414
-
415
- ### Missing Events
416
-
417
- **Causes:**
418
- - Events not firing
419
- - Consent mode blocking
420
- - Filter applied
421
-
422
- **Solutions:**
423
- 1. Verify in DebugView first
424
- 2. Check consent configuration
425
- 3. Review data filters
426
-
427
- ### High Query Costs
428
-
429
- **Causes:**
430
- - SELECT * usage
431
- - Missing date filters
432
- - Large date ranges
433
-
434
- **Solutions:**
435
- 1. Select specific columns
436
- 2. Always use _TABLE_SUFFIX
437
- 3. Narrow date ranges
438
-
439
- ## Quick Reference
440
-
441
- ### Table Names
442
-
443
- - Daily: `events_YYYYMMDD`
444
- - Intraday: `events_intraday_YYYYMMDD`
445
- - Wildcard: `events_*`
446
-
447
- ### Date Filter
448
-
449
- ```sql
450
- WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
451
- ```
452
-
453
- ### Extract Parameter
454
-
455
- ```sql
456
- (SELECT value.string_value FROM UNNEST(event_params)
457
- WHERE key = 'param_name')
458
- ```
459
-
460
- ### UNNEST Items
461
-
462
- ```sql
463
- FROM table, UNNEST(items) as item
464
- ```
465
-
466
- ### Costs
467
-
468
- - Storage: $0.02/GB/month
469
- - Queries: $5/TB scanned
470
- - Free: 10 GB storage, 1 TB queries/month