169 lines
8.1 KiB
Markdown
169 lines
8.1 KiB
Markdown
# 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 volumes:
|
|
- `db-data`
|
|
- `redis-data`
|
|
- `dcm-storage`
|
|
- `typesense-data`
|
|
|
|
Reset all persisted runtime data:
|
|
|
|
```bash
|
|
docker compose down -v
|
|
```
|
|
|
|
## Core Commands
|
|
|
|
Start or rebuild:
|
|
|
|
```bash
|
|
docker compose up --build -d
|
|
```
|
|
|
|
Stop:
|
|
|
|
```bash
|
|
docker compose down
|
|
```
|
|
|
|
Tail logs:
|
|
|
|
```bash
|
|
docker compose logs -f
|
|
```
|
|
|
|
## Host Bind Mounts
|
|
|
|
If you replace Docker named volumes with host bind mounts (for example `./data/storage:/data/storage`), 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:
|
|
|
|
```bash
|
|
mkdir -p ./data/storage
|
|
sudo chown -R 10001:10001 ./data/storage
|
|
sudo chmod -R u+rwX,g+rwX ./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
|