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
Multi-tenant compliance management for consulting firms and individuals. Track filings, manage clients, and stay compliant.
BusinessTypeScript · CSSGitHub @uditguptacaOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
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 ↗Compliance and practice-management platform for an accounting firm: client portal, staff dashboard, service master, smart forms, ledger, payroll and corporate secretary modules. Next.js 14 (App Router) on Vercel, PostgreSQL behind it.
| Part | Where |
|---|---|
| The app | Vercel project, production on the main branch |
| The database | Neon (PostgreSQL), created from the Vercel project's Storage tab. It holds everything: firms, users, clients, forms, ledgers, payroll and every uploaded file. |
| Login sessions | Signed with JWT_SECRET from the project's environment variables |
Nothing else is needed. There is no Supabase, Turso or SQLite in the live setup, and the app refuses to connect to a Supabase address even if one is left in the environment variables (it logs which variable to delete). Nothing is stored on the web server's disk: Vercel's disk is read-only.
DATABASE_URL, DATABASE_URL_UNPOOLED, or the same names with a prefix
you choose). If it says a DATABASE_URL already exists, delete the old
one under Settings → Environment Variables first. The app only ever
uses Neon addresses (pooled first) and ignores any other cloud database.JWT_SECRET with a long random value (40+ characters), then redeploy.
Without it, sessions are signed with a built-in development value that
everyone who can read the source knows.Then open /login. The first login on a fresh database takes a few seconds:
the app creates every table (from src/db/schema.sql and the migrations in
src/db/migrations) and seeds the demo accounts, then signs you in.
The seed creates demo accounts; the login page lists them. Every seeded
account uses the password shown there. Change them (or remove the demo block
from src/app/login/page.tsx) before real client data goes in.
psql: copy DATABASE_URL from Vercel →
Settings → Environment Variables and run psql "<that value>". Treat that
value like a password.tax_intake_*: answers, their full change history, records, documents, review items, frozen submissions), accounting ledgers, payroll, corporate secretary
(cs_*), settings, and schema_migrations (which migration files have
been applied).pg_dump "<DATABASE_URL>" > backup.sql) before relying on it.src/db/seed-reference.ts, data in src/db/reference/). Sample content that earlier one-off
scripts created (sample corporations, sample ledger entries, sample forms) is demo data and is not
created. Real data from a previous database is brought over with Platform → Import data (below).document_blobs table, next
to the row that describes them, and are served by /api/documents/<id>/download after a permission
check. The limit is 4 MB per file because Vercel rejects larger request bodies.Signed in as a platform admin, open Platform → Import data. Paste the old database's address (for a
Supabase project use the Session pooler address from Connect, with the database password filled in), press
Check the old database, choose Replace (empties this database first; you must type REPLACE) or Add
(keeps what is here, skips rows that already exist), and press Start copying. The page copies table by table
with a progress bar and finishes with a report comparing the row counts of both sides. After a Replace, sign in
again: the accounts now come from the old database.
How it stays exact (src/lib/db-import.ts): values are copied as text so the database converts them to the
column's own type; only columns that exist on both sides are copied (an old database that lacks a newer column,
or has an extra one, still imports and the page warns about what is not copied); tables go in foreign-key order
and a row whose parent has not arrived yet is parked and placed at the end; counters for new records are moved
past the highest copied id. The address is used for the one request, never stored, logged or sent back. It refuses
to import a database into itself and refuses a Replace when the old database has no active platform admin.
Uploaded files are not in the old database (they were on a disk); only their records are copied.
Tested by tests/verify/import.py and tests/verify/import_browser.cjs.
| Name | Purpose |
|---|---|
DATABASE_URL | The Neon connection string, added by Vercel when Neon is connected. Prefixed variants (DATABASE_POSTGRES_URL, *_URL_UNPOOLED, ...) are tried too, pooled Neon addresses first. A Supabase address is never used. A local PostgreSQL address also works for development and tests. |
JWT_SECRET | Signs login sessions. Required in production. |
CRON_SECRET | Lets Vercel's scheduler run the daily jobs (/api/cron/*). Any long random value; Vercel sends it automatically once it exists. Without it only a signed-in platform admin can run those jobs. |
See .env.example.
cp .env.example .env.local # then point DATABASE_URL at a local Postgres
npm install
npm run dev # http://localhost:3000
The schema installs itself on the first request. To install it ahead of time, or to check a database by hand:
node --env-file=.env.local scripts/db-setup.js
src/db/schema.sql is the base schema.src/db/migrations/NNN_name.sql are applied after it, in file-name order,
each exactly once; applied names are recorded in the schema_migrations
table.src/db/migrations/. It is bundled
automatically (src/db/migrations/index.ts) and runs on the next deploy's
first request, or on demand with POST /api/migrate.src/lib/db.ts waits for the schema before every query, so no route needs
to think about it.npm run build / npm start — production build and servernpm run lintnpm test — Playwright tests (tests/)