@littlebearapps/platform-admin-sdk 2.1.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 (115) hide show
  1. package/README.md +2 -5
  2. package/dist/templates.d.ts +1 -1
  3. package/dist/templates.js +121 -3
  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/FeatureUsageReport.tsx +339 -0
  9. package/templates/full/dashboard/src/components/search/SearchResultGroup.tsx +46 -0
  10. package/templates/full/dashboard/src/components/search/SearchResultItem.tsx +212 -0
  11. package/templates/full/dashboard/src/pages/api/patterns/[id]/approve.ts +49 -0
  12. package/templates/full/dashboard/src/pages/api/patterns/[id]/reject.ts +50 -0
  13. package/templates/full/dashboard/src/pages/api/reports/digests/stats.ts +38 -0
  14. package/templates/full/dashboard/src/pages/api/reports/digests.ts +39 -0
  15. package/templates/full/dashboard/src/pages/api/search/reindex/[type].ts +56 -0
  16. package/templates/full/dashboard/src/pages/api/test-reports/[id].ts +102 -0
  17. package/templates/full/dashboard/src/pages/feedback.astro +365 -0
  18. package/templates/full/dashboard/src/pages/kiosk.astro +206 -0
  19. package/templates/full/dashboard/src/pages/map.astro +561 -0
  20. package/templates/full/dashboard/src/pages/revenue.astro +72 -0
  21. package/templates/full/dashboard/src/pages/tests.astro +431 -0
  22. package/templates/full/scripts/ops/audit-cost-anomaly.ts +430 -0
  23. package/templates/full/scripts/ops/verify-account-total.ts +256 -0
  24. package/templates/full/tests/integration/feedback-schema.test.ts +361 -0
  25. package/templates/full/tests/integration/r2-archive.test.ts +108 -0
  26. package/templates/shared/.github/workflows/dependabot-automerge.yml +41 -0
  27. package/templates/shared/.github/workflows/validate-controls.yml +27 -0
  28. package/templates/shared/dashboard/src/components/Breadcrumbs.astro +101 -0
  29. package/templates/shared/dashboard/src/components/EmptyState.astro +46 -0
  30. package/templates/shared/dashboard/src/components/ErrorBoundary.astro +79 -0
  31. package/templates/shared/dashboard/src/components/LoadingSkeleton.astro +105 -0
  32. package/templates/shared/dashboard/src/components/PageShell.astro +72 -0
  33. package/templates/shared/dashboard/src/components/SkipLinks.astro +22 -0
  34. package/templates/shared/dashboard/src/components/Toast.astro +170 -0
  35. package/templates/shared/dashboard/src/components/ToastContainer.astro +156 -0
  36. package/templates/shared/dashboard/src/components/costs/ProviderCostsGrid.tsx +401 -0
  37. package/templates/shared/dashboard/src/components/costs/index.ts +4 -0
  38. package/templates/shared/dashboard/src/components/overview/AlertBanner.tsx +94 -0
  39. package/templates/shared/dashboard/src/components/overview/index.ts +9 -0
  40. package/templates/shared/dashboard/src/components/resources/CostChart.tsx +170 -0
  41. package/templates/shared/dashboard/src/components/resources/ProviderCard.tsx +272 -0
  42. package/templates/shared/dashboard/src/components/resources/ProviderDetail.tsx +293 -0
  43. package/templates/shared/dashboard/src/components/settings/SettingsCard.astro +102 -0
  44. package/templates/shared/dashboard/src/components/usage/AllowanceGauge.astro +170 -0
  45. package/templates/shared/dashboard/src/components/usage/AnomalyAlerts.astro +633 -0
  46. package/templates/shared/dashboard/src/components/usage/BillingCycleCountdown.astro +192 -0
  47. package/templates/shared/dashboard/src/components/usage/BurnRateHero.astro +539 -0
  48. package/templates/shared/dashboard/src/components/usage/CircuitBreakerEventLog.astro +542 -0
  49. package/templates/shared/dashboard/src/components/usage/CircuitBreakerPanel.tsx +292 -0
  50. package/templates/shared/dashboard/src/components/usage/CircuitBreakerStatus.astro +669 -0
  51. package/templates/shared/dashboard/src/components/usage/CompactThresholdBanner.astro +531 -0
  52. package/templates/shared/dashboard/src/components/usage/ComparisonModeSelector.astro +651 -0
  53. package/templates/shared/dashboard/src/components/usage/CostBreakdownChart.astro +381 -0
  54. package/templates/shared/dashboard/src/components/usage/CostBreakdownTable.astro +210 -0
  55. package/templates/shared/dashboard/src/components/usage/CostDataTable.astro +0 -0
  56. package/templates/shared/dashboard/src/components/usage/CostDonutChart.astro +311 -0
  57. package/templates/shared/dashboard/src/components/usage/DailyCostChart.astro +632 -0
  58. package/templates/shared/dashboard/src/components/usage/ExportButton.astro +114 -0
  59. package/templates/shared/dashboard/src/components/usage/FeatureBudgetsTable.astro +872 -0
  60. package/templates/shared/dashboard/src/components/usage/FilterBar.astro +190 -0
  61. package/templates/shared/dashboard/src/components/usage/FilterToggles.astro +175 -0
  62. package/templates/shared/dashboard/src/components/usage/GitHubUsageCard.astro +537 -0
  63. package/templates/shared/dashboard/src/components/usage/OverageCostCard.astro +212 -0
  64. package/templates/shared/dashboard/src/components/usage/PlanUtilizationCard.astro +193 -0
  65. package/templates/shared/dashboard/src/components/usage/ProjectCard.astro +640 -0
  66. package/templates/shared/dashboard/src/components/usage/ProjectCardsGrid.astro +272 -0
  67. package/templates/shared/dashboard/src/components/usage/ResourceSearch.astro +279 -0
  68. package/templates/shared/dashboard/src/components/usage/ServiceUtilizationList.astro +604 -0
  69. package/templates/shared/dashboard/src/components/usage/SparklineCard.astro +399 -0
  70. package/templates/shared/dashboard/src/components/usage/StatsHero.astro +600 -0
  71. package/templates/shared/dashboard/src/components/usage/TableFilters.astro +1033 -0
  72. package/templates/shared/dashboard/src/components/usage/ThresholdAlert.astro +271 -0
  73. package/templates/shared/dashboard/src/components/usage/ThresholdSettings.astro +618 -0
  74. package/templates/shared/dashboard/src/components/usage/TopSpenderCard.astro +170 -0
  75. package/templates/shared/dashboard/src/components/usage/UnifiedResourceTable.astro +1737 -0
  76. package/templates/shared/dashboard/src/components/usage/UsageCard.astro +135 -0
  77. package/templates/shared/dashboard/src/components/usage/UsageHealthBanner.astro +387 -0
  78. package/templates/shared/dashboard/src/components/usage/UtilizationBar.astro +159 -0
  79. package/templates/shared/dashboard/src/components/usage/WorkersBreakdownTable.astro +659 -0
  80. package/templates/shared/dashboard/src/components/usage/daily/CostChart.astro +461 -0
  81. package/templates/shared/dashboard/src/components/usage/daily/CostTable.astro +946 -0
  82. package/templates/shared/dashboard/src/components/usage/daily/DailyOverview.astro +1079 -0
  83. package/templates/shared/dashboard/src/components/usage/design-tokens.ts +187 -0
  84. package/templates/shared/dashboard/src/components/usage/filters/InlineDateRange.astro +285 -0
  85. package/templates/shared/dashboard/src/components/usage/filters/PeriodButtons.astro +157 -0
  86. package/templates/shared/dashboard/src/components/usage/filters/ProjectSelect.astro +284 -0
  87. package/templates/shared/dashboard/src/components/usage/scripts/ai-tab-controller.ts +419 -0
  88. package/templates/shared/dashboard/src/components/usage/scripts/constants.ts +60 -0
  89. package/templates/shared/dashboard/src/components/usage/scripts/formatters.ts +62 -0
  90. package/templates/shared/dashboard/src/components/usage/scripts/overview-controller.ts +1633 -0
  91. package/templates/shared/dashboard/src/components/usage/scripts/resource-table-builder.ts +294 -0
  92. package/templates/shared/dashboard/src/components/usage/scripts/tabs-filters-controller.ts +464 -0
  93. package/templates/shared/dashboard/src/components/usage/state/index.ts +55 -0
  94. package/templates/shared/dashboard/src/components/usage/state/usageActions.ts +439 -0
  95. package/templates/shared/dashboard/src/components/usage/state/usageStore.ts +376 -0
  96. package/templates/shared/dashboard/src/components/usage/types.ts +283 -0
  97. package/templates/shared/dashboard/src/components/usage/usage-colors.ts +292 -0
  98. package/templates/shared/dashboard/src/pages/api/usage/ai-models.ts +235 -0
  99. package/templates/shared/dashboard/src/pages/api/usage/billing-context.ts +296 -0
  100. package/templates/shared/scripts/test-telemetry-flow.ts +464 -0
  101. package/templates/shared/tests/e2e/usage-export.test.ts +784 -0
  102. package/templates/shared/tests/e2e/usage-mobile.test.ts +531 -0
  103. package/templates/standard/dashboard/src/components/errors/PriorityBadge.astro +27 -0
  104. package/templates/standard/dashboard/src/components/infrastructure/HealthchecksStatus.tsx +293 -0
  105. package/templates/standard/dashboard/src/components/infrastructure/InfrastructureTabs.tsx +268 -0
  106. package/templates/standard/dashboard/src/pages/analytics.astro +64 -0
  107. package/templates/standard/dashboard/src/pages/api/infrastructure/alerts.ts +85 -0
  108. package/templates/standard/dashboard/src/pages/api/infrastructure/healthchecks/[id]/flips.ts +110 -0
  109. package/templates/standard/dashboard/src/pages/api/infrastructure/healthchecks.ts +101 -0
  110. package/templates/standard/dashboard/src/pages/api/infrastructure/uptime/[id]/response-times.ts +121 -0
  111. package/templates/standard/dashboard/src/pages/api/infrastructure/uptime.ts +89 -0
  112. package/templates/standard/dashboard/src/pages/api/test/service-auth.ts +178 -0
  113. package/templates/standard/tests/integration/connectors.test.ts +241 -0
  114. package/templates/standard/tests/integration/github-monitor.test.ts +143 -0
  115. package/templates/standard/tests/integration/ingestion.test.ts +211 -0
