Diese Seite bildet jeden Begriff aus dem
Benutzer-Glossar auf das Schema ab, das ihn
tatsächlich trägt. Sie ist das Identifier-Pendant zum
zentralen Datenmodell, das die Mandanten- und
Ressourcen-Grundstruktur zeichnet; hier ist die Einheit der Begriff, nicht die
Tabelle. Migrationsnummern verweisen auf Dateien in server/migrations/ (siehe den
Migrationsindex).
Die Benennung folgt der ubiquitären Sprache von
ADR 0040: ein Begriff, eine Bedeutung –
über DB, Code, API und UI hinweg.
Die Mandantentabelle heißt workspaces, umbenannt von teams in Migration
169, gemeinsam mit team_members → workspace_members, team_invites →
workspace_invites und jeder team_id-FK → workspace_id.
organizations.kind='team' bleibt ein interner Enum-Wert; die Bezeichnung
in der Benutzeroberfläche lautet Organisation (org_kind_team), gegenüber
Persönlich für kind='personal'. Der Rohwert wird nie angezeigt.
team/teams ist im Übrigen der Agenten-Domäne vorbehalten (agent_teams,
max_teammates). Ein Architektur-Test lässt eine neue team_id-Spalte oder
einen neuen team-benannten Mandantentyp scheitern, und ein Frontend-i18n-Lint
verbietet eine neue benutzersichtbare „Team“-Zeichenkette außerhalb der
Agenten- und delivery_*-Namespaces.
kind CHECK ist personal oder team, NOT NULL DEFAULT team (Mig. 140). Der Plan hängt an der Organisation über subscriptions, deren PK in Mig. 143 von workspace_id auf organization_id umgeschlüsselt wurde – suche einen Plan also nie am Workspace.
UNIQUE (user_id) erzwingt das Ein-Organisations-Modell (kein Umschalter, kein X-Organization-Id). role ist die weitere Organisationsmenge: owner, billing_admin, admin, member.
Workspace
workspaces; FK workspace_id auf ca. 34 Tabellen
Umbenannt von teams in Mig. 169 (reine Katalog-Umbenennung, kein Zeilen-Rewrite). Trägt außerdem autonomy_level, autonomy_overrides, experience_tier.
Workspace-Mitgliedschaft
workspace_members – workspace_id, user_id, role
role CHECK wurde in Mig. 245 auf owner, admin, member verengt. Der Trigger trg_team_member_org_invariant – von 169 absichtlich nicht umbenannt, damit unveränderte RLS-Policies weiter auflösen – verlangt eine passende organization_members-Zeile für die Organisation des Workspaces; ein Verstoß löst check_violation aus.
Tabelle in Mig. 144 angelegt, die auch die FK ergänzte (ON DELETE SET NULL, ein archivierter Sitzplatz-Typ hebt die Zuweisung also auf, statt zu blockieren). Berechtigungen lösen first-non-null auf: Nutzer-Override › Sitzplatz-Typ › Workspace-Override › Organisations-Plan. Die Abrechnungsmenge liegt auf subscription_items (organization_id, seat_type_id).
Projekt
projects
Die PR-Flow-Autodev-Konfiguration liegt nicht mehr hier: Mig. 299 entfernte 12 auto_developer_*-Spalten (nur auto_developer_workflow_id bleibt), 302 den auto_issue_debate_*-Satz, 297 die Visual-Verify-Spalten. Maßgeblich ist die pr_review-Zeile von project_automations. backlog_merge_policy CHECK ist pr_only, auto_on_green, full_auto (Mig. 287).
config ist der Override-Beutel pro Start (Effort, Harness-Schalter, Teammates, Closeout); agent_profile_id ist die WHO-Autorität. Die Status-, Branch- und Zeitstempel-Spalten sind ein denormalisierter Cache des letzten Runs, nie die Quelle der Wahrheit.
next_event_seq (Mig. 220) erzeugt per atomarem UPDATE … RETURNING eine lückenlose, monotone events.sequence_num pro Run; uq_events_run_seq ist das Sicherheitsnetz. autonomy_policy_json (Mig. 214) ist die beim Start eingefrorene Policy. events.task_id ist seit Mig. 331 nullable, damit ein Workflow-Knoten-Ereignis auf einen Run ohne Task zeigen kann.
agent_profile_id kam in Mig. 293 (ON DELETE SET NULL). cadence CHECK ist seit Mig. 323once, daily, weekly, monthly, interval; dieselbe Migration ergänzte interval_minutes, gebunden durch CHECK ((cadence = 'interval') = (interval_minutes IS NOT NULL)) und einen Bereich von 5–1440 – Cadence und Spalte sind untrennbar.
Workflow
workflows + workflow_nodes + workflow_edges
workflow_nodes ist UNIQUE (workflow_id, node_key); Kanten verbinden über den Textnode_key (source_node/target_node), wobei source_handle auf out vorbelegt ist. workflows.stages JSONB kam in Mig. 311.
tasks.agent_type (plus das aufgelöste Container-Image)
Keine eigene Tabelle – der Agent ist der Harness-Prozess, den ein Run startet. Das Image wird beim Start aus der erkannten Sprache des Repositories gewählt.
execution_mode CHECK ist seit Mig. 285normal oder workflow; ultracode wanderte auf die Effort-Achse (minimal…max), wobei die Laufzeit einen alten, noch laufenden Wert in der Task-Config toleriert. is_workspace_default (Mig. 119) wird durch den partiellen Unique-Index uq_agent_profiles_workspace_default begrenzt – höchstens ein Standard pro Workspace.
Teammates
Keine Spalte.tasks.config-Schlüssel agent_teams (bool) und max_teammates (int)
Keine Tabelle, keine Migration; ADR 0040 behält den Schlüsselnamen, weil es Claude Codes eigener ist. Die Laufzeit setzt CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS / CLAUDE_CODE_MAX_TEAMMATES für claude und AGENT_TEAMS=1 für codex/gemini. max_teammates wird nur gesetzt, wenn agent_teams wahr ist.
Skill
agent_capabilities mit kind='skill' – Markdown in config.instructions
kind CHECK ist mcp oder skill; UNIQUE (workspace_id, kind, name). config trägt außerdem targets, die Allowlist pro Harness. Ein induzierter Skill wird in der separaten Tabelle skill_proposals (Mig. 218) vorgehalten und wird erst nach der Veröffentlichung eine agent_capabilities-Zeile. Capability-Schreibzugriffe sind Workspace-Admin-gated.
Council
councils + council_participants + council_turns
mode CHECK ist analyze, propose, review, standup – die UI-Bezeichnungen weichen von diesen gespeicherten Werten ab, bilde sie also ab, statt sie zu unterstellen. target_type erhielt in Mig. 314 den Wert workflow_step; so führt eine Pipeline-Stufe einen Council aus. Die Synthese landet auf judge_profile_id / judge_synthesis / judge_confidence.
scope CHECK ist personal, workspace, project. Der source_type-CHECK ist absichtlich weiter als die benutzersichtbare Allowlist (er lässt repo_sync, agent_experiment und einen harness_memory:%-Zweig zu); validate_memory_source_type ist das enge Tor, und System-Pfade umgehen es über create_system_memory. Die Governance ist zweistufig: workspace_settings.memory_governance_policy (Mig. 249) mit dem Projekt-Override projects.memory_governance_policy (Mig. 289).
MCP
Keine Tabelle. Der Katalog ist Code, exportiert nach docs/mcp/ und drift-gated
Die Obergrenzen pro Task/Workspace/Profil werden aus audit_events abgeleitet und überleben so Neustarts; laufende Reservierungen liegen in mcp_cap_reservations, deren task_id seit Mig. 268 für das task-lose Prinzipal des externen Gateways nullable ist.
NULL bedeutet erben, daher endet die Kette Profil › Projekt › Workspace immer an einem konkreten Workspace-Wert. Das Ergebnis wird anschließend von der Tarifobergrenze plans.features->'autonomy.level_max' und der Onboarding-Begrenzung geklemmt; ein project_automations.autonomy_override pro Arm (Mig. 210) kann sie nur senken. runs.autonomy_policy_json friert das Ergebnis beim Start ein.
kind CHECK ist tool, question, visual, tier_change (erweitert durch Mig. 321). tier_change ist absichtlich keinquestion, weil die Eltern-Antwort-Absicherung nur question zulässt – eine Maschine darf das Gate, das sie selbst aufgeworfen hat, nicht selbst freigeben. Der partielle Index uq_task_tool_approvals_task_pending erlaubt höchstens eine offene Freigabe pro Task, und Zeilen mit hold-Policy werden nie automatisch abgeräumt.
Backlog
backlog_items sowie der Dispatch-Arm project_automations mit kind='backlog'
project_automations.kind CHECK ist jetzt pr_review, intake, backlog: tracker wurde zu intake umbenannt (Mig. 303), debate wurde stillgelegt (Mig. 291). Issue-Import und Dispatch sind getrennte Pfade – der Import läuft unabhängig vom Modus.
Backlog-Eintrag
backlog_items – source, external_id, scope, state
Der Dedupe-Schlüssel ist UNIQUE (project_id, source, external_id): Mig. 303 ergänzte source und füllte es aus tracker, Mig. 304 entfernte die alte Spalte und ihren Unique-Index. scope ist nullable mit CHECK small, medium, large (Mig. 226); NULL wird neutral geroutet. convergence_round / convergence_cost_usd begrenzen die Review-Schleife (Mig. 232), und closed_at trägt CHECK (closed_at IS NULL OR state = 'done') (Mig. 310).
Die Spalte approval_mode wurde in Mig. 301entfernt, nachdem Mig. 300 sie gefaltet hatte: concept → stages.plan.approval, pr_draft → stages.implement.draft_pr_approval, human_gate → projects.backlog_merge_policy = 'pr_only'. concept_gate_on liest das Flag ohne verbleibenden Enum-Fallback, und das Gate greift nur bei einem Arm mit kind='backlog'.
Die beiden Booleans spannen alle vier Ergebnisse auf, einschließlich des vorher nicht ausdrückbaren stillen Schließens (false, true). Die alte Spalte completion_actionexistiert weiterhin (close, comment, nothing) als verlustbehafteter Dual-Read-Fallback für eine Zeile, deren Boolean-Paar NULL ist; ihr Entfernen ist zurückgestellt. Löse zuerst das Paar auf, das Enum nur als Fallback.
Closeout
workspace_settings.closeout_config (JSONB NOT NULL, vollständiger Default) + projects.closeout_config (nullable, sparse) + task.config.closeout; Signale auf task_outcomes.closeout_signals – Mig. 283
Die Auflösung erfolgt pro Schritt, first-non-null: Task ?? Projekt ?? Workspace ?? eingebauter Default. Es gibt bewusst keinen Hauptschalter; die Faltung liegt einmal in sc-persistence::models::closeout und wird vom Memory-Gate, der Env-Injektion und dem Status-Signal gemeinsam genutzt.
apps.db_namespace_id (Mig. 279) ist die Datenbank-Autorität einer App; app_db_resource_id überlebt nur als Hinweis, welches physische Postgres gemeint ist. app_migrations ist keine Tabelle mehr – Mig. 280 faltete sie auf db_namespace_migrations und ließ eine schreibgeschützte Kompatibilitäts-View zurück. Das Schema heißt app_<id>, und db_namespace_bindings erzwingt genau einen Binder.
Script
scripts (Mig. 066) lokal; die Katalogzeile ist marketplace_items mit kind='script'
Ein installiertes Script wird auf marketplace_installs.installed_script_ids geführt. Das Wasm-Script-Substrat ist per Design rein rechnend und DB-isoliert; es erreicht das Netz nur über die freigegebene Authority einer gebundenen Ressource.
Connector
marketplace_items mit kind='node', plus die Registry workflow_node_types pro Workspace
workflow_node_types ist UNIQUE (workspace_id, slug) und trägt preset_config, required_resource_kinds, source_item_version_id. Die Komponenten-Bytes reiten als component_data_b64 im Versions-Manifest mit.
kind ist eine CHECK-Liste, derzeit smtp, telegram_bot, webhook_endpoint, imap, postgresql, s3, discord, seafile_webdav, fints_bank, chatwoot, intercom, custom (zuletzt erweitert durch Mig. 324). Jede Art hängt am Plan-Feature-Schlüssel resources.<kind>. secret_vault_path ist nullable, eine Ressource ohne Secret ist also darstellbar. Die Benutzeroberfläche nennt sie Verbindungen.
status CHECK ist pending, online, offline, disabled; drain_state CHECK ist active, cordoned, draining (Mig. 234). Der Dispatch liest status='online' AND drain_state='active'. lease_epoch liegt nicht auf runners – es liegt auf runner_work_assignments / connector_run_assignments (Mig. 239), weil das Fencing zur Zuweisung gehört. Das Enrollment liegt in runner_enrollments + runner_grants (Mig. 236).
marketplace_items.kind CHECK ist app, script, bundle, runner_offer, workflow, node – sechs Werte, runner_offer also nicht vergessen. marketplace_installs ist seit Mig. 112UNIQUE (workspace_id, item_id): eine Neuinstallation upsertet, sie dupliziert nie. install_manifest_sha256 treibt die Drift-Erkennung.
Bundle
marketplace_items mit kind='bundle'; der Inhalt reitet in marketplace_item_versions.package_manifest JSONB unter members
members ist ein Manifest-Block, keine Spalte – ein Bundle wird beim Veröffentlichen zu einem Members-Block plus vereinigter Install-Spezifikation und Anforderungen gefaltet, sodass eine Installation genau eine marketplace_installs-Zeile ergibt. Das Veröffentlichen weist weniger als zwei Mitglieder, eine Slug-Kollision, eine Selbstreferenz, einen Zyklus, mehr als ein Mitglieds-db_namespace und ein kostenpflichtiges Mitglied in einem kostenlosen Bundle zurück. Ein App-Mitglied darf seinen Baum inline tragen statt als Paar source_tarball_url / source_tarball_sha256.
Keine Tabelle. Sitzungszustand pro Oberfläche in sc-iface-telegram/src/live_mode und sc-iface-discord/src/live_mode sowie in der Web-Follow-Engine
Follow gilt pro Oberfläche: ein Start in Telegram streamt nur in Telegram. Beide Chat-Oberflächen teilen dasselbe pure Render-Substrat; nur der Transport unterscheidet sich.
Beide nullable mit CHECK reduced oder chatty. NULL ist das Schichtungs-Signal, kein Wert: pro Konto ?? Nutzer-Standard ?? eingebautes reduced. Orthogonal zum Debug-Modus – zwei Achsen, ein Renderer, eine Redaktionswand.
Debug-Modus
workspace_settings.allow_debug BOOLEAN NOT NULL DEFAULT false (Mig. 254)
Standardmäßig fail-closed, anders als onboarding_mode, das auf TRUE coalesct. Die Aktivierung pro Sitzung oberhalb dieser Obergrenze ist ephemer und wird nie persistiert; die Obergrenze wird serverseitig auf jeder Oberfläche erzwungen.
Delivery-Board
Frontend-Route /reports/delivery; HTTP-Oberfläche GET /api/team-board; Rust services::team_board und sc-persistence::queries::delivery_board
UI, i18n (delivery_*) und Route sagen delivery; der HTTP-Pfad und das Rust-Modul sagen weiterhin team_board. Diese Aufteilung ist beabsichtigt und unverändert – eine Backend-Route /delivery gibt es nicht. Nur ein einziger i18n-Schlüssel heißt wörtlich delivery_board_*.