No description
Find a file
dmitry.galkin b5c399257f checkout: omit customerEmail when user has guest-style email
Stripe rejects emails like 'guest-1779719735974' with 400 email_invalid.
Falling back to no email lets Stripe collect it on the checkout page itself,
which is the standard flow for unauthenticated upgrades.
2026-05-25 18:36:12 +04:00
.vscode Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
app checkout: omit customerEmail when user has guest-style email 2026-05-25 18:36:12 +04:00
components Pass data-host-url to Umami script for cross-origin collect endpoint 2026-05-25 17:29:04 +04:00
hooks Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
lib Add Umami analytics, subscription tiers, tool-call metering 2026-05-25 17:27:08 +04:00
public Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
.dockerignore Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
.env.example Add Umami analytics, subscription tiers, tool-call metering 2026-05-25 17:27:08 +04:00
.gitignore Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
biome.jsonc Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
components.json Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
docker-entrypoint.sh Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
Dockerfile Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
drizzle.config.ts Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
LICENSE Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
next.config.ts Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
package.json Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
pnpm-lock.yaml Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
postcss.config.mjs Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00
proxy.ts Add Umami analytics, subscription tiers, tool-call metering 2026-05-25 17:27:08 +04:00
README.md Add Umami analytics, subscription tiers, tool-call metering 2026-05-25 17:27:08 +04:00
tsconfig.json Initial commit: EGBE chatbot template 2026-05-25 14:54:04 +04:00

EGBE Chatbot Template

Next.js chatbot wired to the EGBE infra. Based on vercel/chatbot (Apache 2.0).

What's wired

  • AI via @ai-sdk/openai-compatibleEGBE_AI_API_URL (LiteLLM proxy)
  • Auth — NextAuth credentials + guest mode
  • DB — Drizzle ORM + Postgres (provisioned by app-deploy.sh)
  • Analytics — Umami <Script> mounted when NEXT_PUBLIC_UMAMI_* env are set
  • Subscriptions — Free / Pro tiers, daily quotas, tool-call metering, real Stripe checkout via the EGBE payment gateway

Models (via LiteLLM)

gpt-5.4-mini (default), gpt-5.4, claude-sonnet, claude-haiku, kimi-k2.6, minimax-m2.7, qwen3-coder. Edit lib/ai/models.ts.

Subscription model

Two tiers (see lib/subscription/config.ts):

Tier Messages / day Tool calls / day
Free 10 5
Pro 1000 500
  • Message limit — enforced in app/(chat)/api/chat/route.ts via checkAndConsume(userId, "chat_message") before streamText.
  • Tool limitgetWeather is wrapped with withLimit(tool, "tool_call", userId) (see lib/ai/tools/with-limit.ts). Every tool call deducts 1 unit; if quota is hit the tool returns { error: "limit_exceeded", ... } which the model sees and explains to the user.
  • Quota badge<UsageBadge /> in the chat header polls /api/usage every 15s.
  • Upgrade flow/pricing → POST /api/billing/checkout → redirect to Stripe → webhook at /api/billing/webhook flips the user's tier on checkout.session.completed.

To add a new tool with metering, just wrap it the same way:

const meteredFoo = withLimit(myFooTool, "tool_call", session.user.id);

To add a new limit kind, edit lib/subscription/config.ts (LimitKey, LIMITS) and lib/subscription/service.ts.

Deploy (from inside an OpenClaw instance)

# 1. provision Umami site (optional — chatbot works without analytics)
${SKILLS_DIR}/../analytics/scripts/analytics-site-create.sh chatbot chatbot.${EGBE_INSTANCE_PUBLIC_ID}.p.egbe.app "Chatbot"

# 2. (optional) create a Stripe product + price for the Pro plan
#    Without PRO_STRIPE_PRICE_ID the upgrade button returns 501.
curl -s -H "Authorization: Bearer ${EGBE_GATEWAYS_TOKEN}" -H "Content-Type: application/json" \
  -d '{"name":"Chatbot Pro"}' "${EGBE_PAYMENT_GATEWAY_URL}/v1/products"
# then create a price referencing the returned product id, copy the price id

# 3. deploy
APP_ENV_JSON='{"AUTH_SECRET":"'$(openssl rand -base64 32)'","PRO_STRIPE_PRICE_ID":"price_..."}' \
  ${SKILLS_DIR}/scripts/app-deploy.sh chatbot chatbot-template

app-deploy.sh auto-injects: DATABASE_URL, EGBE_AI_API_*, NEXT_PUBLIC_BASE_URL, NEXT_PUBLIC_UMAMI_*, EGBE_PAYMENT_GATEWAY_*, EGBE_GATEWAYS_TOKEN. You pass AUTH_SECRET and PRO_STRIPE_PRICE_ID (if billing is desired) via APP_ENV_JSON.

Local dev

cp .env.example .env.local
# fill in DATABASE_URL, EGBE_AI_API_KEY, AUTH_SECRET
pnpm install
pnpm db:migrate
pnpm dev

License

Apache 2.0 — derivative work of Vercel, Inc.'s chatbot.