This runbook describes how to run the project locally (developer machine) and on the internal server.
The goal is a clean separation between:
/mnt/niederlassungen)docker-compose.yml
/mnt/niederlassungen:/mnt/niederlassungen:rodocker-compose.local.yml
./.local_nas:/mnt/niederlassungen:roCommitted templates:
.env.docker.example.env.local.exampleLocal runtime env (not committed):
.env.dockerServer runtime env (not committed):
.env.serverThe compose file uses:
ENV_FILE to select which env file is loaded into the app container.Copy the template:
cp .env.docker.example .env.docker
Then edit .env.docker:
SESSION_SECRET (>= 32 characters)For local HTTP testing add:
SESSION_COOKIE_SECURE=false
Create a minimal NAS tree:
mkdir -p ./.local_nas/NL01/2024/10/23
printf "dummy" > ./.local_nas/NL01/2024/10/23/test.pdf
Run with the local override:
docker compose -f docker-compose.yml -f docker-compose.local.yml up --build
curl -s http://localhost:3000/api/health
Expected (example):
db is oknas.entriesSample contains NL01Generate a bcrypt hash (local):
node -e "const bcrypt=require('bcryptjs'); console.log(bcrypt.hashSync('secret-password', 10))"
Open Mongo shell inside the DB container:
docker exec -it rhl-lieferscheine-db mongosh -u root -p supersecret --authenticationDatabase admin
In mongosh:
use rhl-lieferscheine
show collections
db.users.insertOne({
username: "branchuser",
email: "nl01@example.com",
passwordHash: "<PASTE_HASH_HERE>",
role: "branch",
branchId: "NL01",
createdAt: new Date(),
updatedAt: new Date()
})
Login (stores cookie in cookies.txt):
curl -i -c cookies.txt \
-H "Content-Type: application/json" \
-d '{"username":"BranchUser","password":"secret-password"}' \
http://localhost:3000/api/auth/login
Call endpoints with cookie:
curl -i -b cookies.txt http://localhost:3000/api/branches
curl -i -b cookies.txt http://localhost:3000/api/branches/NL01/years
curl -i -b cookies.txt http://localhost:3000/api/branches/NL01/2024/months
curl -i -b cookies.txt http://localhost:3000/api/branches/NL01/2024/10/days
curl -i -b cookies.txt "http://localhost:3000/api/files?branch=NL01&year=2024&month=10&day=23"
RBAC negative test (expected 403):
curl -i -b cookies.txt http://localhost:3000/api/branches/NL02/years
Logout:
curl -i -b cookies.txt -c cookies.txt http://localhost:3000/api/auth/logout
Git Bash may rewrite paths like /mnt/niederlassungen.
If you need to run docker exec ... ls /mnt/niederlassungen, disable MSYS path conversion:
MSYS_NO_PATHCONV=1 docker exec -it rhl-lieferscheine-app ls -la /mnt/niederlassungen
ssh administrator@192.168.0.23
Docker and Docker Compose installed.
The real NAS share is mounted at:
/mnt/niederlassungenThe mount is readable by Docker.
On the server (in the project folder), create .env.server based on the template:
cp .env.docker.example .env.server
Edit .env.server:
SESSION_SECRET.NODE_ENV=production.SESSION_COOKIE_SECURE=false.Use the base compose file only (no local override):
ENV_FILE=.env.server docker compose -f docker-compose.yml up -d --build
.envIf you want a simpler startup command (and to avoid forgetting ENV_FILE=...), you can create a small .env file on the server only that defines which env file Compose should use.
Create ./.env in the project root:
printf "ENV_FILE=.env.server
" > .env
After that, you can start the stack with:
docker compose -f docker-compose.yml up -d --build
Notes:
.env server-local (do not commit it)..env.server still contains secrets and must not be committed.Always run docker compose from the project root so Compose picks up the correct .env file.
### 3.5 Verify
On the server:
```bash
curl -s http://localhost:3000/api/health
Expected:
db is oknas.entriesSample contains real branch folders (NLxx)docker compose -f docker-compose.yml logs --tail=200 app
For real users, the application should be served over HTTPS (reverse proxy / TLS termination).
Local HTTP testing is supported via SESSION_COOKIE_SECURE=false.