package/README.md CHANGED
@@ -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.1.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.1.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 },
@@ -247,6 +325,8 @@ const SHARED_FILES = [
247
325
  { src: 'shared/tests/integration/platform-usage.test.ts', dest: 'tests/integration/platform-usage.test.ts', template: false },
248
326
  { src: 'shared/tests/integration/kv-cache.test.ts', dest: 'tests/integration/kv-cache.test.ts', template: false },
249
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 },
250
330
  // CI — contract check + security workflows (v2.0.0)
251
331
  { src: 'shared/.github/workflows/contract-check.yml.hbs', dest: '.github/workflows/contract-check.yml', template: true },
252
332
  { src: 'shared/.github/workflows/security.yml', dest: '.github/workflows/security.yml', template: false },
@@ -284,9 +364,10 @@ const STANDARD_FILES = [
284
364
  // SDK test client (telemetry + circuit breaker validation)
285
365
  { src: 'standard/wrangler.sdk-test-client.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-sdk-test-client.jsonc', template: true },
286
366
  { src: 'standard/workers/platform-sdk-test-client.ts', dest: 'workers/platform-sdk-test-client.ts', template: false },
287
- // Dashboard — standard tier (error management, health, DLQ)
367
+ // Dashboard — standard tier (error management, health, DLQ, analytics)
288
368
  { src: 'standard/dashboard/src/pages/health.astro', dest: 'dashboard/src/pages/health.astro', template: false },
289
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 },
290
371
  { src: 'standard/dashboard/src/pages/api/errors/index.ts', dest: 'dashboard/src/pages/api/errors/index.ts', template: false },
