Files
ledgerdock/doc/operations-and-configuration.md

8.3 KiB

Operations And Configuration

Runtime Services

docker-compose.yml defines:

  • db (Postgres 16)
  • redis (Redis 7)
  • typesense (Typesense 29)
  • api (FastAPI backend)
  • worker (RQ worker via python -m app.worker.run_worker)
  • frontend (Vite React UI)

Persistent host bind mounts (default root ./data, overridable with DCM_DATA_DIR):

  • ${DCM_DATA_DIR:-./data}/db-data
  • ${DCM_DATA_DIR:-./data}/redis-data
  • ${DCM_DATA_DIR:-./data}/storage
  • ${DCM_DATA_DIR:-./data}/typesense-data

Reset all persisted runtime data:

docker compose down
rm -rf ${DCM_DATA_DIR:-./data}

Core Commands

Start or rebuild:

docker compose up --build -d

Stop:

docker compose down

Tail logs:

docker compose logs -f

Host Bind Mounts

Compose is configured with host bind mounts for persistent data. Ensure host directories exist and are writable by the backend runtime user.

Backend and worker run as non-root user uid=10001 inside containers. For host-mounted storage paths:

mkdir -p ${DCM_DATA_DIR:-./data}/storage
sudo chown -R 10001:10001 ${DCM_DATA_DIR:-./data}/storage
sudo chmod -R u+rwX,g+rwX ${DCM_DATA_DIR:-./data}/storage

If permissions are incorrect, API startup fails with errors similar to:

  • PermissionError: [Errno 13] Permission denied: '/data/storage'
  • FileNotFoundError for /data/storage/originals

Frontend Build Baseline

The frontend Dockerfile uses node:22-slim with a standard npm ci --no-audit install step and no npm-specific build tuning flags.

Authentication Model

  • Legacy shared build-time frontend token behavior was removed.
  • API now uses server-issued sessions that are stored in HttpOnly cookies (dcm_session) with a separate CSRF cookie (dcm_csrf).
  • Bootstrap users are provisioned from environment:
    • AUTH_BOOTSTRAP_ADMIN_USERNAME
    • AUTH_BOOTSTRAP_ADMIN_PASSWORD
    • optional AUTH_BOOTSTRAP_USER_USERNAME
    • optional AUTH_BOOTSTRAP_USER_PASSWORD
  • Login brute-force protection is enabled by default and keyed by username and source IP:
    • AUTH_LOGIN_FAILURE_LIMIT
    • AUTH_LOGIN_FAILURE_WINDOW_SECONDS
    • AUTH_LOGIN_LOCKOUT_BASE_SECONDS
    • AUTH_LOGIN_LOCKOUT_MAX_SECONDS
    • Frontend signs in through /api/v1/auth/login and relies on browser session persistence for valid cookie-backed sessions.

DEV And LIVE Configuration Matrix

Use .env.example as baseline. The table below documents user-managed settings and recommended values.

Variable Local DEV (HTTP, docker-only) LIVE (HTTPS behind reverse proxy)
APP_ENV development production
HOST_BIND_IP 127.0.0.1 or local LAN bind if needed 127.0.0.1 (publish behind proxy only)
PUBLIC_BASE_URL http://localhost:8000 https://api.example.com
VITE_API_BASE empty for host-derived http://<frontend-host>:8000/api/v1, or explicit local URL https://api.example.com/api/v1 (build-time value for production frontend image)
VITE_ALLOWED_HOSTS optional comma-separated hostnames, for example localhost,docs.lan optional comma-separated public frontend hostnames, for example app.example.com
CORS_ORIGINS ["http://localhost:5173","http://localhost:3000"] exact frontend origins only, for example ["https://app.example.com"]
REDIS_URL redis://:<password>@redis:6379/0 in isolated local network rediss://:<password>@redis.internal:6379/0
REDIS_SECURITY_MODE compat or auto strict
REDIS_TLS_MODE allow_insecure or auto required
AUTH_LOGIN_FAILURE_LIMIT default 5 tune to identity-protection policy and support requirements
AUTH_LOGIN_FAILURE_WINDOW_SECONDS default 900 tune to identity-protection policy and support requirements
AUTH_LOGIN_LOCKOUT_BASE_SECONDS default 30 tune to identity-protection policy and support requirements
AUTH_LOGIN_LOCKOUT_MAX_SECONDS default 900 tune to identity-protection policy and support requirements
AUTH_COOKIE_DOMAIN empty (host-only cookies) parent frontend/API domain for split hosts, for example docs.lan
AUTH_COOKIE_SAMESITE auto none for cross-origin frontend/API deployments, lax or strict for same-origin
PROVIDER_BASE_URL_ALLOW_HTTP true only when intentionally testing local HTTP provider endpoints false
PROVIDER_BASE_URL_ALLOW_PRIVATE_NETWORK true only for trusted local development targets false
PROVIDER_BASE_URL_ALLOWLIST allow needed test hosts explicit production allowlist, for example ["api.openai.com"]
PROCESSING_LOG_STORE_MODEL_IO_TEXT false by default; temporary true only for controlled debugging false
PROCESSING_LOG_STORE_PAYLOAD_TEXT false by default; temporary true only for controlled debugging false
CONTENT_EXPORT_MAX_DOCUMENTS default 250 or lower based on host memory tuned to production capacity
CONTENT_EXPORT_MAX_TOTAL_BYTES default 52428800 (50 MiB) or lower tuned to production capacity
CONTENT_EXPORT_RATE_LIMIT_PER_MINUTE default 6 tuned to API throughput and abuse model

