Commit Graph

32 Commits

Author SHA1 Message Date
alex d2b6bba15c fix: use host bind mount for /data/repos so tool containers can access mounted repos
The API container used a named Docker volume (repo_data:/data/repos) for
storing repositories. When creating tool instances with direct mount mode,
the API told Docker to bind-mount /data/repos/<repo>:/workspace into the
tool container. But the Docker daemon resolves bind-mount paths on the HOST
filesystem, not inside the API container. Since the host had no /data/repos
(the repos only existed inside the named volume), tool containers mounted
empty directories.

Changed both compose files to use a host bind mount (/data/repos:/data/repos)
instead of a named volume. This ensures:
- The API container and tool containers both see the same /data/repos path
- Bind mounts from /data/repos into tool containers work correctly

For existing installations: repos previously stored in the repo_data named
volume should be copied to /data/repos on the host before restarting the
stack.

Quality gates: compose file syntax valid
2026-05-30 15:46:02 +02:00
alex 5f39267781 fix: use bind mount for instances in traefik compose
- Change from named volume instance_data to host bind mount
- Consistent with docker-compose.yml fix for clone mode

Refs: clone mode repo files not visible in containers
2026-05-24 11:42:29 +00:00
Fusion 2bd778117f feat(tunnels): switch to temporary Cloudflare tunnels
Replace persistent Cloudflare tunnels (API-based) with temporary tunnels using
'cloudflared tunnel --url'. This removes the need for Cloudflare API tokens,
DNS records, and persistent tunnel management.

Changes:
- Install cloudflared binary in API Dockerfile
- Add start_cloudflared_tunnel() and stop_cloudflared_tunnel() to docker.py
- Update instance start/stop/restart/delete to use temporary tunnels
- Store tunnel PID in tunnel_id field, temporary URL in url/public_url
- Remove Cloudflare API service (cloudflare_tunnel.py)
- Remove cloudflared container from docker-compose
- Remove Cloudflare env vars (CLOUDFLARE_API_TOKEN, ZONE_ID, etc.)
- Remove Cloudflare configuration from config.py
- Remove Cloudflare startup check from main.py
- Remove /health/cloudflare endpoint
2026-05-20 16:23:16 +02:00
Fusion f7be50952a fix(docker): run API container as root for Docker socket access
The API container needs to run docker compose commands via the
mounted Docker socket. Running as non-root user doesn't work well
with socket permissions across container boundaries.

- Remove USER appuser from Dockerfile (API service only)
- Remove group_add from docker-compose (no longer needed)
- Add security note about considering Docker-in-Docker or rootless

This fixes:
permission denied while trying to connect to the docker API at unix:///var/run/docker.sock
2026-05-20 15:38:02 +02:00
Fusion 402e662c0c fix(docker): add docker group to API container for socket access
The API container needs access to /var/run/docker.sock to run
docker compose commands for tool instances. Add group_add to
match the host's docker GID.

Error was:
permission denied while trying to connect to the docker API at unix:///var/run/docker.sock
2026-05-20 15:33:30 +02:00
Fusion b40eb3e88c feat(cloudflare-tunnel): integrate Cloudflare tunnels for instance access
Backend:
- Add cloudflare_tunnel.py service for creating/deleting tunnels via Cloudflare API
- Add public_url and tunnel_id fields to ToolInstance model
- Update start_instance to create Cloudflare tunnel after container starts
- Update stop_instance to delete tunnel before stopping container
- Update delete_instance to cleanup tunnel before deletion
- Update restart_instance to recreate tunnel on restart
- Create Alembic migration 0011 for tunnel fields
- Add Cloudflare config settings (API token, zone ID, account ID, base domain)

Infrastructure:
- Add cloudflared service to docker-compose.traefik.yml
- Mount shared cloudflared_config volume between API and cloudflared containers
- Add Cloudflare env vars to API service

Frontend:
- Update instance Open button to handle both full URLs and proxy paths

The instance URL is now set to the Cloudflare tunnel public URL when available,
falling back to the API proxy path if tunnel creation fails.
2026-05-20 14:25:06 +02:00
Fusion 9d27cd9fe8 fix: install Docker CLI and mount socket for instance management
- Install docker-ce-cli and docker-compose-plugin in API Dockerfile
- Mount /var/run/docker.sock into API container
- Add appuser to docker group for socket permissions
- Fixes FileNotFoundError when deleting instances
2026-05-20 11:32:58 +02:00
Fusion 25662e525c fix(docker): make instance directory configurable and writable
- Add INSTANCE_BASE_PATH config option (defaults to /data/instances)
- Update docker.py to use configured path instead of hardcoded 'data/instances'
- Update Dockerfile to create /data/instances and chown to appuser
- Add instance_data volume to docker-compose.traefik.yml and docker-compose.yml
- Set INSTANCE_BASE_PATH env var in both compose files

