* introduced central package registry by package init function * dynamic registration of routes, model, migrations and initializers. * setting a docker compose project name to prevent shutdown of other containers with the same (composer)name * ai documentation * app template * Create tests for ALL API entpoints in ALL packages Based on current data. Ensure that all API endpoints used in frontend are tested. These tests are crucial for the next refactoring tasks. * adopting agent instructions for a more consistent coding style * added desired module layout and debugging information * Fix All Failing tests All failing tests are fixed now that makes the refactoring more easy since all tests must pass * restored routes for maintenance * added common translations * added new tests for API Endpoint * Merge branch 'separate_business_logic' * added lern and skill improvement cost editing * Set Docker image tag when building to prevent rebuild when nothing has changed * add and remove PP for Weaponskill fixed * add and remove PP for same named skills fixed * add new task
26 KiB
Bamort Infrastructure Findings
Generated: 2026-03-13
Scope: Docker infrastructure, scripts, networking, persistence, dev/prod differences
Table of Contents
- Docker Compose Configurations
- Dockerfiles
- Nginx Configuration
- Scripts
- Database Initialization
- Network Architecture
- Data Persistence
- Development vs Production Differences
1. Docker Compose Configurations
1.1 docker/docker-compose.dev.yml — Development Stack
Compose project name: bamort (set via COMPOSE_PROJECT_NAME env var)
Service: backend-dev
| Property | Value |
|---|---|
| Container name | bamort-backend-dev |
| Build context | ../backend |
| Dockerfile | ../docker/Dockerfile.backend.dev |
| Host port → Container port | 8180 → 8180 |
| Working directory | /app |
| Restart policy | unless-stopped |
| Depends on | mariadb-dev (condition: service_healthy) |
Environment variables:
GO_ENV=development
CGO_ENABLED=1
DATABASE_TYPE=${DATABASE_TYPE:-mysql}
DATABASE_URL=${DATABASE_URL:-<user>:<pass>@tcp(mariadb-dev:3306)/<db>?charset=utf8mb4&parseTime=True&loc=Local}
API_PORT=${API_PORT:-8180}
TEMPLATES_DIR=${TEMPLATES_DIR:-./templatesx}
EXPORT_TEMP_DIR=${EXPORT_TEMP_DIR:-./export_tempx}
GIT_COMMIT=${GIT_COMMIT:-unknown}
Note:
TEMPLATES_DIRdefaults to./templatesx(with trailing 'x') in Docker — this means the container uses the source-mounted../backend:/appvolume and the actual templates directory at/app/templates.
Volumes:
../backend:/app— full backend source mounted for live-reload via Airgo-mod-cache:/go/pkg/mod— named volume to cache Go module downloads
Service: frontend-dev
| Property | Value |
|---|---|
| Container name | bamort-frontend-dev |
| Build context | ../frontend |
| Dockerfile | ../docker/Dockerfile.frontend.dev |
| Host port → Container port | 5173 → 5173 |
| Restart policy | unless-stopped |
| Depends on | backend-dev |
Environment variables:
NODE_ENV=development
VITE_API_URL=${API_URL:-http://192.168.0.1:8180}
VITE_BASE_URL=${BASE_URL:-http://bamort.trokan.de}
VITE_API_PORT=${API_PORT:-8180}
The default
VITE_API_URLpoints to192.168.0.1— a LAN IP. In practice this is overridden via.env.devtohttp://localhost:8180.
Volumes:
../frontend:/app— full frontend source mounted for Vite HMR/app/node_modules— anonymous volume to prevent host from overwriting container's installednode_modules
Service: mariadb-dev
| Property | Value |
|---|---|
| Container name | bamort-mariadb-dev |
| Image | mariadb:11.4 |
| Host port → Container port | 3306 → 3306 |
| Restart policy | unless-stopped |
Environment variables:
MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD:-secure_root_password}
MARIADB_DATABASE=${MARIADB_DATABASE:-bamort}
MARIADB_USER=${MARIADB_USER:-bamort}
MARIADB_PASSWORD=${MARIADB_PASSWORD:-secure_user_password}
MARIADB_CHARSET=utf8mb4
MARIADB_COLLATION=utf8mb4_unicode_ci
Volumes:
./bamort-db-dev:/var/lib/mysql— persistent database files stored indocker/bamort-db-dev/./init-db:/docker-entrypoint-initdb.d— SQL initialization scripts (run only on first container creation)
Health check:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 10s
timeout: 5s
retries: 3
Service: phpmyadmin-dev
| Property | Value |
|---|---|
| Container name | bamort-phpmyadmin-dev |
| Image | phpmyadmin/phpmyadmin:5.2 |
| Host port → Container port | 8081 → 80 |
| Restart policy | unless-stopped |
| Depends on | mariadb-dev (condition: service_healthy) |
Environment variables:
PMA_HOST=mariadb-dev
PMA_PORT=3306
PMA_USER=root
PMA_PASSWORD=${MARIADB_ROOT_PASSWORD:-secure_root_password}
MYSQL_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD:-secure_root_password}
PMA_ARBITRARY=1
Named volumes declared:
volumes:
go-mod-cache:
1.2 docker/docker-compose.yml — Production Stack
Service: backend
| Property | Value |
|---|---|
| Container name | bamort-backend |
| Build context | ../backend |
| Dockerfile | ../docker/Dockerfile.backend |
| Host port → Container port | 8182 → 8180 |
| Working directory | /app |
| Restart policy | unless-stopped |
| Depends on | mariadb (condition: service_healthy) |
Environment variables:
GO_ENV=production
CGO_ENABLED=1
DATABASE_TYPE=${DATABASE_TYPE:-mysql}
DATABASE_URL=<user>:<pass>@tcp(mariadb:3306)/<db>?charset=utf8mb4&parseTime=True&loc=Local
BASE_URL=${BASE_URL:-https://bamort.trokan.de}
API_PORT=${API_PORT:-8180}
Note:
DATABASE_URLin production is NOT wrapped in${}with a fallback — it's constructed inline, which means any unset env vars will result in empty credentials.
Volumes:
./templates:/app/templates— mounts host templates directory (no source code mounted)
Service: frontend
| Property | Value |
|---|---|
| Container name | bamort-frontend |
| Build context | ../frontend |
| Dockerfile | ../docker/Dockerfile.frontend |
| Host port → Container port | 8181 → 80 |
| Restart policy | unless-stopped |
| Depends on | backend |
Build args (baked into the image at build time):
VITE_API_URL: ${API_URL:-https://bamort-api.trokan.de}
VITE_BASE_URL: ${BASE_URL:-https://bamort.trokan.de}
VITE_API_PORT: ${API_PORT:-443}
These are compile-time args embedded into the Vite bundle — runtime
environment:vars have no effect on the built static bundle.
Environment variables (runtime — informational only):
NODE_ENV=production
VITE_API_URL=${API_URL:-https://bamort.trokan.de:8180}
VITE_BASE_URL=${BASE_URL:-https://bamort.trokan.de}
VITE_API_PORT=${API_PORT:-8180}
Service: mariadb
| Property | Value |
|---|---|
| Container name | bamort-mariadb |
| Image | mariadb:11.4 |
| Host port | NOT EXPOSED (ports section commented out) |
| Restart policy | unless-stopped |
Environment variables: Same as dev Volumes:
./bamort-db:/var/lib/mysql— persistent data indocker/bamort-db/./init-db:/docker-entrypoint-initdb.d
Health check: Same, but with longer timeouts (start_period: 20s, timeout: 10s, retries: 3)
Service: phpmyadmin (COMMENTED OUT in production)
The service definition exists in the file but is fully commented out for security. Can be re-enabled via:
sed -i 's/^ # phpmyadmin:/ phpmyadmin:/' docker-compose.yml
docker-compose up -d phpmyadmin
If re-enabled: port 8081 → 80
2. Dockerfiles
2.1 docker/Dockerfile.backend — Production Backend (Multi-stage)
Stage 1: builder — golang:1.25-alpine
FROM golang:1.25-alpine AS builder
RUN apk add --no-cache gcc musl-dev sqlite-dev
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -v -o server cmd/main.go
- Installs GCC (required for CGO), musl-dev, and sqlite-dev (CGO is enabled for SQLite support)
- Builds a static binary named
serverfromcmd/main.go
Stage 2: Runtime — alpine:3.23
FROM alpine:3.23
RUN apk add --no-cache \
chromium chromium-chromedriver \
nss freetype harfbuzz ca-certificates ttf-freefont
ENV CHROME_BIN=/usr/bin/chromium-browser \
CHROME_PATH=/usr/bin/chromium-browser
WORKDIR /app
COPY --from=builder /app/server /app
COPY --from=builder /app/templates /app/default_templates
EXPOSE 8180
CMD ["./server"]
- Installs Chromium for PDF rendering via chromedp
- Copies compiled binary and templates from builder stage
- Templates copied to
default_templates/(runtime templates come from volume mount./templates:/app/templates) - Result: minimal Alpine image with only Chromium and the binary
2.2 docker/Dockerfile.backend.dev — Development Backend (Single-stage)
Base: golang:1.25-alpine (single stage — no build separation)
FROM golang:1.25-alpine
RUN apk add --no-cache gcc musl-dev sqlite-dev
RUN apk add --no-cache chromium chromium-chromedriver nss freetype harfbuzz ca-certificates ttf-freefont
ENV CHROME_BIN=/usr/bin/chromium-browser \
CHROME_PATH=/usr/bin/chromium-browser
RUN go install github.com/air-verse/air@latest
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
EXPOSE 8180
CMD ["air", "-c", ".air.toml"]
Key differences from production:
- Includes the full Go toolchain (for recompilation on file changes)
- Installs
air(live-reload tool fromgithub.com/air-verse/air@latest) - Full source code is mounted at runtime via volume, not copied into image
- Starts with
air -c .air.tomlinstead of the compiled binary
Air configuration (.air.toml):
root = "."
tmp_dir = "tmp"
[build]
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd/main.go"
delay = 1000 # 1 second delay before rebuild
exclude_dir = ["assets", "tmp", "vendor", "testdata", "uploads", "transfer/xporttemp", "export_temp"]
exclude_regex = ["_test.go"] # Test files excluded from watch
include_ext = ["go", "tpl", "tmpl", "html"]
log = "build-errors.log"
Air watches .go, .tpl, .tmpl, .html files, excludes test files, and rebuilds into ./tmp/main on any change.
2.3 docker/Dockerfile.frontend — Production Frontend (Multi-stage)
Stage 1: build — node:22-alpine
FROM node:22-alpine AS build
ARG VITE_API_URL
ARG VITE_BASE_URL
ARG VITE_API_PORT
ENV VITE_API_URL=$VITE_API_URL
ENV VITE_BASE_URL=$VITE_BASE_URL
ENV VITE_API_PORT=$VITE_API_PORT
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
- Accepts
VITE_*values as build ARGs → embedded into the static bundle by Vite - Runs
npm run buildwhich producesdist/
Stage 2: serve — nginx:alpine
FROM nginx:alpine
COPY --from=build /usr/src/app/dist /usr/share/nginx/html
COPY --from=build /usr/src/app/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
- Serves the static Vue bundle via Nginx
- Uses
frontend/nginx.conffor SPA routing (see section 3)
2.4 docker/Dockerfile.frontend.dev — Development Frontend (Single-stage)
Base: node:22-alpine
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
EXPOSE 5173
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
- No build step — Vite dev server handles hot module replacement (HMR)
--host 0.0.0.0binds Vite to all interfaces (required for Docker port exposure)- Full source mounted at
/appvia volume at runtime node_modulesprotected inside container via anonymous volume in compose
3. Nginx Configuration
Note: Both docker/nginx.conf and frontend/nginx.conf are identical in content. The frontend/nginx.conf is the one copied into the production Docker image.
Configuration (both files are the same):
server {
listen 80;
listen [::]:80;
server_name localhost;
# SPA routing: try files, fallback to index.html
location / {
try_files $uri $uri/ /index.html;
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Key behavior:
- SPA routing:
try_files $uri $uri/ /index.html— any URL that doesn't match a static file falls through toindex.html, enabling Vue Router to handle client-side navigation - No backend proxy: Nginx does NOT proxy
/apirequests to the backend. The frontend communicates with the backend API directly via theVITE_API_URLenvironment variable baked into the bundle (e.g.,https://bamort-api.trokan.de) - Static file serving: All files served from
/usr/share/nginx/html - No HTTPS: The Nginx container handles only HTTP on port 80; TLS termination is expected to happen at an external reverse proxy (e.g., Traefik, HAProxy, or a hosting provider)
- No API proxy block: Unlike many SPA setups, there is no
location /apiproxy directive — the API is on a separate domain/port
4. Scripts
4.1 docker/start-dev.sh
#!/bin/bash
# Verifies Docker is running
# Changes to docker/ directory
# Exports GIT_COMMIT=$(git rev-parse --short HEAD)
# Runs: docker-compose -f docker-compose.dev.yml down
# Runs: docker-compose -f docker-compose.dev.yml up --build -d
What it does:
- Checks
docker info— exits with error if Docker daemon is not running cds to the script's own directory (so paths in compose file work)- Exports current short git commit hash as
GIT_COMMIT - Stops any existing dev containers first (
down) - Rebuilds images and starts all dev services in detached mode (
up --build -d)
4.2 docker/stop-dev.sh
#!/bin/bash
# Changes to docker/ directory
# Runs: docker-compose -f docker-compose.dev.yml down
Stops and removes all dev containers (but preserves volumes and images).
4.3 docker/start-prd.sh
#!/bin/bash
# Verifies Docker is running
# Changes to docker/ directory
# Runs: docker-compose -f docker-compose.yml build (pre-build while old containers run)
# Runs: docker-compose -f docker-compose.yml down (stop old containers)
# Runs: docker-compose -f docker-compose.yml up --build -d
Key difference from dev: Runs build before down to minimize downtime. Old containers continue running while new images are being built, then a quick switch happens.
4.4 docker/stop-prd.sh
#!/bin/bash
# Changes to docker/ directory
# Runs: docker-compose -f docker-compose.yml down
Stops and removes production containers. Note: the script message says "Stopping Development Environment" — this is a copy-paste bug in the echo message.
4.5 backend/startserver.sh
This file is not a standard shell script — it is actually a .env-style configuration file that also contains the final command to start the server locally (outside Docker):
# Environment variables for BaMoRT development environment
ENVIRONMENT=development
DATABASE_TYPE=mysql
DATABASE_URL="bamort:bG4)efozrc@tcp(192.168.0.36:3306)/bamort?charset=utf8mb4&parseTime=True&loc=Local"
MARIADB_ROOT_PASSWORD=root_password_dev
MARIADB_PASSWORD="bG4)efozrc"
MARIADB_DATABASE=bamort
MARIADB_USER=bamort
API_URL="http://localhost:8180"
VITE_API_URL="http://localhost:8180"
API_PORT=8180
BASE_URL="http://localhost:5173"
TEMPLATES_DIR=./templates
EXPORT_TEMP_DIR=./export_temp
GIT_COMMIT=d0c177b
LOG_LEVEL=debug
CHROME_BIN="/usr/bin/chromium"
echo $DATABASE_URL
/home/de31a2/.local/bin/go/bin/go run ./cmd/main.go
Used as a local dev helper to set env vars and launch the Go backend directly (no Docker). Points to a MariaDB at 192.168.0.36:3306 (a LAN server).
Security note: Contains hardcoded credentials (
bG4)efozrcfor MariaDB user) — this is development-only but should be in.gitignore.
4.6 backend/transfer_sqlite_to_mariadb.sh
BACKEND_URL="http://localhost:8180"
ENDPOINT="/api/maintenance/transfer-sqlite-to-mariadb"
What it does:
- Optionally accepts argument
clearto wipe MariaDB data before transfer (prompts for confirmation) - Calls
POST http://localhost:8180/api/maintenance/transfer-sqlite-to-mariadb[?clear=true]viacurl - Displays JSON response (formatted via
jqif available) or raw output
Purpose: One-time data migration from the SQLite test database (testdata/prepared_test_data.db) to the MariaDB development database. The actual transfer logic is implemented in the backend's /maintenance module.
4.7 scripts/export-databases.sh
What it does:
- Loads environment variables from
./docker/.env.dev - SQLite export:
- Dumps
backend/testdata/prepared_test_data.dbtobackend/testdata/exports/sqlite_dump.sql - Exports each table as a CSV file:
backend/testdata/exports/sqlite_<table>.csv
- Dumps
- MariaDB export (requires
bamort-mariadb-devcontainer running):- Runs
mariadb-dumpinside the container →backend/testdata/exports/mysql_dump.sql - Exports each table as CSV:
backend/testdata/exports/mysql_<table>.csv
- Runs
- Lists exported files
Purpose: Side-by-side export of SQLite (test data) and MariaDB (dev data) for comparison/debugging during data migration. The TIMESTAMP variable is intentionally empty (left blank in the script), so files are overwritten on each run.
4.8 scripts/update-version.sh
Files updated by this script:
| File | What changes |
|---|---|
backend/appsystem/version.go |
const Version = "X.Y.Z" |
backend/VERSION.md |
## Current Version: X.Y.Z |
frontend/src/version.js |
export const VERSION = 'X.Y.Z' |
frontend/package.json |
"version": "X.Y.Z" |
frontend/VERSION.md |
## Current Version: X.Y.Z |
CLI flags:
-b <version> Set backend version explicitly
-f <version> Set frontend version explicitly
-n Auto-bump patch version on both (reads current, increments Z in X.Y.Z)
-c Create a git commit after version update
-t Create a git tag after commit
Tag strategy:
- If both versions are equal: creates single tag
vX.Y.Z - If they differ: creates
backend-vX.Y.Zandfrontend-vX.Y.Zseparately
Example workflows:
./scripts/update-version.sh -b 0.1.31 -f 0.2.0 # Set explicit versions
./scripts/update-version.sh -b 0.1.31 -c -t # Set + commit + tag
./scripts/update-version.sh -n -c # Auto-bump patch + commit
./scripts/update-version.sh -c -t # Commit + tag from current files
5. Database Initialization
Init directory: docker/init-db/
| File | Status | Description |
|---|---|---|
00-init.sql |
Active | Full schema + seed data (~3,872 lines) |
01-init.sql.bak |
Backup | Earlier version (user data focus) |
02-init.sql.bak |
Backup | Skill tables variant |
09-init.sql.bak |
Backup | Indexes and auto-increments |
00-init.sql — Active Initialization Script
Generated by phpMyAdmin from mariadb-dev:3306 on 2025-12-30.
Contains 78 CREATE TABLE + INSERT INTO statements covering the full database schema.
Tables created (sampled):
audit_log_entries— character field change historychar_bennies— character blessings/bennieschar_characteristics— physical appearance (eye color, hair, size, etc.)- Full game character schema (all character sub-tables)
Settings applied on init:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
SET NAMES utf8mb4;
Character set: utf8mb4 with utf8mb4_unicode_ci collation throughout.
Execution timing: Scripts in init-db/ run only once — when the MariaDB container is created for the first time. If ./bamort-db-dev/ (dev) or ./bamort-db/ (prod) already contain data, init scripts are skipped.
6. Network Architecture
Development Network Topology
Host Machine
├── :5173 ──→ bamort-frontend-dev (Vite HMR, Vue SPA)
├── :8180 ──→ bamort-backend-dev (Go/Gin REST API, Air live-reload)
├── :3306 ──→ bamort-mariadb-dev (MariaDB 11.4)
└── :8081 ──→ bamort-phpmyadmin-dev (phpMyAdmin 5.2)
Docker Internal Network (docker-compose default bridge)
├── bamort-frontend-dev → bamort-backend-dev:8180 (via VITE_API_URL on host)
├── bamort-backend-dev → mariadb-dev:3306 (internal DNS resolution)
└── bamort-phpmyadmin-dev → mariadb-dev:3306 (internal DNS resolution)
Inter-container communication:
- Backend connects to MariaDB using the Docker service name
mariadb-devas hostname (resolved via Docker internal DNS) - Frontend in dev calls the backend via
VITE_API_URLwhich is set to the host's IP (e.g.,http://localhost:8180), not an internal Docker name — meaning the browser makes direct calls to the exposed host port, not through Docker networking - phpMyAdmin connects to
mariadb-dev:3306internally
Production Network Topology
Host Machine
├── :8181 ──→ bamort-frontend (Nginx serving built Vue SPA)
├── :8182 ──→ bamort-backend (Go/Gin REST API, compiled binary)
│ bamort-mariadb (NOT exposed — internal only)
│ [phpmyadmin] (disabled by default)
Docker Internal Network
├── bamort-frontend → bamort-backend [via external VITE_API_URL baked into bundle]
├── bamort-backend → mariadb:3306 (internal DNS)
└── bamort-mariadb (no host port binding — not accessible from outside)
External reverse proxy (implicit): The production setup is designed to sit behind an external reverse proxy (e.g., Nginx, Traefik, or HAProxy) that terminates TLS and routes:
bamort.trokan.de→ container port8181(frontend)bamort-api.trokan.de→ container port8182(backend API)
CORS Configuration
The backend reads FRONTEND_URL from config (defaults to http://localhost:5173) and uses it for CORS origin allow-listing. Production backend receives BASE_URL=https://bamort.trokan.de for this purpose.
7. Data Persistence
Volume Mounts
| Environment | Service | Host path | Container path | Purpose |
|---|---|---|---|---|
| Dev | MariaDB | docker/bamort-db-dev/ |
/var/lib/mysql |
Database files |
| Dev | Backend | ../backend/ |
/app |
Source code (live-reload) |
| Dev | Frontend | ../frontend/ |
/app |
Source code (HMR) |
| Dev | Backend | go-mod-cache (named) |
/go/pkg/mod |
Go module cache |
| Prod | MariaDB | docker/bamort-db/ |
/var/lib/mysql |
Database files |
| Prod | Backend | docker/templates/ |
/app/templates |
PDF templates |
Database Persistence Strategy
Dev: docker/bamort-db-dev/ — a host directory mount. Survives container restarts and recreations. Wiped only if you remove the directory manually or run docker-compose down -v (though -v only removes named volumes, not bind mounts).
Prod: docker/bamort-db/ — same strategy. MariaDB port is NOT exposed to the host, so direct external access requires docker exec.
SQLite (Test Data)
The backend also has a SQLite database at backend/testdata/prepared_test_data.db used for automated tests. This is not a Docker volume — it's part of the source tree.
Backup Strategy
scripts/export-databases.sh: Manual backup script that:
- Dumps SQLite test DB to SQL + per-table CSV files
- Dumps MariaDB dev DB to SQL + per-table CSV files
- Output to
backend/testdata/exports/
No automated backup: There is no cron job or automated backup mechanism in the Docker setup. Backups are manual only. The docker/bamort_20260123_v0.1.37.sql and docker/bamort.sql_backup files are manual one-off snapshots.
8. Development vs Production Differences
| Aspect | Development | Production |
|---|---|---|
| Backend image | Dockerfile.backend.dev — full Go toolchain + Air |
Dockerfile.backend — multi-stage, Alpine runtime only |
| Backend start | air -c .air.toml (live reloads on .go file changes) |
./server (pre-compiled binary) |
| Backend source | Volume-mounted from host (../backend:/app) |
Compiled into image at build time |
| Frontend image | Dockerfile.frontend.dev — Node + Vite dev server |
Dockerfile.frontend — multi-stage, Nginx serving dist/ |
| Frontend start | npm run dev -- --host 0.0.0.0 (Vite HMR) |
nginx -g 'daemon off;' |
| Frontend port | 5173 |
8181 (maps to container 80) |
| Backend port | 8180 |
8182 (maps to container 8180) |
| MariaDB port | 3306 (exposed to host) |
NOT exposed externally |
| phpMyAdmin | Enabled on port 8081 |
Disabled (commented out) |
| VITE_API_URL | Runtime env var (set in compose) | Build-time ARG (baked into bundle) |
| Template source | Mounted from ../backend volume (part of source) |
Mounted from docker/templates/ |
| DB data dir | docker/bamort-db-dev/ |
docker/bamort-db/ |
| Go env | GO_ENV=development |
GO_ENV=production |
| MariaDB hostname | mariadb-dev |
mariadb |
| Health check timing | start_period: 10s |
start_period: 20s |
| Image size | Large (Go toolchain + Chromium) | Smaller (Alpine + Chromium only) |
| Hot reload | Yes (Air for Go, Vite HMR for Vue) | No |
| Startup script | start-dev.sh (includes git commit export) |
start-prd.sh (pre-builds before stopping) |
Notable Configuration Quirks
-
TEMPLATES_DIR=./templatesxin dev compose — has a trailingxsuffix, which means Air/server falls back to default./templates. The actual templates come from the bind-mounted source directory. -
Production DATABASE_URL is constructed inline without
${}fallback syntax, meaning ifMARIADB_USERorMARIADB_PASSWORDare unset, the URL will contain empty strings rather than defaults. -
Frontend VITE_API_URL defaults differ between dev (
192.168.0.1:8180) and prod (bamort-api.trokan.de). The dev default is a LAN IP that only works in the author's local network — other developers must set their own.env.dev. -
No Docker network is explicitly defined — both compose files rely on Docker Compose's default bridge network where all services in the same file can reach each other by service name.
-
startserver.shis misleadingly named — it is actually a combined.envfile + startup command for running outside Docker, not a proper shell script header (no#!/bin/bash).