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:
+59
-4
@@ -22,12 +22,22 @@ class Settings(BaseSettings):
|
||||
postgres_port: int = 5432
|
||||
postgres_db: str = "headquarter"
|
||||
|
||||
# Domain configuration
|
||||
api_domain: str = "localhost"
|
||||
web_domain: str = "localhost"
|
||||
authentik_domain: str = "authentik.local"
|
||||
|
||||
# Public URLs (constructed from domains if not explicitly set)
|
||||
api_public_url: str | None = None
|
||||
web_public_url: str | None = None
|
||||
|
||||
# Authentik configuration - no hardcoded URLs
|
||||
authentik_client_id: str = "headquarter-web"
|
||||
authentik_client_secret: str = "change-me"
|
||||
authentik_authorize_url: str = "https://authentik.local/application/o/authorize/"
|
||||
authentik_token_url: str = "https://authentik.local/application/o/token/"
|
||||
authentik_jwks_url: str = "https://authentik.local/application/o/headquarter-web/jwks/"
|
||||
authentik_issuer: str = "https://authentik.local/application/o/headquarter-web/"
|
||||
authentik_authorize_url: str | None = None
|
||||
authentik_token_url: str | None = None
|
||||
authentik_jwks_url: str | None = None
|
||||
authentik_issuer: str | None = None
|
||||
authentik_audience: str = "headquarter-web"
|
||||
|
||||
jwt_secret: str = "change-me-jwt-secret"
|
||||
@@ -50,6 +60,51 @@ class Settings(BaseSettings):
|
||||
database=self.postgres_db,
|
||||
)
|
||||
|
||||
@property
|
||||
def api_base_url(self) -> str:
|
||||
if self.api_public_url:
|
||||
return self.api_public_url
|
||||
protocol = "https" if self.app_env == "production" else "http"
|
||||
port = "" if self.app_env == "production" else ":8000"
|
||||
return f"{protocol}://{self.api_domain}{port}"
|
||||
|
||||
@property
|
||||
def web_base_url(self) -> str:
|
||||
if self.web_public_url:
|
||||
return self.web_public_url
|
||||
protocol = "https" if self.app_env == "production" else "http"
|
||||
port = "" if self.app_env == "production" else ":3000"
|
||||
return f"{protocol}://{self.web_domain}{port}"
|
||||
|
||||
@property
|
||||
def authentik_base_url(self) -> str:
|
||||
protocol = "https" if self.app_env == "production" else "http"
|
||||
return f"{protocol}://{self.authentik_domain}"
|
||||
|
||||
@property
|
||||
def resolved_authentik_authorize_url(self) -> str:
|
||||
if self.authentik_authorize_url:
|
||||
return self.authentik_authorize_url
|
||||
return f"{self.authentik_base_url}/application/o/authorize/"
|
||||
|
||||
@property
|
||||
def resolved_authentik_token_url(self) -> str:
|
||||
if self.authentik_token_url:
|
||||
return self.authentik_token_url
|
||||
return f"{self.authentik_base_url}/application/o/token/"
|
||||
|
||||
@property
|
||||
def resolved_authentik_jwks_url(self) -> str:
|
||||
if self.authentik_jwks_url:
|
||||
return self.authentik_jwks_url
|
||||
return f"{self.authentik_base_url}/application/o/{self.authentik_client_id}/jwks/"
|
||||
|
||||
@property
|
||||
def resolved_authentik_issuer(self) -> str:
|
||||
if self.authentik_issuer:
|
||||
return self.authentik_issuer
|
||||
return f"{self.authentik_base_url}/application/o/{self.authentik_client_id}/"
|
||||
|
||||
@property
|
||||
def cookie_secure(self) -> bool:
|
||||
return self.app_env == "production"
|
||||
|
||||
Reference in New Issue
Block a user