Files
kite/backend/config.py
T
curo1305 12c6487855 feat(02-01): add BackupCode ORM model, password_must_change field, Alembic migration, extend Settings
- Add BackupCode model to db/models.py with user_id FK, code_hash (Argon2), used_at (nullable)
- Add ix_backup_codes_user_id index on backup_codes.user_id
- Add password_must_change BOOLEAN NOT NULL DEFAULT false to User model (ADMIN-01)
- Extend config.py Settings with JWT, SMTP, admin bootstrap, and CORS fields (D-01, D-04, D-09)
- Add env_list_separator=',' for cors_origins env var parsing
- Append PyJWT, pwdlib[argon2], pyotp, aioredis, slowapi to requirements.txt
- Add .env.example entries for SECRET_KEY, ADMIN_EMAIL, SMTP_*, CORS_ORIGINS
- Create migration 0002 adding backup_codes table and password_must_change column
- Add TDD tests for all Task 1 acceptance criteria (7 tests pass)
2026-05-22 19:19:52 +02:00

89 lines
2.8 KiB
Python

from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""Phase 1 Pydantic Settings — reads all Phase 1 env vars from environment or .env file."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
env_list_separator=",",
)
# Data directory — used only for the flat-file settings.json path (Phase 1)
data_dir: str = "/app/data"
# PostgreSQL
database_url: str = "postgresql+psycopg://docuvault_app:changeme_app@postgres:5432/docuvault"
database_migrate_url: str = "postgresql+psycopg://docuvault_migrate:changeme_migrate@postgres:5432/docuvault"
# MinIO
minio_endpoint: str = "minio:9000"
minio_access_key: str = "docuvault_app"
minio_secret_key: str = "changeme_minio_app"
minio_bucket: str = "docuvault"
# Redis / Celery
redis_url: str = "redis://:changeme_redis@redis:6379/0"
# Security (Phase 2 — documented now, not read by Phase 1 code paths)
secret_key: str = "CHANGEME"
# Auth / JWT (Phase 2)
access_token_expire_minutes: int = 15
refresh_token_expire_days: int = 30
# SMTP (Phase 2 — D-01)
smtp_host: str = ""
smtp_port: int = 587
smtp_user: str = ""
smtp_password: str = ""
smtp_from: str = "noreply@docuvault.local"
# Admin bootstrap (Phase 2 — D-04)
admin_email: str = ""
admin_password: str = ""
# CORS (Phase 2 — D-09)
cors_origins: list[str] = ["http://localhost:5173"]
settings = Settings()
# SETTINGS_FILE: still flat-file in Phase 1; migrates to users.ai_provider in Phase 2
SETTINGS_FILE = Path(settings.data_dir) / "settings.json"
DEFAULT_SYSTEM_PROMPT = """You are a document classification assistant. When given a document's text content and a list of existing topics, you must:
1. Assign the document to one or more relevant topics from the list.
2. If no existing topics fit well, suggest new topic names.
Return ONLY valid JSON in this exact format, with no additional text or explanation:
{"assigned_topics": ["topic1"], "new_topic_suggestions": ["new topic name"]}
If the document fits no topics and you have no suggestions, return: {"assigned_topics": [], "new_topic_suggestions": []}"""
DEFAULT_SETTINGS = {
"system_prompt": DEFAULT_SYSTEM_PROMPT,
"active_provider": "lmstudio",
"providers": {
"anthropic": {
"api_key": "",
"model": "claude-sonnet-4-6"
},
"openai": {
"api_key": "",
"model": "gpt-4o",
"base_url": None
},
"ollama": {
"base_url": "http://host.docker.internal:11434",
"model": "llama3.2"
},
"lmstudio": {
"base_url": "http://host.docker.internal:1234",
"model": "gemma-4-e4b-it"
}
}
}