@littlebearapps/platform-admin-sdk 2.0.0 → 2.2.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 (185) hide show
  1. package/README.md +4 -7
  2. package/dist/templates.d.ts +1 -1
  3. package/dist/templates.js +206 -4
  4. package/package.json +1 -1
  5. package/templates/full/dashboard/src/components/notifications/NotificationDropdown.tsx +130 -0
  6. package/templates/full/dashboard/src/components/notifications/NotificationItem.tsx +264 -0
  7. package/templates/full/dashboard/src/components/patterns/PatternInfoButton.tsx +60 -0
  8. package/templates/full/dashboard/src/components/reports/DigestStats.tsx +151 -0
  9. package/templates/full/dashboard/src/components/reports/FeatureUsageReport.tsx +339 -0
  10. package/templates/full/dashboard/src/components/reports/HealthTrendsReport.tsx +192 -0
  11. package/templates/full/dashboard/src/components/search/SearchResultGroup.tsx +46 -0
  12. package/templates/full/dashboard/src/components/search/SearchResultItem.tsx +212 -0
  13. package/templates/full/dashboard/src/components/usage/AIModelBreakdown.tsx +364 -0
  14. package/templates/full/dashboard/src/components/usage/unified/Recommendations.tsx +149 -0
  15. package/templates/full/dashboard/src/lib/cloudflare/alerting.ts +486 -0
  16. package/templates/full/dashboard/src/lib/cloudflare/graphql.ts +4785 -0
  17. package/templates/full/dashboard/src/lib/cloudflare/project-registry.ts +451 -0
  18. package/templates/full/dashboard/src/lib/notifications/api.ts +197 -0
  19. package/templates/full/dashboard/src/lib/notifications/types.ts.hbs +97 -0
  20. package/templates/full/dashboard/src/lib/patterns/api.ts +120 -0
  21. package/templates/full/dashboard/src/lib/patterns/types.ts +127 -0
  22. package/templates/full/dashboard/src/lib/reports/types.ts +231 -0
  23. package/templates/full/dashboard/src/lib/search/api.ts +258 -0
  24. package/templates/full/dashboard/src/lib/search/types.ts.hbs +115 -0
  25. package/templates/full/dashboard/src/lib/settings/api.ts.hbs +201 -0
  26. package/templates/full/dashboard/src/lib/settings/types.ts.hbs +104 -0
  27. package/templates/full/dashboard/src/lib/usage/allowance-config.ts.hbs +547 -0
  28. package/templates/full/dashboard/src/lib/usage/providers.ts +331 -0
  29. package/templates/full/dashboard/src/pages/api/patterns/[id]/approve.ts +49 -0
  30. package/templates/full/dashboard/src/pages/api/patterns/[id]/reject.ts +50 -0
  31. package/templates/full/dashboard/src/pages/api/reports/digests/stats.ts +38 -0
  32. package/templates/full/dashboard/src/pages/api/reports/digests.ts +39 -0
  33. package/templates/full/dashboard/src/pages/api/search/reindex/[type].ts +56 -0
  34. package/templates/full/dashboard/src/pages/api/test-reports/[id].ts +102 -0
  35. package/templates/full/dashboard/src/pages/feedback.astro +365 -0
  36. package/templates/full/dashboard/src/pages/kiosk.astro +206 -0
  37. package/templates/full/dashboard/src/pages/map.astro +561 -0
  38. package/templates/full/dashboard/src/pages/revenue.astro +72 -0
  39. package/templates/full/dashboard/src/pages/tests.astro +431 -0
  40. package/templates/full/scripts/ops/audit-cost-anomaly.ts +430 -0
  41. package/templates/full/scripts/ops/verify-account-total.ts +256 -0
  42. package/templates/full/tests/integration/feedback-schema.test.ts +361 -0
  43. package/templates/full/tests/integration/r2-archive.test.ts +108 -0
  44. package/templates/shared/.github/workflows/dependabot-automerge.yml +41 -0
  45. package/templates/shared/.github/workflows/validate-controls.yml +27 -0
  46. package/templates/shared/dashboard/src/components/Breadcrumbs.astro +101 -0
  47. package/templates/shared/dashboard/src/components/EmptyState.astro +46 -0
  48. package/templates/shared/dashboard/src/components/ErrorBoundary.astro +79 -0
  49. package/templates/shared/dashboard/src/components/LoadingSkeleton.astro +105 -0
  50. package/templates/shared/dashboard/src/components/PageShell.astro +72 -0
  51. package/templates/shared/dashboard/src/components/SkipLinks.astro +22 -0
  52. package/templates/shared/dashboard/src/components/Toast.astro +170 -0
  53. package/templates/shared/dashboard/src/components/ToastContainer.astro +156 -0
  54. package/templates/shared/dashboard/src/components/costs/ProviderCostsGrid.tsx +401 -0
  55. package/templates/shared/dashboard/src/components/costs/index.ts +4 -0
  56. package/templates/shared/dashboard/src/components/overview/AlertBanner.tsx +94 -0
  57. package/templates/shared/dashboard/src/components/overview/index.ts +9 -0
  58. package/templates/shared/dashboard/src/components/reports/ReportInfoButton.tsx +98 -0
  59. package/templates/shared/dashboard/src/components/resources/CostChart.tsx +170 -0
  60. package/templates/shared/dashboard/src/components/resources/ProviderCard.tsx +272 -0
  61. package/templates/shared/dashboard/src/components/resources/ProviderDetail.tsx +293 -0
  62. package/templates/shared/dashboard/src/components/settings/SettingsCard.astro +102 -0
  63. package/templates/shared/dashboard/src/components/usage/AllowanceGauge.astro +170 -0
  64. package/templates/shared/dashboard/src/components/usage/AnomalyAlerts.astro +633 -0
  65. package/templates/shared/dashboard/src/components/usage/BillingCycleCountdown.astro +192 -0
  66. package/templates/shared/dashboard/src/components/usage/BurnRateHero.astro +539 -0
  67. package/templates/shared/dashboard/src/components/usage/CircuitBreakerEventLog.astro +542 -0
  68. package/templates/shared/dashboard/src/components/usage/CircuitBreakerPanel.tsx +292 -0
  69. package/templates/shared/dashboard/src/components/usage/CircuitBreakerStatus.astro +669 -0
  70. package/templates/shared/dashboard/src/components/usage/CompactThresholdBanner.astro +531 -0
  71. package/templates/shared/dashboard/src/components/usage/ComparisonModeSelector.astro +651 -0
  72. package/templates/shared/dashboard/src/components/usage/CostBreakdownChart.astro +381 -0
  73. package/templates/shared/dashboard/src/components/usage/CostBreakdownTable.astro +210 -0
  74. package/templates/shared/dashboard/src/components/usage/CostDataTable.astro +0 -0
  75. package/templates/shared/dashboard/src/components/usage/CostDonutChart.astro +311 -0
  76. package/templates/shared/dashboard/src/components/usage/DailyCostChart.astro +632 -0
  77. package/templates/shared/dashboard/src/components/usage/ExportButton.astro +114 -0
  78. package/templates/shared/dashboard/src/components/usage/FeatureBudgetsTable.astro +872 -0
  79. package/templates/shared/dashboard/src/components/usage/FilterBar.astro +190 -0
  80. package/templates/shared/dashboard/src/components/usage/FilterToggles.astro +175 -0
  81. package/templates/shared/dashboard/src/components/usage/GitHubUsageCard.astro +537 -0
  82. package/templates/shared/dashboard/src/components/usage/OverageCostCard.astro +212 -0
  83. package/templates/shared/dashboard/src/components/usage/PlanUtilizationCard.astro +193 -0
  84. package/templates/shared/dashboard/src/components/usage/ProjectCard.astro +640 -0
  85. package/templates/shared/dashboard/src/components/usage/ProjectCardsGrid.astro +272 -0
  86. package/templates/shared/dashboard/src/components/usage/ResourceSearch.astro +279 -0
  87. package/templates/shared/dashboard/src/components/usage/ServiceUtilizationList.astro +604 -0
  88. package/templates/shared/dashboard/src/components/usage/SparklineCard.astro +399 -0
  89. package/templates/shared/dashboard/src/components/usage/StatsHero.astro +600 -0
  90. package/templates/shared/dashboard/src/components/usage/TableFilters.astro +1033 -0
  91. package/templates/shared/dashboard/src/components/usage/ThresholdAlert.astro +271 -0
  92. package/templates/shared/dashboard/src/components/usage/ThresholdSettings.astro +618 -0
  93. package/templates/shared/dashboard/src/components/usage/TopSpenderCard.astro +170 -0
  94. package/templates/shared/dashboard/src/components/usage/UnifiedResourceTable.astro +1737 -0
  95. package/templates/shared/dashboard/src/components/usage/UsageCard.astro +135 -0
  96. package/templates/shared/dashboard/src/components/usage/UsageHealthBanner.astro +387 -0
  97. package/templates/shared/dashboard/src/components/usage/UtilizationBar.astro +159 -0
  98. package/templates/shared/dashboard/src/components/usage/WorkersBreakdownTable.astro +659 -0
  99. package/templates/shared/dashboard/src/components/usage/daily/CostChart.astro +461 -0
  100. package/templates/shared/dashboard/src/components/usage/daily/CostTable.astro +946 -0
  101. package/templates/shared/dashboard/src/components/usage/daily/DailyOverview.astro +1079 -0
  102. package/templates/shared/dashboard/src/components/usage/design-tokens.ts +187 -0
  103. package/templates/shared/dashboard/src/components/usage/filters/InlineDateRange.astro +285 -0
  104. package/templates/shared/dashboard/src/components/usage/filters/PeriodButtons.astro +157 -0
  105. package/templates/shared/dashboard/src/components/usage/filters/ProjectSelect.astro +284 -0
  106. package/templates/shared/dashboard/src/components/usage/react/DashboardShell.tsx +263 -0
  107. package/templates/shared/dashboard/src/components/usage/react/StatusBadge.tsx +77 -0
  108. package/templates/shared/dashboard/src/components/usage/react/UsageChart.tsx +391 -0
  109. package/templates/shared/dashboard/src/components/usage/react/index.ts.hbs +30 -0
  110. package/templates/shared/dashboard/src/components/usage/react/types.ts +137 -0
  111. package/templates/shared/dashboard/src/components/usage/scripts/ai-tab-controller.ts +419 -0
  112. package/templates/shared/dashboard/src/components/usage/scripts/constants.ts +60 -0
  113. package/templates/shared/dashboard/src/components/usage/scripts/formatters.ts +62 -0
  114. package/templates/shared/dashboard/src/components/usage/scripts/overview-controller.ts +1633 -0
  115. package/templates/shared/dashboard/src/components/usage/scripts/resource-table-builder.ts +294 -0
  116. package/templates/shared/dashboard/src/components/usage/scripts/tabs-filters-controller.ts +464 -0
  117. package/templates/shared/dashboard/src/components/usage/state/index.ts +55 -0
  118. package/templates/shared/dashboard/src/components/usage/state/usageActions.ts +439 -0
  119. package/templates/shared/dashboard/src/components/usage/state/usageStore.ts +376 -0
  120. package/templates/shared/dashboard/src/components/usage/transformers.ts +478 -0
  121. package/templates/shared/dashboard/src/components/usage/types.ts +283 -0
  122. package/templates/shared/dashboard/src/components/usage/unified/AlertBanner.tsx +172 -0
  123. package/templates/shared/dashboard/src/components/usage/unified/HeroCardsRow.tsx +757 -0
  124. package/templates/shared/dashboard/src/components/usage/unified/LiveHeader.tsx +169 -0
  125. package/templates/shared/dashboard/src/components/usage/unified/ProjectsTable.tsx +448 -0
  126. package/templates/shared/dashboard/src/components/usage/unified/ResourceBreakdown.tsx +236 -0
  127. package/templates/shared/dashboard/src/components/usage/unified/Sparkline.tsx +127 -0
  128. package/templates/shared/dashboard/src/components/usage/unified/UnifiedShell.tsx +893 -0
  129. package/templates/shared/dashboard/src/components/usage/unified/index.ts.hbs +50 -0
  130. package/templates/shared/dashboard/src/components/usage/unified/types.ts +416 -0
  131. package/templates/shared/dashboard/src/components/usage/usage-colors.ts +292 -0
  132. package/templates/shared/dashboard/src/lib/cloudflare/analytics.ts +310 -0
  133. package/templates/shared/dashboard/src/lib/cloudflare/d1.ts +55 -0
  134. package/templates/shared/dashboard/src/lib/cloudflare/index.ts.hbs +120 -0
  135. package/templates/shared/dashboard/src/lib/infrastructure/types.ts +116 -0
  136. package/templates/shared/dashboard/src/lib/usage/fetchWithDedup.ts +101 -0
  137. package/templates/shared/dashboard/src/lib/usage/index.ts.hbs +12 -0
  138. package/templates/shared/dashboard/src/pages/api/usage/ai-models.ts +235 -0
  139. package/templates/shared/dashboard/src/pages/api/usage/billing-context.ts +296 -0
  140. package/templates/shared/scripts/test-telemetry-flow.ts +464 -0
  141. package/templates/shared/tests/e2e/usage-api.test.ts +909 -0
  142. package/templates/shared/tests/e2e/usage-export.test.ts +784 -0
  143. package/templates/shared/tests/e2e/usage-mobile.test.ts +531 -0
  144. package/templates/shared/tests/helpers/mock-storage.ts +166 -0
  145. package/templates/shared/tests/integration/kv-cache.test.ts +252 -0
  146. package/templates/shared/tests/integration/platform-usage.test.ts +956 -0
  147. package/templates/shared/tests/unit/billing.test.ts +331 -0
  148. package/templates/shared/tests/unit/cloudflare/graphql.test.ts +217 -0
  149. package/templates/shared/tests/unit/components/usage-transformers.test.ts +473 -0
  150. package/templates/shared/tests/unit/control.test.ts +226 -0
  151. package/templates/shared/tests/unit/cost-calculator.test.ts +141 -0
  152. package/templates/shared/tests/unit/economics.test.ts +365 -0
  153. package/templates/shared/tests/unit/telemetry-sampling.test.ts +401 -0
  154. package/templates/standard/dashboard/src/components/errors/PriorityBadge.astro +27 -0
  155. package/templates/standard/dashboard/src/components/infrastructure/HealthchecksStatus.tsx +293 -0
  156. package/templates/standard/dashboard/src/components/infrastructure/InfrastructureTabs.tsx +268 -0
  157. package/templates/standard/dashboard/src/components/reports/CircuitBreakerReport.tsx +474 -0
  158. package/templates/standard/dashboard/src/components/reports/CostTrendsReport.tsx +229 -0
  159. package/templates/standard/dashboard/src/components/reports/ErrorTrendsReport.tsx +244 -0
  160. package/templates/standard/dashboard/src/components/reports/ProjectHealthTable.tsx +251 -0
  161. package/templates/standard/dashboard/src/components/reports/WarningDigestsTable.tsx +298 -0
  162. package/templates/standard/dashboard/src/components/usage/react/UsageTable.tsx +385 -0
  163. package/templates/standard/dashboard/src/components/usage/unified/CircuitBreakerEvents.tsx +305 -0
  164. package/templates/standard/dashboard/src/components/usage/unified/FeatureBudgets.tsx +472 -0
  165. package/templates/standard/dashboard/src/lib/errors/api.ts +84 -0
  166. package/templates/standard/dashboard/src/lib/errors/types.ts +75 -0
  167. package/templates/standard/dashboard/src/lib/infrastructure/api.ts +141 -0
  168. package/templates/standard/dashboard/src/lib/infrastructure/gatus.ts.hbs +112 -0
  169. package/templates/standard/dashboard/src/lib/services/proxy/index.ts +20 -0
  170. package/templates/standard/dashboard/src/lib/services/proxy/proxy.ts +244 -0
  171. package/templates/standard/dashboard/src/lib/services/proxy/types.ts +81 -0
  172. package/templates/standard/dashboard/src/pages/analytics.astro +64 -0
  173. package/templates/standard/dashboard/src/pages/api/infrastructure/alerts.ts +85 -0
  174. package/templates/standard/dashboard/src/pages/api/infrastructure/healthchecks/[id]/flips.ts +110 -0
  175. package/templates/standard/dashboard/src/pages/api/infrastructure/healthchecks.ts +101 -0
  176. package/templates/standard/dashboard/src/pages/api/infrastructure/uptime/[id]/response-times.ts +121 -0
  177. package/templates/standard/dashboard/src/pages/api/infrastructure/uptime.ts +89 -0
  178. package/templates/standard/dashboard/src/pages/api/test/service-auth.ts +178 -0
  179. package/templates/standard/tests/integration/connectors.test.ts +241 -0
  180. package/templates/standard/tests/integration/github-monitor.test.ts +143 -0
  181. package/templates/standard/tests/integration/ingestion.test.ts +211 -0
  182. package/templates/standard/tests/integration/platform-sentinel.test.ts +497 -0
  183. package/templates/standard/tests/unit/cloudflare/alerting.test.ts +480 -0
  184. package/templates/standard/tests/unit/error-collector/dedup.test.ts +350 -0
  185. package/templates/standard/tests/unit/error-collector/github.test.ts +187 -0
