mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 18:37:24 +00:00
Billing Worker:
- trials + trial_claims (migration 0005): 2 sandbox hours per new team, no card, no Stripe.
- POST /v1/billing/trial grants it (idempotent, any member); grantTrial/trialOffer exported for
the setup session. offers.trial on GET entitlements only when this caller could still claim it.
- Abuse limits: once per team, Orca user, normalized verified email, GitHub user (token claim)
and GitHub owner (POST /v1/internal/trial/github from the binding; a reused identity revokes),
disposable-domain blocklist, 3 grants per IP per day. Keys stored as SHA-256 hashes.
- Entitlement trial {includedSeconds, usedSeconds, remainingSeconds, exhausted}; metered from
usage_events, concurrency 1, never overage; trial_used_up (suspendRunning) / trial_unavailable.
- Any subscription ends the trial; unused trial hours lapse.
- e2e: trial path (grant, no Stripe customer, concurrency, metering to used up, once per user,
plan ends it) with cleanup of the run's abuse keys.
Desktop: trial_used_up / trial_unavailable classify as 'plan'; copy in billing, phone and CLI;
"Trial" badge, TrialPlanSummary in Plan & billing and the plans page strip, account menu row
"Trial · {{count}} sandbox hours left" (Choose plan for owners/admins); billingClaimTrial IPC
and claimOrcaCloudTrial() for the composer.
32 lines
1.4 KiB
SQL
32 lines
1.4 KiB
SQL
-- One-time trial (N11, O7): 2 sandbox hours per new team, no card, granted once per team and
|
|
-- once per user, verified email, GitHub user and GitHub owner. A subscription on the account ends
|
|
-- it (entitlements.ts ignores the trial once any subscription row exists). Times are epoch ms.
|
|
CREATE TABLE trials (
|
|
account_id TEXT PRIMARY KEY,
|
|
granted_at INTEGER NOT NULL,
|
|
included_seconds INTEGER NOT NULL DEFAULT 7200,
|
|
-- Cache of SUM(usage_events.weighted_seconds) with no subscription (period_start IS NULL).
|
|
used_seconds INTEGER NOT NULL DEFAULT 0,
|
|
exhausted_at INTEGER,
|
|
granted_by_user TEXT NOT NULL,
|
|
github_owner_id TEXT,
|
|
github_user_id TEXT,
|
|
-- Set when a later check (GitHub binding) finds the same GitHub user/owner already used a trial.
|
|
revoked_at INTEGER,
|
|
revoked_reason TEXT
|
|
);
|
|
|
|
-- Abuse keys. kind: 'user' | 'email' | 'github_user' | 'github_owner' | 'ip'. key_hash is SHA-256
|
|
-- of the normalized value, so raw emails and IPs are never stored. granted = 1 once the key is
|
|
-- consumed by a granted trial (0 = seen on the account before a grant, e.g. a GitHub binding).
|
|
CREATE TABLE trial_claims (
|
|
kind TEXT NOT NULL,
|
|
key_hash TEXT NOT NULL,
|
|
account_id TEXT NOT NULL,
|
|
granted INTEGER NOT NULL DEFAULT 1,
|
|
created_at INTEGER NOT NULL,
|
|
PRIMARY KEY (kind, key_hash, account_id)
|
|
);
|
|
CREATE INDEX trial_claims_account ON trial_claims(account_id);
|
|
CREATE INDEX trial_claims_recent ON trial_claims(kind, key_hash, created_at);
|