From 52f6f73eb1a328364510f517f96ca7f6aa7d68f1 Mon Sep 17 00:00:00 2001 From: danbusse <81775558+danbusse@users.noreply.github.com> Date: Mon, 22 Jun 2026 21:23:09 -0600 Subject: [PATCH] docs: update PROJECT_STATE.md after deployment stabilization --- PROJECT_STATE.md | 159 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 47 deletions(-) diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md index 54d8779..56750ea 100644 --- a/PROJECT_STATE.md +++ b/PROJECT_STATE.md @@ -10,67 +10,132 @@ Runs as a Docker Compose stack managed via Portainer, exposed externally via Clo ## Build Progress -### ✅ Step 1 — Project scaffold -### ✅ Step 2 — Database schema -### ✅ Step 3 — Auth + user management -### ✅ Step 4 — Collection import -### ✅ Step 5 — Claude AI integration -### ✅ Step 6 — React frontend -### ✅ Step 7 — First deployment +### ✅ Steps 1-7 — Complete +All backend, frontend, and deployment steps are complete. App is live and accessible. -App is live at http://commander.bussenet.ca +--- + +## Live Deployment + +- **URL:** https://commander.bussenet.ca +- **Admin login:** busse.daniel@gmail.com / Admin1234 +- **Portainer stack:** commander-forge (ID: 54) +- **Stack type:** Pre-built images only — no build directives --- ## Deployment Architecture -- Cloudflare Tunnel → Traefik (port 80) → nginx container -- Portainer stack ID: 52 (commander-forge) -- Backend container manually created outside Portainer — needs reconciliation -- Admin login: busse.daniel@gmail.com / Admin1234 +### Networking +- Cloudflare Tunnel → `http://localhost:80` → Traefik → nginx (`traefik-public` network) +- Traefik routes by hostname label using `traefik.docker.network=traefik-public` +- All other services (backend, db, cache, frontend) on `commander-forge_internal` network +- Cloudflared runs on host network — must use `localhost` not container hostnames -## Known fixes applied -- passlib replaced with bcrypt==4.1.3 -- npm ci replaced with npm install in frontend Dockerfile -- package-lock.json added to repo -- nginx baked into image via nginx/Dockerfile -- docker-compose.yml uses Traefik labels, no port 80 binding -- DATABASE_URL and REDIS_URL passed explicitly as env vars -- UserRole enum uses values_callable for lowercase storage -- Portainer git source caches aggressively — use --no-cache --pull for rebuilds +### Image Management +All three custom images are built manually on the server and Portainer uses pre-built images: +```bash +sudo docker build -t commander-forge-nginx:latest --no-cache --pull http://192.168.0.62:3001/Dan/Commander-Deck-App.git#master:nginx +sudo docker build -t commander-forge-frontend:latest --no-cache http://192.168.0.62:3001/Dan/Commander-Deck-App.git#master:frontend +sudo docker build -t commander-forge-backend:latest --no-cache --pull http://192.168.0.62:3001/Dan/Commander-Deck-App.git#master:backend +``` + +After rebuilding, redeploy the stack in Portainer to pick up the new images. + +### Why pre-built images? +Portainer's repository-based builds aggressively cache the git source. Even with `--no-cache --pull`, Portainer's internal git clone cache serves stale code. Pre-built images bypass this entirely. + +--- + +## Known Fixes Applied + +- `passlib` replaced with `bcrypt==4.1.3` in requirements.txt and security.py +- `npm ci` replaced with `npm install` in frontend Dockerfile (Windows-generated lockfile missing Linux binaries) +- `package-lock.json` added to repo +- nginx baked into its own image via `nginx/Dockerfile` (Portainer pre-creates volume mount paths as directories) +- `docker-compose.yml` uses Traefik labels + `traefik.docker.network=traefik-public` +- `DATABASE_URL` and `REDIS_URL` passed explicitly as env vars +- `UserRole` enum members renamed to lowercase (`pending/approved/admin`) to match database values +- `admin_bootstrap.py` and `deps.py` updated to use lowercase `UserRole.admin`, `UserRole.pending`, etc. +- Portainer git source caches aggressively — always use `--no-cache --pull` and pre-built images + +--- ## Infrastructure -- Gitea: http://192.168.0.62:3001 / https://gitea.bussenet.ca -- GitHub mirror: https://github.com/danbusse/Commander-Deck-App (private) -- Portainer MCP: fixed, using custom mcp-portainer:latest image with -- entrypoint fix -- Cloudflare tunnel: degraded (region2 unreachable, ISP routing issue), region1 stable + +| Service | URL | Notes | +|---------|-----|-------| +| Commander Forge | https://commander.bussenet.ca | Main app | +| Portainer | https://portainer.bussenet.ca | Stack management | +| Gitea | https://gitea.bussenet.ca | Primary git (SSH port 2222) | +| GitHub mirror | https://github.com/danbusse/Commander-Deck-App | Private, Claude's file access path | +| Vault | https://vault.bussenet.ca | Secrets store | +| Portainer MCP | https://mcp-portainer.bussenet.ca/sse | Custom image with entrypoint fix | + +### Portainer MCP +Custom `mcp-portainer:latest` image built from `ghcr.io/serraniel/portainer-mcp-docker:http` with a fixed entrypoint that passes `--` before the portainer-mcp command. Tools written to `/tmp/tools.yaml`. PORTAINER_SERVER must be set without protocol prefix (e.g. `192.168.0.62:9443`) since the MCP binary always prepends `https://`. + +### Cloudflare Tunnel +- Tunnel ID: `3a032a2b-aa42-46a2-b749-e3fa9166ac59` +- Only region1 (`198.41.192.x`) is reachable — region2 (`198.41.200.x`) times out (ISP routing issue, outside our control) +- Tunnel maintains 1 of 4 connections; services are accessible but logs show constant reconnect attempts +- Cloudflared runs on host network — all tunnel ingress entries use `localhost` not container IPs + +### GitHub API Access +Claude can read/write files to the GitHub mirror using token stored in Vault at `secret/github.claude-api-token`. This is the primary mechanism for Claude to update project files between sessions. + +--- ## Environment Variables (Portainer stack env) -- SECRET_KEY: changeme (needs replacing) -- POSTGRES_PASSWORD: changeme (needs replacing) -- DATABASE_URL: postgresql+asyncpg://mtg:changeme@db:5432/mtgdb -- REDIS_URL: redis://cache:6379 -- ANTHROPIC_API_KEY: in Vault at secret/anthropic -- ADMIN_EMAIL: busse.daniel@gmail.com -- ADMIN_PASSWORD: Admin1234 + +| Variable | Value | Notes | +|----------|-------|-------| +| SECRET_KEY | changeme | ⚠️ Needs replacing | +| POSTGRES_PASSWORD | changeme | ⚠️ Needs replacing | +| POSTGRES_DB | mtgdb | | +| POSTGRES_USER | mtg | | +| DATABASE_URL | postgresql+asyncpg://mtg:changeme@db:5432/mtgdb | ⚠️ Update with new password | +| REDIS_URL | redis://cache:6379 | | +| ANTHROPIC_API_KEY | (in Vault at secret/anthropic) | | +| ADMIN_EMAIL | busse.daniel@gmail.com | | +| ADMIN_PASSWORD | Admin1234 | | + +--- + +## Git Workflow + +Two remotes are configured: +- `origin` → Gitea (`ssh://git@192.168.0.62:2222/Dan/Commander-Deck-App.git`) +- `github` → GitHub (`https://github.com/danbusse/Commander-Deck-App.git`) + +Always push to both: +```bash +git push origin master +git push github master +``` + +--- ## Next Session — Start Here -**Priority 1 — Portainer housekeeping:** -Backend container was manually created outside Portainer stack. Needs clean redeploy. +**Priority 1 — Harden credentials:** +- Generate new SECRET_KEY: `openssl rand -hex 32` +- Set strong POSTGRES_PASSWORD +- Update DATABASE_URL to match +- Update these in Portainer stack env vars -**Priority 2 — Harden credentials:** -- SECRET_KEY → openssl rand -hex 32 -- POSTGRES_PASSWORD → strong password -- DATABASE_URL → update to match - -**Priority 3 — Test end to end:** +**Priority 2 — Test end to end:** - Try building a deck via Generate mode -- Test collection import with Archidekt export -- Verify admin approval flow +- Test collection import with an Archidekt export +- Verify admin approval flow for a new registered user -**Priority 4 — GitHub mirror sync:** -When committing from Windows: push to both Gitea and GitHub - git push origin master - git push github master -Or set up automatic mirror push from Gitea. +**Priority 3 — Commit docker-compose.yml changes to repo:** +The docker-compose.yml in the repo still has `build:` directives. Update it to use `image:` directives to match the actual deployment approach: +```yaml + backend: + image: commander-forge-backend:latest + frontend: + image: commander-forge-frontend:latest + nginx: + image: commander-forge-nginx:latest +```