feat(07-01): Alembic migration 0005 + SystemSettings ORM model

- Add backend/migrations/versions/0005_system_settings.py (revision 0005, down_revision 0004)
- Creates system_settings table with 9 columns: id (UUID PK gen_random_uuid()), provider_id (String NOT NULL UNIQUE), api_key_enc (Text NULL), base_url (Text NULL), model_name (Text NOT NULL default ''), context_chars (Integer NOT NULL default 8000), is_active (Boolean NOT NULL default false), created_at/updated_at (TIMESTAMPTZ default now())
- UniqueConstraint uq_system_settings_provider_id on provider_id
- Add SystemSettings ORM model to backend/db/models.py following CloudConnection style
- downgrade() drops system_settings table cleanly
This commit is contained in:
curo1305
2026-06-04 18:46:11 +02:00
parent 4febe2f704
commit 4eb317749f
2 changed files with 122 additions and 0 deletions
+40
View File
@@ -335,3 +335,43 @@ class Group(Base):
created_at: Mapped[datetime] = mapped_column(
TIMESTAMP(timezone=True), nullable=False, server_default=func.now()
)
class SystemSettings(Base):
"""AI provider configuration table — one row per provider.
Stores the active AI provider's API key (Fernet-encrypted), base URL,
model name, and context window size. Only one row has is_active=TRUE
at any given time; the admin panel flips all rows atomically.
Encryption (D-05):
api_key_enc is encrypted with HKDF/Fernet using info=b"ai-provider-settings"
for domain separation from cloud credentials (info=b"cloud-credentials").
Master key is settings.cloud_creds_key (env var CLOUD_CREDS_KEY).
See services/ai_config.py for the encryption helpers.
Design reference: 07-RESEARCH.md Pattern 1.
Migration: 0005_system_settings.py.
"""
__tablename__ = "system_settings"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
provider_id: Mapped[str] = mapped_column(String, nullable=False, unique=True)
api_key_enc: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
base_url: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
model_name: Mapped[str] = mapped_column(Text, nullable=False, default="")
context_chars: Mapped[int] = mapped_column(Integer, nullable=False, default=8000)
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
created_at: Mapped[datetime] = mapped_column(
TIMESTAMP(timezone=True), nullable=False, server_default=func.now()
)
updated_at: Mapped[datetime] = mapped_column(
TIMESTAMP(timezone=True), nullable=False, server_default=func.now()
)
__table_args__ = (
UniqueConstraint("provider_id", name="uq_system_settings_provider_id"),
)