Phase 1-14 complete: - Unified Express.js API (TypeScript, Prisma ORM, PostgreSQL 16) - React Admin GUI (Vite + Ant Design + Zustand) - JWT auth with refresh tokens - Influence: Campaigns, Representatives, Responses, Email Queue - Map: Locations, Cuts, Shifts, Canvassing System - NAR data import infrastructure (2025 format) - Listmonk newsletter integration - Landing page builder (GrapesJS) - MkDocs + Code Server integration - Volunteer portal with GPS tracking - Monitoring stack (Prometheus, Grafana, Alertmanager) - Pangolin tunnel integration Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
218 lines
8.4 KiB
Markdown
218 lines
8.4 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
Changemaker Lite is a self-hosted political campaign platform built with Docker Compose. It consolidates advocacy email campaigns, geographic mapping, volunteer management, and administration into a single TypeScript stack. The primary domain is `cmlite.org`.
|
|
|
|
**Current state:** V2 rebuild in progress on the `v2` branch. See `V2_PLAN.md` for the full roadmap.
|
|
|
|
---
|
|
|
|
## V2 Architecture (Active Development)
|
|
|
|
### Stack
|
|
|
|
- **Single unified Express.js API** — TypeScript, port 4000, Prisma ORM + PostgreSQL 16
|
|
- **React Admin GUI** — Vite + Ant Design + Zustand, port 3000
|
|
- **Nginx reverse proxy** — subdomain routing (`*.cmlite.org`)
|
|
- **NocoDB v2** — read-only data browser on port 8091
|
|
- **JWT auth** — access tokens (15min) + refresh tokens (7 days, stored in DB)
|
|
- **BullMQ** — async email job queue, **Listmonk** for newsletters
|
|
- **Redis** — caching, rate limiting, BullMQ backend
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
changemaker.lite/
|
|
├── api/ # Unified Express.js API (TypeScript)
|
|
│ ├── prisma/ # Schema, migrations, seed
|
|
│ └── src/
|
|
│ ├── config/ # env.ts, database.ts, redis.ts
|
|
│ ├── middleware/ # error-handler, validate, rate-limit, auth, rbac
|
|
│ ├── modules/
|
|
│ │ ├── auth/ # auth.service, auth.routes, auth.schemas
|
|
│ │ ├── users/ # users.service, users.routes, users.schemas
|
|
│ │ ├── influence/ # campaigns, representatives, responses, postal-codes
|
|
│ │ └── map/ # locations, shifts, cuts
|
|
│ ├── types/ # express.d.ts (Request augmentation)
|
|
│ └── utils/ # logger.ts (Winston), metrics.ts (prom-client)
|
|
├── admin/ # React Admin (Vite + Ant Design + Zustand)
|
|
│ └── src/
|
|
│ ├── components/ # ProtectedRoute, AppLayout
|
|
│ ├── pages/ # LoginPage, DashboardPage, UsersPage
|
|
│ ├── stores/ # auth.store.ts (Zustand)
|
|
│ ├── lib/ # api.ts (axios instance + interceptors)
|
|
│ └── types/ # api.ts (TypeScript interfaces)
|
|
├── nginx/ # Reverse proxy config
|
|
├── public-web/ # Public landing pages
|
|
├── docker-compose.yml # V2 orchestration
|
|
├── docker-compose.v1.yml # V1 backup for reference
|
|
└── V2_PLAN.md # Full 14-phase roadmap
|
|
```
|
|
|
|
### Key Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `api/prisma/schema.prisma` | Full database schema (20+ models) |
|
|
| `api/src/server.ts` | API entry point, middleware stack, route wiring |
|
|
| `api/src/config/env.ts` | Zod-validated environment config |
|
|
| `api/src/modules/auth/` | JWT auth (login, register, refresh, logout) |
|
|
| `api/src/modules/users/` | User CRUD with pagination + search |
|
|
| `admin/src/App.tsx` | React admin shell with routing |
|
|
| `admin/src/stores/auth.store.ts` | Zustand auth state with token persistence |
|
|
| `admin/src/lib/api.ts` | Axios instance with 401 refresh interceptor |
|
|
| `docker-compose.yml` | V2 service orchestration |
|
|
| `.env.example` | All required environment variables |
|
|
|
|
### Auth Flow
|
|
|
|
- JWT-based: access tokens (15min) + refresh tokens (7 days, stored in DB)
|
|
- Login → verify bcrypt hash → generate token pair → return tokens + user
|
|
- Refresh → validate refresh token → rotate (invalidate old, issue new) → return new pair
|
|
- Roles: `SUPER_ADMIN`, `INFLUENCE_ADMIN`, `MAP_ADMIN`, `USER`, `TEMP`
|
|
- RBAC middleware: `requireRole(...roles)`, `requireNonTemp`
|
|
|
|
### Nginx Routing
|
|
|
|
| Subdomain | Target |
|
|
|-----------|--------|
|
|
| `app.cmlite.org` | Admin React app (port 3000) |
|
|
| `api.cmlite.org` | Express API (port 4000) |
|
|
| `data.cmlite.org` | NocoDB read-only (port 8091) |
|
|
| `docs.cmlite.org` | MkDocs (port 4001) |
|
|
| `cmlite.org` | Public landing pages |
|
|
|
|
---
|
|
|
|
## V2 Development Commands
|
|
|
|
### API Development
|
|
```bash
|
|
cd api && npm run dev # Dev server with tsx watch (auto-reload)
|
|
cd api && npx tsc --noEmit # Type-check without emitting
|
|
cd api && npx prisma migrate dev # Run/create migrations
|
|
cd api && npx prisma studio # Browse database in browser
|
|
cd api && npx prisma generate # Regenerate Prisma client
|
|
```
|
|
|
|
### Admin GUI Development
|
|
```bash
|
|
cd admin && npm run dev # Vite dev server (port 3000)
|
|
cd admin && npx tsc --noEmit # Type-check without emitting
|
|
cd admin && npm run build # Production build (tsc + vite)
|
|
```
|
|
|
|
### Docker (V2 Services)
|
|
```bash
|
|
docker compose up -d v2-postgres redis api # Start API + dependencies
|
|
docker compose up -d admin # Start admin GUI
|
|
docker compose up -d # Start all v2 services
|
|
docker compose logs -f api # Tail API logs
|
|
docker compose exec api npx prisma migrate dev # Run migrations in container
|
|
docker compose down # Stop all services
|
|
```
|
|
|
|
### Type Checking (Both Projects)
|
|
```bash
|
|
cd api && npx tsc --noEmit && cd ../admin && npx tsc --noEmit
|
|
```
|
|
|
|
---
|
|
|
|
## Port Reference (V2)
|
|
|
|
| Port | Service |
|
|
|------|---------|
|
|
| 3000 | Admin GUI (Vite dev / React) |
|
|
| 3001 | Grafana |
|
|
| 3010 | Homepage |
|
|
| 3030 | Gitea |
|
|
| 4000 | V2 API (Express.js) |
|
|
| 4001 | MkDocs (built static) |
|
|
| 5432 | Listmonk PostgreSQL |
|
|
| 5433 | V2 PostgreSQL (localhost) |
|
|
| 5678 | n8n |
|
|
| 6379 | Redis |
|
|
| 8025 | MailHog Web UI |
|
|
| 8080 | cAdvisor |
|
|
| 8089 | Mini QR |
|
|
| 8091 | NocoDB v2 (read-only) |
|
|
| 8888 | Code Server |
|
|
| 9001 | Listmonk |
|
|
| 9090 | Prometheus |
|
|
| 9093 | Alertmanager |
|
|
|
|
---
|
|
|
|
## V1 Reference (Legacy)
|
|
|
|
V1 code is preserved in `influence/` and `map/` directories and backed up in `docker-compose.v1.yml`.
|
|
|
|
### V1 Architecture
|
|
|
|
Two independent Express.js apps using NocoDB REST API as data layer:
|
|
|
|
- **Influence** (`influence/app/`, port 3333) — Postal code → representative lookup, email campaigns, response tracking
|
|
- **Map** (`map/app/`, port 3000) — Leaflet.js map, volunteer shifts, walk sheets, QR codes
|
|
|
|
Both apps use: session-based auth (Redis-backed), bcryptjs passwords, Bull job queues, NocoDB REST API (not direct DB).
|
|
|
|
### V1 Express App Structure
|
|
```
|
|
app/
|
|
├── server.js # Entry point, middleware stack
|
|
├── config/ # Environment-based configuration
|
|
├── routes/ # Express route definitions
|
|
├── controllers/ # Business logic
|
|
├── services/ # External integrations (nocodb.js, email.js, listmonk.js)
|
|
├── middleware/ # auth.js, csrf.js, rateLimiter.js
|
|
├── utils/ # logger.js, metrics.js, validators.js
|
|
├── public/ # Static assets
|
|
└── templates/ # Server-rendered HTML templates
|
|
```
|
|
|
|
### V1 Commands
|
|
```bash
|
|
cd influence && cp example.env .env
|
|
./scripts/build-nocodb.sh # Initialize NocoDB tables
|
|
docker compose up -d
|
|
docker compose exec influence-app npm test # Run Jest tests
|
|
|
|
cd map && cp example.env .env
|
|
./build-nocodb.sh # Initialize NocoDB tables
|
|
docker compose up -d
|
|
```
|
|
|
|
### V1 Build Scripts
|
|
- `config.sh` — Interactive wizard that generates `.env` with secure random passwords
|
|
- `start-production.sh` — Installs cloudflared, creates tunnel, configures DNS
|
|
- `map/build-nocodb.sh` and `influence/scripts/build-nocodb.sh` — Create NocoDB schema + seed data
|
|
- `reset-site.sh` — Resets MkDocs to baseline
|
|
|
|
### V1 Documentation
|
|
- `influence/README.MD` — Features, config, campaign management, email testing
|
|
- `influence/files-explainer.md` — File-by-file code documentation
|
|
- `map/README.md` — Features, config, setup instructions
|
|
- `map/files-explainer.md` — File-by-file code documentation
|
|
|
|
---
|
|
|
|
## Key Configuration Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `docker-compose.yml` | V2 orchestration (all services) |
|
|
| `docker-compose.v1.yml` | V1 backup |
|
|
| `.env` / `.env.example` | Environment variables (never committed) |
|
|
| `api/prisma/schema.prisma` | Database schema |
|
|
| `nginx/` | Reverse proxy configuration |
|
|
| `configs/prometheus/prometheus.yml` | Monitoring scrape targets |
|
|
| `configs/cloudflare/tunnel-config.yml` | Production ingress routing |
|
|
|
|
## Networking
|
|
|
|
All containers share the `changemaker-lite` bridge network and reference each other by container name. Production uses Cloudflare tunnel with ingress rules mapping `*.cmlite.org` subdomains.
|