feat(openspec): Phase 4 Developer Growth & Go-to-Market Readiness
OpenSpec change: phase-4-developer-growth (spec-driven, 4/4 artifacts) 6 workstreams, 90 implementation tasks, delivery sequence: WS1 → WS2 + WS3 (parallel) → WS4 → WS5 → WS6 Workstreams: 1. Production Hardening — ioredis rate limiting, DB pool tuning, /health/detailed, k6 load tests 2. Developer Portal — Next.js 14, Swagger UI explorer, onboarding wizard, pricing/SDK pages 3. CLI Tool — sentryagent npm CLI, 5 commands, shell completion 4. Agent Marketplace — public searchable registry powered by existing agent/DID infrastructure 5. GitHub Actions — register-agent + issue-token Actions via OIDC (no stored secrets) 6. Billing & Usage Metering — Stripe Checkout, webhook-driven state, free tier enforcement New capabilities (8 specs): production-hardening, developer-portal, cli-tool, agent-marketplace, github-actions, billing-metering (+delta: web-dashboard, monitoring) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Per-tenant usage is tracked for API calls, active agents, and token issuances
|
||||
The system SHALL track the following usage metrics per tenant per day: `api_calls` (every authenticated API request), `token_issuances` (every successful `POST /oauth2/token`), `active_agents` (count of non-revoked agents at end of day). Usage SHALL be aggregated in memory and flushed to a `usage_events` PostgreSQL table every 60 seconds.
|
||||
|
||||
#### Scenario: API call increments usage counter
|
||||
- **WHEN** an authenticated tenant makes any API request
|
||||
- **THEN** the tenant's `api_calls` counter for the current day is incremented
|
||||
|
||||
#### Scenario: Usage is persisted to database on flush interval
|
||||
- **WHEN** 60 seconds elapse since the last flush
|
||||
- **THEN** all in-memory counters are written to the `usage_events` table and reset to zero
|
||||
|
||||
### Requirement: Free tier limits are enforced per tenant
|
||||
The system SHALL enforce free tier limits: 10 active agents maximum, 1,000 API calls per day. When a limit is exceeded, the offending request SHALL be rejected with HTTP 429 and a response body indicating which limit was reached and how to upgrade. Limit summaries SHALL be cached in Redis with a 60-second TTL.
|
||||
|
||||
#### Scenario: Agent registration blocked at free tier limit
|
||||
- **WHEN** a free-tier tenant with 10 active agents calls `POST /agents`
|
||||
- **THEN** the response is HTTP 429 with `{ "error": "free_tier_limit", "limit": "agents", "max": 10, "upgradeUrl": "..." }`
|
||||
|
||||
#### Scenario: API call blocked after daily limit
|
||||
- **WHEN** a free-tier tenant has made 1,000 API calls today and makes another request
|
||||
- **THEN** the response is HTTP 429 with `{ "error": "free_tier_limit", "limit": "api_calls", "max": 1000, "upgradeUrl": "..." }`
|
||||
|
||||
#### Scenario: Paid tenant is not rate limited by usage tiers
|
||||
- **WHEN** a paid-tier tenant exceeds free tier thresholds
|
||||
- **THEN** the request is processed normally with no usage-based rejection
|
||||
|
||||
### Requirement: Stripe Checkout initiates paid tier subscription
|
||||
The system SHALL expose `POST /billing/checkout` (authenticated) that creates a Stripe Checkout session for the paid tier plan and returns a `checkoutUrl`. The tenant is redirected to Stripe Checkout to complete payment. On success, Stripe sends a `customer.subscription.created` webhook event.
|
||||
|
||||
#### Scenario: Checkout session created
|
||||
- **WHEN** an authenticated tenant calls `POST /billing/checkout`
|
||||
- **THEN** the response is HTTP 200 with `{ "checkoutUrl": "https://checkout.stripe.com/..." }`
|
||||
|
||||
#### Scenario: Duplicate subscription prevented
|
||||
- **WHEN** a tenant with an active paid subscription calls `POST /billing/checkout`
|
||||
- **THEN** the response is HTTP 409 with `{ "error": "already_subscribed" }`
|
||||
|
||||
### Requirement: Stripe webhooks update tenant subscription state
|
||||
The system SHALL expose `POST /billing/webhook` (Stripe webhook endpoint) that verifies the `stripe-signature` header using `stripe.webhooks.constructEvent()` and processes: `customer.subscription.created` (set tenant to paid), `invoice.payment_succeeded` (extend subscription period), `customer.subscription.deleted` (revert tenant to free tier). All events without valid signatures SHALL be rejected with HTTP 400.
|
||||
|
||||
#### Scenario: Webhook without valid signature is rejected
|
||||
- **WHEN** `POST /billing/webhook` is called with an invalid or missing `stripe-signature` header
|
||||
- **THEN** the response is HTTP 400 and no state is changed
|
||||
|
||||
#### Scenario: Subscription created webhook activates paid tier
|
||||
- **WHEN** Stripe sends a valid `customer.subscription.created` event for a tenant
|
||||
- **THEN** the tenant's `subscriptionStatus` is updated to `active` and free tier limits no longer apply
|
||||
|
||||
#### Scenario: Subscription deleted webhook reverts to free tier
|
||||
- **WHEN** Stripe sends a valid `customer.subscription.deleted` event
|
||||
- **THEN** the tenant's `subscriptionStatus` is updated to `cancelled` and free tier limits are re-enforced
|
||||
|
||||
### Requirement: Billing is feature-flag gated
|
||||
All billing enforcement and Stripe integration SHALL be gated behind the `BILLING_ENABLED` environment variable. When `BILLING_ENABLED=false`, free tier limits are not enforced, all tenants have paid-tier access, and Stripe webhook endpoint returns HTTP 200 without processing. Usage metering continues regardless of this flag.
|
||||
|
||||
#### Scenario: Billing disabled — no limits enforced
|
||||
- **WHEN** `BILLING_ENABLED=false` and a free-tier tenant has 11 active agents
|
||||
- **THEN** agent registration succeeds without HTTP 429
|
||||
Reference in New Issue
Block a user