feat(gating): free vs Pro feature gating + Anthropic migration#24
Merged
PAMulligan merged 2 commits intoJul 21, 2026
Conversation
…ent-layer-and-feature-flag-system feat(entitlement): add client-side entitlement layer and feature-flag system
Implements the free/Pro split (closes #9), stacked on the #8 entitlement layer. AI provider migrated OpenAI -> Anthropic as part of the same change. Free/Pro matrix (docs/free-vs-pro-gating.md): - SEO scoring + score breakdown: fully free, never gated. - AI recommendations: free via a capped, server-metered hosted proxy; Pro gets a higher proxy cap or unlimited with their own key. - Advanced options, multi-language output, schema generation, and BYO key: Pro only. Every gate reads an entitlement-store flag (canUse*/isPro), never an ad-hoc apiKey check. Three AI paths (app/src/lib/ai.ts + entitlement-store useAiStatus): - byok: Pro + own Anthropic key -> browser->Anthropic directly, unlimited. - pro: Pro, no key -> hosted proxy authenticated by X-Optia-Entitlement. - free: not Pro -> hosted proxy metered by install id. A stored key only unlocks the direct path when isPro, so a free user can never self-serve uncapped AI. The BYO key never transits Optia's backend. Provider migration: - openai.ts -> anthropic.ts using @anthropic-ai/sdk (claude-opus-4-8, dangerouslyAllowBrowser); new ai-proxy.ts for POST /ai/generate; ai.ts facade routes + records server-authoritative quota. Storage key openai_api_key -> anthropic_api_key; dev CORS proxy and all UI labels updated to Anthropic. Quota is server-authoritative: /ai/generate returns quota {limit,remaining, period} which the client caches; on a server quota_exceeded the client drives remaining to 0 so the gate converges to a friendly upsell (no dead ends). Free users generate on demand (auto-generate only runs on the uncapped byok/pro paths) to conserve the monthly allowance. Note: the shipped backend meters a MONTHLY free allowance (not the daily cap the issue proposed); the client follows the backend. Tests: 411 passing. New coverage for the proxy client, the Anthropic direct client, the AI router (all three paths + locked + quota-exhaustion lock + metered-subject), the quota model, and free/Pro rendering of every gated surface (schema, multi-language, BYO-key, advanced options, and the scoring-stays-free guarantee). tsc + vite build + eslint all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PAMulligan
merged commit Jul 21, 2026
e9c737d
into
8-add-client-side-entitlement-layer-and-feature-flag-system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #9. Stacked on #8 (PR #23) — base is the
#8branch, so this diff shows only #9's work. Rebase ontomainonce #8 merges.Per the issue decision, this PR takes the full-build path: it wires every gate to the entitlement layer, builds the hosted free-tier AI proxy client, adds a server-metered free quota, and migrates the AI provider OpenAI → Anthropic.
Free/Pro matrix
Documented in
docs/free-vs-pro-gating.md. Every gate reads an entitlement-store flag (isPro/canUse*), never an ad-hocapiKeycheck.useCanUseAI/useAiStatuscanUseAdvancedOptionscanUseMultiLanguagecanUseSchemacanBringOwnKeyThree AI paths
useAiStatus()collapses provider + entitlement into one mode;ai.tsroutes accordingly:anthropic.ts,claude-opus-4-8), unlimited/unmetered.POST /ai/generatewithX-Optia-Entitlement.Invariants enforced: a stored key only unlocks the direct path when
isPro(a free user can never self-serve uncapped AI); the BYO key never transits Optia's backend; the server is the quota authority (client cachesquota.remaining, never mints it).Provider migration (OpenAI → Anthropic)
openai.ts→anthropic.tson@anthropic-ai/sdk; newai-proxy.ts(typed errors) andai.tsfacade; storage keyopenai_api_key→anthropic_api_key; dev CORS proxy and all UI copy updated to Anthropic.Notable decisions
optia-backend/ai/generate) meters a monthly free allowance; the client follows the backend rather than the issue's proposed daily cap.byok/propaths, so a single analysis doesn't drain a free user's monthly allowance.{checkId, keyword, context}.claude-opus-4-8(Anthropic default). ChangeAI_MODELinanthropic.tsfor a cheaper tier.Review
An adversarial review (13 agents: 4 dimension-finders + per-finding skeptics) confirmed 8 findings; all are fixed in this PR:
quota_exceedednow drives cached remaining to 0 so the gate converges to the upsell (no error-toast loop)./v1/v1/double-prefix that broke BYO-key in the browser preview.generate-allquota writes reconcile conservatively (lowest remaining per period).Acceptance criteria
docs/free-vs-pro-gating.md)canUseAI/aiQuotaRemainingfrom the entitlement layerTest plan
pnpm test— 411 passing across 24 files, incl. the proxy client, the Anthropic direct client, the AI router (all three paths + locked + quota-exhaustion lock + metered-subject), the quota model, and free/Pro rendering of every gated surface.pnpm build(tsc+vite) andpnpm lint— clean.🤖 Generated with Claude Code