feat: add Docker Compose deployment for backend/frontend/postgres

Backend Dockerfile runs drizzle-kit migrate on start, frontend serves the
built Vite app via nginx and proxies /api to the backend container.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBf3yfnnHzMQ5qhLV2285A
This commit is contained in:
patrickandClaude Sonnet 5 committed 2026-09-11 15:28:01 +02:00
1 parent b38a5a4a57
commit b5ac041c32
8 files changed
+123

No files matched your search

+3
View File
@@ -15,6 +15,9 @@ synapse/data/
synapse/pgdata/
!synapse/homeserver.yaml.sample
# talktime app stack runtime data (docker-compose.yml at repo root)
/pgdata/
# misc
.DS_Store
*.pem
+4
View File
@@ -0,0 +1,4 @@
node_modules
dist
.env
.env.local
+10
View File
@@ -0,0 +1,10 @@
FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
ENV NODE_ENV=production
EXPOSE 4000
CMD ["sh", "-c", "npx drizzle-kit migrate && node dist/server.js"]
+39
View File
@@ -0,0 +1,39 @@
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: talktime
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme}
POSTGRES_DB: talktime
volumes:
- ./pgdata:/var/lib/postgresql/data
backend:
build: ./backend
restart: unless-stopped
depends_on:
- db
environment:
DATABASE_URL: postgresql://talktime:${DB_PASSWORD:-changeme}@db:5432/talktime
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET must be set}
PORT: 4000
APP_BASE_URL: ${APP_BASE_URL:-http://localhost:8080}
SYNAPSE_BASE_URL: ${SYNAPSE_BASE_URL}
SYNAPSE_ADMIN_TOKEN: ${SYNAPSE_ADMIN_TOKEN}
SYNAPSE_SERVER_NAME: ${SYNAPSE_SERVER_NAME}
SMTP_HOST: ${SMTP_HOST:-}
SMTP_PORT: ${SMTP_PORT:-587}
SMTP_USER: ${SMTP_USER:-}
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
MAIL_FROM: ${MAIL_FROM:-TalkTime <no-reply@talktime.local>}
ports:
- "4000:4000"
frontend:
build: ./frontend
restart: unless-stopped
depends_on:
- backend
ports:
- "8080:80"
+34
View File
@@ -0,0 +1,34 @@
# Deployment
## Lokal / Server mit Docker Compose
Voraussetzung: Synapse läuft bereits (siehe `synapse/README.md`), Admin-Token liegt vor.
```bash
export DB_PASSWORD=<starkes-passwort>
export JWT_SECRET=<langer-zufalls-string>
export APP_BASE_URL=http://localhost:8080
export SYNAPSE_BASE_URL=http://<synapse-host>:8008
export SYNAPSE_ADMIN_TOKEN=<token>
export SYNAPSE_SERVER_NAME=chat.talktime.local
docker compose up -d --build
```
Startet:
- `db` — PostgreSQL 16, Daten in `./pgdata`
- `backend` — Fastify-API, migriert die DB beim Start automatisch (`drizzle-kit migrate`), Port 4000
- `frontend` — gebautes Vite-Frontend hinter nginx, proxied `/api/*` zu `backend:4000`, Port 8080
App danach unter `http://localhost:8080` erreichbar.
## Produktivbetrieb
- Reverse Proxy (nginx/Caddy) terminiert TLS vor Port 8080 (frontend) und ggf. Synapse (8008/8448) — Ports nicht direkt exponieren.
- `.env`-Datei statt `export` nutzen (nicht committen), Secrets nie in Git.
- Backups: `pgdata/`-Volume (App-DB) und Synapse-eigene Postgres-DB regelmäßig sichern (`pg_dump`).
- Updates: `git pull && docker compose up -d --build`.
## Environment-Variablen (Backend)
Siehe `backend/.env.example` für die vollständige Liste (lokal ohne Docker) bzw. oben für Compose.
+4
View File
@@ -0,0 +1,4 @@
node_modules
dist
.env
.env.local
+11
View File
@@ -0,0 +1,11 @@
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
+18
View File
@@ -0,0 +1,18 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location /api/ {
proxy_pass http://backend:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
try_files $uri /index.html;
}
}