package/README.md CHANGED
@@ -70,8 +70,8 @@ Creates a `.platform-scaffold.json` manifest for projects scaffolded before v1.1
70
70
  | Tier | Workers | What You Get | Est. Cost |
71
71
  |------|---------|-------------|-----------|
72
72
  | **Minimal** | 1 | Budget enforcement, circuit breakers, usage telemetry | ~$0/mo |
73
- | **Standard** | 3 | + Error collector (auto GitHub issues), gap detection sentinel | ~$0/mo |
74
- | **Full** | 8 | + AI pattern discovery, alert router, notifications, search, settings | ~$5/mo |
73
+ | **Standard** | 5 | + Error collector (auto GitHub issues), gap detection sentinel, mapper, test client | ~$0/mo |
74
+ | **Full** | 11 | + AI pattern discovery, alert router, notifications, search, settings, auditor | ~$5/mo |
75
75
 
76
76
  See [Tier Comparison](../../docs/admin-sdk/tiers.md) for a detailed breakdown of what each tier generates.
77
77
 
@@ -276,13 +276,10 @@ See [Upgrade Guide](../../docs/admin-sdk/upgrade-guide.md) for detailed instruct
276
276
 
277
277
  ## What's Not Included
278
278
 
279
- The scaffolder generates core infrastructure only. It does **not** create:
279
+ The scaffolder generates core infrastructure, an Astro SSR dashboard (273 templates), test suites, and CI workflows. It does **not** create:
280
280
 