This fixes the PermissionError when creating tool instances because
appuser can now write to /data/instances.
2026-05-20 10:09:37 +02:00
Fusion d724a92d34 docs: update env and docker-compose for session-based auth
- Replace JWT config with SESSION_SECRET and SESSION_TTL_HOURS
- Remove AUTHENTIK_JWKS_URL, ISSUER, AUDIENCE (no longer needed)
- Update docker-compose.traefik.yml environment variables
2026-05-18 22:56:04 +02:00
Fusion ea6c466c6c feat: add automatic database initialization and recovery
- Add init_database() with alembic programmatic API and retry logic
- Add connection retry with exponential backoff (5 attempts)
- Improve error messages for connection/auth failures
- Add table existence check before seeding data
- Update startup event to run migrations before seeding
- Add wait-for-db.sh script for Docker containers
- Update Docker and docker-compose configurations

Quality gates: ruff ✓, mypy ✓, unit tests (8 passed)
2026-05-18 22:10:15 +02:00
Fusion 0509b9eb4a fix: separate Authentik application slug from OAuth client ID
Authentik uses different values for:
- OAuth Client ID (UUID for authentication)
- Application Slug (URL-friendly identifier like 'headquarter-web')

Add AUTHENTIK_APPLICATION_SLUG config to build correct Authentik URLs
while keeping AUTHENTIK_CLIENT_ID for OAuth token exchange.
2026-05-18 21:46:54 +02:00
Fusion a2c787d474 fix: add tls=true label to all traefik services
Add explicit traefik.http.routers.*.tls=true label to:
- headquarter-frontend
- headquarter-api

This ensures TLS is explicitly enabled for all routed services.
2026-05-18 21:16:29 +02:00
Fusion 8ba2b48967 refactor: rename services and remove TRAEFIK_ROUTER_PREFIX env var
- Rename services to headquarter-frontend and headquarter-api
- Use hardcoded Traefik router names (headquarter-frontend, headquarter-api)
- Remove TRAEFIK_ROUTER_PREFIX environment variable
2026-05-18 21:10:17 +02:00
Fusion ec9b73225c refactor: swap web and api service order in traefik compose
Move web frontend before API service to resolve potential routing conflicts.
2026-05-18 21:02:32 +02:00
Fusion 0296ea5630 refactor: remove unnecessary StripPrefix middleware from API
Frontend calls API directly without /api prefix, so the middleware
was unnecessary. Simplifies Traefik configuration.
2026-05-18 20:36:40 +02:00
Fusion be81aa1c8b fix: pass Vite env vars as Docker build args
Vite reads env vars at build time, not runtime. The previous setup
only set them in docker-compose 'environment' which is only available
at container runtime. Now they are passed as build args so Vite can
embed the correct API URL during the build process.

- Add build args to web service in both compose files
- Update Dockerfile to accept ARGs and set ENV for Vite
- Fixes login redirect always going to localhost:8000
2026-05-18 11:09:37 +02:00
Fusion da0b90ce33 fix: align env var names for frontend API URL
The frontend code uses VITE_API_BASE_URL but docker-compose files
and .env.example were setting VITE_API_URL, causing the login
redirect to fall back to localhost:8000.

- Update docker-compose.traefik.yml: VITE_API_URL → VITE_API_BASE_URL
- Update docker-compose.yml: VITE_API_URL → VITE_API_BASE_URL
- Update .env.example: VITE_API_URL → VITE_API_BASE_URL
2026-05-18 11:02:06 +02:00
Fusion ea9f2e3c98 fix: use configurable router prefix for traefik services
Replace hardcoded 'hq-api' and '' router names with
configurable hq-api and -web. This ensures
unique identifiers per deployment and avoids conflicts with other
services sharing the same Traefik instance.
2026-05-18 10:41:40 +02:00
Fusion 86245671e7 fix: make traefik certresolver configurable via env var
Replace hardcoded 'letsencrypt' certresolver with configurable
letsencrypt in both api and web services.
2026-05-18 10:39:00 +02:00
Fusion b85ec38ff8 fix: revert service network refs to compose key name
Services should reference networks by their compose key name ('traefik'),
not by the env var. The actual Docker network name is already configurable
via TRAEFIK_NETWORK in the network definition at the bottom.
2026-05-18 10:01:47 +02:00
Fusion 8bae77e42c fix: make traefik network configurable in docker-compose.traefik.yml
- Replace hardcoded 'traefik' network references with configurable
  traefik in both api and web services
- Network definition at bottom already supported configuration,
  but service references were still hardcoded
2026-05-18 09:38:33 +02:00
Fusion 577b052c05 feat: implement user profile management and oauth/traefik integration
User Profile (US-004):
- Add authenticated profile endpoints (GET/PUT /users/me)
- Add avatar upload with file validation (PNG/JPEG, max 2MB)
- Create frontend profile page with edit form and avatar upload
- Update app shell to link to profile page

