fix(vv): resolve all 6 V&V issues — field trial unblocked
All findings from the inaugural LeadValidator audit resolved and confirmed. Release gate: PASS. VV_ISSUE_002 (BLOCKER): 15 OpenAPI specs verified present covering all 20 route groups (46 endpoints documented in docs/openapi/) VV_ISSUE_003 (MAJOR): Remove any types from src/db/pool.ts — replaced pool.query shim with unknown[] + Object.defineProperty, zero any types, eslint-disable suppressions removed VV_ISSUE_004 (MAJOR): Remove raw Pool from ScaffoldController and HealthDetailedController — injected AgentRepository/CredentialRepository and DbProbe interface respectively; added CredentialRepository.findActiveClientId() VV_ISSUE_005 (MAJOR): Add unit tests for 5 untested services — ComplianceStatusStore, EventPublisher, MarketplaceService, OIDCTrustPolicyService, UsageService VV_ISSUE_006 (MAJOR): Add integration tests for 7 missing route groups — analytics, billing, tiers, webhooks, marketplace, oidc-trust-policies, oidc-token-exchange VV_ISSUE_001 (MINOR): Create missing design.md and tasks.md in 4 OpenSpec archives — all archives now complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
428
docs/openapi/analytics.yaml
Normal file
428
docs/openapi/analytics.yaml
Normal file
@@ -0,0 +1,428 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
title: SentryAgent.ai — Tenant Analytics
|
||||
version: 1.0.0
|
||||
description: |
|
||||
Tenant analytics endpoints for the SentryAgent.ai AgentIdP platform.
|
||||
|
||||
Provides usage trend data, agent activity heatmaps, and per-agent usage summaries
|
||||
scoped to the authenticated organization (tenant).
|
||||
|
||||
**All endpoints require a valid Bearer JWT.** Data is always scoped to the
|
||||
organization identified by the `organization_id` claim in the token.
|
||||
|
||||
**Feature flag:** When `ANALYTICS_ENABLED=false` these routes return 404.
|
||||
|
||||
**Available endpoints:**
|
||||
- `GET /analytics/tokens` — Daily token issuance trend (last N days)
|
||||
- `GET /analytics/agents/activity` — Agent activity heatmap by day-of-week + hour
|
||||
- `GET /analytics/agents` — Per-agent usage summary for the current month
|
||||
|
||||
servers:
|
||||
- url: http://localhost:3000/api/v1
|
||||
description: Local development server
|
||||
- url: https://api.sentryagent.ai/v1
|
||||
description: Production server
|
||||
|
||||
tags:
|
||||
- name: Analytics
|
||||
description: Tenant-scoped usage analytics and reporting
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
JWT access token obtained via `POST /token`.
|
||||
Include as `Authorization: Bearer <token>`.
|
||||
|
||||
schemas:
|
||||
TokenTrendDataPoint:
|
||||
type: object
|
||||
description: Token issuance count for a single calendar day.
|
||||
required:
|
||||
- date
|
||||
- count
|
||||
properties:
|
||||
date:
|
||||
type: string
|
||||
format: date
|
||||
description: Calendar date (UTC) in `YYYY-MM-DD` format.
|
||||
example: "2026-04-01"
|
||||
count:
|
||||
type: integer
|
||||
description: Number of OAuth 2.0 tokens issued on this date.
|
||||
minimum: 0
|
||||
example: 842
|
||||
|
||||
TokenTrendResponse:
|
||||
type: object
|
||||
description: Daily token issuance trend for the last N days.
|
||||
required:
|
||||
- organizationId
|
||||
- days
|
||||
- data
|
||||
properties:
|
||||
organizationId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Organization the analytics data belongs to.
|
||||
example: "org-1234-5678-abcd-ef01"
|
||||
days:
|
||||
type: integer
|
||||
description: Number of days included in the trend window.
|
||||
example: 30
|
||||
data:
|
||||
type: array
|
||||
description: |
|
||||
Array of daily data points ordered by date ascending.
|
||||
Days with no token issuances have `count: 0`.
|
||||
items:
|
||||
$ref: '#/components/schemas/TokenTrendDataPoint'
|
||||
|
||||
ActivityHeatmapCell:
|
||||
type: object
|
||||
description: |
|
||||
A single cell in the agent activity heatmap, identified by
|
||||
day-of-week (0 = Sunday) and hour of day (0–23 UTC).
|
||||
required:
|
||||
- dayOfWeek
|
||||
- hour
|
||||
- count
|
||||
properties:
|
||||
dayOfWeek:
|
||||
type: integer
|
||||
description: Day of week (0 = Sunday, 6 = Saturday).
|
||||
minimum: 0
|
||||
maximum: 6
|
||||
example: 1
|
||||
hour:
|
||||
type: integer
|
||||
description: Hour of day in UTC (0–23).
|
||||
minimum: 0
|
||||
maximum: 23
|
||||
example: 14
|
||||
count:
|
||||
type: integer
|
||||
description: Number of token issuances or API calls in this slot.
|
||||
minimum: 0
|
||||
example: 217
|
||||
|
||||
AgentActivityResponse:
|
||||
type: object
|
||||
description: |
|
||||
Agent activity heatmap — shows when agents are most active
|
||||
by day-of-week and hour (UTC). Useful for identifying peak usage patterns.
|
||||
required:
|
||||
- organizationId
|
||||
- data
|
||||
properties:
|
||||
organizationId:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "org-1234-5678-abcd-ef01"
|
||||
data:
|
||||
type: array
|
||||
description: |
|
||||
Array of heatmap cells. Contains only cells with `count > 0`.
|
||||
Maximum 168 cells (7 days × 24 hours).
|
||||
items:
|
||||
$ref: '#/components/schemas/ActivityHeatmapCell'
|
||||
|
||||
AgentUsageSummary:
|
||||
type: object
|
||||
description: Per-agent usage summary for the current calendar month.
|
||||
required:
|
||||
- agentId
|
||||
- tokensIssued
|
||||
- apiCalls
|
||||
properties:
|
||||
agentId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: UUID of the agent.
|
||||
example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||
agentEmail:
|
||||
type: string
|
||||
format: email
|
||||
description: Email identifier of the agent.
|
||||
example: "screener-001@sentryagent.ai"
|
||||
tokensIssued:
|
||||
type: integer
|
||||
description: Number of tokens issued for this agent in the current month.
|
||||
minimum: 0
|
||||
example: 1204
|
||||
apiCalls:
|
||||
type: integer
|
||||
description: Total API calls made by this agent in the current month.
|
||||
minimum: 0
|
||||
example: 5432
|
||||
lastActiveAt:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
description: Timestamp of the agent's last API activity. Null if no activity this month.
|
||||
example: "2026-04-07T08:45:00.000Z"
|
||||
|
||||
AgentSummaryResponse:
|
||||
type: object
|
||||
description: Per-agent usage summary for the current month, across all agents in the organization.
|
||||
required:
|
||||
- organizationId
|
||||
- month
|
||||
- data
|
||||
properties:
|
||||
organizationId:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "org-1234-5678-abcd-ef01"
|
||||
month:
|
||||
type: string
|
||||
description: Current billing month in `YYYY-MM` format.
|
||||
example: "2026-04"
|
||||
data:
|
||||
type: array
|
||||
description: Per-agent usage summaries, ordered by `tokensIssued` descending.
|
||||
items:
|
||||
$ref: '#/components/schemas/AgentUsageSummary'
|
||||
|
||||
ErrorResponse:
|
||||
type: object
|
||||
description: Standard error response envelope.
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
example: "UNAUTHORIZED"
|
||||
message:
|
||||
type: string
|
||||
example: "A valid Bearer token is required to access this resource."
|
||||
details:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
responses:
|
||||
Unauthorized:
|
||||
description: Missing or invalid Bearer token.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
example:
|
||||
code: "UNAUTHORIZED"
|
||||
message: "A valid Bearer token is required to access this resource."
|
||||
|
||||
InternalServerError:
|
||||
description: Unexpected server error.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
example:
|
||||
code: "INTERNAL_SERVER_ERROR"
|
||||
message: "An unexpected error occurred. Please try again later."
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
paths:
|
||||
/analytics/tokens:
|
||||
get:
|
||||
operationId: getTokenTrend
|
||||
tags:
|
||||
- Analytics
|
||||
summary: Get daily token issuance trend
|
||||
description: |
|
||||
Returns a daily breakdown of OAuth 2.0 token issuances for the authenticated
|
||||
organization over the last N days.
|
||||
|
||||
The `days` parameter controls the window size (default: 30, max: 90).
|
||||
Days with no token activity are included with `count: 0`.
|
||||
|
||||
Data is scoped to the `organization_id` from the Bearer token.
|
||||
parameters:
|
||||
- name: days
|
||||
in: query
|
||||
required: false
|
||||
description: Number of days to include in the trend window. Default: 30, max: 90.
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 90
|
||||
default: 30
|
||||
example: 30
|
||||
responses:
|
||||
'200':
|
||||
description: Token trend data returned successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TokenTrendResponse'
|
||||
example:
|
||||
organizationId: "org-1234-5678-abcd-ef01"
|
||||
days: 7
|
||||
data:
|
||||
- date: "2026-04-01"
|
||||
count: 842
|
||||
- date: "2026-04-02"
|
||||
count: 967
|
||||
- date: "2026-04-03"
|
||||
count: 0
|
||||
- date: "2026-04-04"
|
||||
count: 1201
|
||||
- date: "2026-04-05"
|
||||
count: 1087
|
||||
- date: "2026-04-06"
|
||||
count: 953
|
||||
- date: "2026-04-07"
|
||||
count: 412
|
||||
'400':
|
||||
description: Invalid `days` parameter.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
tooLarge:
|
||||
summary: Exceeds maximum
|
||||
value:
|
||||
code: "VALIDATION_ERROR"
|
||||
message: "Query parameter `days` must not exceed 90."
|
||||
details:
|
||||
field: "days"
|
||||
max: 90
|
||||
provided: 120
|
||||
invalid:
|
||||
summary: Non-positive integer
|
||||
value:
|
||||
code: "VALIDATION_ERROR"
|
||||
message: "Query parameter `days` must be a positive integer."
|
||||
details:
|
||||
field: "days"
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'404':
|
||||
description: Analytics feature is not enabled on this instance.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
example:
|
||||
code: "NOT_FOUND"
|
||||
message: "Analytics is not enabled on this instance."
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/analytics/agents/activity:
|
||||
get:
|
||||
operationId: getAgentActivity
|
||||
tags:
|
||||
- Analytics
|
||||
summary: Get agent activity heatmap
|
||||
description: |
|
||||
Returns agent activity aggregated by day-of-week (0 = Sunday) and hour of day (UTC).
|
||||
|
||||
The heatmap shows when agents in the organization are most active,
|
||||
based on token issuances and API calls. Only cells with `count > 0` are returned.
|
||||
|
||||
Data is scoped to the `organization_id` from the Bearer token.
|
||||
The heatmap covers the last 90 days of activity.
|
||||
responses:
|
||||
'200':
|
||||
description: Agent activity heatmap returned successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AgentActivityResponse'
|
||||
example:
|
||||
organizationId: "org-1234-5678-abcd-ef01"
|
||||
data:
|
||||
- dayOfWeek: 1
|
||||
hour: 9
|
||||
count: 342
|
||||
- dayOfWeek: 1
|
||||
hour: 14
|
||||
count: 217
|
||||
- dayOfWeek: 2
|
||||
hour: 10
|
||||
count: 189
|
||||
- dayOfWeek: 3
|
||||
hour: 11
|
||||
count: 405
|
||||
- dayOfWeek: 4
|
||||
hour: 14
|
||||
count: 278
|
||||
- dayOfWeek: 5
|
||||
hour: 9
|
||||
count: 121
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'404':
|
||||
description: Analytics feature is not enabled on this instance.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
example:
|
||||
code: "NOT_FOUND"
|
||||
message: "Analytics is not enabled on this instance."
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/analytics/agents:
|
||||
get:
|
||||
operationId: getAgentSummary
|
||||
tags:
|
||||
- Analytics
|
||||
summary: Get per-agent usage summary
|
||||
description: |
|
||||
Returns per-agent token issuance counts and API call totals for the
|
||||
current calendar month, across all agents in the authenticated organization.
|
||||
|
||||
Results are ordered by `tokensIssued` descending (most active agents first).
|
||||
|
||||
Data is scoped to the `organization_id` from the Bearer token.
|
||||
responses:
|
||||
'200':
|
||||
description: Per-agent usage summary returned successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AgentSummaryResponse'
|
||||
example:
|
||||
organizationId: "org-1234-5678-abcd-ef01"
|
||||
month: "2026-04"
|
||||
data:
|
||||
- agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||
agentEmail: "screener-001@sentryagent.ai"
|
||||
tokensIssued: 1204
|
||||
apiCalls: 5432
|
||||
lastActiveAt: "2026-04-07T08:45:00.000Z"
|
||||
- agentId: "b2c3d4e5-f6a7-8901-bcde-f12345678901"
|
||||
agentEmail: "classifier-002@sentryagent.ai"
|
||||
tokensIssued: 876
|
||||
apiCalls: 3120
|
||||
lastActiveAt: "2026-04-06T14:30:00.000Z"
|
||||
- agentId: "c3d4e5f6-a7b8-9012-cdef-123456789012"
|
||||
agentEmail: "router-003@sentryagent.ai"
|
||||
tokensIssued: 0
|
||||
apiCalls: 0
|
||||
lastActiveAt: null
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'404':
|
||||
description: Analytics feature is not enabled on this instance.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
example:
|
||||
code: "NOT_FOUND"
|
||||
message: "Analytics is not enabled on this instance."
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
Reference in New Issue
Block a user