PUBLIC_BASE_URL must point to the backend API public URL, not the frontend URL.

HTTPS Proxy Deployment Notes

This application supports both:

  • local HTTP-only operation (no TLS termination in containers)
  • HTTPS deployment behind a reverse proxy that handles TLS

Recommended LIVE pattern:

  1. Proxy terminates TLS and forwards to api and frontend internal HTTP endpoints.
  2. Keep container published ports bound to localhost or internal network.
  3. Set PUBLIC_BASE_URL and VITE_API_BASE to final HTTPS URLs.
  4. Set CORS_ORIGINS to exact HTTPS frontend origins.
  5. Credentialed CORS is enabled and constrained for cookie-based sessions with strict origin allowlists.

Security Controls

  • CORS uses explicit origin allowlist only; broad origin regex matching is removed.
  • Worker Redis startup validates URL auth and TLS policy before consuming jobs.
  • Provider API keys are encrypted at rest with standard AEAD (cryptography Fernet).
    • legacy enc-v1 payloads are read for backward compatibility
    • new writes use enc-v2
  • Processing logs default to metadata-only persistence.
  • Login endpoint applies escalating temporary lockout on repeated failed credentials using Redis-backed subject keys for username and source IP.
  • Markdown export enforces:
    • max document count
    • max total markdown bytes
    • per-user Redis-backed rate limit
    • spool-file streaming to avoid unbounded memory archives
  • User-role document access is owner-scoped for non-admin accounts.

Frontend Runtime

  • Frontend no longer consumes VITE_API_TOKEN.
  • Frontend image target is environment-driven:
    • APP_ENV=development builds the development target and runs Vite dev server
    • APP_ENV=production builds the production target and serves static assets through unprivileged Nginx
  • Frontend Docker targets are selected from APP_ENV, so use development or production values.
  • Production frontend Nginx uses non-root runtime plus /tmp temp-path configuration so it can run with container capability dropping enabled.
  • Vite dev server host allowlist uses the union of:
    • hostnames extracted from CORS_ORIGINS
    • optional explicit hostnames from VITE_ALLOWED_HOSTS
  • VITE_ALLOWED_HOSTS only affects development mode where Vite is running.
  • API auth cookies support optional domain and SameSite configuration through AUTH_COOKIE_DOMAIN and AUTH_COOKIE_SAMESITE.
  • HTTPS cookie security detection falls back to PUBLIC_BASE_URL scheme when proxy headers are missing.
  • CSRF validation accepts header matches against any dcm_csrf cookie value in the request, covering stale plus fresh duplicate-cookie transitions.
  • Session authentication is cookie-based; browser reloads and new tabs can reuse an active session until it expires or is revoked.
  • Protected media and file download flows still use authenticated fetch plus blob/object URL handling.

Validation Checklist

After configuration changes:

  • GET /api/v1/health returns healthy response
  • login succeeds for bootstrap admin user
  • admin can upload, search, open preview, download, and export markdown
  • user account can only access its own documents
  • admin-only settings and processing logs are not accessible by user role
  • docker compose logs -f api worker shows no startup validation failures