spine-framework 0.3.124 → 0.3.126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.framework/cli/commands/agents.ts +35 -37
- package/.framework/cli/commands/auth.ts +35 -34
- package/.framework/cli/commands/create-app.ts +104 -40
- package/.framework/cli/commands/dev.ts +104 -69
- package/.framework/cli/commands/doctor.ts +179 -69
- package/.framework/cli/commands/generate.ts +83 -143
- package/.framework/cli/commands/init.ts +72 -34
- package/.framework/cli/commands/install-app.ts +260 -125
- package/.framework/cli/commands/items.ts +33 -44
- package/.framework/cli/commands/migrate.ts +122 -40
- package/.framework/cli/commands/migrations.ts +33 -40
- package/.framework/cli/commands/pipelines.ts +31 -39
- package/.framework/cli/commands/status.ts +47 -23
- package/.framework/cli/commands/system.ts +47 -37
- package/.framework/cli/commands/test.ts +112 -68
- package/.framework/cli/commands/validate-app.ts +215 -121
- package/.framework/cli/context.ts +112 -130
- package/.framework/cli/env-loader.ts +47 -18
- package/.framework/cli/index.ts +81 -42
- package/.framework/docs/runtime-types.md +1024 -0
- package/.framework/functions/_shared/agent-runner.ts +1296 -961
- package/.framework/functions/_shared/app-manifest.ts +82 -68
- package/.framework/functions/_shared/audit.ts +135 -83
- package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +224 -335
- package/.framework/functions/_shared/kb.ts +319 -0
- package/.framework/functions/_shared/llm.ts +92 -0
- package/.framework/functions/_shared/logging.ts +288 -0
- package/.framework/functions/_shared/middleware.ts +329 -365
- package/.framework/functions/_shared/outcomes.ts +36 -0
- package/.framework/functions/_shared/permissions.ts +359 -643
- package/.framework/functions/_shared/pipeline-runner.ts +243 -316
- package/.framework/functions/_shared/principal.ts +376 -468
- package/.framework/functions/_shared/resolve-credentials.ts +102 -0
- package/.framework/functions/_shared/resolve-ids.ts +188 -16
- package/.framework/functions/_shared/retry-deliveries.ts +104 -0
- package/.framework/functions/_shared/schema-utils.ts +611 -373
- package/.framework/functions/_shared/testing.ts +207 -137
- package/.framework/functions/_shared/tracing.ts +276 -0
- package/.framework/functions/_shared/trigger-engine.ts +159 -211
- package/.framework/functions/_shared/webhook-registration.ts +95 -81
- package/.framework/functions/_shared/webhook-registry.ts +153 -75
- package/.framework/functions/account-nodes.ts +31 -53
- package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
- package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
- package/.framework/functions/adapters/openai-outbound.ts +40 -0
- package/.framework/functions/admin-data.ts +685 -537
- package/.framework/functions/admin-funnel.ts +31 -20
- package/.framework/functions/admin-install-funnel.ts +47 -28
- package/.framework/functions/admin-signals.ts +47 -29
- package/.framework/functions/ai-agents.ts +122 -147
- package/.framework/functions/ai-interactions.ts +180 -90
- package/.framework/functions/api-keys.ts +250 -192
- package/.framework/functions/apps.ts +203 -197
- package/.framework/functions/auth.ts +98 -91
- package/.framework/functions/cil-agent-ingest.ts +773 -0
- package/.framework/functions/cil-agent.ts +592 -0
- package/.framework/functions/cil-callmap.ts +1227 -0
- package/.framework/functions/cil-config.ts +583 -0
- package/.framework/functions/cil-context.ts +445 -0
- package/.framework/functions/cil-doc.ts +1752 -0
- package/.framework/functions/cil-embeddings.ts +1202 -0
- package/.framework/functions/cil-graph.ts +585 -0
- package/.framework/functions/cil-ingest.ts +2416 -0
- package/.framework/functions/cil-pipeline.ts +318 -0
- package/.framework/functions/cil-project.ts +499 -0
- package/.framework/functions/cil-validate.ts +469 -0
- package/.framework/functions/debug-auth.ts +73 -53
- package/.framework/functions/deliveries.ts +117 -0
- package/.framework/functions/embeddings.ts +528 -516
- package/.framework/functions/eval-harness.ts +158 -106
- package/.framework/functions/integration-outbound.ts +311 -0
- package/.framework/functions/integration-routes.ts +240 -466
- package/.framework/functions/integrations.ts +132 -140
- package/.framework/functions/invites.ts +401 -201
- package/.framework/functions/item-progress.ts +113 -53
- package/.framework/functions/kb.ts +28 -0
- package/.framework/functions/logs.ts +239 -222
- package/.framework/functions/observability.ts +308 -259
- package/.framework/functions/pipeline-executions.ts +179 -235
- package/.framework/functions/pipelines.ts +163 -205
- package/.framework/functions/prompt-configs.ts +109 -156
- package/.framework/functions/roles.ts +97 -147
- package/.framework/functions/system-cron.ts +132 -218
- package/.framework/functions/system.ts +112 -52
- package/.framework/functions/tests.ts +32 -28
- package/.framework/functions/timers.ts +162 -210
- package/.framework/functions/triggers.ts +282 -346
- package/.framework/functions/types.ts +283 -400
- package/.framework/migrations/001_core_schema.sql +630 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
- package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
- package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
- package/.framework/migrations/005_core_observability.sql +598 -0
- package/.framework/migrations/006_security_hardening_rls.sql +97 -0
- package/.framework/migrations/007_kb_article_list.sql +237 -0
- package/.framework/migrations/008_items_target.sql +8 -0
- package/.framework/migrations/009_roles_slug_unique.sql +11 -0
- package/.framework/public/spine.config.json +91 -0
- package/.framework/scripts/app-install-cli.ts +112 -98
- package/.framework/src/App.tsx +67 -20
- package/.framework/src/apps/admin/index.tsx +97 -27
- package/.framework/src/components/AppWrapper.tsx +50 -11
- package/.framework/src/components/CustomAppLoader.tsx +131 -22
- package/.framework/src/components/admin/AdminListPage.tsx +75 -8
- package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
- package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
- package/.framework/src/components/admin/PageInstructions.tsx +49 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
- package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
- package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
- package/.framework/src/components/app-sidebar.tsx +50 -3
- package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
- package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
- package/.framework/src/components/kb/KBArticleList.tsx +557 -0
- package/.framework/src/components/layout/AppShell.tsx +54 -16
- package/.framework/src/components/layout/Header.tsx +50 -38
- package/.framework/src/components/layout/Layout.tsx +48 -32
- package/.framework/src/components/layout/Sidebar.tsx +167 -16
- package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
- package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
- package/.framework/src/components/runtime/DataFilters.tsx +78 -1
- package/.framework/src/components/runtime/DataHeader.tsx +32 -29
- package/.framework/src/components/runtime/DataListPage.tsx +161 -2
- package/.framework/src/components/runtime/DataStats.tsx +48 -1
- package/.framework/src/components/runtime/DataTable.tsx +153 -1
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
- package/.framework/src/components/runtime/index.ts +16 -9
- package/.framework/src/components/search-form.tsx +33 -1
- package/.framework/src/components/shared/AgentView.tsx +48 -51
- package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
- package/.framework/src/components/shared/InviteManager.tsx +113 -52
- package/.framework/src/components/shared/MemberList.tsx +182 -0
- package/.framework/src/components/shared/SchemaFields.tsx +96 -78
- package/.framework/src/components/ui/DataTable.tsx +86 -56
- package/.framework/src/components/ui/Form.tsx +188 -109
- package/.framework/src/components/ui/ItemCard.tsx +86 -58
- package/.framework/src/components/ui/ItemListView.tsx +88 -61
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
- package/.framework/src/components/ui/Modal.tsx +81 -4
- package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
- package/.framework/src/components/ui/accordion.tsx +97 -5
- package/.framework/src/components/ui/alert-dialog.tsx +225 -13
- package/.framework/src/components/ui/alert.tsx +113 -6
- package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
- package/.framework/src/components/ui/avatar.tsx +129 -7
- package/.framework/src/components/ui/badge.tsx +65 -3
- package/.framework/src/components/ui/breadcrumb.tsx +145 -8
- package/.framework/src/components/ui/button-group.tsx +81 -4
- package/.framework/src/components/ui/button.tsx +49 -2
- package/.framework/src/components/ui/calendar.tsx +65 -3
- package/.framework/src/components/ui/card.tsx +145 -8
- package/.framework/src/components/ui/carousel.tsx +129 -7
- package/.framework/src/components/ui/chart.tsx +161 -10
- package/.framework/src/components/ui/checkbox.tsx +49 -2
- package/.framework/src/components/ui/collapsible.tsx +81 -5
- package/.framework/src/components/ui/combobox.tsx +305 -20
- package/.framework/src/components/ui/command.tsx +177 -11
- package/.framework/src/components/ui/context-menu.tsx +273 -17
- package/.framework/src/components/ui/dialog.tsx +209 -27
- package/.framework/src/components/ui/direction.tsx +64 -4
- package/.framework/src/components/ui/drawer.tsx +193 -12
- package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
- package/.framework/src/components/ui/empty.tsx +145 -9
- package/.framework/src/components/ui/field.tsx +209 -14
- package/.framework/src/components/ui/hover-card.tsx +81 -4
- package/.framework/src/components/ui/input-group.tsx +162 -10
- package/.framework/src/components/ui/input-otp.tsx +98 -5
- package/.framework/src/components/ui/input.tsx +49 -2
- package/.framework/src/components/ui/item.tsx +225 -13
- package/.framework/src/components/ui/kbd.tsx +65 -3
- package/.framework/src/components/ui/label.tsx +49 -2
- package/.framework/src/components/ui/menubar.tsx +289 -17
- package/.framework/src/components/ui/native-select.tsx +97 -5
- package/.framework/src/components/ui/navigation-menu.tsx +177 -10
- package/.framework/src/components/ui/pagination.tsx +161 -9
- package/.framework/src/components/ui/popover.tsx +145 -8
- package/.framework/src/components/ui/progress.tsx +49 -2
- package/.framework/src/components/ui/radio-group.tsx +65 -3
- package/.framework/src/components/ui/resizable.tsx +82 -4
- package/.framework/src/components/ui/scroll-area.tsx +65 -3
- package/.framework/src/components/ui/select.tsx +193 -11
- package/.framework/src/components/ui/separator.tsx +49 -2
- package/.framework/src/components/ui/sheet.tsx +193 -11
- package/.framework/src/components/ui/sidebar.tsx +481 -38
- package/.framework/src/components/ui/skeleton.tsx +49 -2
- package/.framework/src/components/ui/slider.tsx +49 -2
- package/.framework/src/components/ui/sonner.tsx +49 -2
- package/.framework/src/components/ui/spinner.tsx +49 -2
- package/.framework/src/components/ui/switch.tsx +49 -2
- package/.framework/src/components/ui/table-primitives.tsx +160 -33
- package/.framework/src/components/ui/table.tsx +161 -9
- package/.framework/src/components/ui/tabs.tsx +113 -6
- package/.framework/src/components/ui/textarea.tsx +49 -2
- package/.framework/src/components/ui/toggle-group.tsx +81 -4
- package/.framework/src/components/ui/toggle.tsx +65 -3
- package/.framework/src/components/ui/tooltip.tsx +97 -5
- package/.framework/src/contexts/AppContext.tsx +129 -45
- package/.framework/src/contexts/AuthContext.tsx +187 -144
- package/.framework/src/hooks/use-mobile.ts +48 -2
- package/.framework/src/hooks/useApi.ts +208 -159
- package/.framework/src/hooks/useAppPath.ts +32 -23
- package/.framework/src/hooks/useApps.ts +51 -20
- package/.framework/src/hooks/useEntityList.ts +32 -78
- package/.framework/src/hooks/useEntityRecord.ts +35 -96
- package/.framework/src/hooks/useForm.ts +32 -92
- package/.framework/src/hooks/useListSchema.ts +49 -78
- package/.framework/src/hooks/useSchemaRecord.ts +114 -105
- package/.framework/src/lib/api.ts +195 -116
- package/.framework/src/lib/supabase.ts +98 -64
- package/.framework/src/lib/utils.ts +287 -151
- package/.framework/src/main.tsx +49 -3
- package/.framework/src/pages/DashboardPage.tsx +52 -29
- package/.framework/src/pages/NotFoundPage.tsx +32 -10
- package/.framework/src/pages/SetupPage.tsx +32 -12
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
- package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
- package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
- package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
- package/.framework/src/pages/admin/AppsPage.tsx +49 -2
- package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
- package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
- package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
- package/.framework/src/pages/admin/LogsPage.tsx +422 -75
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
- package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
- package/.framework/src/pages/admin/RolesPage.tsx +171 -18
- package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
- package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
- package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
- package/.framework/src/pages/admin/TimersPage.tsx +48 -20
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
- package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
- package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
- package/.framework/src/pages/admin/TypesPage.tsx +48 -20
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
- package/.framework/src/pages/auth/LoginPage.tsx +50 -23
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
- package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
- package/.framework/src/types/auth.ts +128 -71
- package/.framework/src/types/types.ts +373 -157
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
- package/docs/README.md +9 -130
- package/netlify.toml +5 -2
- package/package.json +13 -25
- package/scripts/kb-ingest-docs.ts +203 -0
- package/spine.config.json +65 -4
- package/.framework/migrations/001_schema.sql +0 -425
- package/.framework/migrations/002_rls_and_functions.sql +0 -763
- package/.framework/migrations/004_enhancements.sql +0 -43
- package/.framework/migrations/005_auth_user_trigger.sql +0 -105
- package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
- package/.framework/migrations/016_invites.sql +0 -27
- package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
- package/.framework/migrations/018_apps_required_roles.sql +0 -17
- package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
- package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
- package/.framework/migrations/021_app_domains.sql +0 -112
- package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
- package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
- package/.framework/migrations/024_messages_account_id.sql +0 -9
- package/.framework/migrations/025_retype_threads_messages.sql +0 -240
- package/.framework/migrations/026_fix_rls_policies.sql +0 -47
- package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
- package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
- package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
- package/.framework/migrations/030_messages_updated_by.sql +0 -6
- package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
- package/docs/APPS.md +0 -232
- package/docs/ARCHITECTURE.md +0 -246
- package/docs/INSTALL.md +0 -155
- package/docs/design-schema-spec.md +0 -1837
- package/docs/dev-guides/01-create-an-app.md +0 -183
- package/docs/dev-guides/02-create-a-function.md +0 -178
- package/docs/dev-guides/03-create-a-component.md +0 -178
- package/docs/dev-guides/04-webhook-handlers.md +0 -129
- package/docs/dev-guides/05-testing.md +0 -168
- package/docs/dev-guides/README.md +0 -40
- package/docs/npm-packages-plan.md +0 -288
- package/docs/spine-core--api-reference.md +0 -822
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module observability
|
|
3
|
-
* @audience core-contributor
|
|
4
|
-
* @layer api-handler
|
|
5
|
-
* @stability stable
|
|
6
|
-
*
|
|
7
|
-
* Aggregated observability metrics API. All handlers delegate to Postgres
|
|
8
|
-
* analytics RPCs that operate over the `v2.logs` table. Results are
|
|
9
|
-
* read-only; no writes occur in this module.
|
|
10
|
-
*
|
|
11
|
-
* **Routed by:** `GET/POST /.netlify/functions/observability`
|
|
12
|
-
*
|
|
13
|
-
* **Actions (all GET unless noted):**
|
|
14
|
-
* | ?action | handler |
|
|
15
|
-
* |-----------------------|------------------------|
|
|
16
|
-
* | event_volume | getEventVolume |
|
|
17
|
-
* | error_rate | getErrorRate |
|
|
18
|
-
* | latency_percentiles | getLatencyPercentiles |
|
|
19
|
-
* | pipeline_stats | getPipelineStats |
|
|
20
|
-
* | top_actors | getTopActors |
|
|
21
|
-
* | ai_support_metrics | getAiSupportMetrics |
|
|
22
|
-
* | cleanup | cleanupOldLogs (POST) |
|
|
23
|
-
*
|
|
24
|
-
* **Authorization:** All read endpoints require account context (RLS-scoped
|
|
25
|
-
* via `ctx.db`). `cleanup` additionally requires the `system_admin` role.
|
|
26
|
-
*
|
|
27
|
-
* INVARIANT: Every handler requires both `from` and `to` date params
|
|
28
|
-
* (except `cleanup`). Requests without them throw immediately.
|
|
29
|
-
*
|
|
30
|
-
* @seeAlso logs.ts (raw log access with filter/search)
|
|
31
|
-
* @seeAlso system-cron.ts (evaluateThresholds calls observability RPCs)
|
|
32
|
-
* @seeAlso pipeline-executions.ts (pipeline_stats RPC aggregates these)
|
|
33
|
-
*/
|
|
34
1
|
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
// CIL[BEGIN chunk_id="observability_moduleheader_1783968140" type="module_header" identity="imports" parent="none"]
|
|
10
|
+
// CIL[DOC-MACRO purpose="Import dependencies for observability metrics API"]
|
|
11
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Import handler utilities and database access"]
|
|
12
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"\\\"]"]
|
|
13
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Imported modules" errors="Import failures" side_effects="none"]
|
|
14
|
+
// CIL[DOC-MICRO logic_summary="Imports createHandler, adminDb" notable_decisions="[]"]
|
|
15
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
16
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
17
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
18
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, custom/apps/portal/pages/ContentPage.tsx, \."]
|
|
19
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
20
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
21
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
22
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
23
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
35
24
|
import { createHandler } from './_shared/middleware'
|
|
36
25
|
import { adminDb } from './_shared/db'
|
|
26
|
+
import { isSystemAdmin } from './_shared/principal'
|
|
27
|
+
import { resolveTypeId } from './_shared/resolve-ids'
|
|
28
|
+
// CIL[END chunk_id="observability_moduleheader_1783968140"]
|
|
29
|
+
// CIL[BEGIN chunk_id="observability_geteventvolume_1783968140" type="function" identity="getEventVolume" parent="none"]
|
|
30
|
+
// CIL[DOC-MACRO purpose="Get event volume metrics with time bucketing"]
|
|
31
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Query aggregated event statistics"]
|
|
32
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/components/ui/dialog.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/db.ts\",\"\\\"]"]
|
|
33
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Array of event volume data" errors="Account context required, dates required, DB errors" side_effects="DB RPC call"]
|
|
34
|
+
// CIL[DOC-MICRO logic_summary="Calls get_event_volume RPC with date range and bucket parameters" notable_decisions="[]"]
|
|
35
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
36
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
37
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 1. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/src/components/ui/dialog.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/db.ts, \."]
|
|
38
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
|
|
39
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
40
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
41
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
42
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
43
|
+
function floorBucket(date: Date, bucket: string): Date {
|
|
44
|
+
const d = new Date(date)
|
|
45
|
+
d.setMilliseconds(0)
|
|
46
|
+
d.setSeconds(0)
|
|
47
|
+
if (bucket === 'hour' || bucket === 'day') d.setMinutes(0)
|
|
48
|
+
if (bucket === 'day') d.setHours(0)
|
|
49
|
+
return d
|
|
50
|
+
}
|
|
37
51
|
|
|
38
|
-
// ─── HANDLERS ─────────────────────────────────────────────────────────────────
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Returns time-bucketed event volume counts via the `get_event_volume` RPC.
|
|
42
|
-
*
|
|
43
|
-
* Query params: `from` (required, ISO), `to` (required, ISO),
|
|
44
|
-
* `bucket` ('minute'|'hour'|'day', default 'hour')
|
|
45
|
-
*
|
|
46
|
-
* @returns Array of `{ bucket_time, event_type, count }` rows
|
|
47
|
-
* @throws Error('Account context required')
|
|
48
|
-
* @throws Error('from and to dates are required')
|
|
49
|
-
* @sideEffects DB read: get_event_volume RPC
|
|
50
|
-
* @calledBy handler (?action=event_volume)
|
|
51
|
-
*/
|
|
52
52
|
export const getEventVolume = createHandler(async (ctx, body) => {
|
|
53
53
|
const { from, to, bucket = 'hour' } = ctx.query || {}
|
|
54
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
54
55
|
|
|
55
|
-
if (!ctx.accountId) {
|
|
56
|
+
if (!isSystemAdmin(ctx.principal) && !ctx.accountId) {
|
|
56
57
|
throw new Error('Account context required')
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -60,37 +61,50 @@ export const getEventVolume = createHandler(async (ctx, body) => {
|
|
|
60
61
|
throw new Error('from and to dates are required')
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
let query = db
|
|
65
|
+
.from('logs')
|
|
66
|
+
.select('created_at')
|
|
67
|
+
.gte('created_at', from)
|
|
68
|
+
.lte('created_at', to)
|
|
69
|
+
|
|
70
|
+
if (!isSystemAdmin(ctx.principal) && ctx.accountId) {
|
|
71
|
+
query = query.eq('account_id', ctx.accountId)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { data, error: err } = await query.order('created_at', { ascending: true })
|
|
71
75
|
|
|
72
76
|
if (err) throw err
|
|
73
|
-
return data || []
|
|
74
|
-
})
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
78
|
+
const counts: Record<string, number> = {}
|
|
79
|
+
for (const row of data || []) {
|
|
80
|
+
const key = floorBucket(new Date(row.created_at), bucket).toISOString()
|
|
81
|
+
counts[key] = (counts[key] || 0) + 1
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return Object.entries(counts)
|
|
85
|
+
.map(([bucket, count]) => ({ bucket, count }))
|
|
86
|
+
.sort((a, b) => new Date(a.bucket).getTime() - new Date(b.bucket).getTime())
|
|
87
|
+
})
|
|
88
|
+
// CIL[END chunk_id="observability_geteventvolume_1783968140"]
|
|
89
|
+
// CIL[BEGIN chunk_id="observability_geterrorrate_1783968140" type="function" identity="getErrorRate" parent="none"]
|
|
90
|
+
// CIL[DOC-MACRO purpose="Get error rate metrics for date range"]
|
|
91
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Query aggregated error statistics"]
|
|
92
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/db.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
|
|
93
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Error rate data object" errors="Account context required, dates required, DB errors" side_effects="DB RPC call"]
|
|
94
|
+
// CIL[DOC-MICRO logic_summary="Calls get_error_rate RPC with date range parameters" notable_decisions="[]"]
|
|
95
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
96
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
97
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 1. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/db.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
|
|
98
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
|
|
99
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
100
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
101
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
102
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
90
103
|
export const getErrorRate = createHandler(async (ctx, body) => {
|
|
91
104
|
const { from, to } = ctx.query || {}
|
|
105
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
92
106
|
|
|
93
|
-
if (!ctx.accountId) {
|
|
107
|
+
if (!isSystemAdmin(ctx.principal) && !ctx.accountId) {
|
|
94
108
|
throw new Error('Account context required')
|
|
95
109
|
}
|
|
96
110
|
|
|
@@ -98,35 +112,58 @@ export const getErrorRate = createHandler(async (ctx, body) => {
|
|
|
98
112
|
throw new Error('from and to dates are required')
|
|
99
113
|
}
|
|
100
114
|
|
|
101
|
-
|
|
102
|
-
.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
115
|
+
let query = db
|
|
116
|
+
.from('logs')
|
|
117
|
+
.select('outcome, level')
|
|
118
|
+
.gte('created_at', from)
|
|
119
|
+
.lte('created_at', to)
|
|
120
|
+
|
|
121
|
+
if (!isSystemAdmin(ctx.principal) && ctx.accountId) {
|
|
122
|
+
query = query.eq('account_id', ctx.accountId)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const { data, error: err } = await query
|
|
107
126
|
|
|
108
127
|
if (err) throw err
|
|
109
|
-
|
|
128
|
+
|
|
129
|
+
const rows = data || []
|
|
130
|
+
const total = rows.length
|
|
131
|
+
const errors = rows.filter((r: any) => r.outcome === 'failure' || r.level === 'error').length
|
|
132
|
+
return {
|
|
133
|
+
total,
|
|
134
|
+
errors,
|
|
135
|
+
rate: total > 0 ? errors / total : 0,
|
|
136
|
+
}
|
|
110
137
|
})
|
|
138
|
+
// CIL[END chunk_id="observability_geterrorrate_1783968140"]
|
|
139
|
+
// CIL[BEGIN chunk_id="observability_getlatencypercentiles_1783968140" type="function" identity="getLatencyPercentiles" parent="none"]
|
|
140
|
+
// CIL[DOC-MACRO purpose="Get latency percentile metrics for performance monitoring"]
|
|
141
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Query aggregated latency statistics"]
|
|
142
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
143
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Latency percentile data" errors="Account context required, dates required, DB errors" side_effects="DB RPC call"]
|
|
144
|
+
// CIL[DOC-MICRO logic_summary="Calls get_latency_percentiles RPC with source and date range" notable_decisions="[]"]
|
|
145
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
146
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
147
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 1. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/schema-utils.ts, \."]
|
|
148
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
|
|
149
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
150
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
151
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
152
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
153
|
+
function percentile(sorted: number[], p: number): number {
|
|
154
|
+
if (sorted.length === 0) return 0
|
|
155
|
+
const idx = (p / 100) * (sorted.length - 1)
|
|
156
|
+
const lower = Math.floor(idx)
|
|
157
|
+
const upper = Math.ceil(idx)
|
|
158
|
+
const weight = idx - lower
|
|
159
|
+
return sorted[lower] * (1 - weight) + sorted[upper] * weight
|
|
160
|
+
}
|
|
111
161
|
|
|
112
|
-
/**
|
|
113
|
-
* Returns request latency percentiles (p50/p90/p99) via the
|
|
114
|
-
* `get_latency_percentiles` RPC.
|
|
115
|
-
*
|
|
116
|
-
* Query params: `from` (required, ISO), `to` (required, ISO),
|
|
117
|
-
* `source` (log source filter, default 'request')
|
|
118
|
-
*
|
|
119
|
-
* @returns `{ p50: number, p90: number, p99: number }` (milliseconds)
|
|
120
|
-
* @throws Error('Account context required')
|
|
121
|
-
* @throws Error('from and to dates are required')
|
|
122
|
-
* @sideEffects DB read: get_latency_percentiles RPC
|
|
123
|
-
* @calledBy handler (?action=latency_percentiles)
|
|
124
|
-
* @calledBy system-cron.ts evaluateThresholds (metric='latency_p95')
|
|
125
|
-
*/
|
|
126
162
|
export const getLatencyPercentiles = createHandler(async (ctx, body) => {
|
|
127
163
|
const { from, to, source = 'request' } = ctx.query || {}
|
|
164
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
128
165
|
|
|
129
|
-
if (!ctx.accountId) {
|
|
166
|
+
if (!isSystemAdmin(ctx.principal) && !ctx.accountId) {
|
|
130
167
|
throw new Error('Account context required')
|
|
131
168
|
}
|
|
132
169
|
|
|
@@ -134,35 +171,54 @@ export const getLatencyPercentiles = createHandler(async (ctx, body) => {
|
|
|
134
171
|
throw new Error('from and to dates are required')
|
|
135
172
|
}
|
|
136
173
|
|
|
137
|
-
|
|
138
|
-
.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
174
|
+
let query = db
|
|
175
|
+
.from('logs')
|
|
176
|
+
.select('duration_ms')
|
|
177
|
+
.not('duration_ms', 'is', null)
|
|
178
|
+
.gte('created_at', from)
|
|
179
|
+
.lte('created_at', to)
|
|
180
|
+
|
|
181
|
+
if (source) query = query.eq('span_name', source)
|
|
182
|
+
if (!isSystemAdmin(ctx.principal) && ctx.accountId) {
|
|
183
|
+
query = query.eq('account_id', ctx.accountId)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const { data, error: err } = await query
|
|
144
187
|
|
|
145
188
|
if (err) throw err
|
|
146
|
-
return data?.[0] || { p50: 0, p90: 0, p99: 0 }
|
|
147
|
-
})
|
|
148
189
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
190
|
+
const values = (data || [])
|
|
191
|
+
.map((r: any) => Number(r.duration_ms))
|
|
192
|
+
.filter((v: number) => !isNaN(v) && v > 0)
|
|
193
|
+
.sort((a: number, b: number) => a - b)
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
p50: percentile(values, 50),
|
|
197
|
+
p90: percentile(values, 90),
|
|
198
|
+
p95: percentile(values, 95),
|
|
199
|
+
p99: percentile(values, 99),
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
// CIL[END chunk_id="observability_getlatencypercentiles_1783968140"]
|
|
203
|
+
// CIL[BEGIN chunk_id="observability_getpipelinestats_1783968140" type="function" identity="getPipelineStats" parent="none"]
|
|
204
|
+
// CIL[DOC-MACRO purpose="Get pipeline execution statistics for monitoring"]
|
|
205
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Query aggregated pipeline metrics"]
|
|
206
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[]"]
|
|
207
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Array of pipeline statistics" errors="Account context required, dates required, DB errors" side_effects="DB RPC call"]
|
|
208
|
+
// CIL[DOC-MICRO logic_summary="Calls get_pipeline_stats RPC with date range parameters" notable_decisions="[]"]
|
|
209
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
210
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
211
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
212
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
213
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
214
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
215
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
216
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
162
217
|
export const getPipelineStats = createHandler(async (ctx, body) => {
|
|
163
218
|
const { from, to } = ctx.query || {}
|
|
219
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
164
220
|
|
|
165
|
-
if (!ctx.accountId) {
|
|
221
|
+
if (!isSystemAdmin(ctx.principal) && !ctx.accountId) {
|
|
166
222
|
throw new Error('Account context required')
|
|
167
223
|
}
|
|
168
224
|
|
|
@@ -170,34 +226,62 @@ export const getPipelineStats = createHandler(async (ctx, body) => {
|
|
|
170
226
|
throw new Error('from and to dates are required')
|
|
171
227
|
}
|
|
172
228
|
|
|
173
|
-
|
|
174
|
-
.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
229
|
+
let query = db
|
|
230
|
+
.from('pipeline_executions')
|
|
231
|
+
.select('pipeline_id, status, started_at, completed_at')
|
|
232
|
+
.gte('created_at', from)
|
|
233
|
+
.lte('created_at', to)
|
|
234
|
+
|
|
235
|
+
if (!isSystemAdmin(ctx.principal) && ctx.accountId) {
|
|
236
|
+
query = query.eq('account_id', ctx.accountId)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const { data, error: err } = await query
|
|
179
240
|
|
|
180
241
|
if (err) throw err
|
|
181
|
-
return data || []
|
|
182
|
-
})
|
|
183
242
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
243
|
+
const stats: Record<string, any> = {}
|
|
244
|
+
for (const row of data || []) {
|
|
245
|
+
const s = stats[row.pipeline_id] || { pipeline_id: row.pipeline_id, success_count: 0, failure_count: 0, total_duration_ms: 0, duration_count: 0 }
|
|
246
|
+
if (row.status === 'completed') s.success_count++
|
|
247
|
+
if (row.status === 'failed') s.failure_count++
|
|
248
|
+
if (row.started_at && row.completed_at) {
|
|
249
|
+
const duration = new Date(row.completed_at).getTime() - new Date(row.started_at).getTime()
|
|
250
|
+
if (duration > 0) {
|
|
251
|
+
s.total_duration_ms += duration
|
|
252
|
+
s.duration_count++
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
stats[row.pipeline_id] = s
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return Object.values(stats).map((s: any) => ({
|
|
259
|
+
pipeline_id: s.pipeline_id,
|
|
260
|
+
success_count: s.success_count,
|
|
261
|
+
failure_count: s.failure_count,
|
|
262
|
+
avg_duration_ms: s.duration_count > 0 ? Math.round(s.total_duration_ms / s.duration_count) : 0,
|
|
263
|
+
}))
|
|
264
|
+
})
|
|
265
|
+
// CIL[END chunk_id="observability_getpipelinestats_1783968140"]
|
|
266
|
+
// CIL[BEGIN chunk_id="observability_gettopactors_1783968140" type="function" identity="getTopActors" parent="none"]
|
|
267
|
+
// CIL[DOC-MACRO purpose="Get top actors by activity volume for monitoring"]
|
|
268
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Query most active users/system actors"]
|
|
269
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[]"]
|
|
270
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Array of actor activity data" errors="Account context required, dates required, DB errors" side_effects="DB RPC call"]
|
|
271
|
+
// CIL[DOC-MICRO logic_summary="Calls get_top_actors RPC with date range and limit parameters" notable_decisions="[]"]
|
|
272
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
273
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
274
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
275
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
276
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
277
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
278
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
279
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
197
280
|
export const getTopActors = createHandler(async (ctx, body) => {
|
|
198
281
|
const { from, to, limit = 5 } = ctx.query || {}
|
|
282
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
199
283
|
|
|
200
|
-
if (!ctx.accountId) {
|
|
284
|
+
if (!isSystemAdmin(ctx.principal) && !ctx.accountId) {
|
|
201
285
|
throw new Error('Account context required')
|
|
202
286
|
}
|
|
203
287
|
|
|
@@ -205,35 +289,49 @@ export const getTopActors = createHandler(async (ctx, body) => {
|
|
|
205
289
|
throw new Error('from and to dates are required')
|
|
206
290
|
}
|
|
207
291
|
|
|
208
|
-
|
|
209
|
-
.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
292
|
+
let query = db
|
|
293
|
+
.from('logs')
|
|
294
|
+
.select('created_by')
|
|
295
|
+
.gte('created_at', from)
|
|
296
|
+
.lte('created_at', to)
|
|
297
|
+
|
|
298
|
+
if (!isSystemAdmin(ctx.principal) && ctx.accountId) {
|
|
299
|
+
query = query.eq('account_id', ctx.accountId)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const { data, error: err } = await query
|
|
215
303
|
|
|
216
304
|
if (err) throw err
|
|
217
|
-
return data || []
|
|
218
|
-
})
|
|
219
305
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
306
|
+
const counts: Record<string, number> = {}
|
|
307
|
+
for (const row of data || []) {
|
|
308
|
+
const key = row.created_by || 'anonymous'
|
|
309
|
+
counts[key] = (counts[key] || 0) + 1
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return Object.entries(counts)
|
|
313
|
+
.map(([principal_id, event_count]) => ({ principal_id, event_count }))
|
|
314
|
+
.sort((a, b) => b.event_count - a.event_count)
|
|
315
|
+
.slice(0, parseInt(limit.toString()) || 5)
|
|
316
|
+
})
|
|
317
|
+
// CIL[END chunk_id="observability_gettopactors_1783968140"]
|
|
318
|
+
// CIL[BEGIN chunk_id="observability_cleanupoldlogs_1783968140" type="function" identity="cleanupOldLogs" parent="none"]
|
|
319
|
+
// CIL[DOC-MACRO purpose="Delete old log entries for storage management"]
|
|
320
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Perform log retention cleanup"]
|
|
321
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[]"]
|
|
322
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="{deleted_count: number}" errors="System admin required, DB errors" side_effects="DB RPC call, data deletion"]
|
|
323
|
+
// CIL[DOC-MICRO logic_summary="Calls cleanup_old_logs RPC with retention days parameter" notable_decisions="[]"]
|
|
324
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
325
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
326
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
327
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
328
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
329
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
330
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
331
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
233
332
|
export const cleanupOldLogs = createHandler(async (ctx, body) => {
|
|
234
333
|
const { days = 90 } = ctx.query || {}
|
|
235
334
|
|
|
236
|
-
// Only system admins can trigger manual cleanup
|
|
237
335
|
if (!ctx.principal?.roles?.includes('system_admin')) {
|
|
238
336
|
throw new Error('System admin required')
|
|
239
337
|
}
|
|
@@ -246,28 +344,21 @@ export const cleanupOldLogs = createHandler(async (ctx, body) => {
|
|
|
246
344
|
if (err) throw err
|
|
247
345
|
return { deleted_count: data?.[0]?.deleted_count || 0 }
|
|
248
346
|
})
|
|
249
|
-
|
|
250
|
-
//
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
* - knowledge_gaps: Interactions with kb_candidate=false + not_helpful feedback
|
|
265
|
-
*
|
|
266
|
-
* Query params: from, to (ISO dates, optional — defaults to last 30 days)
|
|
267
|
-
*
|
|
268
|
-
* @sideEffects DB reads: items, messages tables
|
|
269
|
-
* @calledBy handler (?action=ai_support_metrics)
|
|
270
|
-
*/
|
|
347
|
+
// CIL[END chunk_id="observability_cleanupoldlogs_1783968140"]
|
|
348
|
+
// CIL[BEGIN chunk_id="observability_getaisupportmetrics_1783968140" type="function" identity="getAiSupportMetrics" parent="none"]
|
|
349
|
+
// CIL[DOC-MACRO purpose="Get AI support metrics and knowledge gaps analysis"]
|
|
350
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Query AI performance and coverage statistics"]
|
|
351
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[]"]
|
|
352
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="AI metrics object with knowledge gaps" errors="Account context required, DB errors" side_effects="DB queries"]
|
|
353
|
+
// CIL[DOC-MICRO logic_summary="Queries AI metrics and knowledge gaps, returns aggregated analysis" notable_decisions="[]"]
|
|
354
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="complex_dependencies"]
|
|
355
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
356
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
357
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
358
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
359
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
360
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
361
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
271
362
|
export const getAiSupportMetrics = createHandler(async (ctx, _body) => {
|
|
272
363
|
if (!ctx.accountId) throw new Error('Account context required')
|
|
273
364
|
|
|
@@ -276,26 +367,22 @@ export const getAiSupportMetrics = createHandler(async (ctx, _body) => {
|
|
|
276
367
|
const from = ctx.query?.from || thirtyDaysAgo
|
|
277
368
|
const to = ctx.query?.to || now.toISOString()
|
|
278
369
|
|
|
279
|
-
|
|
370
|
+
const feedbackTypeId = await resolveTypeId('item', 'ai_feedback_record')
|
|
371
|
+
|
|
280
372
|
const [
|
|
281
|
-
|
|
373
|
+
feedbackResult,
|
|
282
374
|
resolvedResult,
|
|
283
375
|
escalatedResult,
|
|
284
|
-
notHelpfulResult,
|
|
285
|
-
mediumConfResult,
|
|
286
|
-
kbCreatedResult,
|
|
287
|
-
feedbackRecordsResult,
|
|
288
376
|
] = await Promise.allSettled([
|
|
289
|
-
// AI agent messages
|
|
290
377
|
adminDb
|
|
291
|
-
.from('
|
|
292
|
-
.select('
|
|
378
|
+
.from('items')
|
|
379
|
+
.select('data')
|
|
293
380
|
.eq('account_id', ctx.accountId)
|
|
294
|
-
.eq('
|
|
381
|
+
.eq('type_id', feedbackTypeId)
|
|
295
382
|
.gte('created_at', from)
|
|
296
|
-
.lte('created_at', to)
|
|
383
|
+
.lte('created_at', to)
|
|
384
|
+
.limit(5000),
|
|
297
385
|
|
|
298
|
-
// Tickets resolved without AI escalation
|
|
299
386
|
adminDb
|
|
300
387
|
.from('items')
|
|
301
388
|
.select('id', { count: 'exact', head: true })
|
|
@@ -305,7 +392,6 @@ export const getAiSupportMetrics = createHandler(async (ctx, _body) => {
|
|
|
305
392
|
.gte('created_at', from)
|
|
306
393
|
.lte('created_at', to),
|
|
307
394
|
|
|
308
|
-
// Tickets escalated to humans
|
|
309
395
|
adminDb
|
|
310
396
|
.from('items')
|
|
311
397
|
.select('id', { count: 'exact', head: true })
|
|
@@ -313,66 +399,23 @@ export const getAiSupportMetrics = createHandler(async (ctx, _body) => {
|
|
|
313
399
|
.eq('status', 'human_assigned')
|
|
314
400
|
.gte('created_at', from)
|
|
315
401
|
.lte('created_at', to),
|
|
316
|
-
|
|
317
|
-
// Not-helpful AI messages
|
|
318
|
-
adminDb
|
|
319
|
-
.from('messages')
|
|
320
|
-
.select('id', { count: 'exact', head: true })
|
|
321
|
-
.eq('account_id', ctx.accountId)
|
|
322
|
-
.eq('data->>sender_type', 'agent')
|
|
323
|
-
.eq('data->>feedback', 'not_helpful')
|
|
324
|
-
.gte('created_at', from)
|
|
325
|
-
.lte('created_at', to),
|
|
326
|
-
|
|
327
|
-
// Medium-confidence AI messages
|
|
328
|
-
adminDb
|
|
329
|
-
.from('messages')
|
|
330
|
-
.select('id', { count: 'exact', head: true })
|
|
331
|
-
.eq('account_id', ctx.accountId)
|
|
332
|
-
.eq('data->>sender_type', 'agent')
|
|
333
|
-
.gte('data->>confidence', '0.60')
|
|
334
|
-
.lte('data->>confidence', '0.85')
|
|
335
|
-
.gte('created_at', from)
|
|
336
|
-
.lte('created_at', to),
|
|
337
|
-
|
|
338
|
-
// Postmortem KB articles created
|
|
339
|
-
adminDb
|
|
340
|
-
.from('items')
|
|
341
|
-
.select('id', { count: 'exact', head: true })
|
|
342
|
-
.eq('account_id', ctx.accountId)
|
|
343
|
-
.eq('data->>kb_type', 'postmortem')
|
|
344
|
-
.gte('created_at', from)
|
|
345
|
-
.lte('created_at', to),
|
|
346
|
-
|
|
347
|
-
// AI feedback records for reuse + gaps
|
|
348
|
-
adminDb
|
|
349
|
-
.from('items')
|
|
350
|
-
.select('data')
|
|
351
|
-
.eq('account_id', ctx.accountId)
|
|
352
|
-
.gte('created_at', from)
|
|
353
|
-
.lte('created_at', to)
|
|
354
|
-
.limit(500),
|
|
355
402
|
])
|
|
356
403
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const aiAttempted = aiMessages.length
|
|
360
|
-
|
|
361
|
-
const aiResolved = resolvedResult.status === 'fulfilled' ? (resolvedResult.value.count || 0) : 0
|
|
362
|
-
const escalated = escalatedResult.status === 'fulfilled' ? (escalatedResult.value.count || 0) : 0
|
|
363
|
-
const notHelpful = notHelpfulResult.status === 'fulfilled' ? (notHelpfulResult.value.count || 0) : 0
|
|
364
|
-
const mediumConf = mediumConfResult.status === 'fulfilled' ? (mediumConfResult.value.count || 0) : 0
|
|
365
|
-
const kbCreated = kbCreatedResult.status === 'fulfilled' ? (kbCreatedResult.value.count || 0) : 0
|
|
366
|
-
|
|
367
|
-
const feedbackRows = feedbackRecordsResult.status === 'fulfilled'
|
|
368
|
-
? (feedbackRecordsResult.value.data || [])
|
|
404
|
+
const feedbackRows = feedbackResult.status === 'fulfilled'
|
|
405
|
+
? (feedbackResult.value.data || [])
|
|
369
406
|
: []
|
|
370
407
|
|
|
408
|
+
const aiAttempted = feedbackRows.length
|
|
409
|
+
const notHelpful = feedbackRows.filter((r: any) => r.data?.customer_feedback === 'not_helpful').length
|
|
410
|
+
const kbCreated = feedbackRows.filter((r: any) => r.data?.kb_article_id).length
|
|
371
411
|
const kbReuseCount = feedbackRows.reduce((sum: number, r: any) => sum + (Number(r.data?.reuse_count) || 0), 0)
|
|
372
412
|
const knowledgeGaps = feedbackRows.filter((r: any) =>
|
|
373
413
|
r.data?.kb_candidate === false && r.data?.customer_feedback === 'not_helpful'
|
|
374
414
|
).length
|
|
375
415
|
|
|
416
|
+
const aiResolved = resolvedResult.status === 'fulfilled' ? (resolvedResult.value.count || 0) : 0
|
|
417
|
+
const escalated = escalatedResult.status === 'fulfilled' ? (escalatedResult.value.count || 0) : 0
|
|
418
|
+
|
|
376
419
|
const thumbsDownRate = aiAttempted > 0 ? notHelpful / aiAttempted : 0
|
|
377
420
|
|
|
378
421
|
return {
|
|
@@ -381,21 +424,26 @@ export const getAiSupportMetrics = createHandler(async (ctx, _body) => {
|
|
|
381
424
|
ai_resolved: aiResolved,
|
|
382
425
|
human_escalations: escalated,
|
|
383
426
|
thumbs_down_rate: Math.round(thumbsDownRate * 1000) / 1000,
|
|
384
|
-
medium_confidence: mediumConf,
|
|
385
427
|
kb_articles_created: kbCreated,
|
|
386
428
|
kb_reuse_count: kbReuseCount,
|
|
387
429
|
knowledge_gaps: knowledgeGaps,
|
|
388
430
|
}
|
|
389
431
|
})
|
|
390
|
-
|
|
391
|
-
//
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
432
|
+
// CIL[END chunk_id="observability_getaisupportmetrics_1783968140"]
|
|
433
|
+
// CIL[BEGIN chunk_id="observability_handler_1783968140" type="function" identity="handler" parent="none"]
|
|
434
|
+
// CIL[DOC-MACRO purpose="Route observability actions to appropriate metric handlers"]
|
|
435
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Dispatch monitoring requests to correct metric functions"]
|
|
436
|
+
// CIL[DOC-CONTEXT module="observability" layer="api-handler" related_files="[]"]
|
|
437
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Varies by action" errors="Unknown action" side_effects="Delegates to handlers"]
|
|
438
|
+
// CIL[DOC-MICRO logic_summary="Switch statement routes action parameter to appropriate metric handler" notable_decisions="[]"]
|
|
439
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
440
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
441
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
442
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
443
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
444
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
445
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
446
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
399
447
|
export const handler = createHandler(async (ctx, body) => {
|
|
400
448
|
const { action } = ctx.query || {}
|
|
401
449
|
|
|
@@ -418,3 +466,4 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
418
466
|
throw new Error(`Unknown action: ${action}. Valid actions: event_volume, error_rate, latency_percentiles, pipeline_stats, top_actors, ai_support_metrics, cleanup`)
|
|
419
467
|
}
|
|
420
468
|
})
|
|
469
|
+
// CIL[END chunk_id="observability_handler_1783968140"]
|