feat: add dockerized api+postgres local stack

This commit is contained in:
2026-02-26 16:28:27 -06:00
parent 4708144832
commit ab361e1bda
6 changed files with 119 additions and 8 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
node_modules
dist
.git
.gitignore
.env
.env.*
!.env.example
subcult-corp
npm-debug.log*

View File

@@ -1,6 +1,7 @@
OPENROUTER_API_KEY=sk-or-v1-your-key-here
LLM_MODEL=deepseek/deepseek-chat-v3-0324:free
PORT=3001
API_HOST_PORT=3001
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/improv_court
VERDICT_VOTE_WINDOW_MS=20000
SENTENCE_VOTE_WINDOW_MS=20000

30
Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
# syntax=docker/dockerfile:1.7
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
COPY public ./public
COPY db ./db
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
COPY --from=builder /app/db ./db
EXPOSE 3001
CMD ["sh", "-c", "npm run migrate:dist && npm run start"]

View File

@@ -7,13 +7,13 @@ It does **not** depend on `subcult-corp` at runtime.
- Multi-agent courtroom roles (judge, prosecutor, defense, witnesses, bailiff)
- Phase-based court flow:
- `case_prompt`
- `openings`
- `witness_exam`
- `closings`
- `verdict_vote`
- `sentence_vote`
- `final_ruling`
- `case_prompt`
- `openings`
- `witness_exam`
- `closings`
- `verdict_vote`
- `sentence_vote`
- `final_ruling`
- Live SSE stream per session
- Jury verdict and sentence voting endpoints
- Minimal stripped web UI (`public/index.html`)
@@ -47,6 +47,36 @@ If `DATABASE_URL` is missing, the app falls back to in-memory storage (non-durab
4. Open:
- `http://localhost:3001`
## Run with Docker (API + Postgres)
This repo includes a `docker-compose.yml` that starts both:
- `api` (the Improv Court server)
- `db` (Postgres 16)
Start the full stack:
- `npm run docker:up`
Or directly:
- `docker compose up --build`
Stop the stack:
- `npm run docker:down`
The API container runs migrations on startup (`npm run migrate:dist`) before starting the server.
Endpoints when running with compose:
- API: `http://localhost:${API_HOST_PORT:-3001}`
- Postgres: internal-only by default (`db:5432` inside compose network)
If port `3001` is already in use on your machine, set `API_HOST_PORT` in `.env` (for example `API_HOST_PORT=3002`) and restart compose.
If you need host access to Postgres, add a `ports` mapping to the `db` service in `docker-compose.yml` (for example `"5433:5432"` to avoid conflicts with local Postgres).
## API
- `GET /api/health`

38
docker-compose.yml Normal file
View File

@@ -0,0 +1,38 @@
services:
db:
image: postgres:16-alpine
container_name: improv-court-db
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: improv_court
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d improv_court"]
interval: 5s
timeout: 5s
retries: 10
api:
build:
context: .
dockerfile: Dockerfile
container_name: improv-court-api
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
PORT: 3001
DATABASE_URL: postgresql://postgres:postgres@db:5432/improv_court
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
LLM_MODEL: ${LLM_MODEL:-deepseek/deepseek-chat-v3-0324:free}
VERDICT_VOTE_WINDOW_MS: ${VERDICT_VOTE_WINDOW_MS:-20000}
SENTENCE_VOTE_WINDOW_MS: ${SENTENCE_VOTE_WINDOW_MS:-20000}
ports:
- "${API_HOST_PORT:-3001}:3001"
volumes:
postgres_data:

View File

@@ -7,7 +7,10 @@
"dev": "tsx watch src/server.ts",
"build": "tsc -p tsconfig.json",
"start": "node dist/server.js",
"migrate": "tsx src/scripts/migrate.ts"
"migrate": "tsx src/scripts/migrate.ts",
"migrate:dist": "node dist/scripts/migrate.js",
"docker:up": "docker compose up --build",
"docker:down": "docker compose down"
},
"dependencies": {
"dotenv": "^17.2.3",