291
372
  { src: 'standard/dashboard/src/pages/api/errors/stats.ts', dest: 'dashboard/src/pages/api/errors/stats.ts', template: false },
292
373
  { src: 'standard/dashboard/src/pages/api/health/dlq.ts', dest: 'dashboard/src/pages/api/health/dlq.ts', template: false },
@@ -318,10 +399,21 @@ const STANDARD_FILES = [
318
399
  { src: 'standard/tests/unit/error-collector/capture.test.ts', dest: 'tests/unit/error-collector/capture.test.ts', template: false },
319
400
  // Dashboard — standard tier: audit history API route (v2.0.0)
320
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 },
321
409
  // Dashboard — standard tier: usage components (v2.1.0)
322
410
  { src: 'standard/dashboard/src/components/usage/react/UsageTable.tsx', dest: 'dashboard/src/components/usage/react/UsageTable.tsx', template: false },
323
411
  { src: 'standard/dashboard/src/components/usage/unified/FeatureBudgets.tsx', dest: 'dashboard/src/components/usage/unified/FeatureBudgets.tsx', template: false },
324
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 },
325
417
  // Dashboard — standard tier: reports components (v2.1.0)
326
418
  { src: 'standard/dashboard/src/components/reports/CircuitBreakerReport.tsx', dest: 'dashboard/src/components/reports/CircuitBreakerReport.tsx', template: false },
