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
翻訳待ち
For your household or your business: Clandar tracks spending and bills, keeps every project on budget and on schedule, and gives you an AI assistant that handles the busywork — receipts, reminders, bu
翻訳待ち
ビジネスTypeScript · PLpgSQLGitHub @xnjgroupオンライン所有者未確認
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
For your household or your business: Clandar tracks spending and bills, keeps every project on budget and on schedule, and gives you an AI assistant that handles the busywork — receipts, reminders, budgets and follow-ups.
翻訳待ち
Loading the full README. The saved excerpt is shown below.
A multi-tenant business dashboard for any small business: customers, projects, AI-assisted photo
quoting, scheduling, a task/shopping/permit list, the Clandar assistant chat that can act on your
data, and a Gmail-backed customer-support inbox — plus the invoice extraction, approvals, budgets
and spend-analytics module the app started as.
Every page reads from a local Postgres database — there is no fixture data in the app code.
What's shipped, in progress and next is in doc/ROADMAP.md; the architecture is
in doc/DESIGN.md.Read the full README ↗A multi-tenant business dashboard for any small business: customers, projects, AI-assisted photo quoting, scheduling, a task/shopping/permit list, the Clandar assistant chat that can act on your data, and a Gmail-backed customer-support inbox — plus the invoice extraction, approvals, budgets and spend-analytics module the app started as. Every page reads from a local Postgres database — there is no fixture data in the app code.
What's shipped, in progress and next is in doc/ROADMAP.md; the architecture is
in doc/DESIGN.md.
The app expects a local Postgres. If you are already running the clandar-postgres
container, it is ready to use:
docker run -d --name clandar-postgres -p 5432:5432 \
-e POSTGRES_USER=clandar -e POSTGRES_PASSWORD=clandar_dev -e POSTGRES_DB=clandar \
pgvector/pgvector:pg17
Gmail scans and bulk trash, reminders, the lead finder and scheduled automations run as jobs on a
queue in Postgres (background_jobs, lib/jobs.ts) — no Redis. A runner claims and runs them:
npm run dev / npm start runs one in-process (set RUNNER=off to skip it);npm run runner runs one anywhere with the app's env — your laptop, a small always-on box — like a
GitHub Actions runner (RUNNER_NAME, RUNNER_KINDS=trash-label,trash-search, RUNNER_CONCURRENCY);GET /api/cron/tick every minute with Authorization: Bearer $CRON_SECRET (a Vercel
Cron on Pro, or any external pinger) so reminders and automations fire even when no runner is on.Admin → Background jobs shows runners and every job, with cancel and retry.
cp .env.example .env.local
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" # APP_ENCRYPTION_KEY
| Variable | Used for |
|---|---|
DATABASE_URL | Connection string; the database it names is created by db:setup. |
CRON_SECRET | Protects /api/cron/tick (and /api/cron/reminders). |
APP_ENCRYPTION_KEY | AES-256-GCM key for connector secrets. Rotating it makes stored secrets unreadable. |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | OAuth client for the Gmail and Calendar connectors. Leave empty to keep them greyed out. |
GOOGLE_REDIRECT_URI | Optional. Leave unset — the redirect URI is derived per-request from whichever address you're connecting from (see below), which is what lets the same app be reached from localhost and, say, a phone over Tailscale without reconfiguring anything. Set this only to pin one fixed URL for a production deployment behind a stable domain. |
SESSION_SECRET | Signs the sign-in session cookie. Falls back to APP_ENCRYPTION_KEY if unset. Rotating it signs everyone out. |
ADMIN_EMAILS | Comma-separated Google account emails with access to /admin (see Admin). Empty means nobody. |
R2_ACCOUNT_ID / R2_ENDPOINT / R2_ACCESS_KEY_ID / R2_SECRET_ACCESS_KEY / R2_BUCKET | Cloudflare R2 (S3-compatible) storage for project photos/files and chat attachments (lib/storage.ts). Leave empty to store on local disk under UPLOADS_DIR instead. R2_ACCOUNT_ID only derives the default endpoint — set R2_ENDPOINT directly for a custom domain or jurisdiction-specific endpoint. |
npm run db:setup # creates the database if missing, applies db/schema.sql (idempotent)
There's no seed script — every table is real and org-scoped, and the app starts empty for each organization. The first person to sign in with Google creates their org and everything from there (customers, projects, invoices, vendors, budgets, …) is data they actually entered, not a fixture.
npm run dev
The app is multi-tenant and requires signing in with Google — there is no username/password.
Every table below the organizations one is scoped to an org; a signed-in person only ever
sees their own org's data. See lib/auth.ts.
/settings's Team section sends invites — an owner enters an email + role there; no email is
actually sent yet, so tell the person directly to sign in with that Google account).This is a second, separate Google OAuth client usage from the Connectors section below: login
only ever requests openid email profile (who you are) and never stores a token — once the
profile is read, a plain server-side session (sessions table + a signed cookie) takes over.
Connectors request Gmail/Calendar data access scopes and store long-lived tokens instead. Both
reuse the same GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET, but need their own entries under
Authorized redirect URIs on the OAuth client, since the callback paths differ:
{origin}/api/connectors/google/callback — connectors{origin}/api/auth/google/callback — sign-in...for every {origin} you actually use (http://localhost:3000, a Tailscale address, etc.) —
same requirement as the connectors flow, just a second path per address.
The core of the app: a customers table and a projects table (one property, one job of work, a
status from lead through completed/cancelled) that everything else hangs off, all scoped to
the signed-in org.
This is the beginning of the README. Read the rest at the original. Read the full README ↗