A custom-built CRM and operational platform for PauseAI Global. Starts as a CRM, grows into the central hub for managing volunteers, campaigns, and outreach. Supports multi-tenancy via workspaces for PauseAI Global and national chapters.
Production: https://web-production-4523c.up.railway.app Repo: https://github.com/Maximophone/pauseai-everything
A Next.js web app + background worker that replaces Airtable + manual email workflows. Core features:
- Workspaces — multi-tenant architecture with a global workspace (PauseAI Global) and chapter workspaces (e.g., Pause IA France). Each workspace has its own contacts, tags, fields, segments, campaigns, communication categories, and team members. Workspace switcher in the sidebar for users belonging to multiple workspaces.
- Contacts — spreadsheet-style table with inline editing, custom fields, tags, interaction history. Contacts are scoped to workspaces — each workspace sees only its own contacts. A contact can belong to multiple workspaces.
- Segments — visual query builder to define dynamic audiences (e.g. "contacts with tag 'parisien'"). Segments are workspace-scoped.
- Campaigns — compose and send broadcast emails to segments via Mailersend; schedule for later; assign email categories for preference-based filtering
- Communication preferences — three-state subscription model (subscribed/unsubscribed/neutral) per workspace per category; contacts must be explicitly subscribed to receive categorized emails; public unsubscribe page with preference center; HMAC-signed unsubscribe links;
{{unsubscribe}}merge variable for in-body links - Scripts — write JavaScript automation scripts that run on a schedule or on demand (e.g. flag dormant contacts, bulk-update fields)
- Settings — manage workspaces, custom fields, users (per-workspace), API keys, email categories, app-level settings
- My Email Contacts — connect your personal Gmail account to browse email contacts, import them to the workspace, and auto-log email interactions on contact timelines. User-scoped connections with per-contact sync/visibility settings, encrypted OAuth tokens, and worker-based periodic sync.
- Role-based access — two-layer role system (global + workspace roles) with invite-only login via Google OAuth
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, TypeScript) |
| Database | PostgreSQL via Drizzle ORM |
| Job queue | graphile-worker (Postgres-backed) |
| UI | shadcn/ui + Tailwind CSS + AG Grid (Community) |
| Auth | Auth.js v5 (Google OAuth) |
| Mailersend API | |
| Hosting | Railway (web + worker + Postgres) |
| Tests | Vitest |
- Node.js 20+
- PostgreSQL running locally (or use Docker:
docker-compose up -d)
git clone https://github.com/Maximophone/pauseai-everything.git
cd pauseai-everything
npm installcp .env.example .envEdit .env — see docs/development.md for what each variable does and how to get them.
Minimum required for local dev:
DATABASE_URL=postgresql://localhost:5432/pauseai
NEXTAUTH_SECRET=any-random-string
NEXTAUTH_URL=http://localhost:3000
AUTH_GOOGLE_ID=...
AUTH_GOOGLE_SECRET=...
DEV_BYPASS_AUTH=true # skip Google login in development
ADMIN_EMAILS=you@example.com # auto-promote to admin
UNSUBSCRIBE_SECRET=... # openssl rand -hex 32
EMAIL_ENCRYPTION_KEY=... # openssl rand -hex 32 (encrypts OAuth tokens + connection credentials)
NEXT_PUBLIC_APP_URL=http://localhost:3000
npm run db:generate # generate migration files (if schema changed)
npx drizzle-kit push # push schema to local Postgres (no migration files needed in dev)# Web server (Next.js)
npm run dev
# Background worker (in a separate terminal)
npm run workerOpen http://localhost:3000.
With DEV_BYPASS_AUTH=true, you'll be logged in automatically as "Dev User" with admin access — no Google setup needed.
pauseai-everything/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── dashboard/ # All authenticated pages
│ │ │ ├── contacts/ # Contact list + detail pages
│ │ │ ├── email/ # Campaigns
│ │ │ ├── segments/ # Segment builder
│ │ │ ├── automations/ # Script editor (JS automation)
│ │ │ ├── my-email-contacts/ # Gmail integration (personal email contacts)
│ │ │ └── settings/ # Workspaces, fields, users, API keys, email categories
│ │ ├── api/ # API route handlers
│ │ │ ├── contacts/
│ │ │ ├── campaigns/
│ │ │ ├── segments/
│ │ │ ├── scripts/
│ │ │ ├── tags/
│ │ │ ├── fields/
│ │ │ ├── users/
│ │ │ ├── api-keys/
│ │ │ ├── communication-categories/
│ │ │ ├── auth/gmail/ # Gmail OAuth flow
│ │ │ ├── email-connections/ # Email connection CRUD + contacts + import
│ │ │ ├── email-contact-settings/ # Per-contact sync settings
│ │ │ ├── settings/
│ │ │ ├── unsubscribe/
│ │ │ └── webhooks/
│ │ ├── login/
│ │ └── unsubscribe/ # Public unsubscribe preference center
│ ├── components/ # React components
│ ├── db/
│ │ └── schema/ # Drizzle table definitions
│ ├── lib/ # Business logic (no React)
│ └── worker/
│ ├── index.ts # Worker entry point
│ └── tasks/ # One file per background job type
├── docs/ # Documentation
│ ├── architecture.md # System design and patterns
│ ├── build-plan.md # Phase-by-phase build roadmap + status
│ ├── deployment.md # Railway deployment guide
│ ├── development.md # Local development setup
│ └── features.md # Feature specs and backlog
├── .env.example
├── railway.toml # Worker service start command (for Railway deploys)
└── drizzle.config.ts
npm run dev # Next.js dev server (http://localhost:3000)
npm run worker # Background worker
npm run build # Production build
npm run test # Run Vitest tests
npm run test:watch # Watch mode
npm run db:generate # Generate Drizzle migration files
npm run db:migrate # Apply migration files
npm run db:studio # Open Drizzle Studio (DB browser)
npm run db:seed # Seed with sample data
npm run docs:api # Regenerate docs/api-reference.md from Zod schemasAll project documentation lives in this repo. Some docs are served on the frontend at /dashboard/docs (accessible to all logged-in users, configured in src/lib/docs-manifest.ts). Others are developer-only.
If you're new to the project, start with:
- This README (project overview, tech stack, setup)
- docs/architecture.md (system design, data model, key patterns)
- docs/development.md (local dev setup, env vars, workflow)
These reflect the current state of the system and are kept up to date as features change.
| Doc | What's in it | On frontend? |
|---|---|---|
| docs/architecture.md | System design, data model, key patterns | Yes |
| docs/api-reference.md | Full REST API reference (auto-generated via npm run docs:api) |
Yes |
| docs/development.md | Full local setup, env vars, database, tips | Yes |
| docs/deployment.md | Railway deployment, env vars | Yes |
| docs/features.md | Feature descriptions — what's built, what's planned | Yes |
| docs/build-plan.md | 12-phase build progression with completion status | Yes |
| docs/future-features.md | Ideas and backlog items not yet planned | Yes |
| docs/user-guide/ | End-user guides (contacts, email, settings, etc.) | Yes |
Design documents written before or during feature implementation. These capture the original intent and design thinking, but may not reflect the current state of the software — the implementation may have departed from the spec. Valuable for understanding why things were built a certain way; for how things work now, refer to the actively maintained docs above.
| Doc | What's in it |
|---|---|
| docs/specs/workspaces.md | Original multi-tenancy design specification |
| docs/specs/gmail-integration.md | Gmail / personal email integration design |
| docs/specs/crm-research-brief.md | Initial CRM research and requirements |
New feature specs should always be placed in docs/specs/. When a spec leads to implementation, the actively maintained docs should be updated to reflect what was actually built.
One-off assessments, security audits, and investigative reports. These are point-in-time snapshots and are not updated after the fact (though findings may be tracked in BUGS.md).
| Doc | What's in it |
|---|---|
| docs/audits/api-blackbox-audit-2026-04-04.md | API security audit (86 test scenarios, 28 findings) |
| Doc | What's in it |
|---|---|
| CLAUDE.md | Project instructions for AI assistants (Claude Code) |
| DEVLOG.md | Reverse-chronological development session log |
| BUGS.md | Bug tracker — security audit findings and fix status |
Invite-only access — users must be invited by an admin before they can sign in with Google. Uninvited emails are rejected at login.
Two-layer role system:
Users have a global role (system-wide) and a workspace role (per-workspace). The effective role in any workspace is the maximum of the two. For example, a user with global "member" role and workspace "admin" role is effectively an admin in that workspace.
| Role | Can do | Cannot do |
|---|---|---|
| Admin | Manage users, settings, campaigns, scripts, segments, fields, contacts within their workspace | — |
| Member | View/edit contacts, tags, interactions | Send campaigns, manage segments/scripts/fields, access settings |
| Viewer | View all data (read-only) | Create, edit, or delete anything |
Global admins additionally can: create/delete workspaces, define core and global_internal custom fields, view all workspaces.
- Workspace roles assigned by workspace admins in Settings > Users
- Global roles managed by global admins
ADMIN_EMAILSenv var auto-promotes specified emails to global admin- API key auth (
Bearer pai_<key>) grants admin access - All API routes enforce role checks server-side; UI buttons are disabled for insufficient roles
Deployed on Railway with three services: web, worker, Postgres. See docs/deployment.md for the full guide.
Current production URL: https://web-production-4523c.up.railway.app
To deploy:
# Deploy web service
cat > railway.toml << 'EOF'
[build]
builder = "RAILPACK"
[deploy]
startCommand = "npx drizzle-kit push && npm start"
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 10
EOF
railway up --detach --service web
# Deploy worker service
cat > railway.toml << 'EOF'
[build]
builder = "RAILPACK"
[deploy]
startCommand = "npx tsx src/worker/index.ts"
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 10
EOF
railway up --detach --service workerSee docs/development.md for the full development guide including how to add new features, database schema changes, and testing conventions.
At the end of every development session, run the /wrapup slash command (defined in .claude/commands/wrapup.md). This:
- Reviews all commits since the last devlog entry
- Writes a new entry in
DEVLOG.md - Scans every documentation file, triages which ones need updates based on what changed, and updates them
- Commits and pushes all documentation changes
This ensures docs never go stale. If you're wrapping up a session (e.g., "let's commit and push", "I think that's done"), always run /wrapup before ending.