← Admin Panel

Data model

admin panel · workzone

Admin Panel holds the global platform configuration — a singleton with shared settings and AI budgets. The AI-resource registry (providers, models, their assignment by function, spend, tools, system prompt) is factored out into the cross-cutting module AI Foundation, and notifications (channels, routes, personal preferences, delivery feed) — into Notifications. The singleton's ORM model lives in Knowledge Store (knowledge_store/models.py); Admin is a thin facade package (schemas + service + routes) on top of it. Consumers — Harvester, Query Engine, Agent Engine, Auth — read the model directly; nobody imports admin, and there are no cycles between modules.

1 Platform configuration Singleton. One row per instance.
platform_settings global settings
singleton · CHECK (id = 1)
id BigInteger PKCHECK always 1 · → Singleton
org_name Text NOT NULLDEFAULT DEFAULT 'Achilles'
org_logo_url Text NULL
org_description Text NULL
accent_color Text NOT NULLDEFAULT hex · DEFAULT '#6366f1' · → Branding
timezone Text NOT NULLDEFAULT IANA tz · DEFAULT 'UTC'
locale Text NOT NULLDEFAULTCHECK DEFAULT 'ru' · ru · en
date_format Text NOT NULLDEFAULTCHECK DEFAULT 'DD.MM.YYYY'
access_token_ttl Integer NOT NULLDEFAULTCHECK sec · DEFAULT 900 (15 min) · → Session TTLs
refresh_token_ttl Integer NOT NULLDEFAULTCHECK sec · DEFAULT 2592000 (30 days)
session_absolute_ttl Integer NOT NULLDEFAULTCHECK sec · DEFAULT 7776000 (90 days)
maintenance_mode Boolean NOT NULLDEFAULT DEFAULT false · → Maintenance mode
mcp_enabled Boolean NOT NULLDEFAULT DEFAULT true · kill switch for the MCP door · closed ⇒ a request to /mcp is rejected before the key check · → MCP
ai_monthly_budget Numeric NULL monthly spend threshold · NULL = not set · → AI budget
ai_budget_alert_enabled Boolean NOT NULLDEFAULTCHECK alert · DEFAULT false · CHECK: on ⇒ amount set
curation_frequency Text NOT NULLDEFAULTCHECK cadence of the platform curation run · DEFAULT 'daily' · daily · weekly · → Curation Pass
curation_weekday Integer NULLCHECK 0–6 (Mon–Sun) · weekly only · NULL for daily
curation_time Text NOT NULLDEFAULT 'HH:MM' in the organization's local time · DEFAULT '04:00' · heavy run during quiet hours
agent_weekly_token_budget BigInteger NULLCHECK weekly per-user token cap for agents · blocking · NULL = no limit · spend = SUM(tokens_used) over runs · → AI usage · → Agent Engine
chat_weekly_token_budget BigInteger NULLCHECK weekly per-user token cap for chat · informational in v1 (tracked without blocking) · NULL = no limit · spend = SUM(tokens_used) over messages · → AI usage
agent_iteration_cap Integer NOT NULLDEFAULTCHECK cap on steps in a single run · DEFAULT 15 · a safeguard against looping, not a budget · → Agent Engine
agent_max_concurrency Integer NOT NULLDEFAULTCHECK cap on concurrent LLM calls on the agents' background lane · DEFAULT 4 · isolated from live chat · → Agent Engine
created_at DateTime(tz) DEFAULT server_default=now()
updated_at DateTime(tz) DEFAULT now() + trigger
Singleton — one row per instance
CHECK (id = 1) guarantees uniqueness. The migration inserts the row with defaults right away — the application always reads / updates, never creates.
Session TTLs → Auth & Security
Override the auth defaults. Values in seconds — a single format shared with the JWT library. session_absolute_ttl is the maximum lifetime of a token family (= absolute_expires_at in the auth module). Auth imports the model from core and reads the TTLs when issuing tokens.
Branding
accent_color — a hex color applied to the login screen and the header via a CSS custom property. The theme (dark / light) is set on the client: the first visit follows the system preference (prefers-color-scheme), and the choice is stored in localStorage.
Global config — model outside admin → Auth & Security
The PlatformSettings ORM model lives in knowledge_store/models.py, not in admin. Admin provides the CRUD API (settings service / routes); auth and other modules import the model to read it. Dependencies flow admin → KS/auth — no cycles.
CHECK vs ENUM
Fields with a fixed value set (locale, date_format) are Text + CHECK, not a native PostgreSQL ENUM.
why
ALTER TYPE ADD VALUE cannot be rolled back inside a transaction — Alembic migrations are simpler this way.
SMTP settings — in the Email module → Email
The smtp_settings model (fields, password encryption, migration) lives with the Email transport. Here — only the editing screen (→ SMTP screen), which writes the settings through the API.
AI budget — an instance setting; spend — in the registry → AI usage → model_usage → Notifications
The admin enters the monthly AI-spend threshold by hand and turns it on with a toggle — not a hardcode: the amount and the flag live here, in the singleton (ai_monthly_budget + ai_budget_alert_enabled), next to maintenance_mode. The CHECK prevents enabling the alert without an amount set. The control sits on the AI usage screen — a shared home for limits, next to the weekly token caps; the monthly bill by model is accumulated by the AI-resource registry (model_usage, aggregated by model · function · day) and shown as a breakdown by model there too. When the threshold is reached a Budget-type notification is raised — the channel is owned by the notifications module. The models and their assignments — also in AI Foundation.
Per-person spend — derived from journals, no counter → AI usage
The AI usage screen computes per-user totals on the fly from journals: agent spend — from agent_runs.tokens_used (via agents.user_id), chat — from messages.tokens_used (via conversations.user_id). There is no separate per-user counter table — the cap is derived, like the agent budget. Both weekly caps (agent_weekly_token_budget · chat_weekly_token_budget) live here, in the singleton; the agent one blocks runs, chat is informational in v1. Indexing and RAG search are not tied to a person — their aggregate is held by model_usage (by model · function · day); the same screen shows them as a breakdown by model, not by person. Monetary cost per person, a daily user_usage aggregate as load grows, and chat blocking are v2.
2 Migration Creates the tables and seeds the singleton.
alembic/versions/NNN_core_platform_settings.py
Creates the platform_settings table and, in the same step, runs an INSERT of the initial row with defaults — the singleton exists from the first launch, and the application never creates it. downgrade()DROP TABLE.