AI chatbot SaaS for Georgian small & medium businesses. Answers visitor questions in Georgian, English and Russian, 24 / 7, on website widgets, Telegram, Instagram and Facebook Messenger β captures every lead while you sleep.
Peit is a multi-tenant SaaS that lets a Georgian business stand up a production-ready AI assistant in under 10 minutes: paste a website URL, the platform crawls and chunks it, embeds the content with Voyage AI, and serves answers grounded in that knowledge base via Claude Haiku 4.5.
End customers get an embeddable chat widget for their own site. The owner gets a dashboard with conversation analytics, a Kanban-style lead inbox (cold / warm / hot scoring), a CSV exporter, a Lemon-Squeezy-backed billing portal, and full GDPR self-service (data export + account deletion).
| Area | What's inside |
|---|---|
| Retrieval-augmented AI | Voyage voyage-3 embeddings (1024 dim) β pgvector HNSW search β Claude Haiku 4.5 with prompt caching + SSE streaming. Token usage metered per subscription. |
| Multi-channel widget | Shadow-DOM IIFE loader at /widget.js, allowlist-based origin enforcement, per-IP / per-bot / per-visitor rate limiting on every public endpoint. |
| Lead capture | GDPR-compliant collection (explicit consent + audit trail), rule-based scoring (cold / warm / hot), strict email validation, dashboard with filters / search / CSV export. |
| Payments | Lemon Squeezy as Merchant of Record (handles global VAT). HMAC-verified webhooks drive plan changes, period rollover, dunning. Auto-resume checkout after sign-up. |
| Resend transactional pipeline with welcome / lead-alert / trial-ending / trial-ended / receipt / cancelled / payment-failed templates, all in KA / EN / RU, HMAC-signed one-click unsubscribe per RFC 8058. | |
| Legal & GDPR | /terms, /privacy, /gdpr (DPA), /cookies rendered from a single i18n-backed component. Granular cookie consent banner. GET /api/me/export for Art. 15+20, POST /api/me/delete for Art. 17 (Clerk + DB cascade). |
| Observability | /api/health liveness + readiness, daily Vercel cron at 09:00 UTC for trial reminders. |
| i18n | Full Georgian-first localisation with English & Russian throughout the marketing site, dashboard, widget, and every email template. |
| SEO | Dynamic sitemap & robots, OG tags & JSON-LD schema for Organization + SoftwareApplication, 8 statically-generated industry landing pages, 3 competitor-alternative pages. |
- Next.js 16 (App Router, Server Components, dynamic + static routes)
- TypeScript 5 strict mode
- Tailwind CSS v4 + Lucide icons
- Clerk for auth (email / Google OAuth, password reset, session management)
- Drizzle ORM on Postgres (Neon / Supabase) with the
vectorextension - Anthropic Claude Haiku 4.5 for grounded answer generation
- Voyage AI for document + query embeddings
- Lemon Squeezy as Merchant of Record for billing
- Resend for transactional email
- Vercel for hosting + cron + edge runtime
peit/
βββ drizzle/ # SQL migrations (sequential, applied via db:init)
βββ public/ # Static assets, favicons, OG image
βββ scripts/ # One-shot CLIs (db init, migration helpers)
βββ src/
β βββ app/ # Next.js App Router
β β βββ api/
β β β βββ bots/ # Bot CRUD (+ migrate localStorage β cloud)
β β β βββ cron/ # Vercel-cron-protected jobs
β β β β βββ trial-reminders/ # Daily trial-ending + trial-ended emails
β β β βββ health/ # Liveness + readiness probe
β β β βββ leads/ # Lead listing, status update, CSV export
β β β βββ lemon/ # Checkout + customer-portal
β β β βββ me/ # Profile, email-preferences, export, delete
β β β βββ unsubscribe/ # HMAC one-click email opt-out
β β β βββ webhooks/lemon/ # Lemon Squeezy event sink
β β β βββ widget/[id]/ # Public widget endpoints (config / message / stream / lead)
β β βββ dashboard/ # Authed user surface (bots, leads, billing, privacy)
β β βββ industries/[slug]/ # 8 SEO landing pages
β β βββ alternatives/[slug]/ # vs-competitor comparison pages
β β βββ (legal) # /terms, /privacy, /gdpr, /cookies
β β βββ robots.ts # Dynamic robots.txt
β β βββ sitemap.ts # Dynamic sitemap.xml
β β βββ widget.js/ # Public IIFE loader served at /widget.js
β βββ components/ # UI components (Hero, ChatWidget, CookieConsent, β¦)
β βββ context/ # React contexts (Language, Bots)
β βββ db/ # Drizzle schema + query modules
β βββ lib/
β β βββ email/ # Resend client, layout, i18n, unsubscribe HMAC
β β βββ answer-engine.ts # 4-tier retrieval (FAQ β RAG β keyword β fallback)
β β βββ claude.ts # Anthropic SDK wrapper, streaming, prompt caching
β β βββ embeddings.ts # Voyage AI client
β β βββ lemon*.ts # Lemon Squeezy client + plan mapping
β β βββ plan-limits.ts # Single source of truth for tier limits
β βββ middleware.ts # Clerk auth + CSP frame-ancestors for widget pages
βββ .env.example # Documented env var template
βββ vercel.json # Vercel cron schedule
βββ drizzle.config.ts # Drizzle Kit config (db push / generate / migrate)
- Node.js 20+
- A Postgres database with the
vectorextension. Easiest: a free Neon project, which ships pgvector ready-to-use. - A Clerk project (free tier is enough for development).
git clone https://github.com/tornikepe/peit.git
cd peit
cp .env.example .env.local
npm install
npm run db:init # applies all migrations from ./drizzle to DATABASE_URL
npm run devOpen http://localhost:3000.
.env.example documents every variable β only Clerk + Postgres are strictly
required to boot. The AI, email and payment integrations all have graceful
fallbacks so you can develop locally without paying anyone.
| Command | What it does |
|---|---|
npm run dev |
Next.js dev server at :3000 |
npm run build |
Production build (TypeScript + lint enforced) |
npm run lint |
ESLint on the whole src/ tree |
npm run db:generate |
Diff schema.ts β new SQL migration file |
npm run db:push |
Apply schema.ts directly (good for dev, dangerous in prod) |
npm run db:init |
Apply every file in ./drizzle/*.sql sequentially (use this in prod) |
npm run db:studio |
Drizzle Studio data explorer |
Every visitor question runs through src/lib/answer-engine.ts:
- FAQ exact match β instant, no AI cost.
- RAG with Claude β embed query β pgvector HNSW search β top-5 chunks β Claude generates grounded reply. Streams over SSE.
- Keyword search β fallback when embeddings / Claude aren't configured.
- Static fallback message in the bot's primary language.
Each tier degrades cleanly on missing keys (ANTHROPIC_API_KEY, VOYAGE_API_KEY),
so a deployment without those still serves keyword answers instead of crashing.
Customers paste a single <script> tag:
<script src="https://peit.ge/widget.js" data-bot-id="..." defer></script>src/app/widget.js/route.ts returns an IIFE
that mounts a closed Shadow DOM, fetches the bot config from
/api/widget/<id>/config, and renders the chat iframe pointed at
/widget/<id> (server-rendered, no client-side JS bundle download from the
customer's site). Each public endpoint is rate-limited per IP, per visitor,
per bot β see src/lib/rate-limit.ts.
- Checkout URL is generated server-side by
POST /api/lemon/checkout. - All subscription state derives from Lemon Squeezy webhooks via
src/app/api/webhooks/lemon/route.tsβ HMAC-verified, idempotent. - Period rollover resets
messagesThisPeriodand token usage counters atomically insrc/db/queries/subscriptions.ts. - Trial flow: 7-day trial on signup β
trialingstatus β reminder at T-3 days (cron) βpast_dueat T+0 β "trial ended" email (cron) β user upgrades via portal or cancellation.
src/lib/email/ is the entire transactional layer:
send.tsβ Resend client,escapeHtml, RFC-8058List-Unsubscribeheaders.layout.tsβ shared HTML wrapper (Gmail / Apple Mail / Outlook safe).i18n.tsβ every string in KA / EN / RU.unsubscribe.tsβ HMAC-signed stateless tokens for one-click opt-out.index.tsβ 6 public senders (welcome, lead alert, trial-ending, trial-ended, receipt, cancelled, payment-failed).
All senders honour the recipient's per-category EmailPrefs and locale.
Billing emails are transactional and bypass marketing opt-out (legally must).
The intended host is Vercel. The included vercel.json already declares
the daily trial-reminder cron. Set every variable from .env.example in
the Vercel project, then connect the repo β every push to master deploys
to production.
- Provision Postgres (Neon recommended) with the
vectorextension enabled. - Run
npm run db:initagainst the productionDATABASE_URL. - Create a Clerk Production instance (separate from dev) and copy
the
pk_live_β¦/sk_live_β¦keys into Vercel. - Set
NEXT_PUBLIC_APP_URLto your live domain (e.g.https://peit.ge). - Lemon Squeezy: create the product, copy each variant ID into
LEMONSQUEEZY_VARIANT_BASIC|PRO|ULTIMATE, point the webhook at/api/webhooks/lemonwith the same secret asLEMONSQUEEZY_WEBHOOK_SECRET. - Resend: verify your sending domain, set
RESEND_API_KEYandRESEND_FROM=Peit Team <hi@peit.ge>. - Generate a long random
UNSUBSCRIBE_SECRETandCRON_SECRET. - Configure Vercel cron in the project settings (the schedule lives
in
vercel.jsonand applies automatically β but cron must be enabled on your Vercel plan). - Point an uptime monitor at
https://your-domain/api/health.
- Wire Sentry to capture unhandled exceptions (
SENTRY_DSN). - Point Vercel Analytics or PostHog at the site for funnel analysis.
- Generate a Vercel-friendly OG image (
public/og-image.png, 1200Γ630). - Set up Cloudflare in front of Vercel for DDoS protection if you expect large bursts.
- GDPR Art. 15 & 20 β
GET /api/me/exportstreams a JSON dump of every row we hold for the authenticated user (bots, FAQs, chunks, conversations, messages, leads, subscription). Vector embeddings are intentionally omitted (they're derivative). - GDPR Art. 17 β
POST /api/me/deletedeletes the Clerk user then cascade-deletes the local row, taking every owned object with it. Confirmation gate ({ "confirm": "DELETE" }) protects against CSRF. - GDPR Art. 7 (consent) β Cookie banner with granular categories
(necessary / functional / analytics), persisted in
localStorage. - DPA β Public Data Processing Agreement at
/gdprlisting every sub-processor (Clerk, Vercel, Lemon Squeezy, Anthropic, Voyage, Resend, Postgres host) and the SCC basis for international transfers. - Webhook integrity β Lemon Squeezy events verified via
crypto.timingSafeEqualon HMAC-SHA256 of the raw body. - Rate limiting β atomic UPSERT counter
(
src/lib/rate-limit.ts) across per-IP, per-bot, per-visitor windows on every public endpoint.
This is a closed-source SaaS at the moment, but PRs that fix bugs or
improve docs are welcome. Please run npm run lint && npm run build
before opening a PR β CI rejects anything that fails either check.
MIT β see the LICENSE file for details.
Made in Tbilisi π¬πͺ β questions? info@peit.ge