feat(openspec): propose phase-6-market-expansion change
Analytics Dashboard, API Gateway Tiers, AGNTCY Compliance — 62 tasks across 8 groups. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: System generates an on-demand AGNTCY compliance report
|
||||
The system SHALL expose `GET /api/compliance/report` returning a structured JSON compliance report covering: agent identity verification, audit trail integrity, credential rotation status, and federation readiness. The report SHALL be generated on-demand and cached in Redis for 5 minutes (`compliance:report:<tenant_id>`).
|
||||
|
||||
The report SHALL include:
|
||||
- `generated_at`: ISO 8601 timestamp
|
||||
- `tenant_id`: tenant identifier
|
||||
- `agntcy_schema_version`: pinned version string (e.g., `"1.0"`)
|
||||
- `sections`: array of compliance sections, each with `name`, `status` (`pass`/`fail`/`warn`), and `details`
|
||||
- `overall_status`: `pass` if all sections pass, `fail` if any section fails, `warn` if any section warns
|
||||
|
||||
#### Scenario: Successful compliance report generation
|
||||
- **WHEN** an authenticated tenant admin calls `GET /api/compliance/report`
|
||||
- **THEN** the response SHALL be HTTP 200 with a JSON compliance report containing all required sections
|
||||
|
||||
#### Scenario: Compliance report is served from cache within TTL
|
||||
- **WHEN** `GET /api/compliance/report` is called twice within 5 minutes
|
||||
- **THEN** the second response SHALL be served from Redis cache (not recomputed) and include a `X-Cache: HIT` header
|
||||
|
||||
#### Scenario: Compliance report requires authentication
|
||||
- **WHEN** `GET /api/compliance/report` is called without a valid JWT
|
||||
- **THEN** the response SHALL be HTTP 401
|
||||
|
||||
### Requirement: Compliance report covers agent identity verification
|
||||
The compliance report SHALL include an `agent-identity` section validating that all active agents have: a valid DID:WEB identifier, a current credential (not expired), and an AGNTCY agent card on record. The section SHALL report `pass` only if all agents satisfy all three checks.
|
||||
|
||||
#### Scenario: All agents compliant — agent identity section passes
|
||||
- **WHEN** all active agents have valid DIDs, non-expired credentials, and agent cards
|
||||
- **THEN** the `agent-identity` section SHALL have `status: "pass"`
|
||||
|
||||
#### Scenario: Agent with expired credential — section warns
|
||||
- **WHEN** one or more active agents have credentials expiring within 7 days
|
||||
- **THEN** the `agent-identity` section SHALL have `status: "warn"` with details listing affected agents
|
||||
|
||||
#### Scenario: Agent missing DID — section fails
|
||||
- **WHEN** one or more active agents have no DID:WEB identifier
|
||||
- **THEN** the `agent-identity` section SHALL have `status: "fail"` with details listing affected agents
|
||||
|
||||
### Requirement: Compliance report covers audit trail integrity
|
||||
The compliance report SHALL include an `audit-trail` section verifying the Merkle chain integrity of the `audit_events` table for the tenant. The section SHALL report `pass` if the chain is unbroken, `fail` if any hash mismatch is detected.
|
||||
|
||||
#### Scenario: Intact audit chain passes
|
||||
- **WHEN** the Merkle chain for all audit events is valid
|
||||
- **THEN** the `audit-trail` section SHALL have `status: "pass"` with the total event count
|
||||
|
||||
#### Scenario: Broken audit chain fails
|
||||
- **WHEN** a hash mismatch is detected in the audit event chain
|
||||
- **THEN** the `audit-trail` section SHALL have `status: "fail"` with the sequence number of the first invalid event
|
||||
|
||||
### Requirement: System exports AGNTCY-standard agent cards
|
||||
The system SHALL expose `GET /api/compliance/agent-cards` returning an array of all active agents as AGNTCY agent card objects in the standard JSON format. Each agent card SHALL include: `id` (DID:WEB), `name`, `capabilities` (from agent metadata), `endpoint`, `created_at`, and `agntcy_schema_version`.
|
||||
|
||||
#### Scenario: Successful agent card export
|
||||
- **WHEN** an authenticated tenant admin calls `GET /api/compliance/agent-cards`
|
||||
- **THEN** the response SHALL be HTTP 200 with a JSON array of agent card objects for all active agents
|
||||
|
||||
#### Scenario: Agent card export respects tenant isolation
|
||||
- **WHEN** tenant A exports agent cards
|
||||
- **THEN** the response SHALL contain ONLY agents belonging to tenant A
|
||||
|
||||
#### Scenario: Empty tenant returns empty array
|
||||
- **WHEN** the tenant has no active agents
|
||||
- **THEN** the response SHALL be HTTP 200 with an empty array
|
||||
|
||||
### Requirement: AGNTCY interoperability test suite validates protocol conformance
|
||||
The system SHALL include an interoperability test suite at `tests/agntcy-conformance/` that validates the platform's conformance to the AGNTCY agent identity protocol. The suite SHALL test: agent registration (DID:WEB creation), token issuance for agent clients, A2A delegation chain creation and verification, and compliance report generation. All tests SHALL pass in CI.
|
||||
|
||||
#### Scenario: Conformance suite passes in CI environment
|
||||
- **WHEN** `npm run test:agntcy-conformance` is executed in a CI environment with a live test database
|
||||
- **THEN** all conformance tests SHALL pass with exit code 0
|
||||
|
||||
#### Scenario: Conformance suite fails on missing DID endpoint
|
||||
- **WHEN** the DID resolution endpoint is unreachable
|
||||
- **THEN** the conformance test for DID:WEB SHALL fail with a descriptive error message
|
||||
|
||||
### Requirement: Compliance features can be toggled via feature flag
|
||||
The system SHALL respect a `COMPLIANCE_ENABLED` environment variable (default: `true`). When `COMPLIANCE_ENABLED=false`, all `/api/compliance/*` endpoints SHALL return HTTP 404.
|
||||
|
||||
#### Scenario: Compliance disabled returns 404
|
||||
- **WHEN** `COMPLIANCE_ENABLED=false` and `GET /api/compliance/report` is called
|
||||
- **THEN** the response SHALL be HTTP 404
|
||||
@@ -0,0 +1,67 @@
|
||||
## 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
|
||||
@@ -0,0 +1,72 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Tenants are assigned to a tier with defined rate limits
|
||||
The system SHALL maintain a `tenant_tiers` table linking each tenant to a tier (`free`, `pro`, `enterprise`) with associated limits: max agents, max API calls per day, and max token issuances per day. Tier configuration SHALL be defined in a `TIER_CONFIG` constant (not in the database) to enable zero-latency enforcement.
|
||||
|
||||
Tier defaults:
|
||||
- `free`: 10 agents, 1,000 API calls/day, 1,000 token issuances/day
|
||||
- `pro`: 100 agents, 50,000 API calls/day, 50,000 token issuances/day
|
||||
- `enterprise`: unlimited (no enforcement)
|
||||
|
||||
#### Scenario: New tenant defaults to free tier
|
||||
- **WHEN** a new tenant is created via `POST /api/tenants`
|
||||
- **THEN** a `tenant_tiers` row SHALL be created with `tier=free`
|
||||
|
||||
#### Scenario: Enterprise tier bypasses all rate limits
|
||||
- **WHEN** a tenant on the `enterprise` tier makes any API call
|
||||
- **THEN** no rate limit check SHALL be applied for that tenant
|
||||
|
||||
### Requirement: API calls are rate-limited per tenant tier
|
||||
The system SHALL enforce daily API call limits per tenant using Redis keys `rate:tier:calls:<tenant_id>` with a TTL aligned to UTC midnight. When a tenant exceeds their daily call limit, subsequent requests SHALL be rejected.
|
||||
|
||||
#### Scenario: Tenant within call limit proceeds normally
|
||||
- **WHEN** a tenant on the `free` tier has made fewer than 1,000 API calls today
|
||||
- **THEN** the request SHALL proceed and the counter SHALL be incremented
|
||||
|
||||
#### Scenario: Tenant exceeding daily call limit is rejected
|
||||
- **WHEN** a tenant on the `free` tier has made 1,000 or more API calls today
|
||||
- **THEN** any further API request SHALL return HTTP 429 with `Retry-After` header set to seconds until UTC midnight
|
||||
|
||||
#### Scenario: Rate limit headers are present on all responses
|
||||
- **WHEN** any authenticated API request is made
|
||||
- **THEN** the response SHALL include `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers reflecting the tenant's daily call allowance
|
||||
|
||||
### Requirement: Agent count is enforced per tenant tier
|
||||
The system SHALL prevent tenants from creating more agents than their tier allows. The check SHALL occur at agent creation time.
|
||||
|
||||
#### Scenario: Tenant at agent limit cannot create new agent
|
||||
- **WHEN** a `free` tier tenant already has 10 agents and calls `POST /api/agents`
|
||||
- **THEN** the response SHALL be HTTP 429 with an error message indicating the agent limit and a link to upgrade
|
||||
|
||||
#### Scenario: Tenant below agent limit can create agents
|
||||
- **WHEN** a `free` tier tenant has fewer than 10 agents and calls `POST /api/agents`
|
||||
- **THEN** the request SHALL proceed normally
|
||||
|
||||
### Requirement: Tier enforcement can be toggled via feature flag
|
||||
The system SHALL respect a `TIER_ENFORCEMENT` environment variable (default: `true`). When `TIER_ENFORCEMENT=false`, all tier limit checks SHALL be bypassed and requests SHALL proceed as if on the `enterprise` tier. Rate limit headers SHALL still be present but reflect unlimited limits.
|
||||
|
||||
#### Scenario: Tier enforcement disabled allows all requests
|
||||
- **WHEN** `TIER_ENFORCEMENT=false` and a `free` tier tenant has exceeded their daily limit
|
||||
- **THEN** the request SHALL succeed with HTTP 200 (no 429 returned)
|
||||
|
||||
### Requirement: Tenant can self-service upgrade their tier
|
||||
The system SHALL expose `POST /api/tiers/upgrade` allowing an authenticated tenant admin to request an upgrade to a higher tier. The endpoint SHALL validate the target tier is higher than the current tier and initiate a Stripe checkout session for the new tier's price. On successful payment webhook, the `tenant_tiers` row SHALL be updated.
|
||||
|
||||
#### Scenario: Successful tier upgrade initiation
|
||||
- **WHEN** a `free` tier tenant calls `POST /api/tiers/upgrade` with `{ "target_tier": "pro" }`
|
||||
- **THEN** the response SHALL be HTTP 200 with a Stripe checkout URL
|
||||
|
||||
#### Scenario: Downgrade attempt is rejected
|
||||
- **WHEN** a `pro` tier tenant calls `POST /api/tiers/upgrade` with `{ "target_tier": "free" }`
|
||||
- **THEN** the response SHALL be HTTP 400 with an error indicating downgrades require support
|
||||
|
||||
#### Scenario: Stripe webhook updates tier on payment success
|
||||
- **WHEN** Stripe sends a `checkout.session.completed` event for a tier upgrade
|
||||
- **THEN** the tenant's `tier` SHALL be updated to the purchased tier within 5 seconds
|
||||
|
||||
### Requirement: Tenant can view their current tier and usage
|
||||
The system SHALL expose `GET /api/tiers/status` returning the tenant's current tier, daily limits, current usage counts (calls today, tokens today, agent count), and time until daily limit reset.
|
||||
|
||||
#### Scenario: Tier status returns current usage
|
||||
- **WHEN** an authenticated tenant admin calls `GET /api/tiers/status`
|
||||
- **THEN** the response SHALL be HTTP 200 with tier name, limits, and live usage counters
|
||||
@@ -0,0 +1,27 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Portal includes an Analytics page
|
||||
The portal SHALL include a new page at `/analytics` accessible to authenticated tenant admins. The page SHALL render: a line chart (token issuance trend, last 30 days), an activity heatmap (agent activity by day/hour), and a per-agent usage table for the current month. All chart components SHALL be lazy-loaded via `next/dynamic`.
|
||||
|
||||
#### Scenario: Analytics page is accessible to tenant admins
|
||||
- **WHEN** an authenticated tenant admin navigates to `/analytics`
|
||||
- **THEN** the page SHALL render without error and display the token trend chart
|
||||
|
||||
#### Scenario: Analytics page redirects unauthenticated users
|
||||
- **WHEN** an unauthenticated user navigates to `/analytics`
|
||||
- **THEN** the portal SHALL redirect to the login page
|
||||
|
||||
### Requirement: Portal includes a Tier & Billing page
|
||||
The portal SHALL include a new page at `/settings/tier` accessible to authenticated tenant admins showing: current tier name, daily limits (agents, API calls, token issuances), current usage vs. limit, and an "Upgrade" button that initiates a Stripe checkout session for tenants not on the `enterprise` tier.
|
||||
|
||||
#### Scenario: Free tier tenant sees upgrade prompt
|
||||
- **WHEN** a `free` tier tenant admin navigates to `/settings/tier`
|
||||
- **THEN** the page SHALL display current limits, current usage, and an enabled "Upgrade to Pro" button
|
||||
|
||||
#### Scenario: Enterprise tier tenant sees no upgrade prompt
|
||||
- **WHEN** an `enterprise` tier tenant admin navigates to `/settings/tier`
|
||||
- **THEN** the page SHALL display "Enterprise — Unlimited" and SHALL NOT display an upgrade button
|
||||
|
||||
#### Scenario: Upgrade button initiates Stripe checkout
|
||||
- **WHEN** a tenant admin clicks "Upgrade to Pro" on the tier page
|
||||
- **THEN** the portal SHALL call `POST /api/tiers/upgrade` and redirect to the returned Stripe checkout URL
|
||||
Reference in New Issue
Block a user