From 2d20f6f29ca82f1c3b36c65d980ebb48a8d5b05e Mon Sep 17 00:00:00 2001 From: tajniak81 <13187254+tajniak81@users.noreply.github.com> Date: Sun, 19 Jul 2026 19:16:21 +0200 Subject: [PATCH] Bring the Docker setup in line with DriverVault's The combined stack now includes PocketBase as a first-class service instead of assuming an external one: a Docker/pocketbase image built from the release binary that bundles the pb_migrations and upserts the superuser on boot, so a fresh stack checks/creates its collections and super-admin the same way DriverVault does. Add production compose variants (registry images) and .env(.prod).example files for both Docker/ and Docker AIO/, a top-level compose name, a PocketBase healthcheck with a service_healthy dependency, and env-driven ports. Move the containerized PocketBase to :8070 (the live remote PB stays 10.2.1.10:8026). Add a root .dockerignore to trim the repo-root build context used by the pocketbase and AIO images. Co-Authored-By: Claude Opus 4.8 --- .dockerignore | 27 ++++++++++ Docker AIO/.env.example | 21 ++++++++ Docker AIO/.env.prod.example | 28 ++++++++++ Docker AIO/Dockerfile | 10 ++-- Docker AIO/docker-compose.prod.yml | 34 ++++++++++++ Docker AIO/docker-compose.yml | 31 +++++++---- Docker/.env.example | 24 +++++++++ Docker/.env.prod.example | 38 +++++++++++++ Docker/docker-compose.prod.yml | 70 ++++++++++++++++++++++++ Docker/docker-compose.yml | 85 ++++++++++++++++++++++++------ Docker/pocketbase/Dockerfile | 44 ++++++++++++++++ Docker/pocketbase/entrypoint.sh | 19 +++++++ README.md | 2 +- 13 files changed, 401 insertions(+), 32 deletions(-) create mode 100644 .dockerignore create mode 100644 Docker AIO/.env.example create mode 100644 Docker AIO/.env.prod.example create mode 100644 Docker AIO/docker-compose.prod.yml create mode 100644 Docker/.env.example create mode 100644 Docker/.env.prod.example create mode 100644 Docker/docker-compose.prod.yml create mode 100644 Docker/pocketbase/Dockerfile create mode 100644 Docker/pocketbase/entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b97e508 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +# Root build-context ignore. The pocketbase and Docker AIO images build with the +# repo root as their context (they COPY from "API Server/" and "Web App/"), so +# keep the context lean: only those two trees plus Docker/pocketbase are needed. + +# Sibling apps unrelated to the server images. +Adobe Plugin/ +Design/ +Fly App/ +Phone App/ + +# Frontend deps + generated bundles — rebuilt inside the images. +**/node_modules/ +**/dist/ + +# Secrets & local build artifacts — never send to the build context. +**/.env +plugins.json +*.exe +*.exe~ +*.log + +# VCS / editor / tooling noise. +.git/ +.gitignore +.claude/ +.vscode/ +.idea/ diff --git a/Docker AIO/.env.example b/Docker AIO/.env.example new file mode 100644 index 0000000..73371dd --- /dev/null +++ b/Docker AIO/.env.example @@ -0,0 +1,21 @@ +# Copy to .env and fill in. Used by the Docker AIO docker-compose.yml. + +# --- PocketBase superuser (also used by the API Server to authenticate) ------ +POCKETBASE_ADMIN_EMAIL=admin@dji.local +POCKETBASE_ADMIN_PASSWORD=djiadmin2026! + +# The app super-admin login (superadmin@pilotvault.local) is created by the +# bundled PocketBase migrations on first boot. + +# Allowed CORS origin(s) — "*" is convenient for a local demo. +CORS_ALLOW_ORIGINS=* + +# --- Host port mappings (optional; defaults shown) -------------------------- +WEB_PORT=8090 +API_PORT=8080 +PB_PORT=8070 + +# --- Storage ---------------------------------------------------------------- +# Docker-managed named volume by default; set PB_DATA to an absolute host path +# for a bind mount, e.g. PB_DATA=/srv/pilotvault/pb_data +PB_DATA=pb_data diff --git a/Docker AIO/.env.prod.example b/Docker AIO/.env.prod.example new file mode 100644 index 0000000..6a02ce1 --- /dev/null +++ b/Docker AIO/.env.prod.example @@ -0,0 +1,28 @@ +# PilotVault all-in-one — production config. +# Copy to .env and fill in, then: +# docker compose -f docker-compose.prod.yml pull +# docker compose -f docker-compose.prod.yml up -d + +# --- Registry image --------------------------------------------------------- +AIO_IMAGE=10.2.1.10:5500/admin/pilotvault-aio:latest + +# --- PocketBase superuser (required) ---------------------------------------- +# Created/updated on first boot. The API Server uses these to manage the database. +POCKETBASE_ADMIN_EMAIL=admin@dji.local +POCKETBASE_ADMIN_PASSWORD=change-me-long-password + +# The app super-admin login (superadmin@pilotvault.local) is created by the +# bundled PocketBase migrations on first boot. + +# Allowed CORS origin(s) — match your public web URL / WEB_PORT. +CORS_ALLOW_ORIGINS=http://localhost:8090 + +# --- Host port mappings (optional; defaults shown) -------------------------- +WEB_PORT=8090 +API_PORT=8080 +PB_PORT=8070 + +# --- Storage ---------------------------------------------------------------- +# Default is a Docker-managed named volume ("pb_data"). Set PB_DATA to an +# absolute host path for a bind mount, e.g. PB_DATA=/srv/pilotvault/pb_data +PB_DATA=pb_data diff --git a/Docker AIO/Dockerfile b/Docker AIO/Dockerfile index f034a28..440671e 100644 --- a/Docker AIO/Dockerfile +++ b/Docker AIO/Dockerfile @@ -8,10 +8,10 @@ # and "Web App/"). From E:\VS Code Projects\PilotVault run: # # docker build -f "Docker AIO/Dockerfile" -t pilotvault-aio . -# docker run -p 8090:8090 -p 8080:8080 -p 8026:8026 \ +# docker run -p 8090:8090 -p 8080:8080 -p 8070:8070 \ # -v pilotvault_pb:/pb/pb_data pilotvault-aio # -# Internal ports (loopback-wired): PocketBase 8026, API Server 8080, Web App 8090. +# Internal ports (loopback-wired): PocketBase 8070, API Server 8080, Web App 8090. # ============================================================================= # Stage 1 — build the API Server's embedded Vue panel (-> internal/api/dist) @@ -91,7 +91,7 @@ COPY ["API Server/pocketbase/pb_migrations/", "/pb/pb_migrations/"] # Web App reads ADDR / API_BASE # NOTE: these bundle default credentials for convenience — override at `docker run`. ENV API_ADDR=":8080" \ - POCKETBASE_URL="http://127.0.0.1:8026" \ + POCKETBASE_URL="http://127.0.0.1:8070" \ CORS_ALLOW_ORIGINS="*" \ POCKETBASE_ADMIN_EMAIL="admin@dji.local" \ POCKETBASE_ADMIN_PASSWORD="djiadmin2026!" \ @@ -111,7 +111,7 @@ pidfile=/run/supervisord.pid priority=10 directory=/pb # Ensure the service-account superuser exists, then serve on the internal port. -command=/bin/sh -c "/app/pocketbase superuser upsert \"$POCKETBASE_ADMIN_EMAIL\" \"$POCKETBASE_ADMIN_PASSWORD\" --dir=/pb/pb_data ; exec /app/pocketbase serve --http=0.0.0.0:8026 --dir=/pb/pb_data --migrationsDir=/pb/pb_migrations" +command=/bin/sh -c "/app/pocketbase superuser upsert \"$POCKETBASE_ADMIN_EMAIL\" \"$POCKETBASE_ADMIN_PASSWORD\" --dir=/pb/pb_data ; exec /app/pocketbase serve --http=0.0.0.0:8070 --dir=/pb/pb_data --migrationsDir=/pb/pb_migrations" autorestart=true startsecs=3 stdout_logfile=/dev/stdout @@ -145,6 +145,6 @@ EOF # PocketBase data (SQLite). Mount a volume here to persist across restarts. VOLUME ["/pb/pb_data"] -EXPOSE 8090 8080 8026 +EXPOSE 8090 8080 8070 ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] diff --git a/Docker AIO/docker-compose.prod.yml b/Docker AIO/docker-compose.prod.yml new file mode 100644 index 0000000..353a513 --- /dev/null +++ b/Docker AIO/docker-compose.prod.yml @@ -0,0 +1,34 @@ +name: pilotvault-aio + +# Production all-in-one — pulls the prebuilt image from the registry instead of +# building. One container runs PocketBase + API Server + Web App. Everything an +# operator needs to set lives in .env. +# +# 1. cp .env.prod.example .env (then edit it) +# 2. docker compose -f docker-compose.prod.yml pull +# 3. docker compose -f docker-compose.prod.yml up -d +# +# On first boot the bundled PocketBase upserts its superuser from +# POCKETBASE_ADMIN_* and runs the JS migrations, which create/reconcile every +# collection and seed the baseline org + accounts (incl. superadmin@pilotvault.local). +# Idempotent, so restarts and upgrades are safe. + +services: + pilotvault: + image: "${AIO_IMAGE:-10.2.1.10:5500/admin/pilotvault-aio:latest}" + container_name: pilotvault-aio + restart: unless-stopped + environment: + POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL:?set POCKETBASE_ADMIN_EMAIL in .env}" + POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD:?set POCKETBASE_ADMIN_PASSWORD in .env}" + CORS_ALLOW_ORIGINS: "${CORS_ALLOW_ORIGINS:-http://localhost:8090}" + ports: + - "${WEB_PORT:-8090}:8090" # Web App (control panel) + - "${API_PORT:-8080}:8080" # API Server + embedded API web panel (root /) + - "${PB_PORT:-8070}:8070" # PocketBase admin UI / API + volumes: + # Named volume by default; set PB_DATA to a host path in .env for a bind mount. + - "${PB_DATA:-pb_data}:/pb/pb_data" + +volumes: + pb_data: diff --git a/Docker AIO/docker-compose.yml b/Docker AIO/docker-compose.yml index 0499f4e..a323224 100644 --- a/Docker AIO/docker-compose.yml +++ b/Docker AIO/docker-compose.yml @@ -1,7 +1,17 @@ +name: pilotvault-aio + # All-in-one PilotVault stack (PocketBase + API Server + Web App) in ONE container. -# Run from this Docker AIO/ folder: docker compose up --build +# Run from this Docker AIO/ folder: +# +# cp .env.example .env # then edit the credentials/ports +# docker compose up --build +# # The build context is the repo root (..) because the Dockerfile COPYs from # "API Server/" and "Web App/". +# +# On first boot the bundled PocketBase upserts its superuser from +# POCKETBASE_ADMIN_* and runs the JS migrations, which create/reconcile every +# collection and seed the baseline org + accounts (incl. superadmin@pilotvault.local). services: pilotvault: @@ -13,19 +23,20 @@ services: # PB_ARCH: "amd64" # use "arm64" on Apple Silicon image: pilotvault-aio container_name: pilotvault-aio - ports: - - "8090:8090" # Web App (control panel) - - "8080:8080" # API Server - - "8026:8026" # PocketBase + restart: unless-stopped environment: # Loopback-wired between the three in-container services. Override the # bundled default credentials here for anything real. - POCKETBASE_ADMIN_EMAIL: "admin@dji.local" - POCKETBASE_ADMIN_PASSWORD: "djiadmin2026!" - CORS_ALLOW_ORIGINS: "*" + POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL:-admin@dji.local}" + POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD:-djiadmin2026!}" + CORS_ALLOW_ORIGINS: "${CORS_ALLOW_ORIGINS:-*}" + ports: + - "${WEB_PORT:-8090}:8090" # Web App (control panel) + - "${API_PORT:-8080}:8080" # API Server + - "${PB_PORT:-8070}:8070" # PocketBase admin UI / API volumes: - - pb_data:/pb/pb_data # persist PocketBase SQLite across restarts - restart: unless-stopped + # Named volume by default; set PB_DATA to a host path in .env for a bind mount. + - "${PB_DATA:-pb_data}:/pb/pb_data" volumes: pb_data: diff --git a/Docker/.env.example b/Docker/.env.example new file mode 100644 index 0000000..a43297f --- /dev/null +++ b/Docker/.env.example @@ -0,0 +1,24 @@ +# Copy to .env and fill in. Used by the combined docker-compose.yml (build & run). + +# --- PocketBase superuser (also used by the API Server to authenticate) ------ +# Created/updated on the PocketBase container's first boot. REQUIRED. +POCKETBASE_ADMIN_EMAIL=admin@dji.local +POCKETBASE_ADMIN_PASSWORD=change-me-long-password + +# The app super-admin login (superadmin@pilotvault.local) is created by the +# bundled PocketBase migrations on first boot — no separate env var needed. + +# --- API Server ------------------------------------------------------------- +# Allowed CORS origin(s) for the web app (match WEB_PORT / your public URL). +# Native apps are not subject to CORS. +CORS_ALLOW_ORIGINS=http://localhost:8090 + +# --- Host port mappings (optional; defaults shown) -------------------------- +PB_PORT=8070 +API_PORT=8080 +WEB_PORT=8090 + +# --- Storage ---------------------------------------------------------------- +# Docker-managed named volume by default; set PB_DATA to an absolute host path +# for a bind mount, e.g. PB_DATA=/srv/pilotvault/pb_data +PB_DATA=pb_data diff --git a/Docker/.env.prod.example b/Docker/.env.prod.example new file mode 100644 index 0000000..75315b0 --- /dev/null +++ b/Docker/.env.prod.example @@ -0,0 +1,38 @@ +# PilotVault — production stack config. +# Copy to .env and fill in, then: +# docker compose -f docker-compose.prod.yml pull +# docker compose -f docker-compose.prod.yml up -d + +# --- Registry images -------------------------------------------------------- +# Defaults point at the internal registry; override to pin a tag or use a mirror. +PB_IMAGE=10.2.1.10:5500/admin/pilotvault-pocketbase:latest +API_IMAGE=10.2.1.10:5500/admin/pilotvault-api-server:latest +WEB_IMAGE=10.2.1.10:5500/admin/pilotvault-web-app:latest + +# --- PocketBase superuser (required) ---------------------------------------- +# Created/updated on the PocketBase container's first boot. The API Server uses +# these same credentials to manage the database. +POCKETBASE_ADMIN_EMAIL=admin@dji.local +POCKETBASE_ADMIN_PASSWORD=change-me-long-password + +# The app super-admin login (superadmin@pilotvault.local) is created by the +# bundled PocketBase migrations on first boot — distinct from the superuser above. + +# --- API Server ------------------------------------------------------------- +# Allowed CORS origin(s) for the web app (match your public URL / WEB_PORT). +CORS_ALLOW_ORIGINS=http://localhost:8090 + +# --- Ports ------------------------------------------------------------------ +# WEB_PORT is the public front door (bound on all interfaces). +WEB_PORT=8090 +# PocketBase admin UI and the API panel are bound to localhost only by default. +# Set PB_BIND / API_BIND to 0.0.0.0 to expose them on the network. +PB_PORT=8070 +PB_BIND=127.0.0.1 +API_PORT=8080 +API_BIND=127.0.0.1 + +# --- Storage ---------------------------------------------------------------- +# Default is a Docker-managed named volume ("pb_data"). Set PB_DATA to an +# absolute host path for a bind mount, e.g. PB_DATA=/srv/pilotvault/pb_data +PB_DATA=pb_data diff --git a/Docker/docker-compose.prod.yml b/Docker/docker-compose.prod.yml new file mode 100644 index 0000000..472ee71 --- /dev/null +++ b/Docker/docker-compose.prod.yml @@ -0,0 +1,70 @@ +name: pilotvault + +# Production PilotVault stack — pulls prebuilt images from the registry instead of +# building from source. Everything an operator needs to set lives in .env. +# +# 1. cp .env.prod.example .env (then edit — secrets/ports/volumes/images) +# 2. docker compose -f docker-compose.prod.yml pull +# 3. docker compose -f docker-compose.prod.yml up -d +# +# Traffic flow (browser): Web App BFF --/api--> API Server --> PocketBase. +# +# On first boot PocketBase upserts its superuser from POCKETBASE_ADMIN_* and runs +# the bundled migrations (create/reconcile collections + seed the baseline org and +# the superadmin@pilotvault.local login). Idempotent, so restarts/upgrades are safe. + +services: + pocketbase: + image: "${PB_IMAGE:-10.2.1.10:5500/admin/pilotvault-pocketbase:latest}" + container_name: pilotvault-pocketbase + restart: unless-stopped + environment: + POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL:?set POCKETBASE_ADMIN_EMAIL in .env}" + POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD:?set POCKETBASE_ADMIN_PASSWORD in .env}" + volumes: + # Named volume by default; set PB_DATA to a host path in .env for a bind mount. + - "${PB_DATA:-pb_data}:/pb/pb_data" + ports: + # Bound to localhost by default — the admin UI (/_/) is reachable only on the + # host. Set PB_BIND=0.0.0.0 in .env to expose it on the network. + - "${PB_BIND:-127.0.0.1}:${PB_PORT:-8070}:8070" + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8070/api/health || exit 1"] + interval: 10s + timeout: 3s + retries: 12 + start_period: 10s + + api-server: + image: "${API_IMAGE:-10.2.1.10:5500/admin/pilotvault-api-server:latest}" + container_name: pilotvault-api-server + restart: unless-stopped + depends_on: + pocketbase: + condition: service_healthy + environment: + API_ADDR: ":8080" + POCKETBASE_URL: "http://pocketbase:8070" + POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL}" + POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD}" + CORS_ALLOW_ORIGINS: "${CORS_ALLOW_ORIGINS:-http://localhost:8090}" + ports: + # Localhost-only by default (the Web App reaches it over the internal + # network). Set API_BIND=0.0.0.0 to expose the API panel on the network. + - "${API_BIND:-127.0.0.1}:${API_PORT:-8080}:8080" + + web-app: + image: "${WEB_IMAGE:-10.2.1.10:5500/admin/pilotvault-web-app:latest}" + container_name: pilotvault-web-app + restart: unless-stopped + depends_on: + - api-server + environment: + ADDR: ":8090" + API_BASE: "http://api-server:8080" + ports: + # The public front door. Bound on all interfaces so browsers can reach it. + - "${WEB_PORT:-8090}:8090" + +volumes: + pb_data: diff --git a/Docker/docker-compose.yml b/Docker/docker-compose.yml index 6b386c9..6f7b0e1 100644 --- a/Docker/docker-compose.yml +++ b/Docker/docker-compose.yml @@ -1,40 +1,93 @@ -# Combined stack: API Server + Web App on a shared network. -# Run from this Docker/ folder: docker compose up --build -# Build contexts point back up to each service directory. +name: pilotvault + +# Combined PilotVault stack: PocketBase (database) + API Server + Web App, built +# from source on a shared network. Run from this Docker/ folder: +# +# cp .env.example .env # then edit the secrets/ports +# docker compose up --build +# +# Traffic flow (browser): Web App BFF --/api--> API Server --> PocketBase. +# +# On first boot PocketBase upserts its superuser from POCKETBASE_ADMIN_* and runs +# the bundled JS migrations, which create/reconcile every collection and seed the +# baseline org + accounts (including the superadmin@pilotvault.local app login). +# Every step is idempotent, so restarts and upgrades are safe. services: + pocketbase: + build: + # Repo root — the Dockerfile bundles the migrations from "API Server/". + context: .. + dockerfile: Docker/pocketbase/Dockerfile + image: pilotvault-pocketbase + container_name: pilotvault-pocketbase + restart: unless-stopped + environment: + # The superuser is created/updated on boot (the API Server authenticates + # with it). This is the only place the first superuser can be created — the + # REST API cannot bootstrap it. + POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL:?set POCKETBASE_ADMIN_EMAIL in .env}" + POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD:?set POCKETBASE_ADMIN_PASSWORD in .env}" + volumes: + # Named volume by default; set PB_DATA to a host path in .env for a bind mount. + - "${PB_DATA:-pb_data}:/pb/pb_data" + ports: + # Admin UI / API exposed on the host for management (http://host:8070/_/). + - "${PB_PORT:-8070}:8070" + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8070/api/health || exit 1"] + interval: 10s + timeout: 3s + retries: 12 + start_period: 10s + networks: + - pilotvault + api-server: build: context: "../API Server" image: pilotvault-api-server container_name: pilotvault-api-server - # Config (POCKETBASE_URL, CORS_ALLOW_ORIGINS, POCKETBASE_ADMIN_*) from .env. - env_file: - - "../API Server/.env" + restart: unless-stopped + depends_on: + pocketbase: + condition: service_healthy + environment: + API_ADDR: ":8080" + # Reach PocketBase by its service name on the shared network. + POCKETBASE_URL: "http://pocketbase:8070" + POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL}" + POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD}" + # Same-origin requests go through the Web App BFF, so CORS is only needed if + # a browser ever calls the API Server directly. Default to the web origin. + CORS_ALLOW_ORIGINS: "${CORS_ALLOW_ORIGINS:-http://localhost:8090}" ports: - - "8080:8080" + # Optional direct access to the API Server (and its panel at /); the Web App + # reaches it over the internal network, not this host port. + - "${API_PORT:-8080}:8080" networks: - pilotvault - restart: unless-stopped web-app: build: context: "../Web App" image: pilotvault-web-app container_name: pilotvault-web-app - environment: - ADDR: ":8090" - # Reach the API Server by its service name on the shared network — - # no host.docker.internal needed here. - API_BASE: "http://api-server:8080" - ports: - - "8090:8090" + restart: unless-stopped depends_on: - api-server + environment: + ADDR: ":8090" + # The BFF reverse-proxies /api/* to the API Server over the shared network. + API_BASE: "http://api-server:8080" + ports: + - "${WEB_PORT:-8090}:8090" networks: - pilotvault - restart: unless-stopped networks: pilotvault: driver: bridge + +volumes: + pb_data: diff --git a/Docker/pocketbase/Dockerfile b/Docker/pocketbase/Dockerfile new file mode 100644 index 0000000..f30e133 --- /dev/null +++ b/Docker/pocketbase/Dockerfile @@ -0,0 +1,44 @@ +# syntax=docker/dockerfile:1 +# +# PocketBase for PilotVault, built from the official release binary on alpine. +# +# It bundles the JS migrations from "API Server/pocketbase/pb_migrations" so that +# on first serve PocketBase creates/reconciles every collection and seeds the +# baseline organization + accounts (including the superadmin@pilotvault.local app +# login). Together with the `superuser upsert` in the entrypoint, THIS is where +# PilotVault "checks" that the schema and the super-admin exist — all idempotent, +# so restarts and upgrades are safe. +# +# BUILD CONTEXT IS THE REPO ROOT (the migrations live under "API Server/"). It is +# built for you by Docker/docker-compose.yml; to build it by hand run from +# E:\VS Code Projects\PilotVault: +# +# docker build -f Docker/pocketbase/Dockerfile -t pilotvault-pocketbase . + +FROM alpine:latest + +# Pin the version to match the rest of PilotVault; override with --build-arg. +# PB_ARCH is "amd64" (default) or "arm64" (e.g. Apple Silicon). +ARG PB_VERSION=0.22.21 +ARG PB_ARCH=amd64 + +RUN apk add --no-cache ca-certificates tzdata unzip wget + +WORKDIR /pb +RUN set -eux; \ + wget -q -O /tmp/pb.zip \ + "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_${PB_ARCH}.zip"; \ + unzip /tmp/pb.zip -d /pb; \ + rm /tmp/pb.zip + +# Schema + seed migrations (single source of truth in the API Server tree). +COPY ["API Server/pocketbase/pb_migrations/", "/pb/pb_migrations/"] + +COPY ["Docker/pocketbase/entrypoint.sh", "/entrypoint.sh"] +RUN chmod +x /entrypoint.sh + +# pb_data holds the SQLite database and uploads — mount a volume here. +VOLUME ["/pb/pb_data"] +EXPOSE 8070 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/Docker/pocketbase/entrypoint.sh b/Docker/pocketbase/entrypoint.sh new file mode 100644 index 0000000..16a9550 --- /dev/null +++ b/Docker/pocketbase/entrypoint.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -e + +# Create/update the superuser from env vars so the API Server can authenticate on +# first boot. `superuser upsert` is idempotent (PocketBase v0.22+/v0.23). Accepts +# either the PilotVault names (POCKETBASE_ADMIN_*) or the short PB_ADMIN_* aliases. +ADMIN_EMAIL="${POCKETBASE_ADMIN_EMAIL:-$PB_ADMIN_EMAIL}" +ADMIN_PASSWORD="${POCKETBASE_ADMIN_PASSWORD:-$PB_ADMIN_PASSWORD}" + +if [ -n "$ADMIN_EMAIL" ] && [ -n "$ADMIN_PASSWORD" ]; then + echo "Ensuring PocketBase superuser $ADMIN_EMAIL exists..." + /pb/pocketbase superuser upsert "$ADMIN_EMAIL" "$ADMIN_PASSWORD" \ + || echo "warning: superuser upsert failed; create an admin via the UI at /_/" +fi + +# Serve. --migrationsDir applies the bundled JS migrations on boot, which +# create/reconcile every collection and seed the baseline org + accounts +# (including superadmin@pilotvault.local) — all idempotent. +exec /pb/pocketbase serve --http=0.0.0.0:8070 --migrationsDir=/pb/pb_migrations diff --git a/README.md b/README.md index 5741e8a..1da1c32 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ in memory by the API Server and fanned out over WebSockets. | [`Fly App/`](Fly%20App/) | Flutter (Android) + Kotlin DJI MSDK V4 bridge | — | ✅ Built & run on a real device; live telemetry uplink | | [`Adobe Plugin/`](Adobe%20Plugin/) | — | — | 🚧 Placeholder | | [`Phone App/`](Phone%20App/) | — | — | 🚧 Placeholder | -| [`Docker/`](Docker/) · [`Docker AIO/`](Docker%20AIO/) | Docker Compose | `:8080` `:8090` `:8026` | ✅ Combined stack + single all-in-one container | +| [`Docker/`](Docker/) · [`Docker AIO/`](Docker%20AIO/) | Docker Compose | `:8080` `:8090` `:8070` | ✅ Combined stack + single all-in-one container | ## Data model (PocketBase)