Skip to main content
Administration und Sicherheit

Mandantenisolierung

Wie Ottili ONE Ihr Unternehmen von anderen trennt: unternehmensbezogene Datensätze, fail-closed Erzwingung, Datenbank-Zeilensicherheit, eine einzige Mandantengrenze und durchgehende Durchsetzung über Plattform, Realtime, Berechtigungen und Suche.

Überblick

Ottili ONE ist mandantenbezogen (company-scoped) gebaut. Jedes Unternehmen arbeitet in einem eigenen, klar abgegrenzten Mandantenkontext, und sensible Aktionen laufen niemals ohne die richtige Berechtigung oder eine menschliche Freigabe. Dieser Artikel erklärt, wie die Mandantenisolierung technisch funktioniert — von der unternehmensbezogenen Datenspeicherung über die fail-closed Erzwingung bis zur plattformweiten Durchsetzung in der Unified-API, im Realtime-Bus, in der Berechtigungs-Engine und in der Suche.

Die Mandantenisolierung ist kein Zusatzmodul und kein nachträglicher Filter. Sie ist Teil der gemeinsamen Steuerungsebene (Platform Core) und wird auf jeder Anfrage erzwungen. Eine vertiefende, bereichsübergreifende Sicht finden Sie in der [Sicherheitsübersicht](/docs/security-overview).

Unternehmensbezogene Mandantentrennung

In Ottili ONE gehört jeder geschäftsrelevante Datensatz zu genau einer verifizierten company_id. Der Zugriff über Unternehmensgrenzen hinweg wird niemals aus einem Standardwert, einer ersten Mitgliedschaft oder einer Eingabe des Aufrufers abgeleitet.

  • Jede geschäftliche Entität — Datensätze, Ereignisse, Dateien, Flow-Läufe, Webhooks, API-Schlüssel und Abrechnungsereignisse — trägt eine explizite company_id.
  • Die Mandantenzugehörigkeit wird aus dem verifizierten Token abgeleitet, nicht aus einer vom Aufrufer mitgelieferten Angabe.
  • Ein Unternehmen kann niemals auf die Daten eines anderen Unternehmens zugreifen, es sei denn, eine explizite, berechtigte Freigabe erlaubt es.

Fail-closed Erzwingung mit assert_same_company()

Die gemeinsame Primitive assert_same_company() ist fail-closed: Sie lehnt jede Anfrage ohne oder mit falschem Unternehmenskontext ab. Eine vom Aufrufer mitgelieferte company_id wird niemals vertraut.

  • Jede mandanteneigene Operation, die eine company_id aus der Anfrage erhält, muss ihren wirksamen Mandanten über assert_same_company() auflösen, anstatt dem Aufrufer zu vertrauen.
  • Ein None-Ziel wird auf das eigene Unternehmen des Akteurs aufgelöst — niemals auf einen globalen Standard.
  • Ein Konflikt (Zielunternehmen ungleich verifiziertem Unternehmen) führt zur Ablehnung mit einem klar definierten Fehler.

Datenbank-Zeilensicherheit mit PostgreSQL (RLS)

Die Datenbank filtert jede Plattformzeile nach der verifizierten company_id über PostgreSQL Row-Level Security (RLS). Der Laufzeit-Standardzustand ist „verweigern" (deny-by-default).

  • Der Sitzungszustand ohne explizit positive company_id (kein Superadmin-Umgehungspfad im Anfragepfad) wird als Fehler behandelt.
  • Die Mandantensitzung bindet die verifizierte company_id pro Transaktion, sodass jede Abfrage unternehmensbezogen bleibt.
  • Ein Kontext ohne Unternehmen löst einen MissingCompanyContextError aus — es gibt keinen versteckten globalen Standard.

Eine Mandantengrenze: PlatformContext

PlatformContext ist die einzige Mandantengrenze der Plattform. Es gibt keine zweite, konkurrierende Grenze.

  • validate(require_company=True) liefert einen HTTP-403-Fehler, wenn kein verifiziertes Unternehmen vorhanden ist.
  • assert_company() lehnt jeden Konflikt ab, sobald ein anderes Unternehmen als das verifizierte erreicht würde.
  • company_id aus PlatformContext ist die alleinige Quelle des Mandantenbereichs für alle nachgelagerten Dienste.

Plattformweite Durchsetzung über die Unified-API-Middleware

