+
+
+
+
+
+
diff --git a/Dockerfile b/Dockerfile
index a63399d..3221e31 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,9 +4,15 @@
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
-# Copy only the csproj and restore first, so the NuGet restore layer stays
-# cached as long as the dependencies do not change.
+# Copy the solution-wide build files first (Central Package Management lives in
+# Directory.Packages.props; without it a restore fails with NU1015). Then the
+# csproj of every project in the web app's dependency tree. Restoring before
+# copying the rest of the source keeps the NuGet layer cached as long as the
+# dependencies do not change.
+COPY Directory.Build.props Directory.Packages.props ./
COPY Elternbeirat.Web/Elternbeirat.Web.csproj Elternbeirat.Web/
+COPY Elternbeirat.PocketBase/Elternbeirat.PocketBase.csproj Elternbeirat.PocketBase/
+COPY Elternbeirat.Contracts/Elternbeirat.Contracts.csproj Elternbeirat.Contracts/
RUN dotnet restore Elternbeirat.Web/Elternbeirat.Web.csproj
# Then the rest of the source.
diff --git a/compose.dev.yaml b/compose.dev.yaml
new file mode 100644
index 0000000..860932b
--- /dev/null
+++ b/compose.dev.yaml
@@ -0,0 +1,38 @@
+# Dev overlay: layered on top of compose.yaml for local development.
+# docker compose -f compose.yaml -f compose.dev.yaml up --build
+#
+# It adds host port mappings (so the stack is reachable from the browser), builds
+# the web image from local source instead of pulling it from the registry, and
+# swaps the Unraid pb_data bind mount for a throwaway named volume (the /mnt/user
+# path only exists on the server).
+
+services:
+ eb-pocketbase:
+ ports:
+ - "8090:8090" # PocketBase admin UI at http://localhost:8090/_/
+ environment:
+ # Local only: on a fresh pb_data the image auto-creates this superuser, so
+ # you skip the /_/ setup screen. Same credentials as the test fixture. This
+ # stays out of the prod base -- there the superuser is set up by hand / #9.
+ PB_ADMIN_EMAIL: test@example.com
+ PB_ADMIN_PASSWORD: test-password
+ volumes:
+ # Local: a named Docker volume instead of the Unraid /mnt/user bind mount
+ # from the base file (that path only exists on the server). The "!reset"
+ # tag clears the inherited bind mount so only this volume applies.
+ - !reset null
+ - pb_data_dev:/pb_data
+
+ eb-web:
+ # Build from local source instead of pulling the registry image, so local code
+ # changes show up without a push+CI round-trip. image: "" clears the inherited
+ # tag from the base, which forces compose to use the build below.
+ image: ""
+ build:
+ context: .
+ dockerfile: Dockerfile
+ ports:
+ - "5000:8080" # web app at http://localhost:5000
+
+volumes:
+ pb_data_dev: # throwaway local volume; remove with `docker volume rm`
diff --git a/compose.yaml b/compose.yaml
index e3ff3ef..6806670 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -1,24 +1,41 @@
-# TEST setup for the first run on Unraid (without NPM).
+# Base compose: production-like. Both services, no host port mappings (NPM is the
+# only path to the web app; the editors reach PocketBase through an NPM subdomain).
+# Only PocketBase's data is a volume; everything else lives inside the images.
#
-# Pulls the finished image from the Gitea registry (the build happens on the
-# development machine, see docs/deployment.md) instead of building from source
-# on Unraid.
+# For local development use the dev overlay on top, which adds host ports and builds
+# the web image from source:
+# docker compose -f compose.yaml -f compose.dev.yaml up --build
+# (The Rider run config "DevEnvironment" does exactly this with one click.)
#
-# Deliberately differs from the production setup:
-# - There is a port mapping (5000 outside -> 8080 inside) so the app is
-# reachable in the local network at http://:5000. In production the
-# mapping is dropped; there NPM is the only path to the container (use the
-# external npm network instead, see docs/deployment.md).
-#
-# Once NPM is in place, this file is replaced by the production compose.
+# Startup order: PocketBase comes up first; once it reports healthy the web app
+# starts (depends_on -> service_healthy).
services:
+ eb-pocketbase:
+ image: ghcr.io/muchobien/pocketbase:0.40.4
+ container_name: eb-pocketbase
+ restart: unless-stopped
+ environment:
+ TZ: Europe/Berlin
+ volumes:
+ # The only state that must survive a restart or redeploy.
+ - /mnt/user/appdata/pocketbase/pb_data:/pb_data
+ healthcheck:
+ # The image ships this endpoint; the web app waits for it to pass.
+ test: ["CMD", "wget", "--spider", "-q", "http://localhost:8090/api/health"]
+ interval: 5s
+ timeout: 3s
+ retries: 10
+
eb-web:
image: gitea.anticarnist.de/tom/elternbeirat:latest
container_name: eb-web
restart: unless-stopped
+ depends_on:
+ eb-pocketbase:
+ condition: service_healthy
environment:
ASPNETCORE_URLS: http://+:8080
TZ: Europe/Berlin
- ports:
- - "5000:8080" # TEST access, remove in production
+ # The web app reads content from PocketBase over the compose network.
+ PocketBase__BaseUrl: http://eb-pocketbase:8090