## ADDED Requirements ### Requirement: Analytics events are recorded for token issuances and agent activity The system SHALL record an analytics event row in `analytics_events` for every OAuth2 token issuance and every agent registration, update, and deactivation, scoped to the tenant. Each row SHALL contain: `tenant_id`, `date` (UTC date), `metric_type` (e.g., `token_issued`, `agent_registered`), and `count` (aggregated daily). #### Scenario: Token issuance recorded in analytics - **WHEN** `POST /oauth2/token` succeeds for a tenant - **THEN** the `analytics_events` table SHALL have a row incremented for `metric_type=token_issued` for that tenant on today's UTC date #### Scenario: Agent registration recorded in analytics - **WHEN** `POST /api/agents` succeeds - **THEN** the `analytics_events` table SHALL have a row incremented for `metric_type=agent_registered` for the owning tenant on today's UTC date #### Scenario: Analytics recording does not block the primary response - **WHEN** the analytics write fails (e.g., DB timeout) - **THEN** the primary API response SHALL still succeed and the error SHALL be logged ### Requirement: Tenant can retrieve token issuance trend data The system SHALL expose `GET /api/analytics/tokens` returning daily token issuance counts for the authenticated tenant over a configurable date range (default: last 30 days, max: 90 days). Response SHALL include an array of `{ date, count }` objects sorted ascending by date. #### Scenario: Successful token trend retrieval - **WHEN** an authenticated tenant admin calls `GET /api/analytics/tokens?days=30` - **THEN** the response SHALL be HTTP 200 with a JSON array of up to 30 `{ date, count }` objects #### Scenario: Date range exceeding maximum is rejected - **WHEN** the request specifies `days` greater than 90 - **THEN** the response SHALL be HTTP 400 with an error indicating the maximum is 90 days #### Scenario: Tenant sees only their own data - **WHEN** tenant A retrieves analytics - **THEN** the response SHALL contain only rows where `tenant_id` matches tenant A — no cross-tenant data leakage ### Requirement: Tenant can retrieve agent activity heatmap data The system SHALL expose `GET /api/analytics/agents/activity` returning per-agent event counts grouped by day-of-week and hour-of-day for the authenticated tenant (last 30 days). Response SHALL include an array of `{ agent_id, dow, hour, count }` objects suitable for rendering a heatmap. #### Scenario: Successful activity heatmap retrieval - **WHEN** an authenticated tenant admin calls `GET /api/analytics/agents/activity` - **THEN** the response SHALL be HTTP 200 with a JSON array of activity buckets #### Scenario: Tenant with no agents returns empty array - **WHEN** the tenant has no registered agents - **THEN** the response SHALL be HTTP 200 with an empty array ### Requirement: Tenant can retrieve a per-agent usage summary The system SHALL expose `GET /api/analytics/agents` returning a list of agents with their total token issuances for the current billing period (current calendar month). Response SHALL include `{ agent_id, name, token_count }` sorted descending by `token_count`. #### Scenario: Successful per-agent summary - **WHEN** an authenticated tenant admin calls `GET /api/analytics/agents` - **THEN** the response SHALL be HTTP 200 with a sorted list of agent usage summaries #### Scenario: Analytics endpoint requires authentication - **WHEN** a request to any `/api/analytics/*` endpoint is made without a valid JWT - **THEN** the response SHALL be HTTP 401 ### Requirement: Analytics data is accessible via the developer portal The portal SHALL include an Analytics page at `/analytics` with: - A line chart showing token issuance trend (last 30 days) rendered with `recharts` - A heatmap chart showing agent activity by day/hour rendered with `recharts` - A table listing per-agent usage for the current month #### Scenario: Analytics page loads token trend chart - **WHEN** a tenant admin navigates to `/analytics` in the portal - **THEN** the page SHALL render a line chart with token issuance data from `GET /api/analytics/tokens` #### Scenario: Analytics page is code-split (lazy loaded) - **WHEN** the portal bundle is built - **THEN** `recharts` and analytics page components SHALL be in a separate chunk (via `next/dynamic`) and NOT included in the main bundle