This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Polis is an AI-powered democratic engagement platform for large-scale opinion gathering. It uses real-time machine learning to cluster participants and surface representative comments.
make start # Start full dev environment (uses .env)
make start-rebuild # Start with rebuild
make stop # Stop all containers
make PROD start # Production mode (uses prod.env); runs no math engine (see README "Math engine")
make DETACH=true start # Run in backgroundmake rebuild-server # Rebuild server (auto-restarts on code changes)
make rebuild-web # Rebuild client web apps (file-server + client-participation-alpha)
make rebuild-delphi # Rebuild delphi ML servicemake psql-shell # Open psql shell
make refresh-db # Drop DB volume and reinitialize
make refresh-prodclone # Reinitialize from prodclone.dump
# Direct psql access
psql postgresql://postgres:oiPorg3Nrz0yqDLE@localhost:5432/polis-devmake e2e-run # Run E2E tests (Cypress)
make e2e-run-interactive # Open Cypress GUI
# Server unit tests (run inside container or with local node)
cd server && npm test
cd server && npm run test:unit
cd server && npm run test:integration
# Client-participation-alpha
cd client-participation-alpha && npm run lint
cd client-participation-alpha && npm run format
cd client-participation-alpha && npm run verify # format + lint + buildcd e2e
npm run test:admin # Admin interface tests
npm run test:alpha # Alpha client tests
npm run test:auth # Authentication tests
npm run test:participation # Participation & embed tests
npm run test:conversation # Conversation workflow tests- server (Node.js/TypeScript) - REST API, handles votes, comments, conversations
- math-python (Python, delphi image) - Math engine: polls votes, runs PCA and K-means, writes
math_mainunder itsmath_envlabel (the Clojuremathservice is retired) - delphi (Python) - Modern ML: UMAP, topic modeling, LLM narrative synthesis
- client-participation-alpha (Astro/React) - Participant-facing UI
- file-server - Serves static assets for client-admin and client-report
- nginx-proxy - Routes requests to appropriate services
- postgres - Primary data store
- dynamodb - Delphi job queue and results storage
- ollama - Local LLM inference (optional)
- minio - S3-compatible storage for dev
server/ # Node.js API (TypeScript)
delphi/ # Python ML service (see delphi/CLAUDE.md for details)
client-admin/ # Admin console (React/Webpack)
client-participation-alpha/ # Participant UI (Astro/React)
client-report/ # Analytics/reports (React/D3)
file-server/ # Static file serving + nginx config
e2e/ # Cypress E2E tests
docs/ # Configuration and deployment docs
- Participants submit votes/comments via client apps
- Server stores in PostgreSQL and triggers math/delphi processing
- Math engine (math-python) polls DB, runs PCA/K-means, writes results back
- Delphi service uses DynamoDB job queue for UMAP/LLM processing
- Results displayed in client-report and admin dashboards
- zid - conversation ID (internal)
- pid - participant ID
- tid - comment (statement) ID
- PCA - Principal Component Analysis (dimensionality reduction)
- UMAP - Uniform Manifold Approximation (modern dimensionality reduction)
- Docker and Docker Compose
- mkcert for SSL certificates (required for OIDC simulator)
- JWT keys for participant auth
# Install SSL certificates
brew install mkcert nss
mkcert -install
mkdir -p ~/.simulacrum/certs
cd ~/.simulacrum/certs
mkcert -cert-file localhost.pem -key-file localhost-key.pem localhost 127.0.0.1 ::1 oidc-simulator host.docker.internal
cp "$(mkcert -CAROOT)/rootCA.pem" ~/.simulacrum/certs/
# Generate JWT keys
make generate-jwt-keys
# Start
cp example.env .env
make startadmin@polis.test/Te$tP@ssw0rd*moderator@polis.test/Te$tP@ssw0rd*test.user.0@polis.testthroughtest.user.49@polis.test(same password)
- 80/443: nginx-proxy (main entry point)
- 5000: server API (direct, dev only)
- 4321: client-participation-alpha
- 5432: PostgreSQL
- 8000: DynamoDB local
- 9000/9001: MinIO (S3)
- 11434: Ollama
Environment variables are documented in configuration, with per-site defaults and secret status in the source census. Deployment configuration distinguishes Compose/build inputs and all 153 P065 external-service entries. Key files:
.env- Development config (copy fromexample.env)prod.env- Production configtest.env- Test config
--profile postgres- Include containerized PostgreSQL--profile local-services- Include DynamoDB, MinIO, SES local emulators
The server auto-rebuilds and restarts on TypeScript changes when running in dev mode. Key patterns:
- Express 3.x API (legacy)
- PostgreSQL via
pglibrary - TypeScript; server
strictandnoImplicitAnyare false in server/tsconfig.json:28. Do not assume strict-mode checks passed. - Jest for testing
- Auto-reload via nodemon in dev mode
Commands:
cd server
npm run dev # Build watch + nodemon
npm run build # TypeScript compile
npm run format # Prettier formatting
npm run lint # ESLint
npm run test:unit # Unit tests only
npm run test:integration # Integration tests onlyModern participant UI with Astro server output, a Node standalone adapter and React components (astro.config.mjs:10). Does NOT auto-rebuild in Docker.
Commands:
cd client-participation-alpha
npm run dev # Local dev server (port 4321)
npm run build # Production build
npm run preview # Preview production build
npm run lint # ESLint
npm run format # Prettier formatting
npm run verify # format + lint + buildKey structure:
src/pages/- Astro routessrc/components/- React components (visualization, surveys, topics)src/api/- Centralized API clientsrc/strings/- 30+ language translations
See delphi/CLAUDE.md for comprehensive Delphi documentation including:
- DynamoDB table schemas
- Job queue system
- Pipeline execution
- Debugging procedures
Key debugging:
# View Delphi logs
docker logs polis-dev-delphi-1
# Check job results in DynamoDB (contains FULL system logs)
docker exec polis-dev-delphi-1 python -c "
import boto3, json
dynamodb = boto3.resource('dynamodb', endpoint_url='http://dynamodb:8000', region_name='us-east-1')
table = dynamodb.Table('Delphi_JobQueue')
# List recent jobs or get specific job by ID
"Since client apps don't auto-rebuild in Docker:
# Make changes in client-participation-alpha
make DETACH=true rebuild-web # Rebuilds file-server + client-participation-alpha# Open psql shell
make psql-shell
# Common queries
SELECT zid, topic FROM conversations WHERE LOWER(topic) LIKE '%keyword%';
SELECT COUNT(*) FROM votes WHERE zid = 123;
SELECT COUNT(DISTINCT pid) FROM participants WHERE zid = 123;docker logs polis-dev-server-1 # Server logs
docker logs polis-dev-delphi-1 # Delphi logs
docker logs polis-dev-math-python-1 # Math engine logs
docker logs polis-dev-nginx-proxy-1 # Nginx logsmake start-FULL-REBUILD # Nuclear option: removes all containers, volumes, imagesmake start-recreate # Recreate containers with new envDisable AirPlay Receiver in System Settings, or change API_SERVER_PORT in .env.
Client apps (client-admin, client-participation-alpha) are pre-built and served as static assets via file-server. They don't auto-rebuild:
make DETACH=true rebuild-web # Rebuild and restart web containersServer should auto-rebuild on TypeScript changes. If not:
make rebuild-server # Force rebuild server container- JWT-based using keys in
server/keys/ - XID (cross-identity) system for SSO
- OIDC simulator for development
- Email/password or OIDC
- Test accounts listed above
Server runs on port 5000 (dev) or via nginx proxy on 80/443:
/api/v3/conversations- Conversation CRUD/api/v3/comments- Submit/retrieve comments/api/v3/votes- Submit votes/api/v3/participationInit- Initialize participant session/api/v3/participants- Participant data/api/v3/math/pca2- PCA visualization data/api/v3/delphi/*- Delphi ML results
TAG- Image tag (from .env)GIT_HASH- Git commit hashPOSTGRES_DOCKER- Use containerized PostgreSQLLOCAL_SERVICES_DOCKER- Use local service emulators
make PROD start # Use prod.env configuration
make build-web-assets # Build and extract static assets to build/- Unit Tests - Server TypeScript code
- Integration Tests - API endpoints with database
- E2E Tests - Full user workflows via Cypress
- Manual Testing - Use test accounts above
- Server uses
--max_old_space_size=2048for Node memory - Math engine (math-python) processes conversations with a per-conversation worker pool
- Delphi uses job queue for async processing
- Client-participation-alpha uses SSR for initial load