OAuth/Traefik Integration:
- Externalize all Authentik URLs to environment variables
- Add domain configuration (API_DOMAIN, WEB_DOMAIN, AUTHENTIK_DOMAIN)
- Create docker-compose.traefik.yml for reverse proxy deployment
- Update OAuth redirect/callback URLs to use configured domains
- Add VITE_APP_URL for frontend public URL configuration

Quality gates: pytest (50 passed), ruff, mypy, npm test (12 passed), typecheck, lint, build
2026-05-17 23:17:10 +02:00
alex e7819bfc82 feat: implement docker infrastructure (US-001)
- Add docker-compose.yml with postgres, redis, api, and web services
- Add multi-stage Dockerfile for API (Python 3.11)
- Add multi-stage Dockerfile for web (Node.js 20 + nginx)
- Add Makefile with common development commands
- Add .env.example with all required environment variables
- Add placeholder pyproject.toml and package.json for builds
- Configure health checks for all services
- Setup persistent volumes for postgres, redis, and repos
- Run services as non-root users
2026-05-16 17:44:39 +00:00
alex ab400d7ad9 Merge branch 'main' of ssh://git.commumedia.org:2222/alex/headquarter
CI / Web CI (push) Failing after 9s
CI / API CI (push) Failing after 10s
2026-05-16 13:16:24 +00:00
alex 44e2ae60ef fix: add VITE_OIDC_REDIRECT_URI and build args for frontend
- Add VITE_OIDC_REDIRECT_URI to .env.example and docker-compose files
- Pass OIDC variables as build args in Dockerfile (build-time only)
- Update both docker-compose.prod.yml and docker-compose.traefik.yml
- Fixes undefined OIDC variables causing 404 on login redirect
2026-05-16 13:14:09 +00:00
alex be2cb09dad fix: remove non-existent sec-headers middleware causing 404
The sec-headers@file middleware was referenced but not defined,
causing Traefik to return 404 for all routes.

- Changed sec-headers@file to default-security-headers@file in both
  docker-compose.prod.yml and docker-compose.traefik.yml
- This assumes the external Traefik has default-security-headers defined
  in its file provider configuration (e.g., in dynamic/middlewares.yml)

If you don't have this middleware defined, either:
1. Define it in your Traefik dynamic configuration, or
2. Remove the middleware label entirely
2026-05-16 13:08:46 +00:00
alex 09920c1ca1 removed secs middleware from docker compose
CI / Web CI (push) Failing after 9s
CI / API CI (push) Failing after 11s
2026-05-16 15:07:04 +02:00
alex f92f9c33e6 fix: traefik compose contains app services only (no traefik service)
- docker-compose.traefik.yml now contains api, web, db services only
- Assumes external Traefik proxy is already deployed
- Uses external traefik network for discovery
- docker-compose.prod.yml remains the full stack with embedded Traefik
2026-05-16 12:41:37 +00:00
alex 2655a29886 feat: restore traefik to prod compose and add standalone traefik compose
CI / Web CI (push) Failing after 10s
CI / API CI (push) Failing after 11s
- Add Traefik v3.2 service back to docker-compose.prod.yml with:
  - Dashboard with basic auth middleware
  - Let's Encrypt TLS challenge
  - HTTP→HTTPS redirect
  - Health checks and structured logging
- Create docker-compose.traefik.yml for standalone Traefik deployment:
  - Mirrors production Traefik configuration
  - Isolated network for external proxy usage
  - Persistent certificate storage
- Add TRAEFIK_ACME_EMAIL to .env.example
- All compose files validated with docker compose config
2026-05-16 12:37:03 +00:00
alex ae4fe95c40 refactor(docker): remove traefik compose, cleanup deploy folder
- Delete docker-compose.traefik.yml (redundant overlay)
- Remove Traefik service from docker-compose.prod.yml
- Add traefik external network and labels to api/web services in prod compose
- Add TRAEFIK_ENTRYPOINT env var to all Traefik router labels
- Remove deploy/ folder (portainer-stack.yml, .env examples, README)

Production compose now assumes external Traefik proxy on Docker network.
All environment variables come from host environment only.
2026-05-16 12:13:38 +00:00
alex dab37a88e8 refactor(docker): replace env_file with explicit environment variables
CI / Web CI (push) Failing after 9s
CI / API CI (push) Failing after 10s
- Remove env_file references from docker-compose.yml and docker-compose.prod.yml
- Add explicit environment variable forwarding for all services
- Use TRAEFIK_NETWORK env var in docker-compose.traefik.yml instead of hardcoded name
- Add VITE_* frontend variables to .env.example and deploy/.env.example
- Add missing production variables (TRAEFIK_ENTRYPOINT, TRAEFIK_CERT_RESOLVER) to deploy/.env.example

This makes environment configuration more explicit and easier to manage
across different deployment scenarios (local dev, CI/CD, Portainer).
2026-05-16 11:50:39 +00:00
Fusion 7b45344237 feat(FN-002): complete Step 5 — Docker Compose and Portainer/Traefik Skeleton 2026-05-14 01:58:18 +02:00