Synaplan
Open-source AI platform for companies: self-hosted AI agents, GDPR-compliant chatbot widget, RAG knowledge base, WhatsApp and Outlook AI, MCP, multi-model routing. Docker, Kubernetes or hosted in Germ
AI-powered CRM that scores every lead, surfaces the ones ready to buy, and automates the follow-up — so your team only chases deals that actually close.
BusinessGitHub @murtaza008OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗An AI-powered CRM that scores every lead 0–100, tells your reps who to call today, and schedules the follow-ups for them.
Live demo: https://lead-flow-ai-six.vercel.app/ — click Try demo to explore a fully seeded workspace without signing up, or sign up with any email to start your own.
LeadFlow AI is a multi-tenant sales CRM. Add leads, and Google Gemini scores each one on how likely it is to close, explains why, writes a next-best-action from the lead's activity history, and picks the handful of leads worth a rep's time today. A drag-and-drop pipeline, rule-based follow-up automation, analytics, team workspaces and Stripe billing round it out.
The whole stack runs on free tiers: Neon Postgres, the Gemini API free key, Vercel Hobby, and Stripe test mode, which you can skip entirely (billing then runs in demo mode).
| Area | What you get |
|---|---|
| Dashboard | Stat cards (hot leads, open pipeline value, average score, win rate), an AI "Focus today" digest, and a priority-leads list |
| Leads | Searchable lead table with stage filter; add leads (name, company, title, email, phone, source, deal value, notes) |
| Lead profile | AI score badge with priority (Hot / Warm / Cold) and reasons, Score / Re-score with AI, AI customer insight + next action, edit details and owner, stage selector, activity timeline, log notes / emails / calls, linked follow-ups, delete |
| Pipeline | Drag-and-drop kanban (@dnd-kit) across New → Contacted → Qualified → Won / Lost; moving a card triggers automations |
| Follow-ups | Every follow-up in the workspace grouped into Overdue / Upcoming / Done, tick to complete |
| Analytics | Stage funnel (count and value), lead-source mix, score distribution, 8-week created-vs-won trend, totals and win rate (Recharts) |
| Team | Member list with roles (Owner / Admin / Member), invite by email with a role |
| Billing | Starter (free) / Team ($79) / Agency ($199) plans via Stripe Checkout + Customer Portal, or instant demo mode with no Stripe keys |
| Settings | Workspace name and brand colour |
| Marketing site | Landing page with hero, feature cards, before/after, social proof, pricing, FAQ and CTA, animated with motion |
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, Route Handlers, proxy.ts), React 19, TypeScript 5 |
| Styling | Tailwind CSS v4, Radix UI primitives, class-variance-authority, motion, lucide-react, sonner toasts |
| Database | Neon serverless Postgres, Prisma 7 via @prisma/adapter-neon (WebSocket driver) |
| Auth | Auth.js (NextAuth v5), Credentials provider, bcrypt (12 rounds), JWT sessions |
| AI | Vercel AI SDK (ai, @ai-sdk/google), Gemini gemini-flash-latest, structured output with generateObject + zod |
| Data fetching | TanStack Query against the app's own Route Handlers |
| Charts / DnD | Recharts, @dnd-kit/core |
| Payments | Stripe Checkout, Billing Portal and webhooks (test mode), with a demo-mode fallback |
git clone <this-repo-url> leadflow-ai
cd leadflow-ai
npm install # also runs `prisma generate` (postinstall)
.envCreate a .env file in the project root (see Environment variables
for every key):
# Neon → Connect → copy the pooled connection string
DATABASE_URL="postgresql://user:[email protected]/neondb?sslmode=require"
# openssl rand -base64 32
NEXTAUTH_SECRET="replace-with-a-random-secret"
NEXTAUTH_URL="http://localhost:3000"
# https://aistudio.google.com/apikey (free)
GOOGLE_GENERATIVE_AI_API_KEY=""
# Optional: leave blank for demo billing mode
STRIPE_SECRET_KEY=""
STRIPE_WEBHOOK_SECRET=""
STRIPE_PRICE_TEAM=""
STRIPE_PRICE_AGENCY=""
NEXT_PUBLIC_APP_URL="http://localhost:3000"
Without GOOGLE_GENERATIVE_AI_API_KEY everything else still works; the AI
score, insight and focus features return a clear "AI is not configured" message
instead of crashing.
The repo ships a Prisma migration (prisma/migrations/…_init). Apply it:
npx prisma migrate deploy
npm run dev
Open http://localhost:3000, sign up, name your workspace on the onboarding screen, and add your first lead. Open the lead and click Score with AI to run Gemini on it.
| Script | What it does |
|---|---|
npm run dev | Dev server on http://localhost:3000 |
npm run build | prisma migrate deploy && next build (applies pending migrations first) |
npm start | Serve the production build |
npm run lint | ESLint |
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL | yes | Neon Postgres connection string (pooled is fine; the app uses Neon's serverless driver) |
NEXTAUTH_SECRET | yes | Signs session JWTs. AUTH_SECRET works too (Auth.js v5 reads either) |
NEXTAUTH_URL | no | Local base URL. Not needed on Vercel, where Auth.js trusts the host |
GOOGLE_GENERATIVE_AI_API_KEY | recommended | Enables lead scoring, insights and the daily focus digest |
NEXT_PUBLIC_APP_URL | for Stripe | Base URL for Stripe Checkout / Portal redirects (defaults to http://localhost:3000) |
STRIPE_SECRET_KEY | no | Turns on real Stripe Checkout; leave empty for demo billing mode |
STRIPE_WEBHOOK_SECRET | with Stripe | Verifies /api/webhooks/stripe signatures |
STRIPE_PRICE_TEAM / STRIPE_PRICE_AGENCY | with Stripe | Recurring Price IDs for the two paid plans |
DEMO_PASSWORD | for the demo | Password of the shared demo account. A long random string; "Try demo" uses it server-side, it never reaches the browser |
CRON_SECRET | for the demo | Protects /api/cron/demo-reset; Vercel Cron sends it automatically |
SEED_USER_EMAIL | no | Account for scripts/seed-leads.ts if none is passed on the command line |
Visitors can click Try demo (landing page hero or the sign-in page) to land in a
fully populated workspace, Northwind Digital, a fictional B2B agency. Nobody types
credentials: POST /api/demo/login signs in to the shared [email protected]
account on the server with DEMO_PASSWORD. A banner reminds visitors that the data
resets daily.
What's seeded (lib/demo-data.ts, lib/demo-seed.ts):
35 leads across every stage (won and lost included) and five sources, spread over
90 days; a stored AI score, reasons, insight and next action for every lead; today's
focus picks; activity timelines; sent and scheduled follow-ups; and two teammates
(Admin and Member) who own part of the pipeline. The workspace is on the Agency plan,
so every feature is unlocked. All AI output is stored, so browsing the demo makes no
Gemini calls. Every name, email (.example) and phone number (555-01xx) is fictional.
Seeding and reset. npm run seed:demo builds or rebuilds the demo workspace. It
only ever writes the demo users, the demo workspace and the demo AI-usage counter,
and it refuses to run if a demo email or the demo workspace id belongs to a real
account. Dates are relative to the day it runs, so the data always looks current. A
Vercel Cron job (vercel.json) calls /api/cron/demo-reset daily at
00:00 UTC to undo visitors' changes.
What visitors can and can't do. Dragging leads through the pipeline, editing lead
details, adding notes, adding leads and ticking follow-ups all work. Deleting leads,
inviting teammates, joining or creating other workspaces, changing workspace settings,
Stripe checkout and the billing portal are blocked server-side with a friendly message
(forbidInDemo() in lib/session.ts). Live AI scoring and insights
are capped at 10 calls per hour, shared by all demo visitors (lib/demo-limits.ts).
Sign-ups with the reserved leadflow.demo / northwind.demo domains are rejected.
scripts/seed-leads.ts fills an existing account's workspace with 7 realistic
leads across every stage, each with notes, an activity timeline and a follow-up,
so the dashboard, pipeline and analytics look like a CRM in use. Sign up and finish
onboarding first, then:
npx tsx scripts/seed-leads.ts [email protected] --dry # preview, writes nothing
npx tsx scripts/seed-leads.ts [email protected] # insert
npx tsx scripts/check-seed.ts [email protected] # read-only summary table
It is safe to re-run: leads are matched by name and skipped if they already exist. The seeded scores and reasons are hand-written demo values; click Re-score with AI on a lead to see a real Gemini run.
All three live in lib/gemini.ts and use generateObject with a
zod schema, so the model must return typed, validated data rather than free text.
The model is gemini-flash-latest, a rolling alias that keeps working as Google
retires dated model versions.
| Feature | Route | Input → output |
|---|---|---|
Lead scoring (scoreLead) | POST /api/leads/[id]/score | Title, company, source, deal value, stage and notes → score 0–100, priority HOT/WARM/COLD, one-line summary and 2–4 reasons. Saved on the lead and logged to its timeline |
Customer insights (generateCustomerInsights) | POST /api/leads/[id]/insights | The lead plus its recent activity → one sharp insight and one concrete next action, saved on the lead |
Daily focus (recommendDailyFocus) | GET /api/recommendations | The workspace's top 25 open leads → the 3–5 to work today with a reason each. Ids the model returns are checked against the input list, so it cannot invent a lead. Picks are cached on the workspace for 6 hours |
Rule-based and synchronous, so no queue, worker or cron is needed
(lib/automations.ts):
| Trigger | Automation |
|---|---|
| A lead is created | "Reach out within 24h" email follow-up due tomorrow, plus a timeline note |
| A lead's stage changes | A "Stage changed from X to Y" entry on the timeline |
| A lead moves to Qualified | "Send proposal" task due in 2 days |
lib/workspace.ts) and scopes every Prisma
query by workspaceId. A lead, activity or follow-up id from another workspace
returns 403. Isolation is enforced in the application layer (no Postgres RLS).proxy.ts (Next.js 16's name for middleware)
redirects signed-out visitors away from the app pages using an edge-safe Auth.js
config; the API routes check the session themselves.| Plan | Price | Listed features |
|---|---|---|
| Starter | $0 | 500 leads / mo, 1 seat, AI scoring, manual follow-ups |
| Team | $79 / mo | 10,000 leads / mo, 5 seats, automated follow-ups, analytics, AI daily focus |
| Agency | $199 / mo | Unlimited leads, 20 seats, custom scoring weights, priority support |
STRIPE_* variables, and plan changes go through Stripe Checkout. The Customer
Portal handles cancellations. For local webhooks run
stripe listen --forward-to localhost:3000/api/webhooks/stripe and put the printed
secret in STRIPE_WEBHOOK_SECRET. The webhook handles
checkout.session.completed, customer.subscription.updated and
customer.subscription.deleted.| Method | Route | Purpose |
|---|---|---|
POST | /api/auth/signup | Create an account (email, password ≥ 8 chars, optional name) |
* | /api/auth/[...nextauth] | Auth.js sign-in / sign-out / session |
POST | /api/workspaces | Create the user's workspace (onboarding) |
GET | /api/workspaces/current | Current workspace and the caller's role |
PATCH | /api/workspaces/[id] | Rename / change brand colour (Owner, Admin) |
GET | /api/workspaces/[id]/members | Members with roles |
GET POST | /api/workspaces/[id]/invites | Pending invites / create an invite (Owner, Admin) |
GET POST | /api/invites/[token] | Read an invite / accept it |
GET POST | /api/leads | List leads (by score) / create a lead (runs the "lead created" automation) |
GET PATCH DELETE | /api/leads/[id] | Lead with activities and follow-ups / update (stage change runs automations) / delete |
POST | /api/leads/[id]/activities | Log a note, email or call |
POST | /api/leads/[id]/score | AI score the lead |
POST | /api/leads/[id]/insights | AI insight + next action |
GET | /api/recommendations | AI daily focus picks |
GET | /api/followups | All follow-ups in the workspace |
PATCH | /api/followups/[id] | Mark done / not done |
app/
page.tsx Marketing landing page
login/ signup/ Auth pages
onboarding/ Create your workspace
invite/[token]/ Accept a team invite
(dashboard)/ Signed-in app (Shell + Sidebar layout)
dashboard/ Stat cards, AI "Focus today", priority leads
leads/ Lead table; leads/[id] is the customer profile
pipeline/ Drag-and-drop kanban
follow-ups/ Overdue / upcoming / done
analytics/ Charts
team/ billing/ settings/
api/ Route handlers (see API routes)
components/
ui/ Radix-based primitives (button, dialog, select, table, tabs, …)
landing/ Landing page sections
dashboard/ Shell, Sidebar, Topbar
leads/ LeadFormDialog, ScoreBadge
motion/ Reveal, CountUp
auth/ Shared login / sign-up form
lib/
gemini.ts AI scoring, insights, daily focus
automations.ts Follow-up rules
workspace.ts Tenant resolution and role checks
auth.ts, auth.config.ts Auth.js (full config / edge-safe config)
demo.ts, demo-data.ts, Public demo account: constants, seeded content,
demo-seed.ts, demo-limits.ts reset logic, hourly AI cap
prisma.ts, stripe.ts, plans.ts, serialize.ts, format.ts, handle-error.ts
hooks/ TanStack Query hooks
generated/prisma/ Generated Prisma client (do not edit)
prisma/
schema.prisma Data model
migrations/ SQL migrations
seed-demo.ts `npm run seed:demo`: rebuild the demo workspace
scripts/
seed-leads.ts Demo pipeline seeder
check-seed.ts Read-only check of seeded data
proxy.ts Route protection
vercel.json Daily demo-reset cron
User ─< WorkspaceMember >─ Workspace ─< Lead ─< Activity / FollowUp,
plus WorkspaceInvite. Enums: Role (OWNER, ADMIN, MEMBER), WorkspacePlan
(FREE, TEAM, AGENCY), LeadStatus (NEW, CONTACTED, QUALIFIED, WON, LOST),
LeadPriority (HOT, WARM, COLD), ActivityType, FollowUpType.
The app deploys to the free Hobby tier with no extra configuration.
DATABASE_URL — your Neon connection stringNEXTAUTH_SECRET — a new openssl rand -base64 32 valueGOOGLE_GENERATIVE_AI_API_KEY — your Gemini keyNEXT_PUBLIC_APP_URL — your Vercel URL, e.g. https://lead-flow-ai-six.vercel.appSTRIPE_* — optional; leave unset for demo billing. Only test-mode keys are acceptedDEMO_PASSWORD, CRON_SECRET — two long random strings, for the public demonpm run build runs prisma migrate deploy first, so the first deploy
creates the tables and later deploys apply new migrations.npm run seed:demo once against the production database to create the demo
workspace (the daily cron keeps it fresh afterwards).https://<your-domain>/api/webhooks/stripe in the Stripe dashboard and put its
signing secret in STRIPE_WEBHOOK_SECRET./invite/<token>, where the token is on the WorkspaceInvite row.GET | /api/analytics | Funnel, sources, score distribution, weekly trend, totals |
POST | /api/billing/checkout | Start Stripe Checkout (or switch plan in demo mode) |
POST | /api/billing/portal | Open the Stripe Customer Portal |
POST | /api/webhooks/stripe | Stripe webhook receiver |
POST | /api/demo/login | "Try demo": sign in to the shared demo account |
GET | /api/cron/demo-reset | Rebuild the demo workspace (Vercel Cron, CRON_SECRET) |