Synaplan
기업을 위한 오픈소스 AI 플랫폼
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A simple, mobile-friendly CRM for managing leads, sales reps, and follow-ups.
/api/cron/reminders) emails reps about follow-ups that are
due, if SMTP is configured.CB/2026-27/0001), a PDF, and is
recorded on the server's disk along with monthly and yearly registers.
See Invoices below.POST /api/external/leads, gated
by an EXTERNAL_LEADS_SECRET bearer token, lets another internal tool
push leads straight in — used by the companion Leads Finder tool's
"Push to CRM" button. Dedupes by phone number (a lead already in the
system under that phone is skipped, not duplicated) and auto-creates the
named source if it doesn't already exist as a Lead Source. Each lead may
include an assignedToId (a User.id from this CRM) to assign it on
creation; an id that doesn't match an active user is left unassigned
rather than failing the push. A matching GET /api/external/sources lists
current source names, and GET /api/external/team lists active team
members (id, name, email), so the pushing tool can offer pickers
instead of fixed, hardcoded values.tel: link — works great on mobile, needs a
softphone on desktop). A dedicated Dialer page turns this into a queue:
call the lead on top, log the outcome and an optional follow-up, and it
automatically advances to the next one.{{name}} placeholder filled in from the lead's contact name), then send
one to any lead's number in one click — opens WhatsApp with the message
pre-filled, ready to send. Attach an image straight from your device (no
need to host it yourself first — it's uploaded to the app's own server
and the link is generated automatically) and it shows up as a preview
thumbnail under the message. Any plain URL typed into the message becomes
a tappable link automatically. Real tappable Quick Reply buttons aren't
possible this way — that needs the paid, Meta-approved WhatsApp Business
API, not the free wa.me link this feature sends through.npm install
cp .env.example .env # fill in DATABASE_URL (a Postgres connection
# string — see the comment in .env.example for a
# one-line local Docker Postgres, or just use a
# free Neon database), NEXTAUTH_SECRET (any
# random string), and the seed admin credentials
npm run db:migrate # applies the schema (also seeds an initial admin user)
npm run dev
Visit http://localhost:3000 and log in with the seed admin credentials from
.env (defaults: [email protected] / ChangeMe123! — change the password
after first login by editing the user, or create additional admins from the
Team page).
From the Team page (as an admin) you can add sales reps, who log in with the email/password you set for them.
Best option when you need this live quickly — sign-up is just email/GitHub, no KYC/ID verification on either service. Cost: $0/month at this scale. Trade-off: the free Neon database auto-suspends after ~5 minutes idle, so the very first request after a quiet spell takes an extra 0.5-2s to wake back up — not noticeable in daily use.
1. Create a free Neon Postgres database at neon.tech (sign in with
GitHub or email, no card required). Create a project, then copy its
connection string from the dashboard (starts with postgresql://).
2. Create a free Vercel account at vercel.com (sign in with GitHub —
this also lets it see your repos). Click Add New → Project, and import
bhavansh-arora/crm, selecting the claude/crm-admin-lead-management-2dea2w
branch.
3. Before clicking Deploy, add these Environment Variables in the import screen (Settings → Environment Variables works too, if you've already deployed once):
| Name | Value |
|---|---|
DATABASE_URL | the Neon connection string from step 1 |
NEXTAUTH_SECRET | any random string — generate one with openssl rand -base64 32 |
NEXTAUTH_URL | your Vercel URL, e.g. https://crm-yourname.vercel.app (Vercel shows this after first deploy — add it, then redeploy once) |
SEED_ADMIN_EMAIL | the email your team's admin will log in with |
SEED_ADMIN_PASSWORD | a temporary password (change it after first login) |
CRON_SECRET | any random string — Vercel automatically sends it to /api/cron/reminders on the schedule in vercel.json |
4. Click Deploy. Vercel detects the vercel-build script in
package.json, which runs migrations and creates the admin account
automatically as part of the build — no separate step needed. When it
finishes, open the URL it gives you and log in.
Giving employees access tomorrow: once you're logged in as admin, go to the Team page and add a sales-rep account for each employee (their own email + a temporary password); each one logs in at the same URL.
Redeploying after code changes: push to the branch, or click Redeploy in the Vercel dashboard — migrations and the admin check re-run safely every time (they no-op if there's nothing new to do).
Moving to the VPS later: once your VPS's KYC clears, you can point it
at this exact same Neon database (paste the same connection string into
deploy/setup-vps.sh when it asks) — no data migration, no re-entering
leads.
This gets the app onto a small always-on server you control.
1. Create the cheapest VPS you can find running Ubuntu 22.04 or 24.04, at least 1GB RAM (2GB is safer for the build step) — e.g. a Hetzner CX22, a DigitalOcean Basic Droplet, or a Vultr/Linode equivalent. Any provider works; this doesn't depend on which one you pick.
2. Open a terminal to it. Either SSH from your own machine:
ssh root@YOUR_SERVER_IP
or use the provider's browser-based console (every major one has one) if you don't have an SSH client set up.
3. Run one command:
curl -fsSL https://raw.githubusercontent.com/bhavansh-arora/crm/claude/crm-admin-lead-management-2dea2w/deploy/setup-vps.sh -o setup-vps.sh
bash setup-vps.sh
It will ask for an admin email/password (or auto-generate a password) and optionally a domain name, then install Docker, build the app, start it, and schedule the follow-up reminder check — unattended from there. It prints the live URL and admin login when it's done.
No domain yet? It'll run on http://<server-ip> immediately. Get a cheap
domain later (~$10/year, e.g. from Namecheap or Cloudflare), point its A
record at the server's IP, and re-run the same command — it'll notice you
now have a domain and automatically get you a free HTTPS certificate via
Caddy. Do this before real passwords/data go in — until then, login posts
over plain HTTP.
Redeploying after code changes: re-run bash deploy/setup-vps.sh (or, if
already cloned, cd /opt/crm && git pull && docker compose up -d --build).
Your .env, Caddyfile, and database are untouched — Caddyfile is
git-ignored on purpose (see Caddyfile.example) so redeploying can never
wipe out your domain/HTTPS config.
Logs: cd /opt/crm && docker compose logs -f
The in-app "Follow-ups" page is always accurate and needs no configuration.
To also send emails when a follow-up becomes due, set the SMTP_*
variables and redeploy/restart:
vercel.json already schedules a daily call to
/api/cron/reminders via Vercel Cron (Vercel's free Hobby plan limits
cron jobs to once per day — fine as a daily digest of what's due; upgrade
to Pro for hourly/minute-level scheduling).deploy/setup-vps.sh already schedules this call every
10 minutes via crontab.Either way, just fill in SMTP_* — nothing else to wire up.
Lets reps generate a payment link straight from a lead and see whether it's been paid. Disabled by default (leads simply show no "Request payment" result and an error saying it isn't set up).
RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET.https://yourdomain.com/api/webhooks/razorpay with the
payment_link.paid event enabled, and set RAZORPAY_WEBHOOK_SECRET to
the same secret you enter there. This makes "Paid" show up automatically,
in real time.SMTP_* settings as follow-up reminder
emails. If SMTP_HOST isn't set, this is skipped (logged, not an error).Redeploy/restart after setting these.
invoices.codebunny.net is an invoices-only site served by the same app.
It has its own "CodeBunny Invoices" login page, a dashboard (this month,
this financial year, received, unpaid, a 12-month chart, recent invoices,
top customers), and only the invoice pages in its menu. Admin accounts can
sign in there; sales reps get an "admins only" message. To set it up, add a
DNS A record invoices → your VPS IP, then re-run
bash deploy/setup-vps.sh, which adds the site to the Caddyfile and reloads
Caddy. HTTPS is issued automatically once the DNS record resolves. Set
INVOICES_DOMAIN in .env to use a different hostname, or "none" to skip it.
In the CRM itself, admins get the same Invoices page (top nav / mobile menu) for invoices issued
as CodeBunny, A8, Flower Valley, VIP Road, Raipur - 492001,
[email protected]. These are built in; override them with the
INVOICE_COMPANY_* settings in .env if they change. GST is off for now:
invoices are plain "INVOICE"s with no tax line. Set
INVOICE_DEFAULT_TAX_RATE (e.g. 18) later to turn it on.
Two ways invoices get created:
RAZORPAY_KEY_ID /
RAZORPAY_KEY_SECRET are set, every captured Razorpay payment becomes an
invoice by itself. On the VPS, deploy/setup-vps.sh schedules a sync every
15 minutes, so there's nothing else to set up. For instant invoices, also
enable the payment.captured event on the Razorpay webhook described
above. To catch up right away, click Sync from Razorpay → Sync now
on the Invoices page (last 30 days). The same panel can import an older
date range or a single pay_... ID. A payment is only ever invoiced once,
however many times it's synced. The customer comes from the payment, and
from the matching CRM lead (by email/phone) when there is one.Records on the server: every invoice is a row in the database, and its PDF is also saved on the VPS disk alongside a register CSV for each month and each financial year (April–March):
/app/invoices/ (Docker volume "invoices-data")
FY2026-27/register.csv yearly register
FY2026-27/2026-09/register.csv monthly register
FY2026-27/2026-09/CB_2026-27_0001.pdf
The registers are rewritten whenever an invoice in that month changes, and the
nightly deploy/backup-db.sh also archives this folder into
/opt/crm/backups/invoices-YYYY-MM-DD.tar.gz. To copy the files off the
server: docker compose cp app:/app/invoices ./invoices. The Monthly & yearly
records tab shows the same totals, with CSV downloads.
Issued invoices can't be edited or deleted, only marked paid/unpaid or cancelled. A cancelled invoice keeps its number, gets a CANCELLED stamp, and is left out of the totals. That way every number stays in the registers. PDFs use the built-in PDF fonts, so the rupee sign prints as "INR" and non-Latin characters (e.g. Devanagari) print as "?". The database keeps the original text.
src/lib/constants.ts and are enforced by the API layer with zod.npm audit currently reports one high-severity advisory in a postcss
version bundled internally by Next.js itself (not a direct dependency of
this project). It affects Next's own build-time CSS tooling, not runtime
behavior of this app; re-run npm audit after upgrading Next.js to pick
up the fix once it ships in a stable release.