Compare commits

..

2 Commits

6 changed files with 53 additions and 31 deletions

View File

@@ -4,6 +4,9 @@
# Development defaults (HTTP local stack) # Development defaults (HTTP local stack)
APP_ENV=development APP_ENV=development
HOST_BIND_IP=127.0.0.1 HOST_BIND_IP=127.0.0.1
# Optional host directory for persistent bind mounts in docker-compose.yml.
# Defaults to ./data when unset.
# DCM_DATA_DIR=./data
POSTGRES_USER=dcm POSTGRES_USER=dcm
POSTGRES_PASSWORD=ChangeMe-Postgres-Secret POSTGRES_PASSWORD=ChangeMe-Postgres-Secret

5
.gitignore vendored
View File

@@ -20,9 +20,8 @@ build/
!.env.example !.env.example
# Data and generated artifacts (runtime only) # Data and generated artifacts (runtime only)
data/postgres/ data/
data/redis/ typesense-data/
data/storage/
# OS / IDE # OS / IDE
.DS_Store .DS_Store

View File

@@ -3,7 +3,7 @@
## Stack Snapshot ## Stack Snapshot
- DMS monorepo with FastAPI API + RQ worker (`backend/`) and React + Vite + TypeScript frontend (`frontend/`). - DMS monorepo with FastAPI API + RQ worker (`backend/`) and React + Vite + TypeScript frontend (`frontend/`).
- Services in `docker-compose.yml`: `api`, `worker`, `frontend`, `db` (Postgres), `redis`, `typesense`. - Services in `docker-compose.yml`: `api`, `worker`, `frontend`, `db` (Postgres), `redis`, `typesense`.
- Runtime persistence uses Docker named volumes (`db-data`, `redis-data`, `dcm-storage`, `typesense-data`). - Runtime persistence uses host bind mounts under `${DCM_DATA_DIR:-./data}` (`db-data`, `redis-data`, `storage`, `typesense-data`).
## Project Layout ## Project Layout
- Backend app code: `backend/app/` (`api/`, `services/`, `db/`, `models/`, `schemas/`, `worker/`). - Backend app code: `backend/app/` (`api/`, `services/`, `db/`, `models/`, `schemas/`, `worker/`).

View File

@@ -113,17 +113,26 @@ docker compose logs -f api worker
## Where Your Data Is Stored ## Where Your Data Is Stored
LedgerDock stores data in Docker volumes so it survives container restarts: LedgerDock stores persistent runtime data in host bind mounts. By default the host root is `./data`, or set `DCM_DATA_DIR` to move it:
- `db-data` for PostgreSQL data - `${DCM_DATA_DIR:-./data}/db-data` for PostgreSQL data
- `redis-data` for Redis data - `${DCM_DATA_DIR:-./data}/redis-data` for Redis data
- `dcm-storage` for uploaded files and app storage - `${DCM_DATA_DIR:-./data}/storage` for uploaded files and app storage
- `typesense-data` for the search index - `${DCM_DATA_DIR:-./data}/typesense-data` for the search index
Before first run, create storage and grant write access to container runtime user `uid=10001`:
```bash
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
```
To remove everything, including data: To remove everything, including data:
```bash ```bash
docker compose down -v docker compose down
rm -rf ${DCM_DATA_DIR:-./data}
``` ```
Warning: this permanently deletes your LedgerDock data on this machine. Warning: this permanently deletes your LedgerDock data on this machine.

View File

@@ -10,16 +10,17 @@
- `worker` (RQ worker via `python -m app.worker.run_worker`) - `worker` (RQ worker via `python -m app.worker.run_worker`)
- `frontend` (Vite React UI) - `frontend` (Vite React UI)
Persistent volumes: Persistent host bind mounts (default root `./data`, overridable with `DCM_DATA_DIR`):
- `db-data` - `${DCM_DATA_DIR:-./data}/db-data`
- `redis-data` - `${DCM_DATA_DIR:-./data}/redis-data`
- `dcm-storage` - `${DCM_DATA_DIR:-./data}/storage`
- `typesense-data` - `${DCM_DATA_DIR:-./data}/typesense-data`
Reset all persisted runtime data: Reset all persisted runtime data:
```bash ```bash
docker compose down -v docker compose down
rm -rf ${DCM_DATA_DIR:-./data}
``` ```
## Core Commands ## Core Commands
@@ -42,6 +43,22 @@ Tail logs:
docker compose logs -f 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:
```bash
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 ## 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. The frontend Dockerfile uses `node:22-slim` with a standard `npm ci --no-audit` install step and no npm-specific build tuning flags.

View File

@@ -6,7 +6,7 @@ services:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}
POSTGRES_DB: ${POSTGRES_DB:?POSTGRES_DB must be set} POSTGRES_DB: ${POSTGRES_DB:?POSTGRES_DB must be set}
volumes: volumes:
- db-data:/var/lib/postgresql/data - ${DCM_DATA_DIR:-./data}/db-data:/var/lib/postgresql/data
healthcheck: healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:?POSTGRES_USER must be set} -d ${POSTGRES_DB:?POSTGRES_DB must be set}"] test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:?POSTGRES_USER must be set} -d ${POSTGRES_DB:?POSTGRES_DB must be set}"]
interval: 10s interval: 10s
@@ -25,7 +25,7 @@ services:
- "--requirepass" - "--requirepass"
- "${REDIS_PASSWORD:?REDIS_PASSWORD must be set}" - "${REDIS_PASSWORD:?REDIS_PASSWORD must be set}"
volumes: volumes:
- redis-data:/data - ${DCM_DATA_DIR:-./data}/redis-data:/data
networks: networks:
- internal - internal
@@ -36,7 +36,7 @@ services:
- "--api-key=${TYPESENSE_API_KEY:?TYPESENSE_API_KEY must be set}" - "--api-key=${TYPESENSE_API_KEY:?TYPESENSE_API_KEY must be set}"
- "--enable-cors" - "--enable-cors"
volumes: volumes:
- typesense-data:/data - ${DCM_DATA_DIR:-./data}/typesense-data:/data
restart: unless-stopped restart: unless-stopped
networks: networks:
- internal - internal
@@ -84,7 +84,7 @@ services:
- ALL - ALL
volumes: volumes:
- ./backend/app:/app/app - ./backend/app:/app/app
- dcm-storage:/data - ${DCM_DATA_DIR:-./data}/storage:/data/storage
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
@@ -124,7 +124,7 @@ services:
TYPESENSE_COLLECTION_NAME: documents TYPESENSE_COLLECTION_NAME: documents
volumes: volumes:
- ./backend/app:/app/app - ./backend/app:/app/app
- dcm-storage:/data - ${DCM_DATA_DIR:-./data}/storage:/data/storage
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
cap_drop: cap_drop:
@@ -169,12 +169,6 @@ services:
internal: internal:
restart: unless-stopped restart: unless-stopped
volumes:
db-data:
redis-data:
dcm-storage:
typesense-data:
networks: networks:
internal: internal:
driver: bridge driver: bridge