281
- - Dashboards or admin UIs
282
- - Email workers or notification templates
281
+ - Email workers or notification email templates
283
282
  - Data connectors (Stripe, GA4, Plausible, etc.)
284
- - Test suites
285
- - CI/CD workflows (use the [consumer-check.yml](../../docs/admin-sdk/ci-workflow.md) reusable workflow)
286
283
 
287
284
  These are project-specific — build them as you need them.
288
285
 
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import type { Tier } from './prompts.js';
8
8
  /** Single source of truth for the SDK version. */
9
- export declare const SDK_VERSION = "2.0.0";
9
+ export declare const SDK_VERSION = "2.2.0";
10
10
  /** Returns true if `to` is the same or higher tier than `from`. */
11
11
  export declare function isTierUpgradeOrSame(from: Tier, to: Tier): boolean;
12
12
  /** Check if a template file is a numbered migration (not seed.sql). */
package/dist/templates.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * All other files are copied verbatim.
6
6
  */
7
7
  /** Single source of truth for the SDK version. */
8
- export const SDK_VERSION = '2.0.0';
8
+ export const SDK_VERSION = '2.2.0';
9
9
  /** Tier ordering for upgrade validation. */
10
10
  const TIER_ORDER = { minimal: 0, standard: 1, full: 2 };
11
11
  /** Returns true if `to` is the same or higher tier than `from`. */