Die Mandantenisolation endet nicht an der Datenbank. Die Unified-API-Middleware extrahiert die verifizierte company_id pro Anfrage und aktiviert den RLS-Hook der Datenbanksitzung, sodass jede Transaktion unternehmensbezogen bleibt.

  • Der Token wird bei jedem authentifizierten Aufruf verifiziert.
  • Die extrahierte company_id fließt in den Sitzungskontext, bevor Geschäftslogik ausgeführt wird.
  • Dienste, die über die Unified-API sprechen, erben den gleichen unternehmensbezogenen Kontext, ohne ihn neu ableiten zu müssen.

Realtime: ein Bus, geschützte Kanäle

Ottili ONE betreibt einen einzigen Realtime-Bus. Kanäle sind mandantenbezogen und werden deny-by-default autorisiert.

  • Kanäle folgen dem Muster co.{company_id}; eine nicht positive ID wird abgelehnt.
  • authorize_channel_access lehnt den Zugriff ab, wenn der Aufrufer keinen Kontext hat oder einem fremden Kanal gehört.
  • In den Kanälen werden nur typisierte payload_ref-Verweise gespeichert — Secrets, Token und personenbezogene Daten erscheinen dort niemals.

Eine Berechtigungs-Engine mit deny-by-default

Es gibt genau eine Berechtigungs-Engine. Unbekannte Rolle, unbekannte Berechtigung, fehlendes Unternehmen oder fremder Mandant führen zur Verweigerung.

  • Es gibt keinen versteckten Admin-Umweg und keine Platzhalter-Rechte (*).
  • Berechtigungen wirken unternehmensbezogen: Ein Nutzer sieht und darf nur das, was seinem eigenen Unternehmen und seiner Rolle gehört.
  • Dies schließt KI-gestützte Aktionen ein: Freigabepflichtige Schritte laufen nur mit menschlicher Freigabe über die [Freigabewarteschlange](/docs/approval-queue).

Unternehmensbezogene Suche

Die globale Suche ist unternehmensbezogen: Die Suchschicht indiziert und liefert nur Dokumente, die zum anfragenden Unternehmen gehören, und erfasst den Unternehmensbereich in der Observability.

  • Suchmodelle tragen eine explizite company_id.
  • Die unternehmensbezogene Suche hängt davon ab, dass der Indexierungsjob die company_id berücksichtigt. Dies ist ein bekannter, ehrlicher Vorbehalt: Die mandantenbezogene Suche ist qualifiziert (abhängig von der Indexierung) und wird nicht als universelle Garantie ohne Vorbehalt veröffentlicht.

Statusbegriffe und Verfügbarkeit

Die in diesem Artikel beschriebenen Mandantenisolierungsmechanismen — unternehmensbezogene Datensätze, assert_same_company(), PostgreSQL RLS, der einzige PlatformContext, die Unified-API-Middleware, geschützte Realtime-Kanäle und die eine Berechtigungs-Engine — sind live und im Quellcode belegt. Die unternehmensbezogene Suche ist qualifiziert (siehe oben).

Ottili ONE unterscheidet klar zwischen Live, Beta, Private Beta, In Entwicklung, Geplant und Konzept. Was diese Begriffe bedeuten, ist in [Funktionsstatus-Labels verstehen](/docs/understand-feature-status-labels) erklärt.

Verwandte Artikel

  • [Sicherheitsübersicht](/docs/security-overview) — der bereichsübergreifende Blick auf die Sicherheitsarchitektur.
  • [Konto- und Datensicherheit](/docs/account-and-data-security) — Authentifizierung, Sitzungen, Isolation, Audit, Schwachstellenmeldung.
  • [Rollen und Berechtigungen](/docs/roles-and-permissions) — wer darf was.
  • [Geteilte Berechtigungen und Entitlements](/docs/shared-permissions-and-entitlements) — das plattformweite Berechtigungsmodell.
  • [Freigabewarteschlange](/docs/approval-queue) — menschliche Freigabe für sensible Aktionen.
  • [Unternehmen, Team & Berechtigungen](/docs/company-and-team) — wie Rollen und Zugriff funktionieren.
  • [Die Ottili Console navigieren](/docs/navigate-ottili-console) — wo Sie Einstellungen und Administration finden.
  • [Funktionsstatus-Labels verstehen](/docs/understand-feature-status-labels) — was die Statusbegriffe bedeuten.

War dieser Artikel hilfreich?