@littlebearapps/create-platform 1.0.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 (31) hide show
  1. package/dist/index.d.ts +11 -0
  2. package/dist/index.js +59 -0
  3. package/dist/prompts.d.ts +15 -0
  4. package/dist/prompts.js +58 -0
  5. package/dist/scaffold.d.ts +5 -0
  6. package/dist/scaffold.js +65 -0
  7. package/dist/templates.d.ts +16 -0
  8. package/dist/templates.js +53 -0
  9. package/package.json +46 -0
  10. package/templates/full/migrations/006_pattern_discovery.sql +199 -0
  11. package/templates/full/migrations/007_notifications_search.sql +127 -0
  12. package/templates/full/wrangler.alert-router.jsonc.hbs +34 -0
  13. package/templates/full/wrangler.notifications.jsonc.hbs +23 -0
  14. package/templates/full/wrangler.pattern-discovery.jsonc.hbs +33 -0
  15. package/templates/full/wrangler.search.jsonc.hbs +16 -0
  16. package/templates/full/wrangler.settings.jsonc.hbs +23 -0
  17. package/templates/shared/README.md.hbs +69 -0
  18. package/templates/shared/config/budgets.yaml.hbs +72 -0
  19. package/templates/shared/config/services.yaml.hbs +45 -0
  20. package/templates/shared/migrations/001_core_tables.sql +117 -0
  21. package/templates/shared/migrations/002_usage_warehouse.sql +830 -0
  22. package/templates/shared/migrations/003_feature_tracking.sql +250 -0
  23. package/templates/shared/migrations/004_settings_alerts.sql +452 -0
  24. package/templates/shared/migrations/seed.sql.hbs +4 -0
  25. package/templates/shared/package.json.hbs +21 -0
  26. package/templates/shared/scripts/sync-config.ts +242 -0
  27. package/templates/shared/tsconfig.json +12 -0
  28. package/templates/shared/wrangler.usage.jsonc.hbs +58 -0
  29. package/templates/standard/migrations/005_error_collection.sql +162 -0
  30. package/templates/standard/wrangler.error-collector.jsonc.hbs +44 -0
  31. package/templates/standard/wrangler.sentinel.jsonc.hbs +45 -0
