feat: tiered LLM (GLM free / Claude paid) + rate limits + quota enforcement
All checks were successful
Deploy to Production / deploy (push) Successful in 53s

The free tier was hemorrhaging Anthropic cost with no abuse cap (no rate
limit on /preview, Opus default in the build worker, 5-min cache TTL that
made cache-miss the common case). This switches free users to GLM, paid
users to Claude tiers, and tightens every leak found in the audit.

Backend:
- @bmm/llm: GLM provider via Zhipu's OpenAI-compatible endpoint, pickPreviewModel
  + pickBuildModel helpers, plan-aware ModelChoice
- preview-cache TTL 5min -> 24h (kills the cache-miss path)
- /v1/servers/preview: picks model from caller's plan, returns model name to UI
- /v1/servers POST: enforces SERVER_LIMITS per plan (402), rate-limits builds
- daily rate-limit on preview (5/40/150/1000) and build (3/20/100/500)
- /v1/auth/me returns plan so the wizard can show the right model name
- generator worker: GLM default, Anthropic Sonnet fallback if GLM errors

Frontend:
- Wizard fetches plan, shows "<model> is drafting the tool spec" pre-emptively,
  upgrade hint for hobby users, friendly errors for 402 / 429
- Pricing page: AI-model line per tier (Open-tier / Haiku / Sonnet / Opus),
  Team €149 -> €199, Enterprise €499 -> €999, daily-preview limit per tier
- Privacy + Security: explicit subprocessor disclosure for Anthropic (US) /
  Zhipu (CN) and which tier uses which

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marco Sadjadi
2026-05-23 23:50:00 +02:00
parent 66128c73d8
commit bc174c1302
14 changed files with 537 additions and 58 deletions

View File

@@ -14,9 +14,12 @@ const TIERS = [
price: '€0',
tag: 'Forever free',
description: 'For trying things out and shipping single-user tools.',
model: 'Open-tier AI',
modelDetail: 'Free-tier model · ~30-60s analyze',
features: [
'1 MCP server',
'100,000 tool calls / month',
'5 prompt analyses / day',
'BuildMyMCP subdomain',
'Community support',
],
@@ -28,9 +31,12 @@ const TIERS = [
price: '€49',
tag: '/ month',
description: 'For solo founders and small teams shipping production tools.',
model: 'Claude Haiku 4.5',
modelDetail: 'Anthropic · ~10-20s analyze',
features: [
'5 MCP servers',
'1M tool calls / month',
'40 prompt analyses / day',
'Custom domain',
'Priority build queue',
'Email support, 1 business-day SLA',
@@ -41,12 +47,15 @@ const TIERS = [
},
{
name: 'Team',
price: '€149',
price: '€199',
tag: '/ month',
description: 'For teams with RBAC, audit, and 99.9% SLA needs.',
model: 'Claude Sonnet 4.6',
modelDetail: "Anthropic's flagship",
features: [
'25 MCP servers',
'10M tool calls / month',
'150 prompt analyses / day',
'RBAC + extended audit log',
'99.9% uptime SLA',
'Shared Slack channel support',
@@ -56,9 +65,11 @@ const TIERS = [
},
{
name: 'Enterprise',
price: '€499+',
price: '€999+',
tag: '/ month',
description: 'For organizations bringing their own cloud, SSO and dedicated infra.',
model: 'Sonnet + Opus on build',
modelDetail: 'EU data-residency option',
features: [
'Unlimited servers',
'BYOC (AWS, GCP, Azure, Hetzner)',
@@ -122,6 +133,13 @@ export default function Pricing() {
<p className="mt-2 text-[12px] leading-relaxed text-[--color-fg-muted]">
{t.description}
</p>
<div className="mt-3 rounded-md border border-[--color-border] bg-[--color-bg-subtle] px-2.5 py-1.5">
<div className="text-[10.5px] uppercase tracking-wider text-[--color-fg-subtle]">
AI model
</div>
<div className="mt-0.5 text-[12.5px] font-medium text-[--color-fg]">{t.model}</div>
<div className="text-[10.5px] text-[--color-fg-subtle]">{t.modelDetail}</div>
</div>
<ul className="mt-4 space-y-1.5 text-[12.5px] text-[--color-fg-muted]">
{t.features.map((f) => (
<li key={f}> {f}</li>

View File

@@ -36,11 +36,21 @@ const SECTIONS = [
{
h: 'Subprocessors',
p: [
"Anthropic (generation) — only the prompt text you send. Anthropic's data-retention policy applies.",
'Hetzner (compute).',
'Backblaze (encrypted backups).',
'Stripe (billing).',
'Cloudflare (DNS + DDoS).',
"Anthropic, USA (Claude AI — used for prompt analysis and code generation on Pro / Team / Enterprise tiers). Only the prompt text and resulting spec are sent. Anthropic's data-retention policy applies.",
'Zhipu AI, China (GLM model — used for prompt analysis on the free Hobby tier only). Only the prompt text and resulting spec are sent. Upgrade to a paid tier to keep all AI processing within Anthropic (US).',
'Hetzner, Germany (compute).',
'Backblaze, EU (encrypted backups).',
'Stripe, Ireland (billing).',
'Cloudflare (DNS + DDoS protection).',
],
},
{
h: 'AI processing per tier',
p: [
'Hobby (free): prompts are sent to Zhipu AI (GLM, China) for analysis. Choose a paid tier if your prompts contain data that must not leave the EU/US.',
'Pro: prompts are sent to Anthropic (Claude Haiku 4.5, USA).',
'Team: prompts are sent to Anthropic (Claude Sonnet 4.6, USA).',
'Enterprise: Anthropic (Claude Sonnet + Opus, USA) with EU-data-residency opt-in available on request.',
],
},
{

View File

@@ -40,7 +40,11 @@ const PILLARS = [
},
{
title: 'Rate limiting',
body: 'Default 100 requests/min/IP per tool, enforced at the Traefik layer before traffic ever reaches your container.',
body: 'Default 100 requests/min/IP per tool, enforced at the Traefik layer before traffic ever reaches your container. Daily preview + build caps per tier protect against runaway LLM spend.',
},
{
title: 'AI provider by tier — transparent',
body: "Hobby (free) tier uses Zhipu's GLM model (servers in China) for prompt analysis — chosen for cost so we can offer a real free tier. Pro, Team and Enterprise use Anthropic Claude (US). Enterprise can request EU-only data residency. The provider is shown live in the wizard so you always know where your prompt is going.",
},
];