327
419
  { src: 'standard/dashboard/src/components/reports/ErrorTrendsReport.tsx', dest: 'dashboard/src/components/reports/ErrorTrendsReport.tsx', template: false },
@@ -333,6 +425,9 @@ const STANDARD_FILES = [
333
425
  { src: 'standard/tests/unit/error-collector/dedup.test.ts', dest: 'tests/unit/error-collector/dedup.test.ts', template: false },
334
426
  { src: 'standard/tests/unit/error-collector/github.test.ts', dest: 'tests/unit/error-collector/github.test.ts', template: false },
335
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 },
336
431
  ];
337
432
  const FULL_FILES = [
338
433
  // Additional migrations
@@ -382,8 +477,15 @@ const FULL_FILES = [
382
477
  { src: 'full/scripts/ops/set-kv-pricing.ts', dest: 'scripts/ops/set-kv-pricing.ts', template: false },
383
478
  // Universal backfill cascade (v1.8.0)
384
479
  { src: 'full/scripts/ops/universal-backfill.ts', dest: 'scripts/ops/universal-backfill.ts', template: false },
385
- // 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)
386
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 },
387
489
  { src: 'full/dashboard/src/pages/api/patterns/index.ts', dest: 'dashboard/src/pages/api/patterns/index.ts', template: false },
388
490
  { src: 'full/dashboard/src/pages/api/patterns/approve.ts', dest: 'dashboard/src/pages/api/patterns/approve.ts', template: false },
389
491
  { src: 'full/dashboard/src/pages/api/patterns/reject.ts', dest: 'dashboard/src/pages/api/patterns/reject.ts', template: false },
@@ -395,8 +497,12 @@ const FULL_FILES = [
395
497
  { src: 'full/dashboard/src/components/patterns/index.ts', dest: 'dashboard/src/components/patterns/index.ts', template: false },
396
498
  { src: 'full/dashboard/src/components/notifications/NotificationBell.tsx', dest: 'dashboard/src/components/notifications/NotificationBell.tsx', template: false },
397
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 },
398
502
  { src: 'full/dashboard/src/components/notifications/index.ts', dest: 'dashboard/src/components/notifications/index.ts', template: false },
399
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 },
400
506
  // Dashboard — full tier: pattern tabs component (v1.6.0)
401
507
  { src: 'full/dashboard/src/components/patterns/PatternTabs.tsx', dest: 'dashboard/src/components/patterns/PatternTabs.tsx', template: false },
402
508
  // Dashboard — full tier: additional pattern API routes (v2.0.0)
@@ -417,15 +523,24 @@ const FULL_FILES = [
417
523
  // Dashboard — full tier: reports API routes (v2.0.0)
418
524
  { src: 'full/dashboard/src/pages/api/reports/audit.ts', dest: 'dashboard/src/pages/api/reports/audit.ts', template: false },
419
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 },
420
528
  // Dashboard — full tier: topology API route (v2.0.0)
421
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 },
422
535
  // Dashboard — full tier: additional pattern components (v2.0.0)
423
536
  { src: 'full/dashboard/src/components/patterns/ActivePatterns.tsx', dest: 'dashboard/src/components/patterns/ActivePatterns.tsx', template: false },
424
537
  { src: 'full/dashboard/src/components/patterns/SystemPatterns.tsx', dest: 'dashboard/src/components/patterns/SystemPatterns.tsx', template: false },
425
538
  // Dashboard — full tier: reports components (v2.0.0)
426
539
  { src: 'full/dashboard/src/components/reports/SdkAuditReport.tsx', dest: 'dashboard/src/components/reports/SdkAuditReport.tsx', template: false },
427
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 },
428
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 },
429
544
  // Dashboard — full tier: lib modules (v2.1.0)
430
545
  { src: 'full/dashboard/src/lib/cloudflare/graphql.ts', dest: 'dashboard/src/lib/cloudflare/graphql.ts', template: false },
431
546
  { src: 'full/dashboard/src/lib/cloudflare/alerting.ts', dest: 'dashboard/src/lib/cloudflare/alerting.ts', template: false },
@@ -447,6 +562,9 @@ const FULL_FILES = [
447
562
  // Dashboard — full tier: reports components (v2.1.0)
448
563
  { src: 'full/dashboard/src/components/reports/HealthTrendsReport.tsx', dest: 'dashboard/src/components/reports/HealthTrendsReport.tsx', template: false },
449
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 },
450
568
  ];
451
569
  export function getFilesForTier(tier) {
452
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.1.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;