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
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# Docker Compose for deployment behind an existing Traefik reverse proxy
|
||||
# All domains and the proxy web name are configurable via environment variables
|
||||
|
||||
services:
|
||||
# PostgreSQL Database
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: hq-postgres
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-headquarter}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-headquarter}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-headquarter}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-headquarter} -d ${POSTGRES_DB:-headquarter}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
networks:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
# Redis Cache
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: hq-redis
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 5s
|
||||
networks:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
# API Service
|
||||
api:
|
||||
build:
|
||||
context: ./apps/api
|
||||
dockerfile: Dockerfile
|
||||
container_name: hq-api
|
||||
environment:
|
||||
APP_ENV: production
|
||||
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-headquarter}:${POSTGRES_PASSWORD:-headquarter}@postgres:5432/${POSTGRES_DB:-headquarter}
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
JWT_SECRET: ${JWT_SECRET:-change-me-in-production}
|
||||
REPO_BASE_PATH: /data/repos
|
||||
API_DOMAIN: ${API_DOMAIN}
|
||||
WEB_DOMAIN: ${WEB_DOMAIN}
|
||||
AUTHENTIK_DOMAIN: ${AUTHENTIK_DOMAIN}
|
||||
API_PUBLIC_URL: ${API_PUBLIC_URL:-}
|
||||
WEB_PUBLIC_URL: ${WEB_PUBLIC_URL:-}
|
||||
AUTHENTIK_CLIENT_ID: ${AUTHENTIK_CLIENT_ID:-headquarter-web}
|
||||
AUTHENTIK_CLIENT_SECRET: ${AUTHENTIK_CLIENT_SECRET}
|
||||
AUTHENTIK_AUTHORIZE_URL: ${AUTHENTIK_AUTHORIZE_URL:-}
|
||||
AUTHENTIK_TOKEN_URL: ${AUTHENTIK_TOKEN_URL:-}
|
||||
AUTHENTIK_JWKS_URL: ${AUTHENTIK_JWKS_URL:-}
|
||||
AUTHENTIK_ISSUER: ${AUTHENTIK_ISSUER:-}
|
||||
AUTHENTIK_AUDIENCE: ${AUTHENTIK_AUDIENCE:-headquarter-web}
|
||||
volumes:
|
||||
- repo_data:/data/repos
|
||||
- avatar_uploads:/app/uploads
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- backend
|
||||
- traefik
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.hq-api.rule=Host(`${API_DOMAIN}`)"
|
||||
- "traefik.http.routers.hq-api.entrypoints=websecure"
|
||||
- "traefik.http.routers.hq-api.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.hq-api.loadbalancer.server.port=8000"
|
||||
- "traefik.http.middlewares.hq-api-strip.stripprefix.prefixes=/api"
|
||||
- "traefik.http.routers.hq-api.middlewares=hq-api-strip"
|
||||
|
||||
# Web Frontend
|
||||
web:
|
||||
build:
|
||||
context: ./apps/web
|
||||
dockerfile: Dockerfile
|
||||
container_name: hq-web
|
||||
environment:
|
||||
VITE_API_URL: ${API_PUBLIC_URL:-https://${API_DOMAIN}}
|
||||
VITE_APP_URL: ${WEB_PUBLIC_URL:-https://${WEB_DOMAIN}}
|
||||
depends_on:
|
||||
- api
|
||||
networks:
|
||||
- backend
|
||||
- traefik
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.${PROXY_WEB_NAME:-hq-web}.rule=Host(`${WEB_DOMAIN}`)"
|
||||
- "traefik.http.routers.${PROXY_WEB_NAME:-hq-web}.entrypoints=websecure"
|
||||
- "traefik.http.routers.${PROXY_WEB_NAME:-hq-web}.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.${PROXY_WEB_NAME:-hq-web}.loadbalancer.server.port=80"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
repo_data:
|
||||
avatar_uploads:
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: bridge
|
||||
traefik:
|
||||
external: true
|
||||
name: ${TRAEFIK_NETWORK:-traefik}
|
||||
Reference in New Issue
Block a user