Synaplan
기업을 위한 오픈소스 AI 플랫폼
Open-source CRM for churches and parishes: members, families, events, accounting and tax receipts
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A free, self-hosted church management system — families & members, accounting,
event ticketing, petty cash, membership, and receipts, in one app your church runs itself.
🌐 Website & documentation — every feature in detail: how to use it, how it works, and how to configure it.
Single-tenant by design. One deployment per church, driven by settings a church
types in — not a multi-tenant SaaS. Your data stays on your server, encrypted at rest.README 전문 보기 ↗A free, self-hosted church management system — families & members, accounting, event ticketing, petty cash, membership, and receipts, in one app your church runs itself.
🌐 Website & documentation — every feature in detail: how to use it, how it works, and how to configure it.
🧪 Live demo — one-click login as each role, sample data only, resets nightly. Free hosting, so the first visit can take a minute to wake up.
Single-tenant by design. One deployment per church, driven by settings a church types in — not a multi-tenant SaaS. Your data stays on your server, encrypted at rest.
ParishCRM began as the in-house CRM for one church and is being generalised into a product any church can run. Church identity (name, address, contacts, branding) is configuration; region-specific behaviour (fiscal year, currency, tax receipts, bank import) is moving behind config presets.
Requires Node ≥ 24 (
engines.nodeinpackage.json).postinstallrunsprisma generateautomatically.
npm install
cp .env.example .env.local # then fill in values
Minimum .env.local for local dev:
DATABASE_URL="postgresql://postgres:postgres@localhost:51214/template1?sslmode=disable"
AUTH_SECRET="<generate: openssl rand -base64 32>"
AUTH_URL="http://localhost:3000"
ENCRYPTION_KEY="<generate: openssl rand -base64 32>"
GMAIL_USER="[email protected]"
GMAIL_APP_PASSWORD="xxxxxxxxxxxxxxxx"
CHURCH_NAME="Your Church Name"
CHURCH_ADDRESS="123 Example St, ..."
DISABLE_OTP=true # local only — never set in production
See .env.example for the full list including the encryption keyring (ENCRYPTION_KEY_V1/_V2… + ENCRYPTION_KEY_ID).
npx prisma dev --detach # local PostgreSQL daemon at port 51214 (once per session)
npm run db:push # sync schema to the DB
ALLOW_DEMO_SEED=true npm run db:seed # demo users + chart of accounts (opt-in: demo passwords are public)
npm run dev # http://localhost:3000
Seed login credentials (development only — change before any real use):
| Password | Role | |
|---|---|---|
| [email protected] | admin123 | ADMIN |
| [email protected] | pastor123 | PASTOR |
| [email protected] | viewer123 | VIEWER |
No AUDITOR or OFFICE_ADMIN user is seeded — create one via
/usersif you need to test those roles.
# Dev
npm run dev # Next.js at http://localhost:3000
# Database — Prisma (primary)
npx prisma dev --detach # start local PostgreSQL daemon
npx prisma dev ls # show daemon status / URLs
npx prisma dev stop default # stop daemon
npm run db:push # sync schema (prisma db push)
npx prisma generate # regen client after schema change
ALLOW_DEMO_SEED=true npm run db:seed # seed demo users + chart of accounts
npm run db:studio # Prisma Studio GUI
# Database — Docker Compose (alt)
npm run db:start / npm run db:stop
# Build / lint / test
npm run build # production build
npm run lint # ESLint
npm run knip # find unused files, deps, exports
npm test # Jest unit tests
npm test -- --no-coverage # faster
npm test -- --testPathPatterns="auth" # single suite (Jest 30 flag)
npm run test:watch # watch mode
Schema change workflow: edit prisma/schema.prisma → npm run db:push → npx prisma generate.
src/
app/ Next.js App Router
(auth)/ /login, /forgot-password, /reset-password — unauthenticated
(dashboard)/ /, families, people, users, accounting/*, events/* — auth + sidebar
(public)/ /e/[slug], /privacy, /membershipform — public, no auth
(print)/ print layouts
api/ API routes
components/ React components
ui/ shadcn/ui (generated — do not edit)
layout/ sidebar, nav
accounting/ auth/ dashboard/ events/ families/ people/ petty-cash/ ...
lib/
actions/ Server Actions (mutations)
generated/prisma/ Prisma client (generated — not in node_modules)
reports/ pure P&L / ledger calculation helpers
crypto.ts AES-256-GCM field encryption
prisma.ts Prisma client singleton
auth.ts NextAuth full config (Node runtime, Prisma)
auth.config.ts Edge-safe auth config (used by middleware)
middleware.ts route protection & redirects
prisma/ schema.prisma, migrations, seed.ts
docs/ topic docs + specs/plans
/e/[slug]), ticketed events with custom questions, tiered pricing, optional Stripe card payments, check-in, CSV export.Full per-feature guides (usage by role, internals, configuration) live in the documentation.
| Role | Access |
|---|---|
ADMIN | Full CRUD, user management, accounting admin |
PASTOR | Full CRUD + pastoral notes + accounting view/entry |
OFFICE_ADMIN | People/family/event edit, read-only accounting, user management (not ADMIN accounts), no pastoral notes |
AUDITOR | Read-only accounting (transactions, reports, petty cash, CSV export) — no member PII, no mutations |
VIEWER | Read-only people/families/events (clearance status badge only) — no pastoral notes, no accounting |
EVENT_ORGANISER | No dashboard — own managed events only (registrations, check-in, edit public details), plus rolls for Sunday School classes they're assigned to |
Role helpers live in src/lib/roleGuard.ts. Accounting read paths gate on canViewAccounting; accounting mutations require canAccessAccounting (ADMIN | PASTOR only). All DB mutations are guarded at both the page and the action.
auth() from @/auth. Client Components: useSession().All queries via Prisma (@prisma/adapter-pg) — no raw SQL.
import { prisma } from "@/lib/prisma"
Generated client at src/lib/generated/prisma/; enums from @/lib/generated/prisma/enums.
Sensitive fields are encrypted at rest with AES-256-GCM, automatically on read/write through the Server Actions layer — family contact/location, person contact + date of birth, pastoral notes, transaction descriptions, receipt destinations, and registration contact details, and child-safety clearance numbers/documents. Email fields carry a blind-index emailHash for lookups without decryption. A versioned keyring supports rotation.
All mutations write to the AuditLog table with VERB_NOUN action strings (e.g. FAMILY_CREATED, TRANSACTION_RECONCILED). Privacy-sensitive exports log PERSON_EXPORTED.
ParishCRM is a standard Next.js app backed by PostgreSQL. Run the published container
image against your own Postgres: set the required secrets (AUTH_SECRET, ENCRYPTION_KEY,
DATABASE_URL, mail credentials) and start the container — it applies migrations on start.
Step-by-step guide: docs/self-hosting.md.
One-click: — see the Railway guide.
ParishCRM is free to self-host, forever. If you'd rather not run it yourself, paid options are available:
| Option | What you get |
|---|---|
| Community (free) | Self-host from the guide above; questions via GitHub Discussions, bugs via issues |
| Hosted plan | We run your church's instance — updates, daily backups, monitoring, HTTPS on your domain |
| Setup & migration | One-off import of your existing spreadsheets/records, branding, and staff training |
| Priority support | Email support, priority bug fixes, upgrade help for self-hosted churches |
To ask about a hosted plan or setup, start a thread in Discussions → Hosting & support.
Fees from paid plans fund ongoing development of the free, open-source version.
Contributions are welcome — see CONTRIBUTING.md for the branch/PR workflow, coding conventions, and the schema-change process, and CODE_OF_CONDUCT.md for community expectations.
To report a security vulnerability, follow SECURITY.md — do not open a public issue.
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later). You may run, study, share, and modify it freely; if you run a modified version as a network service, you must offer that service's users the corresponding source. Churches self-hosting an unmodified copy have no additional obligations.