Files
InkNote/docker-compose.dev.yml
T
marcandClaude Opus 5 43a98b0972 A second way in: signing in through an identity provider
OpenID Connect, off unless four settings are present. It is a second way to
the same token the password login mints — every route and the WebSocket
still know only a signed JWT — which is why it fits in one file and needs no
new dependency: Node imports a JWK itself, so checking an ID token is a
signature and five claims.

Authorization Code with PKCE, exchanged on the server so the client secret
stays there. The browser comes home with a one-time ticket rather than the
token, because a token in a redirect URL sits in the history, in the proxy's
log and in the referrer of the next request.

Somebody the app has not seen gets an account; an account that already
exists under that name is linked to the identity rather than duplicated, by
subject from then on. Never an administrator. An account made this way has
no password here, and the interface stops offering one — but an admin can
still set one, which is the way back in if the provider is ever gone.

The suite signs in at a provider of its own that signs real RS256 tokens,
and holds down the four ways the journey must fail as well as the way it
must work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 16:38:24 +02:00

103 lines
4.1 KiB
YAML

# ─────────────────────────────────────────────
# InkNote — lokales Test-Setup (baut aus dem Quellcode)
#
# Prod-nah (nginx + gebautes Bundle) auf :3000
# docker compose -f docker-compose.dev.yml up -d --build
#
# Mit Hot-Reload-Dev-Server auf :5173 zusätzlich
# docker compose -f docker-compose.dev.yml --profile dev up -d --build
#
# docker compose -f docker-compose.dev.yml logs -f
# docker compose -f docker-compose.dev.yml down
#
# Secrets kommen aus .env (nicht committen!)
# Daten liegen unter ${INKNOTE_DATA_DIR:-./data} auf dem Host.
# ─────────────────────────────────────────────
services:
inknote-server:
build:
context: ./backend
dockerfile: Dockerfile
container_name: inknote-server-dev
restart: unless-stopped
environment:
- PORT=4000
- JWT_SECRET=${JWT_SECRET}
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
# Only used when the database has no users at all: creates the first admin.
- INKNOTE_ADMIN_USER=${INKNOTE_ADMIN_USER:-}
- INKNOTE_ADMIN_PASSWORD=${INKNOTE_ADMIN_PASSWORD:-}
- NODE_ENV=development
# Optional tuning; unset means the server's own defaults apply.
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-}
- INKNOTE_MAX_IMAGE_MB=${INKNOTE_MAX_IMAGE_MB:-}
- INKNOTE_MAX_PDF_MB=${INKNOTE_MAX_PDF_MB:-}
- MAX_VERSIONS_PER_NOTE=${MAX_VERSIONS_PER_NOTE:-}
- VERSION_RETENTION_DAYS=${VERSION_RETENTION_DAYS:-}
- VERSION_COALESCE_MINUTES=${VERSION_COALESCE_MINUTES:-}
# Signing in through an identity provider — see .env.example. Unset means
# the app is password-only and the sign-in screen shows nothing about it.
# Signing in through an identity provider. In development this points at
# the throwaway one the OIDC suite starts (e2e/fakeIdp.mjs) — which only
# exists while that suite runs, so the button on the sign-in screen is
# there the rest of the time and simply fails. That is the price of
# testing the real redirect against a real signature.
- INKNOTE_PUBLIC_URL=${INKNOTE_PUBLIC_URL:-http://localhost:3000}
- INKNOTE_OIDC_ISSUER=${INKNOTE_OIDC_ISSUER:-http://idp.test:3011}
- INKNOTE_OIDC_CLIENT_ID=${INKNOTE_OIDC_CLIENT_ID:-inknote-test}
- INKNOTE_OIDC_CLIENT_SECRET=${INKNOTE_OIDC_CLIENT_SECRET:-test-secret}
- INKNOTE_OIDC_LABEL=${INKNOTE_OIDC_LABEL:-Test IdP}
- INKNOTE_OIDC_SCOPES=${INKNOTE_OIDC_SCOPES:-}
- INKNOTE_OIDC_REDIRECT_URI=${INKNOTE_OIDC_REDIRECT_URI:-}
# The provider runs on the Docker host (inside the test container, which
# shares the host's network). Same name on both sides, or the issuer in the
# token would not match the one configured here.
extra_hosts:
- "idp.test:host-gateway"
# Bind mounts, not named volumes: the data sits in a plain directory on the
# Docker host where the host's own backup picks it up.
user: "${INKNOTE_UID:-1000}:${INKNOTE_GID:-1000}"
volumes:
- ${INKNOTE_DATA_DIR:-./data}/db:/app/data
- ${INKNOTE_DATA_DIR:-./data}/uploads:/app/uploads
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:4000/api/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
inknote-web:
build:
context: ./frontend
dockerfile: dockerfile
container_name: inknote-web-dev
restart: unless-stopped
ports:
- "3000:80"
depends_on:
inknote-server:
condition: service_healthy
# Vite mit Hot-Reload — nur mit "--profile dev"
inknote-vite:
image: node:20-alpine
container_name: inknote-vite-dev
profiles: ["dev"]
working_dir: /app
command: sh -c "npm install && npm run dev"
environment:
- VITE_API_TARGET=http://inknote-server:4000
volumes:
- ./frontend:/app
- inknote-dev-node-modules:/app/node_modules
ports:
- "5173:5173"
depends_on:
inknote-server:
condition: service_healthy
volumes:
inknote-dev-node-modules: