Files
LLeMbas/src/lembas/db/models/setting.py
T
Jaroslav Beneš 5ef2af6a9f Scaffold project, data model and artwork
Establish the LLeMbas foundation: FastAPI/Jinja/SQLite layout, the ORM
schema, and the original SVG identity.

Notable decisions, all recorded in comments at the point they matter:

- No Alembic. SQLite only, schema created at startup, so models carry a
  few columns nothing reads yet (Message.parent_id for branching,
  content_parts_json for multimodal turns). Adding them later to a live
  database without migrations is the painful path.
- Sessions are server-side rows keyed by a SHA-256 of the cookie value,
  not JWTs, so logout and bans revoke access immediately.
- Upstream API keys are Fernet-encrypted with a key derived from
  LEMBAS_SECRET_KEY. decrypt() fails soft to "" so rotating the secret
  degrades to re-entering keys rather than crashing the admin UI.
- Artwork is generated by scripts/build_artwork.py rather than hand-drawn
  per file: the mallorn leaf appears in the icon, favicon, lockup and
  banner, and one source is the only way those stay in sync. The wordmark
  is Source Serif 4 (OFL) converted to outlines, because a README banner
  cannot load a webfont and <text> would render in whatever serif the
  viewer happens to have.
- Icons live in a template partial, not assets/, because same-document
  <use href="#id"> is universally supported and the cross-document form
  is not.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 10:34:48 +02:00

29 lines
870 B
Python

"""Instance-wide settings, stored as a key/value table."""
from __future__ import annotations
from typing import Any
from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column
from lembas.db.base import Base, Timestamps
from lembas.db.types import JSONDict
class Setting(Timestamps, Base):
"""One row per settings group, value is an arbitrary JSON object.
A key/value table rather than a wide typed table: admin settings grow with
every feature (tools, agents, image generation) and adding a column to a
live SQLite database without migrations is exactly what this avoids.
"""
__tablename__ = "settings"
key: Mapped[str] = mapped_column(String(120), primary_key=True)
value: Mapped[dict[str, Any]] = mapped_column(JSONDict, default=dict)
def __repr__(self) -> str:
return f"<Setting {self.key}>"