Changemaker Control Panel (CCP)¶
The Changemaker Control Panel is a multi-tenant management layer for operators who run multiple Changemaker Lite instances from a single server. It provides a web UI to provision, monitor, and maintain a fleet of instances without manual configuration.
Single instance?
If you're running a single Changemaker Lite instance, you don't need CCP. Skip this page and continue with First Steps.
When to Use CCP¶
CCP is designed for:
- Campaign organizations managing instances for multiple chapters or regions
- Hosting providers offering Changemaker Lite as a managed service
- Development teams spinning up isolated test instances
CCP handles the entire instance lifecycle: provisioning, configuration, health monitoring, backups, and upgrades — all from a single dashboard.
Architecture¶
CCP runs as 4 Docker containers alongside (but independent from) your CML instances:
┌──────────────────────────┐
│ CCP Admin GUI (5100) │ React + Vite + Ant Design
│ Dark theme, SPA │ Zustand auth store
└────────────┬─────────────┘
│
┌────────────▼─────────────┐
│ CCP API (5000) │ Express + TypeScript
│ JWT auth, RBAC │ Prisma ORM → PostgreSQL
│ Docker socket access │ Winston logger
└────────────┬─────────────┘
│
┌────────┼────────┐
▼ ▼ ▼
ccp-postgres ccp-redis Docker Socket
(port 5480) (port 6399)
| Service | Container | Port | Description |
|---|---|---|---|
| CCP API | ccp-api |
5000 | Express API with Docker CLI access |
| CCP Admin | ccp-admin |
5100 | React admin GUI |
| CCP PostgreSQL | ccp-postgres |
5480 | CCP metadata database |
| CCP Redis | ccp-redis |
6399 | Rate limiting, caching |
Each managed CML instance gets its own isolated set of containers and PostgreSQL database, with ports allocated from non-overlapping ranges.
Setup¶
1. Run the Setup Script¶
The setup script:
- Detects the installation directory and resolves absolute paths
- Creates
instances/andbackups/directories - Copies
.env.exampleto.envif not present - Sets
INSTANCES_BASE_PATH,BACKUP_STORAGE_PATH, andCML_SOURCE_PATH - Generates random secrets for any placeholder values
2. Review Environment¶
Edit .env and verify the key settings:
| Variable | Default | Description |
|---|---|---|
JWT_ACCESS_SECRET |
Auto-generated | JWT signing key |
JWT_REFRESH_SECRET |
Auto-generated | Refresh token signing key |
ENCRYPTION_KEY |
Auto-generated | AES-256 key for instance secrets at rest |
INITIAL_ADMIN_EMAIL |
admin@example.com |
Bootstrap admin email |
INITIAL_ADMIN_PASSWORD |
ChangeMe2025!! |
Bootstrap admin password |
INSTANCES_BASE_PATH |
./instances |
Where instance directories are created |
CML_SOURCE_PATH |
Auto-detected | Path to CML source repo for provisioning |
BACKUP_STORAGE_PATH |
./backups |
Backup archive storage |
PANGOLIN_API_URL |
— | Pangolin API for tunnel management |
PANGOLIN_API_KEY |
— | Pangolin authentication |
PANGOLIN_ORG_ID |
— | Pangolin organization |
3. Start CCP¶
docker compose up -d
# Run database migrations and seed the admin user
docker compose exec ccp-api npx prisma migrate deploy
docker compose exec ccp-api npx prisma db seed
4. Log In¶
Open http://localhost:5100 and sign in with the admin credentials from .env.
Creating an Instance¶
The Create Instance wizard walks through 5 steps:
Step 1: Basic Information¶
- Instance name — human-readable label (e.g., "Edmonton Chapter")
- Slug — URL-safe identifier (e.g.,
edmonton), used for directory names and compose project - Domain — the domain this instance will serve (e.g.,
edmonton.example.org)
Step 2: Features¶
Toggle which platform features to enable for this instance:
- Media Manager
- Listmonk newsletter sync
- Payments
- Rocket.Chat
- Gancio events
- Jitsi Meet
- SMS Campaigns
Step 3: Email¶
Configure SMTP for the instance, or use MailHog for testing.
Step 4: Tunnel¶
Optionally configure Pangolin tunnel credentials for public access.
Step 5: Review¶
Review all settings, then click Create to start provisioning.
Provisioning Flow¶
When you create an instance, CCP runs a 13-step async provisioning process:
| Step | What Happens |
|---|---|
| 1 | Validate uniqueness (slug + domain) |
| 2 | Allocate 4 ports from ranges |
| 3 | Generate 14 secrets (passwords, JWT keys, encryption keys) |
| 4 | Create Instance record (status: PROVISIONING) |
| 5 | Create instance directory |
| 6 | Copy CML source code (rsync, excluding node_modules/.git/.env) |
| 7 | Decrypt secrets and build template context |
| 8 | Render 7 config files from Handlebars templates (docker-compose.yml, .env, nginx configs, Pangolin, Prometheus) |
| 9 | Copy static files (nginx.conf) |
| 10 | docker compose pull (non-fatal if images are cached) |
| 11 | docker compose build |
| 12 | Start infrastructure (PostgreSQL + Redis), wait for healthy |
| 13 | Start API (runs migrations + seed), then start all remaining services |
The admin GUI polls every 3 seconds during provisioning to show progress. When complete, the instance status changes to RUNNING.
Port Allocation¶
CCP allocates ports from 4 non-overlapping ranges to prevent conflicts between instances:
| Range | Start | End | Purpose |
|---|---|---|---|
| API | 14000 | 14999 | Express API server |
| Admin | 13000 | 13999 | React admin GUI |
| PostgreSQL | 15400 | 15499 | Database |
| Nginx | 10000 | 10999 | Reverse proxy |
Each new instance receives one port from each range. Ports are tracked in the database and released when instances are deleted.
Pages Overview¶
Dashboard¶
At-a-glance fleet status:
- Total instances, running, healthy, degraded, stopped, error counts
- Instance cards with status indicators and quick actions
Instance List¶
Searchable, filterable table of all instances with status, domain, health, and creation date.
Instance Detail¶
5-tab view for each instance:
| Tab | Content |
|---|---|
| Overview | Status, domain, ports, features, health summary |
| Services | Per-container status grid with restart and log-view actions |
| Logs | Real-time log viewer with service filter, tail count, and time range |
| Backups | Backup list with create, download, and delete actions |
| Tunnel | Pangolin tunnel status and configuration |
Backups¶
Cross-instance backup management:
- All backups in one table with instance filter
- Stats: total count, total size, last backup time
- "Backup All Running" bulk action
- Download and delete individual archives
Audit Log¶
Filterable activity trail with 18 action types:
- Instance lifecycle: CREATE, UPDATE, DELETE, START, STOP, RESTART, UPGRADE
- Backups: CREATE, DELETE
- Tunnel: PANGOLIN_SETUP, PANGOLIN_SYNC
- Users: LOGIN, CREATE, UPDATE, DELETE
- Settings: UPDATE
Each entry includes timestamp, user, action, instance, IP address, and details (expandable JSON).
Settings¶
CCP-level configuration:
- Port ranges
- Pangolin credentials
- Default feature flags for new instances
- Health check interval
- Backup retention period
Roles¶
| Role | Capabilities |
|---|---|
| SUPER_ADMIN | Full access: create/delete instances, manage users, view secrets, delete backups |
| OPERATOR | Manage instances: create, start/stop/restart, backups, health checks |
| VIEWER | Read-only: view instances, logs, health, backups, audit log |
Security¶
- JWT authentication with 15-minute access tokens and 7-day refresh tokens (atomic rotation)
- AES-256-GCM encryption for instance secrets stored in the database
- Audit logging on all operations with IP address capture
- Role-based access control on all API endpoints
- Docker socket access restricted to the CCP API container only
Next Steps¶
- Services Overview — learn about the services CCP provisions for each instance
- Updates & Upgrades — upgrading CML instances
- Deployment — production setup with tunneling and SSL