@@ -0,0 +1,830 @@
1
+ -- =============================================================================
2
+ -- 002_usage_warehouse.sql — Time-series usage warehouse
3
+ -- =============================================================================
4
+ -- Consolidated from original migrations: 003, 004, 005, 006, 010, 012, 013,
5
+ -- 014, 015, 019, 036, 037, 040
6
+ --
7
+ -- Tables:
8
+ -- hourly_usage_snapshots — Tier 1: Hourly snapshots (7-day retention)
9
+ -- daily_usage_rollups — Tier 2: Daily rollups (90-day retention)
10
+ -- monthly_usage_rollups — Tier 3: Monthly rollups (forever retention)
11
+ -- third_party_usage — External service usage tracking
12
+ -- usage_anomalies — Detected anomaly records
13
+ -- circuit_breaker_logs — Circuit breaker event audit trail
14
+ -- usage_settings — Per-project alert thresholds
15
+ -- workersai_model_usage — Workers AI per-model hourly breakdown
16
+ -- aigateway_model_usage — AI Gateway per-model hourly breakdown
17
+ -- workersai_model_daily — Workers AI per-model daily rollup
18
+ -- aigateway_model_daily — AI Gateway per-model daily rollup
19
+ -- pricing_versions — CF pricing change audit trail
20
+ -- dataset_registry — GraphQL dataset drift detection
21
+ -- resource_usage_snapshots — Per-resource hourly metrics (finest granularity)
22
+ -- resource_registry — Resource discovery and project mapping
23
+ -- gap_detection_log — Gap detection run results
24
+ -- backfill_log — Backfill operation audit trail
25
+ -- attribution_reports — Resource-to-project attribution status
26
+ -- feature_coverage_audit — Feature activity tracking
27
+ -- comprehensive_audit_reports — Weekly aggregate audit reports
28
+ --
29
+ -- Views:
30
+ -- v_account_daily_usage — Account-level daily summary
31
+ -- v_tool_daily_usage — Per-CF-tool daily summary
32
+ -- v_project_daily_usage — Per-project daily summary
33
+ -- v_project_tool_daily_usage — Per-project per-tool daily summary
34
+ -- =============================================================================
35
+
36
+
37
+ -- =============================================================================
38
+ -- Tier 1: HOURLY SNAPSHOTS (7-day retention)
39
+ -- =============================================================================
40
+ -- Granular hourly data collected by scheduled handler.
41
+ -- Columns merged from migrations 003, 004, 005, 010, 014, 019, 036.
42
+
43
+ CREATE TABLE IF NOT EXISTS hourly_usage_snapshots (
44
+ id TEXT PRIMARY KEY,
45
+ snapshot_hour TEXT NOT NULL, -- YYYY-MM-DDTHH:00:00Z (ISO8601)
46
+ project TEXT NOT NULL DEFAULT 'all', -- 'all' or project slug
47
+
48
+ -- Workers metrics
49
+ workers_requests INTEGER DEFAULT 0,
50
+ workers_errors INTEGER DEFAULT 0,
51
+ workers_cpu_time_ms REAL DEFAULT 0,
52
+ workers_duration_p50_ms REAL DEFAULT 0,
53
+ workers_duration_p99_ms REAL DEFAULT 0,
54
+ workers_cost_usd REAL DEFAULT 0,
55
+
56
+ -- D1 metrics
57
+ d1_rows_read INTEGER DEFAULT 0,
58
+ d1_rows_written INTEGER DEFAULT 0,
59
+ d1_storage_bytes INTEGER DEFAULT 0,
60
+ d1_cost_usd REAL DEFAULT 0,
61
+
62
+ -- KV metrics
63
+ kv_reads INTEGER DEFAULT 0,
64
+ kv_writes INTEGER DEFAULT 0,
65
+ kv_deletes INTEGER DEFAULT 0,
66
+ kv_list_ops INTEGER DEFAULT 0,
67
+ kv_storage_bytes INTEGER DEFAULT 0,
68
+ kv_cost_usd REAL DEFAULT 0,
69
+
70
+ -- R2 metrics
71
+ r2_class_a_ops INTEGER DEFAULT 0,
72
+ r2_class_b_ops INTEGER DEFAULT 0,
73
+ r2_storage_bytes INTEGER DEFAULT 0,
74
+ r2_egress_bytes INTEGER DEFAULT 0,
75
+ r2_cost_usd REAL DEFAULT 0,
76
+
77
+ -- Durable Objects metrics (includes do_gb_seconds from 004, do_storage_bytes from 010)
78
+ do_requests INTEGER DEFAULT 0,
79
+ do_websocket_connections INTEGER DEFAULT 0,
80
+ do_storage_reads INTEGER DEFAULT 0,
81
+ do_storage_writes INTEGER DEFAULT 0,
82
+ do_storage_deletes INTEGER DEFAULT 0,
83
+ do_gb_seconds REAL DEFAULT 0,
84
+ do_storage_bytes INTEGER DEFAULT 0,
85
+ do_cost_usd REAL DEFAULT 0,
86
+
87
+ -- Vectorize metrics
88
+ vectorize_queries INTEGER DEFAULT 0,
89
+ vectorize_vectors_stored INTEGER DEFAULT 0,
90
+ vectorize_dimensions INTEGER DEFAULT 0,
91
+ vectorize_cost_usd REAL DEFAULT 0,
92
+
93
+ -- AI Gateway metrics
94
+ aigateway_requests INTEGER DEFAULT 0,
95
+ aigateway_tokens_in INTEGER DEFAULT 0,
96
+ aigateway_tokens_out INTEGER DEFAULT 0,
97
+ aigateway_cached_requests INTEGER DEFAULT 0,
98
+ aigateway_cost_usd REAL DEFAULT 0,
99
+
100
+ -- Pages metrics (renamed from pages_requests to pages_deployments per 019)
101
+ pages_deployments INTEGER DEFAULT 0,
102
+ pages_bandwidth_bytes INTEGER DEFAULT 0,
103
+ pages_cost_usd REAL DEFAULT 0,
104
+
105
+ -- Queues metrics
106
+ queues_messages_produced INTEGER DEFAULT 0,
107
+ queues_messages_consumed INTEGER DEFAULT 0,
108
+ queues_cost_usd REAL DEFAULT 0,
109
+
110
+ -- Workers AI metrics
111
+ workersai_requests INTEGER DEFAULT 0,
112
+ workersai_neurons INTEGER DEFAULT 0,
113
+ workersai_cost_usd REAL DEFAULT 0,
114
+
115
+ -- Workflows metrics (from 005)
116
+ workflows_executions INTEGER DEFAULT 0,
117
+ workflows_successes INTEGER DEFAULT 0,
118
+ workflows_failures INTEGER DEFAULT 0,
119
+ workflows_wall_time_ms REAL DEFAULT 0,
120
+ workflows_cpu_time_ms REAL DEFAULT 0,
121
+ workflows_cost_usd REAL DEFAULT 0,
122
+
123
+ -- Totals
124
+ total_cost_usd REAL DEFAULT 0,
125
+
126
+ -- Metadata
127
+ collection_timestamp INTEGER NOT NULL, -- Unix timestamp when collected
128
+ sampling_mode TEXT DEFAULT 'FULL', -- 'FULL', 'HALF', 'QUARTER', 'MINIMAL'
129
+
130
+ -- Provenance fields (from 014, 036)
131
+ source TEXT DEFAULT 'live', -- 'live' or 'backfill'
132
+ ingested_at TEXT, -- When data was written to D1
133
+ completeness INTEGER DEFAULT 100, -- 0-100% data quality
134
+ confidence INTEGER DEFAULT 100, -- 0-100 confidence score
135
+ backfill_reason TEXT, -- Audit trail for backfilled data
136
+
137
+ created_at INTEGER DEFAULT (unixepoch())
138
+ );
139
+
140
+ CREATE INDEX IF NOT EXISTS idx_hourly_hour ON hourly_usage_snapshots(snapshot_hour DESC);
141
+ CREATE INDEX IF NOT EXISTS idx_hourly_project_hour ON hourly_usage_snapshots(project, snapshot_hour DESC);
142
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_hourly_unique ON hourly_usage_snapshots(snapshot_hour, project);
143
+
144
+
145
+ -- =============================================================================
146
+ -- Tier 2: DAILY ROLLUPS (90-day retention)
147
+ -- =============================================================================
148
+ -- Aggregated daily totals from hourly snapshots.
149
+ -- Columns merged from migrations 003, 004, 005, 010, 012, 014, 019, 036.
150
+
151
+ CREATE TABLE IF NOT EXISTS daily_usage_rollups (
152
+ snapshot_date TEXT NOT NULL, -- YYYY-MM-DD
153
+ project TEXT NOT NULL,
154
+
155
+ -- Workers metrics
156
+ workers_requests INTEGER DEFAULT 0,
157
+ workers_errors INTEGER DEFAULT 0,
158
+ workers_cpu_time_ms REAL DEFAULT 0,
159
+ workers_duration_p50_ms_avg REAL DEFAULT 0,
160
+ workers_duration_p99_ms_max REAL DEFAULT 0,
161
+ workers_cost_usd REAL DEFAULT 0,
162
+
163
+ -- D1 metrics
164
+ d1_rows_read INTEGER DEFAULT 0,
165
+ d1_rows_written INTEGER DEFAULT 0,
166
+ d1_storage_bytes_max INTEGER DEFAULT 0,
167
+ d1_cost_usd REAL DEFAULT 0,
168
+
169
+ -- KV metrics
170
+ kv_reads INTEGER DEFAULT 0,
171
+ kv_writes INTEGER DEFAULT 0,
172
+ kv_deletes INTEGER DEFAULT 0,
173
+ kv_list_ops INTEGER DEFAULT 0,
174
+ kv_storage_bytes_max INTEGER DEFAULT 0,
175
+ kv_cost_usd REAL DEFAULT 0,
176
+
177
+ -- R2 metrics
178
+ r2_class_a_ops INTEGER DEFAULT 0,
179
+ r2_class_b_ops INTEGER DEFAULT 0,
180
+ r2_storage_bytes_max INTEGER DEFAULT 0,
181
+ r2_egress_bytes INTEGER DEFAULT 0,
182
+ r2_cost_usd REAL DEFAULT 0,
183
+
184
+ -- Durable Objects metrics
185
+ do_requests INTEGER DEFAULT 0,
186
+ do_websocket_connections INTEGER DEFAULT 0,
187
+ do_storage_reads INTEGER DEFAULT 0,
188
+ do_storage_writes INTEGER DEFAULT 0,
189
+ do_storage_deletes INTEGER DEFAULT 0,
190
+ do_gb_seconds REAL DEFAULT 0,
191
+ do_storage_bytes_max INTEGER DEFAULT 0,
192
+ do_cost_usd REAL DEFAULT 0,
193
+
194
+ -- Vectorize metrics
195
+ vectorize_queries INTEGER DEFAULT 0,
196
+ vectorize_vectors_stored_max INTEGER DEFAULT 0,
197
+ vectorize_cost_usd REAL DEFAULT 0,
198
+
199
+ -- AI Gateway metrics
200
+ aigateway_requests INTEGER DEFAULT 0,
201
+ aigateway_tokens_in INTEGER DEFAULT 0,
202
+ aigateway_tokens_out INTEGER DEFAULT 0,
203
+ aigateway_cached_requests INTEGER DEFAULT 0,
204
+ aigateway_cost_usd REAL DEFAULT 0,
205
+
206
+ -- Pages metrics
207
+ pages_deployments INTEGER DEFAULT 0,
208
+ pages_bandwidth_bytes INTEGER DEFAULT 0,
209
+ pages_cost_usd REAL DEFAULT 0,
210
+
211
+ -- Queues metrics
212
+ queues_messages_produced INTEGER DEFAULT 0,
213
+ queues_messages_consumed INTEGER DEFAULT 0,
214
+ queues_cost_usd REAL DEFAULT 0,
215
+
216
+ -- Workers AI metrics
217
+ workersai_requests INTEGER DEFAULT 0,
218
+ workersai_neurons INTEGER DEFAULT 0,
219
+ workersai_cost_usd REAL DEFAULT 0,
220
+
221
+ -- Workflows metrics
222
+ workflows_executions INTEGER DEFAULT 0,
223
+ workflows_successes INTEGER DEFAULT 0,
224
+ workflows_failures INTEGER DEFAULT 0,
225
+ workflows_wall_time_ms REAL DEFAULT 0,
226
+ workflows_cpu_time_ms REAL DEFAULT 0,
227
+ workflows_cost_usd REAL DEFAULT 0,
228
+
229
+ -- Totals
230
+ total_cost_usd REAL DEFAULT 0,
231
+
232
+ -- Rollup metadata
233
+ samples_count INTEGER DEFAULT 0,
234
+ pricing_version_id INTEGER, -- FK to pricing_versions (from 012)
235
+
236
+ -- Provenance fields (from 014, 036)
237
+ source TEXT DEFAULT 'rollup',
238
+ ingested_at TEXT,
239
+ completeness INTEGER DEFAULT 100,
240
+ confidence INTEGER DEFAULT 100,
241
+
242
+ created_at INTEGER DEFAULT (unixepoch()),
243
+
244
+ PRIMARY KEY (snapshot_date, project)
245
+ );
246
+
247
+ CREATE INDEX IF NOT EXISTS idx_daily_date ON daily_usage_rollups(snapshot_date DESC);
248
+ CREATE INDEX IF NOT EXISTS idx_daily_project_date ON daily_usage_rollups(project, snapshot_date DESC);
249
+
250
+
251
+ -- =============================================================================
252
+ -- Tier 3: MONTHLY ROLLUPS (forever retention)
253
+ -- =============================================================================
254
+ -- Aggregated monthly totals for long-term trends. Never deleted.
255
+ -- Columns merged from migrations 003, 004, 005, 012, 014.
256
+
257
+ CREATE TABLE IF NOT EXISTS monthly_usage_rollups (
258
+ snapshot_month TEXT NOT NULL, -- YYYY-MM
259
+ project TEXT NOT NULL,
260
+
261
+ -- Workers metrics
262
+ workers_requests INTEGER DEFAULT 0,
263
+ workers_errors INTEGER DEFAULT 0,
264
+ workers_cost_usd REAL DEFAULT 0,
265
+
266
+ -- D1 metrics
267
+ d1_rows_read INTEGER DEFAULT 0,
268
+ d1_rows_written INTEGER DEFAULT 0,
269
+ d1_cost_usd REAL DEFAULT 0,
270
+
271
+ -- KV metrics
272
+ kv_reads INTEGER DEFAULT 0,
273
+ kv_writes INTEGER DEFAULT 0,
274
+ kv_cost_usd REAL DEFAULT 0,
275
+
276
+ -- R2 metrics
277
+ r2_class_a_ops INTEGER DEFAULT 0,
278
+ r2_class_b_ops INTEGER DEFAULT 0,
279
+ r2_egress_bytes INTEGER DEFAULT 0,
280
+ r2_cost_usd REAL DEFAULT 0,
281
+
282
+ -- Durable Objects metrics (from 004)
283
+ do_requests INTEGER DEFAULT 0,
284
+ do_gb_seconds REAL DEFAULT 0,
285
+ do_cost_usd REAL DEFAULT 0,
286
+
287
+ -- AI Gateway metrics
288
+ aigateway_requests INTEGER DEFAULT 0,
289
+ aigateway_tokens_total INTEGER DEFAULT 0,
290
+ aigateway_cost_usd REAL DEFAULT 0,
291
+
292
+ -- Workers AI metrics
293
+ workersai_requests INTEGER DEFAULT 0,
294
+ workersai_neurons INTEGER DEFAULT 0,
295
+ workersai_cost_usd REAL DEFAULT 0,
296
+
297
+ -- Workflows metrics (from 005)
298
+ workflows_executions INTEGER DEFAULT 0,
299
+ workflows_failures INTEGER DEFAULT 0,
300
+ workflows_cpu_time_ms REAL DEFAULT 0,
301
+ workflows_cost_usd REAL DEFAULT 0,
302
+
303
+ -- Totals
304
+ total_cost_usd REAL DEFAULT 0,
305
+
306
+ -- Rollup metadata
307
+ days_count INTEGER DEFAULT 0,
308
+ pricing_version_id INTEGER, -- FK to pricing_versions (from 012)
309
+
310
+ -- Provenance fields (from 014)
311
+ source TEXT DEFAULT 'rollup',
312
+ ingested_at TEXT,
313
+
314
+ created_at INTEGER DEFAULT (unixepoch()),
315
+
316
+ PRIMARY KEY (snapshot_month, project)
317
+ );
318
+
319
+ CREATE INDEX IF NOT EXISTS idx_monthly_month ON monthly_usage_rollups(snapshot_month DESC);
320
+
321
+
322
+ -- =============================================================================
323
+ -- THIRD-PARTY USAGE (GitHub, etc.)
324
+ -- =============================================================================
325
+ -- Tracks usage from external services that contribute to costs.
326
+ -- Columns merged from 003, 014.
327
+
328
+ CREATE TABLE IF NOT EXISTS third_party_usage (
329
+ id TEXT PRIMARY KEY,
330
+ snapshot_date TEXT NOT NULL, -- YYYY-MM-DD
331
+ provider TEXT NOT NULL, -- 'github', 'vercel', etc.
332
+ resource_type TEXT NOT NULL, -- 'advanced_security_seats', 'actions_minutes', etc.
333
+ resource_name TEXT,
334
+ usage_value REAL NOT NULL DEFAULT 0,
335
+ usage_unit TEXT NOT NULL, -- 'seats', 'minutes', 'bytes', 'dollars', etc.
336
+ cost_usd REAL DEFAULT 0,
337
+ raw_response TEXT,
338
+ collection_timestamp INTEGER NOT NULL,
339
+
340
+ -- Provenance (from 014)
341
+ source TEXT DEFAULT 'live',
342
+ ingested_at TEXT,
343
+
344
+ created_at INTEGER DEFAULT (unixepoch())
345
+ );
346
+
347
+ CREATE INDEX IF NOT EXISTS idx_third_party_date ON third_party_usage(snapshot_date DESC);
348
+ CREATE INDEX IF NOT EXISTS idx_third_party_provider ON third_party_usage(provider, snapshot_date DESC);
349
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_third_party_unique ON third_party_usage(snapshot_date, provider, resource_type, COALESCE(resource_name, ''));
350
+
351
+
352
+ -- =============================================================================
353
+ -- ANOMALY TRACKING
354
+ -- =============================================================================
355
+ -- Records detected anomalies for audit trail and trend analysis.
356
+
357
+ CREATE TABLE IF NOT EXISTS usage_anomalies (
358
+ id TEXT PRIMARY KEY,
359
+ detected_at INTEGER NOT NULL,
360
+ metric_name TEXT NOT NULL,
361
+ project TEXT NOT NULL DEFAULT 'all',
362
+
363
+ -- Anomaly details
364
+ current_value REAL NOT NULL,
365
+ rolling_avg REAL NOT NULL,
366
+ rolling_stddev REAL NOT NULL,
367
+ deviation_factor REAL NOT NULL,
368
+
369
+ -- Alert status
370
+ alert_sent INTEGER DEFAULT 0,
371
+ alert_channel TEXT,
372
+ alert_message_id TEXT,
373
+
374
+ -- Resolution
375
+ resolved INTEGER DEFAULT 0,
376
+ resolved_at INTEGER,
377
+ resolved_by TEXT,
378
+
379
+ created_at INTEGER DEFAULT (unixepoch())
380
+ );
381
+
382
+ CREATE INDEX IF NOT EXISTS idx_anomalies_detected ON usage_anomalies(detected_at DESC);
383
+ CREATE INDEX IF NOT EXISTS idx_anomalies_unresolved ON usage_anomalies(resolved) WHERE resolved = 0;
384
+ CREATE INDEX IF NOT EXISTS idx_anomalies_metric ON usage_anomalies(metric_name, detected_at DESC);
385
+
386
+
387
+ -- =============================================================================
388
+ -- CIRCUIT BREAKER AUDIT LOG
389
+ -- =============================================================================
390
+ -- Records circuit breaker events for operational visibility.
391
+ -- Columns merged from 003, 011.
392
+
393
+ CREATE TABLE IF NOT EXISTS circuit_breaker_logs (
394
+ id TEXT PRIMARY KEY,
395
+ event_type TEXT NOT NULL, -- 'trip', 'reset', 'sample_reduce', 'sample_restore'
396
+ service TEXT NOT NULL,
397
+ reason TEXT NOT NULL,
398
+
399
+ -- State at time of event
400
+ d1_writes_24h INTEGER,
401
+ d1_limit INTEGER DEFAULT 1000000,
402
+ sampling_mode TEXT,
403
+ previous_sampling_mode TEXT,
404
+
405
+ -- DO GB-seconds tracking (from 011)
406
+ do_gb_seconds_24h REAL DEFAULT NULL,
407
+ do_gb_seconds_limit REAL DEFAULT 200000,
408
+
409
+ -- Alert tracking
410
+ alert_sent INTEGER DEFAULT 0,
411
+ alert_channel TEXT,
412
+
413
+ created_at INTEGER DEFAULT (unixepoch())
414
+ );
415
+
416
+ CREATE INDEX IF NOT EXISTS idx_cb_created ON circuit_breaker_logs(created_at DESC);
417
+ CREATE INDEX IF NOT EXISTS idx_cb_service ON circuit_breaker_logs(service, created_at DESC);
418
+ CREATE INDEX IF NOT EXISTS idx_cb_type ON circuit_breaker_logs(event_type, created_at DESC);
419
+
420
+
421
+ -- =============================================================================
422
+ -- USAGE SETTINGS (per-project alert thresholds)
423
+ -- =============================================================================
424
+ -- Stores user-configurable alert thresholds for each resource type.
425
+
426
+ CREATE TABLE IF NOT EXISTS usage_settings (
427
+ id TEXT PRIMARY KEY,
428
+ project TEXT NOT NULL DEFAULT 'all',
429
+ setting_key TEXT NOT NULL,
430
+ setting_value TEXT NOT NULL,
431
+ updated_at INTEGER DEFAULT (unixepoch()),
432
+ created_at INTEGER DEFAULT (unixepoch()),
433
+ UNIQUE(project, setting_key)
434
+ );
435
+
436
+ CREATE INDEX IF NOT EXISTS idx_settings_project ON usage_settings(project);
437
+
438
+
439
+ -- =============================================================================
440
+ -- AI MODEL BREAKDOWN TABLES (from 006)
441
+ -- =============================================================================
442
+
443
+ -- Workers AI per-model hourly usage
444
+ CREATE TABLE IF NOT EXISTS workersai_model_usage (
445
+ id TEXT PRIMARY KEY,
446
+ snapshot_hour TEXT NOT NULL,
447
+ project TEXT NOT NULL,
448
+ model TEXT NOT NULL,
449
+ requests INTEGER DEFAULT 0,
450
+ input_tokens INTEGER DEFAULT 0,
451
+ output_tokens INTEGER DEFAULT 0,
452
+ cost_usd REAL DEFAULT 0,
453
+ is_estimated INTEGER DEFAULT 0,
454
+ created_at INTEGER DEFAULT (unixepoch())
455
+ );
456
+
457
+ CREATE INDEX IF NOT EXISTS idx_workersai_model_hour ON workersai_model_usage(snapshot_hour DESC);
458
+ CREATE INDEX IF NOT EXISTS idx_workersai_model_project ON workersai_model_usage(project, snapshot_hour DESC);
459
+ CREATE INDEX IF NOT EXISTS idx_workersai_model_model ON workersai_model_usage(model, snapshot_hour DESC);
460
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_workersai_model_unique ON workersai_model_usage(snapshot_hour, project, model);
461
+
462
+ -- AI Gateway per-model hourly usage
463
+ CREATE TABLE IF NOT EXISTS aigateway_model_usage (
464
+ id TEXT PRIMARY KEY,
465
+ snapshot_hour TEXT NOT NULL,
466
+ gateway_id TEXT NOT NULL,
467
+ provider TEXT NOT NULL,
468
+ model TEXT NOT NULL,
469
+ requests INTEGER DEFAULT 0,
470
+ cached_requests INTEGER DEFAULT 0,
471
+ tokens_in INTEGER DEFAULT 0,
472
+ tokens_out INTEGER DEFAULT 0,
473
+ cost_usd REAL DEFAULT 0,
474
+ created_at INTEGER DEFAULT (unixepoch())
475
+ );
476
+
477
+ CREATE INDEX IF NOT EXISTS idx_aigateway_model_hour ON aigateway_model_usage(snapshot_hour DESC);
478
+ CREATE INDEX IF NOT EXISTS idx_aigateway_model_gateway ON aigateway_model_usage(gateway_id, snapshot_hour DESC);
479
+ CREATE INDEX IF NOT EXISTS idx_aigateway_model_provider ON aigateway_model_usage(provider, snapshot_hour DESC);
480
+ CREATE INDEX IF NOT EXISTS idx_aigateway_model_model ON aigateway_model_usage(model, snapshot_hour DESC);
481
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_aigateway_model_unique ON aigateway_model_usage(snapshot_hour, gateway_id, provider, model);
482
+
483
+ -- Workers AI daily rollup
484
+ CREATE TABLE IF NOT EXISTS workersai_model_daily (
485
+ snapshot_date TEXT NOT NULL,
486
+ project TEXT NOT NULL,
487
+ model TEXT NOT NULL,
488
+ requests INTEGER DEFAULT 0,
489
+ input_tokens INTEGER DEFAULT 0,
490
+ output_tokens INTEGER DEFAULT 0,
491
+ cost_usd REAL DEFAULT 0,
492
+ samples_count INTEGER DEFAULT 0,
493
+ created_at INTEGER DEFAULT (unixepoch()),
494
+ PRIMARY KEY (snapshot_date, project, model)
495
+ );
496
+
497
+ CREATE INDEX IF NOT EXISTS idx_workersai_daily_date ON workersai_model_daily(snapshot_date DESC);
498
+ CREATE INDEX IF NOT EXISTS idx_workersai_daily_model ON workersai_model_daily(model, snapshot_date DESC);
499
+
500
+ -- AI Gateway daily rollup
501
+ CREATE TABLE IF NOT EXISTS aigateway_model_daily (
502
+ snapshot_date TEXT NOT NULL,
503
+ gateway_id TEXT NOT NULL,
504
+ provider TEXT NOT NULL,
505
+ model TEXT NOT NULL,
506
+ requests INTEGER DEFAULT 0,
507
+ cached_requests INTEGER DEFAULT 0,
508
+ tokens_in INTEGER DEFAULT 0,
509
+ tokens_out INTEGER DEFAULT 0,
510
+ cost_usd REAL DEFAULT 0,
511
+ samples_count INTEGER DEFAULT 0,
512
+ created_at INTEGER DEFAULT (unixepoch()),
513
+ PRIMARY KEY (snapshot_date, gateway_id, provider, model)
514
+ );
515
+
516
+ CREATE INDEX IF NOT EXISTS idx_aigateway_daily_date ON aigateway_model_daily(snapshot_date DESC);
517
+ CREATE INDEX IF NOT EXISTS idx_aigateway_daily_provider ON aigateway_model_daily(provider, snapshot_date DESC);
518
+
519
+
520
+ -- =============================================================================
521
+ -- PRICING VERSIONS (from 012)
522
+ -- =============================================================================
523
+ -- Audit trail for Cloudflare pricing changes with historical recomputation support.
524
+
525
+ CREATE TABLE IF NOT EXISTS pricing_versions (
526
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
527
+ version_name TEXT NOT NULL,
528
+ effective_from TEXT NOT NULL,
529
+ effective_to TEXT,
530
+ source_url TEXT,
531
+ pricing_json TEXT NOT NULL,
532
+ allowances_json TEXT NOT NULL,
533
+ notes TEXT,
534
+ created_at TEXT DEFAULT (datetime('now')),
535
+ created_by TEXT DEFAULT 'system'
536
+ );
537
+
538
+ CREATE INDEX IF NOT EXISTS idx_pricing_versions_effective
539
+ ON pricing_versions (effective_from, effective_to);
540
+
541
+
542
+ -- =============================================================================
543
+ -- DATASET REGISTRY (from 013)
544
+ -- =============================================================================
545
+ -- Tracks Cloudflare GraphQL datasets and detects when new ones appear.
546
+
547
+ CREATE TABLE IF NOT EXISTS dataset_registry (
548
+ dataset_name TEXT PRIMARY KEY,
549
+ first_seen TEXT NOT NULL,
550
+ last_seen TEXT NOT NULL,
551
+ is_queried INTEGER DEFAULT 0,
552
+ is_billable INTEGER DEFAULT 0,
553
+ category TEXT,
554
+ notes TEXT,
555
+ created_at TEXT DEFAULT (datetime('now')),
556
+ updated_at TEXT DEFAULT (datetime('now'))
557
+ );
558
+
559
+ CREATE INDEX IF NOT EXISTS idx_dataset_registry_billable_unqueried
560
+ ON dataset_registry (is_billable, is_queried)
561
+ WHERE is_billable = 1 AND is_queried = 0;
562
+
563
+ CREATE INDEX IF NOT EXISTS idx_dataset_registry_last_seen
564
+ ON dataset_registry (last_seen);
565
+
566
+
567
+ -- =============================================================================
568
+ -- RESOURCE USAGE SNAPSHOTS (from 015)
569
+ -- =============================================================================
570
+ -- Per-resource hourly metrics — finest granularity for flexible aggregation.
571
+
572
+ CREATE TABLE IF NOT EXISTS resource_usage_snapshots (
573
+ id TEXT PRIMARY KEY,
574
+ snapshot_hour TEXT NOT NULL,
575
+ resource_type TEXT NOT NULL,
576
+ resource_id TEXT NOT NULL,
577
+ resource_name TEXT,
578
+ project TEXT NOT NULL,
579
+
580
+ -- Usage metrics (nullable — not all types have all metrics)
581
+ requests INTEGER,
582
+ cpu_time_ms REAL,
583
+ wall_time_ms REAL,
584
+ duration_ms REAL,
585
+ gb_seconds REAL,
586
+ storage_bytes INTEGER,
587
+ reads INTEGER,
588
+ writes INTEGER,
589
+ deletes INTEGER,
590
+ rows_read INTEGER,
591
+ rows_written INTEGER,
592
+ class_a_ops INTEGER,
593
+ class_b_ops INTEGER,
594
+ egress_bytes INTEGER,
595
+ neurons INTEGER,
596
+
597
+ -- Cost
598
+ cost_usd REAL,
599
+
600
+ -- Provenance
601
+ source TEXT DEFAULT 'live',
602
+ confidence INTEGER DEFAULT 100,
603
+ allocation_basis TEXT,
604
+
605
+ -- Timestamps
606
+ ingested_at TEXT,
607
+ created_at TEXT DEFAULT (datetime('now')),
608
+
609
+ UNIQUE(snapshot_hour, resource_type, resource_id)
610
+ );
611
+
612
+ CREATE INDEX IF NOT EXISTS idx_resource_usage_hour
613
+ ON resource_usage_snapshots (snapshot_hour);
614
+ CREATE INDEX IF NOT EXISTS idx_resource_usage_type_hour
615
+ ON resource_usage_snapshots (resource_type, snapshot_hour);
616
+ CREATE INDEX IF NOT EXISTS idx_resource_usage_project_hour
617
+ ON resource_usage_snapshots (project, snapshot_hour);
618
+ CREATE INDEX IF NOT EXISTS idx_resource_usage_project_type_hour
619
+ ON resource_usage_snapshots (project, resource_type, snapshot_hour);
620
+ CREATE INDEX IF NOT EXISTS idx_resource_usage_provenance
621
+ ON resource_usage_snapshots (source, confidence)
622
+ WHERE source = 'estimated' OR confidence < 100;
623
+
624
+
625
+ -- =============================================================================
626
+ -- RESOURCE REGISTRY (from 015)
627
+ -- =============================================================================
628
+ -- Maps discovered resources to projects with lifecycle tracking.
629
+
630
+ CREATE TABLE IF NOT EXISTS resource_registry (
631
+ resource_type TEXT NOT NULL,
632
+ resource_id TEXT NOT NULL,
633
+ resource_name TEXT,
634
+ project TEXT NOT NULL,
635
+ first_seen TEXT NOT NULL,
636
+ last_seen TEXT NOT NULL,
637
+ is_active INTEGER DEFAULT 1,
638
+ environment TEXT DEFAULT 'production',
639
+ tags TEXT, -- JSON array
640
+ created_at TEXT DEFAULT (datetime('now')),
641
+ updated_at TEXT DEFAULT (datetime('now')),
642
+ PRIMARY KEY (resource_type, resource_id)
643
+ );
644
+
645
+ CREATE INDEX IF NOT EXISTS idx_resource_registry_project
646
+ ON resource_registry (project);
647
+ CREATE INDEX IF NOT EXISTS idx_resource_registry_active
648
+ ON resource_registry (is_active, last_seen)
649
+ WHERE is_active = 1;
650
+
651
+
652
+ -- =============================================================================
653
+ -- GAP DETECTION LOG (from 036)
654
+ -- =============================================================================
655
+ -- Stores results of gap detection runs from the sentinel worker.
656
+
657
+ CREATE TABLE IF NOT EXISTS gap_detection_log (
658
+ id TEXT PRIMARY KEY,
659
+ detection_time TEXT NOT NULL,
660
+ missing_hours_count INTEGER NOT NULL DEFAULT 0,
661
+ stale_projects_count INTEGER NOT NULL DEFAULT 0,
662
+ severity TEXT NOT NULL CHECK (severity IN ('ok', 'warning', 'critical')),
663
+ report_json TEXT NOT NULL,
664
+ created_at TEXT DEFAULT (datetime('now'))
665
+ );
666
+
667
+ CREATE INDEX IF NOT EXISTS idx_gap_detection_time ON gap_detection_log(detection_time);
668
+ CREATE INDEX IF NOT EXISTS idx_gap_detection_severity ON gap_detection_log(severity);
669
+
670
+
671
+ -- =============================================================================
672
+ -- BACKFILL LOG (from 036)
673
+ -- =============================================================================
674
+ -- Tracks backfill operations for audit and debugging.
675
+
676
+ CREATE TABLE IF NOT EXISTS backfill_log (
677
+ id TEXT PRIMARY KEY,
678
+ start_date TEXT NOT NULL,
679
+ end_date TEXT NOT NULL,
680
+ projects TEXT, -- JSON array of project IDs or null for all
681
+ hours_processed INTEGER NOT NULL DEFAULT 0,
682
+ hours_created INTEGER NOT NULL DEFAULT 0,
683
+ hours_updated INTEGER NOT NULL DEFAULT 0,
684
+ errors_count INTEGER NOT NULL DEFAULT 0,
685
+ errors_json TEXT,
686
+ average_confidence INTEGER NOT NULL DEFAULT 75,
687
+ triggered_by TEXT, -- 'manual' | 'auto' | 'sentinel'
688
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'failed')),
689
+ started_at TEXT DEFAULT (datetime('now')),
690
+ completed_at TEXT,
691
+ created_at TEXT DEFAULT (datetime('now'))
692
+ );
693
+
694
+ CREATE INDEX IF NOT EXISTS idx_backfill_log_status ON backfill_log(status);
695
+ CREATE INDEX IF NOT EXISTS idx_backfill_log_started ON backfill_log(started_at);
696
+
697
+
698
+ -- =============================================================================
699
+ -- ATTRIBUTION REPORTS (from 037)
700
+ -- =============================================================================
701
+ -- Stores resource-to-project attribution status from discovery runs.
702
+
703
+ CREATE TABLE IF NOT EXISTS attribution_reports (
704
+ id TEXT PRIMARY KEY,
705
+ discovery_time TEXT NOT NULL,
706
+ total_resources INTEGER NOT NULL DEFAULT 0,
707
+ attributed_count INTEGER NOT NULL DEFAULT 0,
708
+ unattributed_count INTEGER NOT NULL DEFAULT 0,
709
+ report_json TEXT NOT NULL,
710
+ created_at TEXT DEFAULT (datetime('now'))
711
+ );
712
+
713
+ CREATE INDEX IF NOT EXISTS idx_attribution_discovery_time ON attribution_reports(discovery_time);
714
+
715
+
716
+ -- =============================================================================
717
+ -- FEATURE COVERAGE AUDIT (from 037)
718
+ -- =============================================================================
719
+ -- Tracks which features from budgets config are active vs dormant.
720
+
721
+ CREATE TABLE IF NOT EXISTS feature_coverage_audit (
722
+ id TEXT PRIMARY KEY,
723
+ audit_time TEXT NOT NULL,
724
+ project TEXT NOT NULL,
725
+ feature TEXT NOT NULL,
726
+ status TEXT NOT NULL CHECK (status IN ('active', 'dormant', 'undefined')),
727
+ last_heartbeat TEXT,
728
+ events_last_7d INTEGER DEFAULT 0,
729
+ defined_budget INTEGER,
730
+ budget_unit TEXT,
731
+ created_at TEXT DEFAULT (datetime('now'))
732
+ );
733
+
734
+ CREATE INDEX IF NOT EXISTS idx_feature_coverage_project ON feature_coverage_audit(project);
735
+ CREATE INDEX IF NOT EXISTS idx_feature_coverage_status ON feature_coverage_audit(status);
736
+ CREATE INDEX IF NOT EXISTS idx_feature_coverage_audit_time ON feature_coverage_audit(audit_time);
737
+
738
+
739
+ -- =============================================================================
740
+ -- COMPREHENSIVE AUDIT REPORTS (from 037)
741
+ -- =============================================================================
742
+ -- Weekly comprehensive reports aggregating all audit findings.
743
+
744
+ CREATE TABLE IF NOT EXISTS comprehensive_audit_reports (
745
+ id TEXT PRIMARY KEY,
746
+ generated_at TEXT NOT NULL,
747
+ gap_events_count INTEGER NOT NULL DEFAULT 0,
748
+ total_missing_hours INTEGER NOT NULL DEFAULT 0,
749
+ worst_gap_day TEXT,
750
+ average_gap_severity TEXT,
751
+ total_resources INTEGER NOT NULL DEFAULT 0,
752
+ attributed_count INTEGER NOT NULL DEFAULT 0,
753
+ unattributed_count INTEGER NOT NULL DEFAULT 0,
754
+ unattributed_resources TEXT, -- JSON array of {type, name}
755
+ defined_features_count INTEGER NOT NULL DEFAULT 0,
756
+ active_features_count INTEGER NOT NULL DEFAULT 0,
757
+ dormant_features_count INTEGER NOT NULL DEFAULT 0,
758
+ undefined_features_count INTEGER NOT NULL DEFAULT 0,
759
+ ai_judge_avg_score REAL,
760
+ ai_judge_recommendations TEXT, -- JSON array
761
+ action_items_count INTEGER NOT NULL DEFAULT 0,
762
+ critical_items_count INTEGER NOT NULL DEFAULT 0,
763
+ action_items TEXT, -- JSON array
764
+ report_json TEXT NOT NULL,
765
+ created_at TEXT DEFAULT (datetime('now'))
766
+ );
767
+
768
+ CREATE INDEX IF NOT EXISTS idx_comprehensive_audit_generated ON comprehensive_audit_reports(generated_at);
769
+
770
+
771
+ -- =============================================================================
772
+ -- VIEWS for common aggregation patterns (from 015)
773
+ -- =============================================================================
774
+
775
+ -- Account-level daily summary
776
+ CREATE VIEW IF NOT EXISTS v_account_daily_usage AS
777
+ SELECT
778
+ date(snapshot_hour) as usage_date,
779
+ SUM(requests) as total_requests,
780
+ SUM(cpu_time_ms) as total_cpu_time_ms,
781
+ SUM(storage_bytes) as total_storage_bytes,
782
+ SUM(cost_usd) as total_cost_usd,
783
+ COUNT(DISTINCT resource_id) as resource_count,
784
+ AVG(confidence) as avg_confidence
785
+ FROM resource_usage_snapshots
786
+ GROUP BY date(snapshot_hour);
787
+
788
+ -- Per-CF-tool daily summary
789
+ CREATE VIEW IF NOT EXISTS v_tool_daily_usage AS
790
+ SELECT
791
+ date(snapshot_hour) as usage_date,
792
+ resource_type,
793
+ SUM(requests) as total_requests,
794
+ SUM(cpu_time_ms) as total_cpu_time_ms,
795
+ SUM(storage_bytes) as total_storage_bytes,
796
+ SUM(cost_usd) as total_cost_usd,
797
+ COUNT(DISTINCT resource_id) as resource_count,
798
+ AVG(confidence) as avg_confidence
799
+ FROM resource_usage_snapshots
800
+ GROUP BY date(snapshot_hour), resource_type;
801
+
802
+ -- Per-project daily summary
803
+ CREATE VIEW IF NOT EXISTS v_project_daily_usage AS
804
+ SELECT
805
+ date(snapshot_hour) as usage_date,
806
+ project,
807
+ SUM(requests) as total_requests,
808
+ SUM(cpu_time_ms) as total_cpu_time_ms,
809
+ SUM(storage_bytes) as total_storage_bytes,
810
+ SUM(cost_usd) as total_cost_usd,
811
+ COUNT(DISTINCT resource_id) as resource_count,
812
+ COUNT(DISTINCT resource_type) as tool_count,
813
+ AVG(confidence) as avg_confidence
814
+ FROM resource_usage_snapshots
815
+ GROUP BY date(snapshot_hour), project;
816
+
817
+ -- Per-project per-tool daily summary (most granular rollup)
818
+ CREATE VIEW IF NOT EXISTS v_project_tool_daily_usage AS
819
+ SELECT
820
+ date(snapshot_hour) as usage_date,
821
+ project,
822
+ resource_type,
823
+ SUM(requests) as total_requests,
824
+ SUM(cpu_time_ms) as total_cpu_time_ms,
825
+ SUM(storage_bytes) as total_storage_bytes,
826
+ SUM(cost_usd) as total_cost_usd,
827
+ COUNT(DISTINCT resource_id) as resource_count,
828
+ AVG(confidence) as avg_confidence
829
+ FROM resource_usage_snapshots
830
+ GROUP BY date(snapshot_hour), project, resource_type;