From 22a172e92db012be3c176697ce32f9f3f7487270 Mon Sep 17 00:00:00 2001 From: "dmitry.galkin" Date: Mon, 25 May 2026 17:27:08 +0400 Subject: [PATCH] Add Umami analytics, subscription tiers, tool-call metering - Analytics: in root layout loads umami when NEXT_PUBLIC_UMAMI_* env are set - Subscription: free/pro tiers in Postgres, daily quotas (10msg/5tool free, 1000/500 pro) - Chat route: checkAndConsume(chat_message) gate before streamText, 429 when exhausted - Tool metering: getWeather wrapped with withLimit decorator that deducts tool_call quota - Pricing page at /pricing with upgrade button - /api/billing/checkout posts to EGBE payment gateway, /api/billing/webhook verifies HMAC and upgrades user on checkout.session.completed - UsageBadge in chat header polls /api/usage every 15s - Dropped now-unused entitlements.ts --- .env.example | 22 +- README.md | 75 +-- app/(chat)/api/billing/checkout/route.ts | 41 ++ app/(chat)/api/billing/webhook/route.ts | 99 ++++ app/(chat)/api/chat/route.ts | 41 +- app/(chat)/api/usage/route.ts | 16 + app/layout.tsx | 2 + app/pricing/page.tsx | 96 ++++ components/analytics.tsx | 20 + components/chat/chat-header.tsx | 28 +- components/chat/usage-badge.tsx | 44 ++ components/pricing-client.tsx | 48 ++ lib/ai/entitlements.ts | 14 - lib/ai/models.ts | 2 +- lib/ai/tools/with-limit.ts | 40 ++ lib/billing/gateway.ts | 105 +++++ .../migrations/0001_even_baron_strucker.sql | 37 ++ lib/db/migrations/meta/0001_snapshot.json | 435 ++++++++++++++++++ lib/db/migrations/meta/_journal.json | 7 + lib/db/schema.ts | 47 ++ lib/subscription/config.ts | 27 ++ lib/subscription/service.ts | 210 +++++++++ proxy.ts | 4 + 23 files changed, 1374 insertions(+), 86 deletions(-) create mode 100644 app/(chat)/api/billing/checkout/route.ts create mode 100644 app/(chat)/api/billing/webhook/route.ts create mode 100644 app/(chat)/api/usage/route.ts create mode 100644 app/pricing/page.tsx create mode 100644 components/analytics.tsx create mode 100644 components/chat/usage-badge.tsx create mode 100644 components/pricing-client.tsx delete mode 100644 lib/ai/entitlements.ts create mode 100644 lib/ai/tools/with-limit.ts create mode 100644 lib/billing/gateway.ts create mode 100644 lib/db/migrations/0001_even_baron_strucker.sql create mode 100644 lib/db/migrations/meta/0001_snapshot.json create mode 100644 lib/subscription/config.ts create mode 100644 lib/subscription/service.ts diff --git a/.env.example b/.env.example index 73adfe5..50bec30 100644 --- a/.env.example +++ b/.env.example @@ -5,8 +5,28 @@ AUTH_SECRET=replace-me DATABASE_URL=postgres://user:pass@host:5432/db # EGBE LiteLLM proxy — auto-injected by app-deploy.sh from the deploying instance -EGBE_AI_API_URL=https://proxy.gcp.egbe.dev/v1 +EGBE_AI_API_URL=https://litellm.gcp.egbe.dev EGBE_AI_API_KEY= # Public origin of this app — auto-injected by app-deploy.sh NEXT_PUBLIC_BASE_URL=http://localhost:3000 + +# --- analytics (umami) --- +# Auto-injected by app-deploy.sh after `analytics-site-create.sh ""` +NEXT_PUBLIC_UMAMI_SCRIPT_URL= +NEXT_PUBLIC_UMAMI_WEBSITE_ID= + +# --- billing (payment gateway) --- +# Auto-injected by app-deploy.sh from the deploying instance +EGBE_PAYMENT_GATEWAY_URL=https://payments.gcp.egbe.dev +EGBE_GATEWAYS_TOKEN= +EGBE_PAYMENT_GATEWAY_WEBHOOK_SECRET= +EGBE_PAYMENT_GATEWAY_WEBHOOK_HEADER=x-egbe-payment-signature + +# Stripe price ID for the Pro plan — set per-product after creating the product via +# the payment gateway API. Without it the upgrade button returns 501. +PRO_STRIPE_PRICE_ID= + +# App slug used in the webhook URL when creating checkout sessions. Must match the +# slug you passed to app-deploy.sh. +APP_SLUG=chatbot diff --git a/README.md b/README.md index f164e63..14cc904 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,59 @@ # EGBE Chatbot Template -Next.js chatbot wired to the EGBE LiteLLM proxy. Based on [vercel/chatbot](https://github.com/vercel/chatbot) (Apache 2.0), stripped of Vercel-specific bits and rewired for our infra. +Next.js chatbot wired to the EGBE infra. Based on [vercel/chatbot](https://github.com/vercel/chatbot) (Apache 2.0). -## Stack +## What's wired -- **Next.js 16** (App Router, standalone output) -- **AI SDK** + `@ai-sdk/openai-compatible` → routes to `EGBE_AI_API_URL` (our LiteLLM) -- **NextAuth** (credentials + guest) -- **Drizzle ORM** + Postgres (DB gateway) -- **shadcn/ui** + Tailwind +- **AI** via `@ai-sdk/openai-compatible` → `EGBE_AI_API_URL` (LiteLLM proxy) +- **Auth** — NextAuth credentials + guest mode +- **DB** — Drizzle ORM + Postgres (provisioned by app-deploy.sh) +- **Analytics** — Umami `