@@ -28,6 +28,10 @@ const SHARED_FILES = [
28
28
  { src: 'shared/scripts/ops/reset-budget-state.ts', dest: 'scripts/ops/reset-budget-state.ts', template: false },
29
29
  { src: 'shared/scripts/ops/verify-account-completeness.ts', dest: 'scripts/ops/verify-account-completeness.ts', template: false },
30
30
  { src: 'shared/scripts/ops/validate-pipeline.ts', dest: 'scripts/ops/validate-pipeline.ts', template: false },
31
+ { src: 'shared/scripts/test-telemetry-flow.ts', dest: 'scripts/test-telemetry-flow.ts', template: false },
32
+ // CI/CD Workflows (v2.2.0)
33
+ { src: 'shared/.github/workflows/validate-controls.yml', dest: '.github/workflows/validate-controls.yml', template: false },
34
+ { src: 'shared/.github/workflows/dependabot-automerge.yml', dest: '.github/workflows/dependabot-automerge.yml', template: false },
31
35
  // Contracts — JSON schemas + TypeScript types
32
36
  { src: 'shared/contracts/schemas/envelope.v1.schema.json', dest: 'contracts/schemas/envelope.v1.schema.json', template: false },
33
37
  { src: 'shared/contracts/schemas/error_report.v1.schema.json', dest: 'contracts/schemas/error_report.v1.schema.json', template: false },
@@ -143,10 +147,82 @@ const SHARED_FILES = [
143
147
  { src: 'shared/dashboard/src/components/resources/CostCentreOverview.tsx', dest: 'dashboard/src/components/resources/CostCentreOverview.tsx', template: false },
144
148
  { src: 'shared/dashboard/src/components/resources/AllowanceStatus.tsx', dest: 'dashboard/src/components/resources/AllowanceStatus.tsx', template: false },
145
149
  { src: 'shared/dashboard/src/components/resources/index.ts', dest: 'dashboard/src/components/resources/index.ts', template: false },
150
+ { src: 'shared/dashboard/src/components/resources/CostChart.tsx', dest: 'dashboard/src/components/resources/CostChart.tsx', template: false },
151
+ { src: 'shared/dashboard/src/components/resources/ProviderCard.tsx', dest: 'dashboard/src/components/resources/ProviderCard.tsx', template: false },
152
+ { src: 'shared/dashboard/src/components/resources/ProviderDetail.tsx', dest: 'dashboard/src/components/resources/ProviderDetail.tsx', template: false },
146
153
  { src: 'shared/dashboard/src/components/settings/SettingsCard.tsx', dest: 'dashboard/src/components/settings/SettingsCard.tsx', template: false },
154
+ { src: 'shared/dashboard/src/components/settings/SettingsCard.astro', dest: 'dashboard/src/components/settings/SettingsCard.astro', template: false },
147
155
  { src: 'shared/dashboard/src/components/settings/index.ts', dest: 'dashboard/src/components/settings/index.ts', template: false },
156
+ { src: 'shared/dashboard/src/components/overview/AlertBanner.tsx', dest: 'dashboard/src/components/overview/AlertBanner.tsx', template: false },
157
+ { src: 'shared/dashboard/src/components/overview/index.ts', dest: 'dashboard/src/components/overview/index.ts', template: false },
158
+ { src: 'shared/dashboard/src/components/costs/index.ts', dest: 'dashboard/src/components/costs/index.ts', template: false },
159
+ { src: 'shared/dashboard/src/components/costs/ProviderCostsGrid.tsx', dest: 'dashboard/src/components/costs/ProviderCostsGrid.tsx', template: false },
148
160
  { src: 'shared/dashboard/src/lib/types.ts', dest: 'dashboard/src/lib/types.ts', template: false },
149
161
  { src: 'shared/dashboard/src/lib/fetch.ts', dest: 'dashboard/src/lib/fetch.ts', template: false },
162
+ // Dashboard — shared tier: Astro shell components (v2.2.0)
163
+ { src: 'shared/dashboard/src/components/Breadcrumbs.astro', dest: 'dashboard/src/components/Breadcrumbs.astro', template: false },
164
+ { src: 'shared/dashboard/src/components/EmptyState.astro', dest: 'dashboard/src/components/EmptyState.astro', template: false },
165
+ { src: 'shared/dashboard/src/components/ErrorBoundary.astro', dest: 'dashboard/src/components/ErrorBoundary.astro', template: false },
166
+ { src: 'shared/dashboard/src/components/LoadingSkeleton.astro', dest: 'dashboard/src/components/LoadingSkeleton.astro', template: false },
167
+ { src: 'shared/dashboard/src/components/PageShell.astro', dest: 'dashboard/src/components/PageShell.astro', template: false },
168
+ { src: 'shared/dashboard/src/components/SkipLinks.astro', dest: 'dashboard/src/components/SkipLinks.astro', template: false },
169
+ { src: 'shared/dashboard/src/components/Toast.astro', dest: 'dashboard/src/components/Toast.astro', template: false },
170
+ { src: 'shared/dashboard/src/components/ToastContainer.astro', dest: 'dashboard/src/components/ToastContainer.astro', template: false },
171
+ // Dashboard — shared tier: usage Astro components (v2.2.0)
172
+ { src: 'shared/dashboard/src/components/usage/types.ts', dest: 'dashboard/src/components/usage/types.ts', template: false },
173
+ { src: 'shared/dashboard/src/components/usage/design-tokens.ts', dest: 'dashboard/src/components/usage/design-tokens.ts', template: false },
174
+ { src: 'shared/dashboard/src/components/usage/usage-colors.ts', dest: 'dashboard/src/components/usage/usage-colors.ts', template: false },
175
+ { src: 'shared/dashboard/src/components/usage/AllowanceGauge.astro', dest: 'dashboard/src/components/usage/AllowanceGauge.astro', template: false },
176
+ { src: 'shared/dashboard/src/components/usage/AnomalyAlerts.astro', dest: 'dashboard/src/components/usage/AnomalyAlerts.astro', template: false },
177
+ { src: 'shared/dashboard/src/components/usage/BillingCycleCountdown.astro', dest: 'dashboard/src/components/usage/BillingCycleCountdown.astro', template: false },
178
+ { src: 'shared/dashboard/src/components/usage/BurnRateHero.astro', dest: 'dashboard/src/components/usage/BurnRateHero.astro', template: false },
179
+ { src: 'shared/dashboard/src/components/usage/CircuitBreakerEventLog.astro', dest: 'dashboard/src/components/usage/CircuitBreakerEventLog.astro', template: false },
180
+ { src: 'shared/dashboard/src/components/usage/CircuitBreakerPanel.tsx', dest: 'dashboard/src/components/usage/CircuitBreakerPanel.tsx', template: false },
181
+ { src: 'shared/dashboard/src/components/usage/CircuitBreakerStatus.astro', dest: 'dashboard/src/components/usage/CircuitBreakerStatus.astro', template: false },
182
+ { src: 'shared/dashboard/src/components/usage/CompactThresholdBanner.astro', dest: 'dashboard/src/components/usage/CompactThresholdBanner.astro', template: false },
183
+ { src: 'shared/dashboard/src/components/usage/ComparisonModeSelector.astro', dest: 'dashboard/src/components/usage/ComparisonModeSelector.astro', template: false },
184
+ { src: 'shared/dashboard/src/components/usage/CostBreakdownChart.astro', dest: 'dashboard/src/components/usage/CostBreakdownChart.astro', template: false },
185
+ { src: 'shared/dashboard/src/components/usage/CostBreakdownTable.astro', dest: 'dashboard/src/components/usage/CostBreakdownTable.astro', template: false },
186
+ { src: 'shared/dashboard/src/components/usage/CostDataTable.astro', dest: 'dashboard/src/components/usage/CostDataTable.astro', template: false },
187
+ { src: 'shared/dashboard/src/components/usage/CostDonutChart.astro', dest: 'dashboard/src/components/usage/CostDonutChart.astro', template: false },
188
+ { src: 'shared/dashboard/src/components/usage/DailyCostChart.astro', dest: 'dashboard/src/components/usage/DailyCostChart.astro', template: false },
189
+ { src: 'shared/dashboard/src/components/usage/ExportButton.astro', dest: 'dashboard/src/components/usage/ExportButton.astro', template: false },
190
+ { src: 'shared/dashboard/src/components/usage/FeatureBudgetsTable.astro', dest: 'dashboard/src/components/usage/FeatureBudgetsTable.astro', template: false },
191
+ { src: 'shared/dashboard/src/components/usage/FilterBar.astro', dest: 'dashboard/src/components/usage/FilterBar.astro', template: false },
192
+ { src: 'shared/dashboard/src/components/usage/FilterToggles.astro', dest: 'dashboard/src/components/usage/FilterToggles.astro', template: false },
193
+ { src: 'shared/dashboard/src/components/usage/GitHubUsageCard.astro', dest: 'dashboard/src/components/usage/GitHubUsageCard.astro', template: false },
194
+ { src: 'shared/dashboard/src/components/usage/OverageCostCard.astro', dest: 'dashboard/src/components/usage/OverageCostCard.astro', template: false },
195
+ { src: 'shared/dashboard/src/components/usage/PlanUtilizationCard.astro', dest: 'dashboard/src/components/usage/PlanUtilizationCard.astro', template: false },
196
+ { src: 'shared/dashboard/src/components/usage/ProjectCard.astro', dest: 'dashboard/src/components/usage/ProjectCard.astro', template: false },
197
+ { src: 'shared/dashboard/src/components/usage/ProjectCardsGrid.astro', dest: 'dashboard/src/components/usage/ProjectCardsGrid.astro', template: false },
198
+ { src: 'shared/dashboard/src/components/usage/ResourceSearch.astro', dest: 'dashboard/src/components/usage/ResourceSearch.astro', template: false },
199
+ { src: 'shared/dashboard/src/components/usage/ServiceUtilizationList.astro', dest: 'dashboard/src/components/usage/ServiceUtilizationList.astro', template: false },
200
+ { src: 'shared/dashboard/src/components/usage/SparklineCard.astro', dest: 'dashboard/src/components/usage/SparklineCard.astro', template: false },
201
+ { src: 'shared/dashboard/src/components/usage/StatsHero.astro', dest: 'dashboard/src/components/usage/StatsHero.astro', template: false },
202
+ { src: 'shared/dashboard/src/components/usage/TableFilters.astro', dest: 'dashboard/src/components/usage/TableFilters.astro', template: false },
203
+ { src: 'shared/dashboard/src/components/usage/ThresholdAlert.astro', dest: 'dashboard/src/components/usage/ThresholdAlert.astro', template: false },
204
+ { src: 'shared/dashboard/src/components/usage/ThresholdSettings.astro', dest: 'dashboard/src/components/usage/ThresholdSettings.astro', template: false },
205
+ { src: 'shared/dashboard/src/components/usage/TopSpenderCard.astro', dest: 'dashboard/src/components/usage/TopSpenderCard.astro', template: false },
206
+ { src: 'shared/dashboard/src/components/usage/UnifiedResourceTable.astro', dest: 'dashboard/src/components/usage/UnifiedResourceTable.astro', template: false },
207
+ { src: 'shared/dashboard/src/components/usage/UsageCard.astro', dest: 'dashboard/src/components/usage/UsageCard.astro', template: false },
208
+ { src: 'shared/dashboard/src/components/usage/UsageHealthBanner.astro', dest: 'dashboard/src/components/usage/UsageHealthBanner.astro', template: false },
209
+ { src: 'shared/dashboard/src/components/usage/UtilizationBar.astro', dest: 'dashboard/src/components/usage/UtilizationBar.astro', template: false },
210
+ { src: 'shared/dashboard/src/components/usage/WorkersBreakdownTable.astro', dest: 'dashboard/src/components/usage/WorkersBreakdownTable.astro', template: false },
211
+ { src: 'shared/dashboard/src/components/usage/daily/CostChart.astro', dest: 'dashboard/src/components/usage/daily/CostChart.astro', template: false },
212
+ { src: 'shared/dashboard/src/components/usage/daily/CostTable.astro', dest: 'dashboard/src/components/usage/daily/CostTable.astro', template: false },
213
+ { src: 'shared/dashboard/src/components/usage/daily/DailyOverview.astro', dest: 'dashboard/src/components/usage/daily/DailyOverview.astro', template: false },
214
+ { src: 'shared/dashboard/src/components/usage/filters/InlineDateRange.astro', dest: 'dashboard/src/components/usage/filters/InlineDateRange.astro', template: false },
215
+ { src: 'shared/dashboard/src/components/usage/filters/PeriodButtons.astro', dest: 'dashboard/src/components/usage/filters/PeriodButtons.astro', template: false },
216
+ { src: 'shared/dashboard/src/components/usage/filters/ProjectSelect.astro', dest: 'dashboard/src/components/usage/filters/ProjectSelect.astro', template: false },
217
+ { src: 'shared/dashboard/src/components/usage/scripts/ai-tab-controller.ts', dest: 'dashboard/src/components/usage/scripts/ai-tab-controller.ts', template: false },
218
+ { src: 'shared/dashboard/src/components/usage/scripts/constants.ts', dest: 'dashboard/src/components/usage/scripts/constants.ts', template: false },
219
+ { src: 'shared/dashboard/src/components/usage/scripts/formatters.ts', dest: 'dashboard/src/components/usage/scripts/formatters.ts', template: false },
220
+ { src: 'shared/dashboard/src/components/usage/scripts/overview-controller.ts', dest: 'dashboard/src/components/usage/scripts/overview-controller.ts', template: false },
221
+ { src: 'shared/dashboard/src/components/usage/scripts/resource-table-builder.ts', dest: 'dashboard/src/components/usage/scripts/resource-table-builder.ts', template: false },
222
+ { src: 'shared/dashboard/src/components/usage/scripts/tabs-filters-controller.ts', dest: 'dashboard/src/components/usage/scripts/tabs-filters-controller.ts', template: false },
223
+ { src: 'shared/dashboard/src/components/usage/state/index.ts', dest: 'dashboard/src/components/usage/state/index.ts', template: false },
224
+ { src: 'shared/dashboard/src/components/usage/state/usageActions.ts', dest: 'dashboard/src/components/usage/state/usageActions.ts', template: false },
225
+ { src: 'shared/dashboard/src/components/usage/state/usageStore.ts', dest: 'dashboard/src/components/usage/state/usageStore.ts', template: false },
150
226
  // Dashboard — shared tier: UI primitives (v1.6.0)
151
227
  { src: 'shared/dashboard/src/components/ui/EmptyState.tsx', dest: 'dashboard/src/components/ui/EmptyState.tsx', template: false },
152
228
  { src: 'shared/dashboard/src/components/ui/LoadingSkeleton.tsx', dest: 'dashboard/src/components/ui/LoadingSkeleton.tsx', template: false },
@@ -159,6 +235,8 @@ const SHARED_FILES = [
159
235
  { src: 'shared/dashboard/src/pages/api/usage/projects.ts', dest: 'dashboard/src/pages/api/usage/projects.ts', template: false },
160
236
  { src: 'shared/dashboard/src/pages/api/usage/allowances.ts', dest: 'dashboard/src/pages/api/usage/allowances.ts', template: false },
161
237
  { src: 'shared/dashboard/src/pages/api/usage/anomalies.ts', dest: 'dashboard/src/pages/api/usage/anomalies.ts', template: false },
238
+ { src: 'shared/dashboard/src/pages/api/usage/ai-models.ts', dest: 'dashboard/src/pages/api/usage/ai-models.ts', template: false },
239
+ { src: 'shared/dashboard/src/pages/api/usage/billing-context.ts', dest: 'dashboard/src/pages/api/usage/billing-context.ts', template: false },
162
240
  // Dashboard — shared tier: costs API routes (v1.6.0)
163
241
  { src: 'shared/dashboard/src/pages/api/costs/overview.ts', dest: 'dashboard/src/pages/api/costs/overview.ts', template: false },
164
242
  { src: 'shared/dashboard/src/pages/api/costs/providers.ts', dest: 'dashboard/src/pages/api/costs/providers.ts', template: false },
@@ -169,6 +247,15 @@ const SHARED_FILES = [
169
247
  { src: 'shared/dashboard/src/pages/api/user/identity.ts', dest: 'dashboard/src/pages/api/user/identity.ts', template: false },
170
248
  // Dashboard — shared tier: cloudflare lib (v1.6.0)
171
249
  { src: 'shared/dashboard/src/lib/cloudflare/costs.ts', dest: 'dashboard/src/lib/cloudflare/costs.ts', template: false },
250
+ // Dashboard — shared tier: cloudflare lib (v2.1.0)
251
+ { src: 'shared/dashboard/src/lib/cloudflare/index.ts.hbs', dest: 'dashboard/src/lib/cloudflare/index.ts', template: true },
252
+ { src: 'shared/dashboard/src/lib/cloudflare/d1.ts', dest: 'dashboard/src/lib/cloudflare/d1.ts', template: false },
253
+ { src: 'shared/dashboard/src/lib/cloudflare/analytics.ts', dest: 'dashboard/src/lib/cloudflare/analytics.ts', template: false },
254
+ // Dashboard — shared tier: usage lib (v2.1.0)
255
+ { src: 'shared/dashboard/src/lib/usage/index.ts.hbs', dest: 'dashboard/src/lib/usage/index.ts', template: true },
256
+ { src: 'shared/dashboard/src/lib/usage/fetchWithDedup.ts', dest: 'dashboard/src/lib/usage/fetchWithDedup.ts', template: false },
257
+ // Dashboard — shared tier: infrastructure lib (v2.1.0)
258
+ { src: 'shared/dashboard/src/lib/infrastructure/types.ts', dest: 'dashboard/src/lib/infrastructure/types.ts', template: false },
172
259
  // Dashboard — shared tier: infrastructure components (v1.6.0)
173
260
  { src: 'shared/dashboard/src/components/infrastructure/InfrastructureStats.tsx', dest: 'dashboard/src/components/infrastructure/InfrastructureStats.tsx', template: false },
174
261
  { src: 'shared/dashboard/src/components/infrastructure/index.ts', dest: 'dashboard/src/components/infrastructure/index.ts', template: false },
@@ -206,6 +293,40 @@ const SHARED_FILES = [
206
293
  // Dashboard — shared tier: additional UI components (v2.0.0)
207
294
  { src: 'shared/dashboard/src/components/ui/ErrorBoundary.tsx', dest: 'dashboard/src/components/ui/ErrorBoundary.tsx', template: false },
208
295
  { src: 'shared/dashboard/src/components/ui/PageShell.tsx', dest: 'dashboard/src/components/ui/PageShell.tsx', template: false },
296
+ // Dashboard — shared tier: usage/unified components (v2.1.0)
297
+ { src: 'shared/dashboard/src/components/usage/unified/UnifiedShell.tsx', dest: 'dashboard/src/components/usage/unified/UnifiedShell.tsx', template: false },
298
+ { src: 'shared/dashboard/src/components/usage/unified/HeroCardsRow.tsx', dest: 'dashboard/src/components/usage/unified/HeroCardsRow.tsx', template: false },
299
+ { src: 'shared/dashboard/src/components/usage/unified/ResourceBreakdown.tsx', dest: 'dashboard/src/components/usage/unified/ResourceBreakdown.tsx', template: false },
300
+ { src: 'shared/dashboard/src/components/usage/unified/LiveHeader.tsx', dest: 'dashboard/src/components/usage/unified/LiveHeader.tsx', template: false },
301
+ { src: 'shared/dashboard/src/components/usage/unified/AlertBanner.tsx', dest: 'dashboard/src/components/usage/unified/AlertBanner.tsx', template: false },
302
+ { src: 'shared/dashboard/src/components/usage/unified/Sparkline.tsx', dest: 'dashboard/src/components/usage/unified/Sparkline.tsx', template: false },
303
+ { src: 'shared/dashboard/src/components/usage/unified/ProjectsTable.tsx', dest: 'dashboard/src/components/usage/unified/ProjectsTable.tsx', template: false },
304
+ { src: 'shared/dashboard/src/components/usage/unified/types.ts', dest: 'dashboard/src/components/usage/unified/types.ts', template: false },
305
+ { src: 'shared/dashboard/src/components/usage/unified/index.ts.hbs', dest: 'dashboard/src/components/usage/unified/index.ts', template: true },
306
+ // Dashboard — shared tier: usage/react components (v2.1.0)
307
+ { src: 'shared/dashboard/src/components/usage/react/StatusBadge.tsx', dest: 'dashboard/src/components/usage/react/StatusBadge.tsx', template: false },
308
+ { src: 'shared/dashboard/src/components/usage/react/UsageChart.tsx', dest: 'dashboard/src/components/usage/react/UsageChart.tsx', template: false },
309
+ { src: 'shared/dashboard/src/components/usage/react/DashboardShell.tsx', dest: 'dashboard/src/components/usage/react/DashboardShell.tsx', template: false },
310
+ { src: 'shared/dashboard/src/components/usage/react/types.ts', dest: 'dashboard/src/components/usage/react/types.ts', template: false },
311
+ { src: 'shared/dashboard/src/components/usage/react/index.ts.hbs', dest: 'dashboard/src/components/usage/react/index.ts', template: true },
312
+ // Dashboard — shared tier: usage utilities (v2.1.0)
313
+ { src: 'shared/dashboard/src/components/usage/transformers.ts', dest: 'dashboard/src/components/usage/transformers.ts', template: false },
314
+ // Dashboard — shared tier: reports components (v2.1.0)
315
+ { src: 'shared/dashboard/src/components/reports/ReportInfoButton.tsx', dest: 'dashboard/src/components/reports/ReportInfoButton.tsx', template: false },
316
+ // Tests — shared tier (v2.1.0)
317
+ { src: 'shared/tests/helpers/mock-storage.ts', dest: 'tests/helpers/mock-storage.ts', template: false },
318
+ { src: 'shared/tests/unit/billing.test.ts', dest: 'tests/unit/billing.test.ts', template: false },
319
+ { src: 'shared/tests/unit/economics.test.ts', dest: 'tests/unit/economics.test.ts', template: false },
320
+ { src: 'shared/tests/unit/control.test.ts', dest: 'tests/unit/control.test.ts', template: false },
321
+ { src: 'shared/tests/unit/cost-calculator.test.ts', dest: 'tests/unit/cost-calculator.test.ts', template: false },
322
+ { src: 'shared/tests/unit/telemetry-sampling.test.ts', dest: 'tests/unit/telemetry-sampling.test.ts', template: false },
323
+ { src: 'shared/tests/unit/cloudflare/graphql.test.ts', dest: 'tests/unit/cloudflare/graphql.test.ts', template: false },
324
+ { src: 'shared/tests/unit/components/usage-transformers.test.ts', dest: 'tests/unit/components/usage-transformers.test.ts', template: false },
325
+ { src: 'shared/tests/integration/platform-usage.test.ts', dest: 'tests/integration/platform-usage.test.ts', template: false },
326
+ { src: 'shared/tests/integration/kv-cache.test.ts', dest: 'tests/integration/kv-cache.test.ts', template: false },
327
+ { src: 'shared/tests/e2e/usage-api.test.ts', dest: 'tests/e2e/usage-api.test.ts', template: false },
328
+ { src: 'shared/tests/e2e/usage-export.test.ts', dest: 'tests/e2e/usage-export.test.ts', template: false },
329
+ { src: 'shared/tests/e2e/usage-mobile.test.ts', dest: 'tests/e2e/usage-mobile.test.ts', template: false },
209
330
  // CI — contract check + security workflows (v2.0.0)
210
331
  { src: 'shared/.github/workflows/contract-check.yml.hbs', dest: '.github/workflows/contract-check.yml', template: true },
211
332
  { src: 'shared/.github/workflows/security.yml', dest: '.github/workflows/security.yml', template: false },
@@ -243,9 +364,10 @@ const STANDARD_FILES = [
243
364
  // SDK test client (telemetry + circuit breaker validation)
244
365
  { src: 'standard/wrangler.sdk-test-client.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-sdk-test-client.jsonc', template: true },
245
366
  { src: 'standard/workers/platform-sdk-test-client.ts', dest: 'workers/platform-sdk-test-client.ts', template: false },
246
- // Dashboard — standard tier (error management, health, DLQ)
367
+ // Dashboard — standard tier (error management, health, DLQ, analytics)
247
368
  { src: 'standard/dashboard/src/pages/health.astro', dest: 'dashboard/src/pages/health.astro', template: false },
248
369
  { src: 'standard/dashboard/src/pages/errors.astro', dest: 'dashboard/src/pages/errors.astro', template: false },
370
+ { src: 'standard/dashboard/src/pages/analytics.astro', dest: 'dashboard/src/pages/analytics.astro', template: false },
249
371
  { src: 'standard/dashboard/src/pages/api/errors/index.ts', dest: 'dashboard/src/pages/api/errors/index.ts', template: false },
250
372
  { src: 'standard/dashboard/src/pages/api/errors/stats.ts', dest: 'dashboard/src/pages/api/errors/stats.ts', template: false },
251
373
  { src: 'standard/dashboard/src/pages/api/health/dlq.ts', dest: 'dashboard/src/pages/api/health/dlq.ts', template: false },
@@ -255,7 +377,14 @@ const STANDARD_FILES = [
255
377
  { src: 'standard/dashboard/src/components/errors/ErrorsTable.tsx', dest: 'dashboard/src/components/errors/ErrorsTable.tsx', template: false },
256
378
  { src: 'standard/dashboard/src/components/errors/ErrorStats.tsx', dest: 'dashboard/src/components/errors/ErrorStats.tsx', template: false },
257
379
  { src: 'standard/dashboard/src/components/errors/index.ts', dest: 'dashboard/src/components/errors/index.ts', template: false },
258
- { src: 'standard/dashboard/src/lib/errors.ts', dest: 'dashboard/src/lib/errors.ts', template: false },
380
+ // Dashboard standard tier: lib modules (v2.1.0) replaces old errors.ts
381
+ { src: 'standard/dashboard/src/lib/errors/types.ts', dest: 'dashboard/src/lib/errors/types.ts', template: false },
382
+ { src: 'standard/dashboard/src/lib/errors/api.ts', dest: 'dashboard/src/lib/errors/api.ts', template: false },
383
+ { src: 'standard/dashboard/src/lib/infrastructure/api.ts', dest: 'dashboard/src/lib/infrastructure/api.ts', template: false },
384
+ { src: 'standard/dashboard/src/lib/infrastructure/gatus.ts.hbs', dest: 'dashboard/src/lib/infrastructure/gatus.ts', template: true },
385
+ { src: 'standard/dashboard/src/lib/services/proxy/types.ts', dest: 'dashboard/src/lib/services/proxy/types.ts', template: false },
386
+ { src: 'standard/dashboard/src/lib/services/proxy/proxy.ts', dest: 'dashboard/src/lib/services/proxy/proxy.ts', template: false },
387
+ { src: 'standard/dashboard/src/lib/services/proxy/index.ts', dest: 'dashboard/src/lib/services/proxy/index.ts', template: false },
259
388
  // Dashboard — standard tier: error detail API routes (v1.6.0)
260
389
  { src: 'standard/dashboard/src/pages/api/errors/[fingerprint].ts', dest: 'dashboard/src/pages/api/errors/[fingerprint].ts', template: false },
261
390
  { src: 'standard/dashboard/src/pages/api/errors/[fingerprint]/mute.ts', dest: 'dashboard/src/pages/api/errors/[fingerprint]/mute.ts', template: false },
@@ -270,6 +399,35 @@ const STANDARD_FILES = [
270
399
  { src: 'standard/tests/unit/error-collector/capture.test.ts', dest: 'tests/unit/error-collector/capture.test.ts', template: false },
271
400
  // Dashboard — standard tier: audit history API route (v2.0.0)
272
401
  { src: 'standard/dashboard/src/pages/api/health/audit-history.ts', dest: 'dashboard/src/pages/api/health/audit-history.ts', template: false },
402
+ // Dashboard — standard tier: infrastructure API routes (v2.2.0)
403
+ { src: 'standard/dashboard/src/pages/api/infrastructure/alerts.ts', dest: 'dashboard/src/pages/api/infrastructure/alerts.ts', template: false },
404
+ { src: 'standard/dashboard/src/pages/api/infrastructure/healthchecks.ts', dest: 'dashboard/src/pages/api/infrastructure/healthchecks.ts', template: false },
405
+ { src: 'standard/dashboard/src/pages/api/infrastructure/healthchecks/[id]/flips.ts', dest: 'dashboard/src/pages/api/infrastructure/healthchecks/[id]/flips.ts', template: false },
406
+ { src: 'standard/dashboard/src/pages/api/infrastructure/uptime.ts', dest: 'dashboard/src/pages/api/infrastructure/uptime.ts', template: false },
407
+ { src: 'standard/dashboard/src/pages/api/infrastructure/uptime/[id]/response-times.ts', dest: 'dashboard/src/pages/api/infrastructure/uptime/[id]/response-times.ts', template: false },
408
+ { src: 'standard/dashboard/src/pages/api/test/service-auth.ts', dest: 'dashboard/src/pages/api/test/service-auth.ts', template: false },
409
+ // Dashboard — standard tier: usage components (v2.1.0)
410
+ { src: 'standard/dashboard/src/components/usage/react/UsageTable.tsx', dest: 'dashboard/src/components/usage/react/UsageTable.tsx', template: false },
411
+ { src: 'standard/dashboard/src/components/usage/unified/FeatureBudgets.tsx', dest: 'dashboard/src/components/usage/unified/FeatureBudgets.tsx', template: false },
412
+ { src: 'standard/dashboard/src/components/usage/unified/CircuitBreakerEvents.tsx', dest: 'dashboard/src/components/usage/unified/CircuitBreakerEvents.tsx', template: false },
413
+ // Dashboard — standard tier: infrastructure components (v2.2.0)
414
+ { src: 'standard/dashboard/src/components/infrastructure/HealthchecksStatus.tsx', dest: 'dashboard/src/components/infrastructure/HealthchecksStatus.tsx', template: false },
415
+ { src: 'standard/dashboard/src/components/infrastructure/InfrastructureTabs.tsx', dest: 'dashboard/src/components/infrastructure/InfrastructureTabs.tsx', template: false },
416
+ { src: 'standard/dashboard/src/components/errors/PriorityBadge.astro', dest: 'dashboard/src/components/errors/PriorityBadge.astro', template: false },
417
+ // Dashboard — standard tier: reports components (v2.1.0)
418
+ { src: 'standard/dashboard/src/components/reports/CircuitBreakerReport.tsx', dest: 'dashboard/src/components/reports/CircuitBreakerReport.tsx', template: false },
419
+ { src: 'standard/dashboard/src/components/reports/ErrorTrendsReport.tsx', dest: 'dashboard/src/components/reports/ErrorTrendsReport.tsx', template: false },
420
+ { src: 'standard/dashboard/src/components/reports/ProjectHealthTable.tsx', dest: 'dashboard/src/components/reports/ProjectHealthTable.tsx', template: false },
421
+ { src: 'standard/dashboard/src/components/reports/CostTrendsReport.tsx', dest: 'dashboard/src/components/reports/CostTrendsReport.tsx', template: false },
422
+ { src: 'standard/dashboard/src/components/reports/WarningDigestsTable.tsx', dest: 'dashboard/src/components/reports/WarningDigestsTable.tsx', template: false },
423
+ // Tests — standard tier (v2.1.0)
424
+ { src: 'standard/tests/unit/cloudflare/alerting.test.ts', dest: 'tests/unit/cloudflare/alerting.test.ts', template: false },
425
+ { src: 'standard/tests/unit/error-collector/dedup.test.ts', dest: 'tests/unit/error-collector/dedup.test.ts', template: false },
426
+ { src: 'standard/tests/unit/error-collector/github.test.ts', dest: 'tests/unit/error-collector/github.test.ts', template: false },
427
+ { src: 'standard/tests/integration/platform-sentinel.test.ts', dest: 'tests/integration/platform-sentinel.test.ts', template: false },
428
+ { src: 'standard/tests/integration/connectors.test.ts', dest: 'tests/integration/connectors.test.ts', template: false },
429
+ { src: 'standard/tests/integration/github-monitor.test.ts', dest: 'tests/integration/github-monitor.test.ts', template: false },
430
+ { src: 'standard/tests/integration/ingestion.test.ts', dest: 'tests/integration/ingestion.test.ts', template: false },
273
431
  ];
274
432
  const FULL_FILES = [
275
433
  // Additional migrations
@@ -319,8 +477,15 @@ const FULL_FILES = [
319
477
  { src: 'full/scripts/ops/set-kv-pricing.ts', dest: 'scripts/ops/set-kv-pricing.ts', template: false },
320
478
  // Universal backfill cascade (v1.8.0)
321
479
  { src: 'full/scripts/ops/universal-backfill.ts', dest: 'scripts/ops/universal-backfill.ts', template: false },
322
- // Dashboard full tier (patterns, notifications, search)
480
+ { src: 'full/scripts/ops/verify-account-total.ts', dest: 'scripts/ops/verify-account-total.ts', template: false },
481
+ { src: 'full/scripts/ops/audit-cost-anomaly.ts', dest: 'scripts/ops/audit-cost-anomaly.ts', template: false },
482
+ // Dashboard — full tier (patterns, notifications, search, additional pages)
323
483
  { src: 'full/dashboard/src/pages/notifications.astro', dest: 'dashboard/src/pages/notifications.astro', template: false },
484
+ { src: 'full/dashboard/src/pages/map.astro', dest: 'dashboard/src/pages/map.astro', template: false },
485
+ { src: 'full/dashboard/src/pages/revenue.astro', dest: 'dashboard/src/pages/revenue.astro', template: false },
486
+ { src: 'full/dashboard/src/pages/tests.astro', dest: 'dashboard/src/pages/tests.astro', template: false },
487
+ { src: 'full/dashboard/src/pages/kiosk.astro', dest: 'dashboard/src/pages/kiosk.astro', template: false },
488
+ { src: 'full/dashboard/src/pages/feedback.astro', dest: 'dashboard/src/pages/feedback.astro', template: false },
324
489
  { src: 'full/dashboard/src/pages/api/patterns/index.ts', dest: 'dashboard/src/pages/api/patterns/index.ts', template: false },
325
490
  { src: 'full/dashboard/src/pages/api/patterns/approve.ts', dest: 'dashboard/src/pages/api/patterns/approve.ts', template: false },
326
491
  { src: 'full/dashboard/src/pages/api/patterns/reject.ts', dest: 'dashboard/src/pages/api/patterns/reject.ts', template: false },
@@ -332,8 +497,12 @@ const FULL_FILES = [
332
497
  { src: 'full/dashboard/src/components/patterns/index.ts', dest: 'dashboard/src/components/patterns/index.ts', template: false },
333
498
  { src: 'full/dashboard/src/components/notifications/NotificationBell.tsx', dest: 'dashboard/src/components/notifications/NotificationBell.tsx', template: false },
334
499
  { src: 'full/dashboard/src/components/notifications/NotificationList.tsx', dest: 'dashboard/src/components/notifications/NotificationList.tsx', template: false },
500
+ { src: 'full/dashboard/src/components/notifications/NotificationDropdown.tsx', dest: 'dashboard/src/components/notifications/NotificationDropdown.tsx', template: false },
501
+ { src: 'full/dashboard/src/components/notifications/NotificationItem.tsx', dest: 'dashboard/src/components/notifications/NotificationItem.tsx', template: false },
335
502
  { src: 'full/dashboard/src/components/notifications/index.ts', dest: 'dashboard/src/components/notifications/index.ts', template: false },
336
503
  { src: 'full/dashboard/src/components/search/SearchModal.tsx', dest: 'dashboard/src/components/search/SearchModal.tsx', template: false },
504
+ { src: 'full/dashboard/src/components/search/SearchResultGroup.tsx', dest: 'dashboard/src/components/search/SearchResultGroup.tsx', template: false },
505
+ { src: 'full/dashboard/src/components/search/SearchResultItem.tsx', dest: 'dashboard/src/components/search/SearchResultItem.tsx', template: false },
337
506
  // Dashboard — full tier: pattern tabs component (v1.6.0)
338
507
  { src: 'full/dashboard/src/components/patterns/PatternTabs.tsx', dest: 'dashboard/src/components/patterns/PatternTabs.tsx', template: false },
339
508
  // Dashboard — full tier: additional pattern API routes (v2.0.0)
@@ -354,15 +523,48 @@ const FULL_FILES = [
354
523
  // Dashboard — full tier: reports API routes (v2.0.0)
355
524
  { src: 'full/dashboard/src/pages/api/reports/audit.ts', dest: 'dashboard/src/pages/api/reports/audit.ts', template: false },
356
525
  { src: 'full/dashboard/src/pages/api/reports/usage.ts', dest: 'dashboard/src/pages/api/reports/usage.ts', template: false },
526
+ { src: 'full/dashboard/src/pages/api/reports/digests.ts', dest: 'dashboard/src/pages/api/reports/digests.ts', template: false },
527
+ { src: 'full/dashboard/src/pages/api/reports/digests/stats.ts', dest: 'dashboard/src/pages/api/reports/digests/stats.ts', template: false },
357
528
  // Dashboard — full tier: topology API route (v2.0.0)
358
529
  { src: 'full/dashboard/src/pages/api/topology/index.ts', dest: 'dashboard/src/pages/api/topology/index.ts', template: false },
530
+ // Dashboard — full tier: test reports + parameterized pattern/search routes (v2.2.0)
531
+ { src: 'full/dashboard/src/pages/api/test-reports/[id].ts', dest: 'dashboard/src/pages/api/test-reports/[id].ts', template: false },
532
+ { src: 'full/dashboard/src/pages/api/patterns/[id]/approve.ts', dest: 'dashboard/src/pages/api/patterns/[id]/approve.ts', template: false },
533
+ { src: 'full/dashboard/src/pages/api/patterns/[id]/reject.ts', dest: 'dashboard/src/pages/api/patterns/[id]/reject.ts', template: false },
534
+ { src: 'full/dashboard/src/pages/api/search/reindex/[type].ts', dest: 'dashboard/src/pages/api/search/reindex/[type].ts', template: false },
359
535
  // Dashboard — full tier: additional pattern components (v2.0.0)
360
536
  { src: 'full/dashboard/src/components/patterns/ActivePatterns.tsx', dest: 'dashboard/src/components/patterns/ActivePatterns.tsx', template: false },
361
537
  { src: 'full/dashboard/src/components/patterns/SystemPatterns.tsx', dest: 'dashboard/src/components/patterns/SystemPatterns.tsx', template: false },
362
538
  // Dashboard — full tier: reports components (v2.0.0)
363
539
  { src: 'full/dashboard/src/components/reports/SdkAuditReport.tsx', dest: 'dashboard/src/components/reports/SdkAuditReport.tsx', template: false },
364
540
  { src: 'full/dashboard/src/components/reports/GapDetectionReport.tsx', dest: 'dashboard/src/components/reports/GapDetectionReport.tsx', template: false },
541
+ { src: 'full/dashboard/src/components/reports/FeatureUsageReport.tsx', dest: 'dashboard/src/components/reports/FeatureUsageReport.tsx', template: false },
365
542
  { src: 'full/dashboard/src/components/reports/index.ts', dest: 'dashboard/src/components/reports/index.ts', template: false },
543
+ { src: 'full/dashboard/src/components/patterns/PatternInfoButton.tsx', dest: 'dashboard/src/components/patterns/PatternInfoButton.tsx', template: false },
544
+ // Dashboard — full tier: lib modules (v2.1.0)
545
+ { src: 'full/dashboard/src/lib/cloudflare/graphql.ts', dest: 'dashboard/src/lib/cloudflare/graphql.ts', template: false },
546
+ { src: 'full/dashboard/src/lib/cloudflare/alerting.ts', dest: 'dashboard/src/lib/cloudflare/alerting.ts', template: false },
547
+ { src: 'full/dashboard/src/lib/cloudflare/project-registry.ts', dest: 'dashboard/src/lib/cloudflare/project-registry.ts', template: false },
548
+ { src: 'full/dashboard/src/lib/usage/allowance-config.ts.hbs', dest: 'dashboard/src/lib/usage/allowance-config.ts', template: true },
549
+ { src: 'full/dashboard/src/lib/usage/providers.ts', dest: 'dashboard/src/lib/usage/providers.ts', template: false },
550
+ { src: 'full/dashboard/src/lib/patterns/api.ts', dest: 'dashboard/src/lib/patterns/api.ts', template: false },
551
+ { src: 'full/dashboard/src/lib/patterns/types.ts', dest: 'dashboard/src/lib/patterns/types.ts', template: false },
552
+ { src: 'full/dashboard/src/lib/notifications/api.ts', dest: 'dashboard/src/lib/notifications/api.ts', template: false },
553
+ { src: 'full/dashboard/src/lib/notifications/types.ts.hbs', dest: 'dashboard/src/lib/notifications/types.ts', template: true },
554
+ { src: 'full/dashboard/src/lib/search/api.ts', dest: 'dashboard/src/lib/search/api.ts', template: false },
555
+ { src: 'full/dashboard/src/lib/search/types.ts.hbs', dest: 'dashboard/src/lib/search/types.ts', template: true },
556
+ { src: 'full/dashboard/src/lib/settings/api.ts.hbs', dest: 'dashboard/src/lib/settings/api.ts', template: true },
557
+ { src: 'full/dashboard/src/lib/settings/types.ts.hbs', dest: 'dashboard/src/lib/settings/types.ts', template: true },
558
+ { src: 'full/dashboard/src/lib/reports/types.ts', dest: 'dashboard/src/lib/reports/types.ts', template: false },
559
+ // Dashboard — full tier: usage components (v2.1.0)
560
+ { src: 'full/dashboard/src/components/usage/AIModelBreakdown.tsx', dest: 'dashboard/src/components/usage/AIModelBreakdown.tsx', template: false },
561
+ { src: 'full/dashboard/src/components/usage/unified/Recommendations.tsx', dest: 'dashboard/src/components/usage/unified/Recommendations.tsx', template: false },
562
+ // Dashboard — full tier: reports components (v2.1.0)
563
+ { src: 'full/dashboard/src/components/reports/HealthTrendsReport.tsx', dest: 'dashboard/src/components/reports/HealthTrendsReport.tsx', template: false },
564
+ { src: 'full/dashboard/src/components/reports/DigestStats.tsx', dest: 'dashboard/src/components/reports/DigestStats.tsx', template: false },
565
+ // Tests — full tier (v2.2.0)
566
+ { src: 'full/tests/integration/r2-archive.test.ts', dest: 'tests/integration/r2-archive.test.ts', template: false },
567
+ { src: 'full/tests/integration/feedback-schema.test.ts', dest: 'tests/integration/feedback-schema.test.ts', template: false },
366
568
  ];
367
569
  export function getFilesForTier(tier) {
368
570
  const files = [...SHARED_FILES];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@littlebearapps/platform-admin-sdk",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Platform Admin SDK — scaffold backend infrastructure with workers, circuit breakers, and cost protection for Cloudflare",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,130 @@
1
+ /**
2
+ * NotificationDropdown.tsx
3
+ *
4
+ * Dropdown panel showing recent notifications with mark-as-read actions.
5
+ *
6
+ * @module dashboard/components/notifications/NotificationDropdown
7
+ * @created 2026-02-03
8
+ * @task task-303.2
9
+ */
10
+
11
+ import { NotificationItem } from './NotificationItem';
12
+ import type { Notification } from '../../lib/notifications/types';
13
+
14
+ export interface NotificationDropdownProps {
15
+ notifications: Notification[];
16
+ readIds: Set<string>;
17
+ isOpen: boolean;
18
+ onMarkRead: (id: string) => void;
19
+ onMarkAllRead: () => void;
20
+ onClose: () => void;
21
+ loading?: boolean;
22
+ }
23
+
24
+ export function NotificationDropdown({
25
+ notifications,
26
+ readIds,
27
+ isOpen,
28
+ onMarkRead,
29
+ onMarkAllRead,
30
+ _onClose,
31
+ loading = false,
32
+ }: NotificationDropdownProps): JSX.Element | null {
33
+ if (!isOpen) return null;
34
+
35
+ const hasUnread = notifications.some((n) => !readIds.has(n.id));
36
+
37
+ return (
38
+ <div
39
+ className="absolute right-0 mt-2 w-80 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 z-60 overflow-hidden animate-slide-down"
40
+ role="menu"
41
+ aria-orientation="vertical"
42
+ aria-label="Notifications"
43
+ >
44
+ {/* Header */}
45
+ <div className="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700">
46
+ <h3 className="text-sm font-semibold text-gray-900 dark:text-white">Notifications</h3>
47
+ {hasUnread ? (
48
+ <button
49
+ onClick={onMarkAllRead}
50
+ className="text-xs text-blue-600 dark:text-blue-400 hover:underline focus:outline-none"
51
+ >
52
+ Mark all as read
53
+ </button>
54
+ ) : (
55
+ <span className="text-xs text-gray-400">All read</span>
56
+ )}
57
+ </div>
58
+
59
+ {/* Notification list */}
60
+ <div className="max-h-80 overflow-y-auto">
61
+ {loading ? (
62
+ <div className="px-4 py-8 text-center">
63
+ <svg
64
+ className="animate-spin h-6 w-6 mx-auto text-blue-500"
65
+ fill="none"
66
+ viewBox="0 0 24 24"
67
+ >
68
+ <circle
69
+ className="opacity-25"
70
+ cx="12"
71
+ cy="12"
72
+ r="10"
73
+ stroke="currentColor"
74
+ strokeWidth="4"
75
+ />
76
+ <path
77
+ className="opacity-75"
78
+ fill="currentColor"
79
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
80
+ />
81
+ </svg>
82
+ <p className="mt-2 text-sm text-gray-500 dark:text-gray-400">Loading...</p>
83
+ </div>
84
+ ) : notifications.length === 0 ? (
85
+ <div className="px-4 py-8 text-center">
86
+ <svg
87
+ className="mx-auto h-8 w-8 text-gray-400"
88
+ fill="none"
89
+ stroke="currentColor"
90
+ viewBox="0 0 24 24"
91
+ >
92
+ <path
93
+ strokeLinecap="round"
94
+ strokeLinejoin="round"
95
+ strokeWidth={2}
96
+ d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
97
+ />
98
+ </svg>
99
+ <p className="mt-2 text-sm text-gray-500 dark:text-gray-400">No notifications</p>
100
+ <p className="text-xs text-gray-400 dark:text-gray-500">You're all caught up!</p>
101
+ </div>
102
+ ) : (
103
+ <div className="group">
104
+ {notifications.map((notification) => (
105
+ <NotificationItem
106
+ key={notification.id}
107
+ notification={notification}
108
+ isRead={readIds.has(notification.id)}
109
+ onMarkRead={onMarkRead}
110
+ compact
111
+ />
112
+ ))}
113
+ </div>
114
+ )}
115
+ </div>
116
+
117
+ {/* Footer */}
118
+ <div className="px-4 py-3 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50">
119
+ <a
120
+ href="/notifications"
121
+ className="text-sm text-blue-600 dark:text-blue-400 hover:underline"
122
+ >
123
+ View all notifications
124
+ </a>
125
+ </div>
126
+ </div>
127
+ );
128
+ }
129
+
130
+ export default NotificationDropdown;