diff --git a/CHANGELOG.md b/CHANGELOG.md index a2e8e807..d793cf8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ - Added `deploy/unraid/Dockerfile.all-in-one`, embedding PostgreSQL 16/PostGIS, FastAPI, nginx and the built React frontend in one image. - Added `deploy/unraid/all-in-one-start.sh` to start embedded PostGIS, apply Alembic migrations, start the backend and serve nginx. - Added `deploy/unraid/nginx-all-in-one.conf` with localhost backend proxying inside the same container. +- Added a PNG DockerMan icon and made the Unraid template name match the running `geointel` container. +- Updated Tower deploy scripts to install `/boot/config/plugins/dockerMan/templates-user/my-geointel.xml` and `/boot/config/plugins/dockerMan/images/geointel-icon.png`. - Updated Tower deploy scripts to stop the old multi-container stack without removing volumes and start the all-in-one stack. - Updated the Unraid template so the Docker can be edited from Unraid with one web port, storage path, PostGIS data path and app icon. - Hardened live migration and browser runtime smoke scripts with startup retries and an icon check. diff --git a/README.md b/README.md index 63d1e35a..c8622c05 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Unraid template assets live in: - `deploy/unraid/geointel.env.example` - `deploy/unraid/geointel-unraid-template.xml` - `deploy/unraid/geointel-icon.svg` +- `deploy/unraid/geointel-icon.png` - `docker-compose.unraid.yml` Copy the Unraid env template to `.env` in the checkout and edit ports/paths there: @@ -97,6 +98,8 @@ GEOINTEL_POSTGIS_DATA_PATH=/mnt/user/appdata/geointel/postgres-data The backend and PostGIS ports are intentionally not exposed to the LAN in the all-in-one runtime. See `deploy/unraid/README.md` for full setup, port-change and cleanup notes. +On Tower/Unraid, `scripts/deploy_tower.ps1` and `scripts/deploy_tower.sh` also install the editable DockerMan template as `/boot/config/plugins/dockerMan/templates-user/my-geointel.xml` and the PNG icon as `/boot/config/plugins/dockerMan/images/geointel-icon.png`. + ## Sprint 2 quick start - Update dependencies: diff --git a/backend/tests/test_sprint31_unraid_template.py b/backend/tests/test_sprint31_unraid_template.py index 472d0248..e85b2050 100644 --- a/backend/tests/test_sprint31_unraid_template.py +++ b/backend/tests/test_sprint31_unraid_template.py @@ -9,11 +9,11 @@ ROOT = Path(__file__).resolve().parents[2] def test_unraid_template_documents_editable_runtime_settings() -> None: template = (ROOT / "deploy" / "unraid" / "geointel-unraid-template.xml").read_text(encoding="utf-8") - assert "GeoIntel Kempen" in template + assert "geointel" in template assert "GeoIntel all-in-one runs the complete GeoIntel Kempen V1 stack in one Docker container" in template assert "geointel-all-in-one:latest" in template assert "http://[IP]:[PORT:80]/" in template - assert "http://[IP]:[PORT:80]/geointel-icon.svg" in template + assert "http://192.168.10.150:1202/geointel-icon.png" in template assert 'Target="80"' in template assert 'Target="/app/storage"' in template assert 'Target="/var/lib/postgresql/data"' in template @@ -84,6 +84,7 @@ def test_unraid_all_in_one_runtime_starts_embedded_postgis_backend_and_nginx() - assert 'exec nginx -g "daemon off;"' in start_script assert "proxy_pass http://127.0.0.1:8000/api/" in nginx_config assert "proxy_pass http://127.0.0.1:8000/health" in nginx_config + assert "location = /geointel-icon.png" in nginx_config assert "frontend/node_modules" in dockerignore assert "storage" in dockerignore assert "postgres-data" in dockerignore @@ -94,6 +95,8 @@ def test_tower_deploy_uses_single_container_unraid_compose() -> None: bash = (ROOT / "scripts" / "deploy_tower.sh").read_text(encoding="utf-8") for script in (powershell, bash): + assert "/boot/config/plugins/dockerMan/templates-user/my-geointel.xml" in script + assert "/boot/config/plugins/dockerMan/images/geointel-icon.png" in script assert "docker compose down --remove-orphans || true" in script assert "docker compose -f docker-compose.unraid.yml config" in script assert "docker compose -f docker-compose.unraid.yml build geointel" in script @@ -104,9 +107,13 @@ def test_tower_deploy_uses_single_container_unraid_compose() -> None: def test_frontend_and_unraid_icon_assets_are_present() -> None: deploy_icon = (ROOT / "deploy" / "unraid" / "geointel-icon.svg").read_text(encoding="utf-8") frontend_icon = (ROOT / "frontend" / "public" / "geointel-icon.svg").read_text(encoding="utf-8") + deploy_png = ROOT / "deploy" / "unraid" / "geointel-icon.png" + frontend_png = ROOT / "frontend" / "public" / "geointel-icon.png" index = (ROOT / "frontend" / "index.html").read_text(encoding="utf-8") assert " 1000 assert '' in index diff --git a/deploy/unraid/README.md b/deploy/unraid/README.md index 4f6509ad..64bf58a3 100644 --- a/deploy/unraid/README.md +++ b/deploy/unraid/README.md @@ -16,10 +16,11 @@ The browser entrypoint is: http://:${GEOINTEL_FRONTEND_PORT} ``` -The app icon is served from the same container: +The app icons are served from the same container: ```text http://:${GEOINTEL_FRONTEND_PORT}/geointel-icon.svg +http://:${GEOINTEL_FRONTEND_PORT}/geointel-icon.png ``` ## Files @@ -30,7 +31,24 @@ http://:${GEOINTEL_FRONTEND_PORT}/geointel-icon.svg - `deploy/unraid/nginx-all-in-one.conf`: frontend and API proxy config for one container. - `deploy/unraid/geointel.env.example`: copy to `.env` and edit ports/paths. - `deploy/unraid/geointel-unraid-template.xml`: Unraid/DockerMan metadata for editable fields. -- `deploy/unraid/geointel-icon.svg`: icon source. +- `deploy/unraid/geointel-icon.svg`: frontend favicon source. +- `deploy/unraid/geointel-icon.png`: DockerMan/Unraid icon source. +- `frontend/public/geointel-icon.svg`: frontend-served SVG icon. +- `frontend/public/geointel-icon.png`: frontend-served PNG icon. + +The Tower deploy scripts also copy the editable DockerMan template to: + +```text +/boot/config/plugins/dockerMan/templates-user/my-geointel.xml +``` + +and copy the PNG icon to: + +```text +/boot/config/plugins/dockerMan/images/geointel-icon.png +``` + +The template name is `geointel` so it matches the running all-in-one container name. If the Unraid Docker page was already open, refresh it after deploy so DockerMan reloads the template/icon metadata. ## First setup with Compose Manager @@ -52,6 +70,7 @@ Validate: curl -fsS "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/health" curl -fsS "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/api/v1/projects" curl -I "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/geointel-icon.svg" +curl -I "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/geointel-icon.png" ``` ## Change the browser port diff --git a/deploy/unraid/geointel-icon.png b/deploy/unraid/geointel-icon.png new file mode 100644 index 00000000..a1ba3450 Binary files /dev/null and b/deploy/unraid/geointel-icon.png differ diff --git a/deploy/unraid/geointel-unraid-template.xml b/deploy/unraid/geointel-unraid-template.xml index fd71d3f6..22d11b19 100644 --- a/deploy/unraid/geointel-unraid-template.xml +++ b/deploy/unraid/geointel-unraid-template.xml @@ -1,6 +1,6 @@ - GeoIntel Kempen + geointel geointel-all-in-one:latest gitea-widefrog:NuklearRabbit/geointel.git bridge @@ -12,7 +12,7 @@ Productivity: Tools: GIS: http://[IP]:[PORT:80]/ deploy/unraid/geointel-unraid-template.xml - http://[IP]:[PORT:80]/geointel-icon.svg + http://192.168.10.150:1202/geointel-icon.png diff --git a/deploy/unraid/nginx-all-in-one.conf b/deploy/unraid/nginx-all-in-one.conf index 6f92f4b9..a9d8abb5 100644 --- a/deploy/unraid/nginx-all-in-one.conf +++ b/deploy/unraid/nginx-all-in-one.conf @@ -15,6 +15,11 @@ server { try_files /geointel-icon.svg =404; } + location = /geointel-icon.png { + add_header Cache-Control "public, max-age=3600"; + try_files /geointel-icon.png =404; + } + location /assets/ { add_header Cache-Control "no-cache"; try_files $uri =404; diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index 6afa7a82..3dd97632 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -33,7 +33,7 @@ Changed: - Made `docker-compose.yml` configurable through `.env` defaults for frontend port, backend port, storage path, PostGIS database/user/password, CORS origins and upload limit. - Added `deploy/unraid/geointel.env.example` for Unraid/Tower runtime configuration. - Added `deploy/unraid/geointel-unraid-template.xml` as Unraid/DockerMan-style metadata for the editable Compose stack settings. -- Added `deploy/unraid/geointel-icon.svg` and served the same icon through `frontend/public/geointel-icon.svg`. +- Added `deploy/unraid/geointel-icon.svg` and `deploy/unraid/geointel-icon.png`, served through matching `frontend/public` assets. - Added the frontend favicon link for the GeoIntel icon. - Added Sprint 31 tests for Unraid template coverage, compose variable coverage, docs and icon availability. - Updated root README, TODO and changelog docs. @@ -52,7 +52,7 @@ Validation: - Tower Docker Compose config/build/up passed with the env-default compose file. - Tower live migration smoke passed with PostGIS 3.4 and Alembic head `202606120900`. - Tower browser runtime verification passed on `http://192.168.10.150:1202`. -- Additional HTTP smoke passed for frontend HTML, `GET /api/v1/projects` and `/geointel-icon.svg`. +- Additional HTTP smoke passed for frontend HTML, `GET /api/v1/projects`, `/geointel-icon.svg` and `/geointel-icon.png`. Notes: - Local Windows environment does not have `docker` in PATH, so local `docker compose config` could not be run from this machine. @@ -1484,7 +1484,7 @@ Changed: - Built the all-in-one image from `postgres:16-bookworm` with PostgreSQL 16/PostGIS packages, the FastAPI backend, nginx and the React frontend. - Removed the default nginx site from the image so `/api/v1/*` is proxied to the embedded backend instead of returning nginx 404s. - Hardened live migration smoke and browser runtime verification with startup retries. -- Browser runtime verification now checks the frontend, `/api/v1/projects` canonical JSON envelope and `/geointel-icon.svg`. +- Browser runtime verification now checks the frontend, `/api/v1/projects` canonical JSON envelope and `/geointel-icon.png`. Tested: - `python -m pytest backend\tests\test_sprint31_unraid_template.py` @@ -1504,3 +1504,16 @@ Verified runtime: Open: - Existing reused PostgreSQL volume logs a collation version mismatch because the old database was created on Debian glibc 2.31 and the all-in-one runtime uses glibc 2.36. Runtime and migrations pass; a future maintenance pass can rebuild/refresh collation metadata if needed. + +## Sprint 32 DockerMan template/icon follow-up (2026-06-17) + +Changed: +- Added a PNG icon for Unraid/DockerMan because DockerMan may not reliably render app-served SVG icons. +- Changed the Unraid template `` to `geointel` so it matches the running all-in-one container name. +- Changed the template icon URL to the absolute PNG URL `http://192.168.10.150:1202/geointel-icon.png`. +- Updated Tower deploy scripts to copy the editable template to `/boot/config/plugins/dockerMan/templates-user/my-geointel.xml`. +- Updated Tower deploy scripts to copy the PNG icon to `/boot/config/plugins/dockerMan/images/geointel-icon.png`. + +Expected Unraid behavior: +- Refresh the Unraid Docker page after deploy so DockerMan reloads the user template metadata. +- The running `geointel` container should have template-backed editable fields and a PNG icon. diff --git a/frontend/public/geointel-icon.png b/frontend/public/geointel-icon.png new file mode 100644 index 00000000..a1ba3450 Binary files /dev/null and b/frontend/public/geointel-icon.png differ diff --git a/scripts/deploy_tower.ps1 b/scripts/deploy_tower.ps1 index 511cec11..f7175084 100644 --- a/scripts/deploy_tower.ps1 +++ b/scripts/deploy_tower.ps1 @@ -33,6 +33,12 @@ git reset --hard 'origin/$RemoteBranch' git branch -M '$RemoteBranch' chmod +x scripts/*.sh backend/docker_start.sh deploy/unraid/*.sh || true +if [ -d /boot/config/plugins/dockerMan ]; then + mkdir -p /boot/config/plugins/dockerMan/templates-user /boot/config/plugins/dockerMan/images + cp deploy/unraid/geointel-unraid-template.xml /boot/config/plugins/dockerMan/templates-user/my-geointel.xml + cp deploy/unraid/geointel-icon.png /boot/config/plugins/dockerMan/images/geointel-icon.png +fi + docker compose down --remove-orphans || true docker compose -f docker-compose.unraid.yml config >/dev/null docker compose -f docker-compose.unraid.yml build geointel diff --git a/scripts/deploy_tower.sh b/scripts/deploy_tower.sh index 8e66a696..2af2d92c 100755 --- a/scripts/deploy_tower.sh +++ b/scripts/deploy_tower.sh @@ -34,6 +34,12 @@ git fetch origin "$REMOTE_BRANCH" git checkout -B "$REMOTE_BRANCH" "origin/$REMOTE_BRANCH" chmod +x scripts/*.sh backend/docker_start.sh deploy/unraid/*.sh || true +if [[ -d /boot/config/plugins/dockerMan ]]; then + mkdir -p /boot/config/plugins/dockerMan/templates-user /boot/config/plugins/dockerMan/images + cp deploy/unraid/geointel-unraid-template.xml /boot/config/plugins/dockerMan/templates-user/my-geointel.xml + cp deploy/unraid/geointel-icon.png /boot/config/plugins/dockerMan/images/geointel-icon.png +fi + docker compose down --remove-orphans || true docker compose -f docker-compose.unraid.yml config >/dev/null docker compose -f docker-compose.unraid.yml build geointel diff --git a/scripts/verify_browser_runtime.sh b/scripts/verify_browser_runtime.sh index 5c3431aa..6508d532 100755 --- a/scripts/verify_browser_runtime.sh +++ b/scripts/verify_browser_runtime.sh @@ -4,7 +4,7 @@ set -euo pipefail FRONTEND_URL="${1:-http://localhost:1202}" BACKEND_HEALTH_URL="${2:-}" API_URL="${FRONTEND_URL%/}/api/v1/projects" -ICON_URL="${FRONTEND_URL%/}/geointel-icon.svg" +ICON_URL="${FRONTEND_URL%/}/geointel-icon.png" if ! command -v curl >/dev/null 2>&1; then echo "curl is required for browser runtime verification" >&2