Multi-Tenant Architektur: Kundenisolation für mehrere Ticketsysteme und Git-Hosts #63

Open
opened 2026-03-30 20:14:16 +00:00 by David · 0 comments
Collaborator

Beschreibung

Bruno um eine Multi-Tenant-Architektur erweitern, sodass mehrere Kunden
(z.B. verschiedene Systemhäuser/Software-Projekte) jeweils eigene
Ticketsysteme, Git-Hosts, Repos und Pipeline-Konfigurationen nutzen können —
mit vollständiger Datenisolation im selben System.

Hintergrund

Bruno ist aktuell Single-Tenant: eine Odoo-Instanz, ein GitLab, ein
globaler Repo-Pool. Für den Einsatz als Systemhaus-Tool müssen mehrere
Kunden parallel bedient werden, ohne dass Tickets, Repos oder Configs
vermischt werden. Dieses Issue vereint und ersetzt die Teilaspekte
aus #14 (Multi-Ticketsystem) und #31 (Plugin-System).

Akzeptanzkriterien

Datenmodell

  • Neue Tabelle customers mit Name, Slug und Konfigurationsreferenzen
  • Neue Tabelle odoo_instances (URL, DB, User, Password, Poll-Intervall pro Kunde)
  • Neue Tabelle gitlab_instances (URL, Token, Assignee pro Kunde)
  • FK customer_id auf tickets, repos, appsignal_apps
  • User-Customer-Zuordnung (User kann 1..n Kunden sehen/verwalten)
  • Alembic-Migration für alle Schema-Änderungen

Backend-Services

  • Odoo-Poller iteriert über alle aktiven odoo_instances und setzt customer_id beim Ticket-Import
  • AppSignal-Poller ordnet Tickets dem richtigen Kunden zu
  • Scoring-Engine filtert Repos nach customer_id bei Repo-Matching
  • Preparation-Engine wählt nur kundeneigene Repos zur Vorbereitung
  • GitLab-Service nutzt pro Ticket die korrekte GitLab-Instanz des Kunden
  • Pipeline routet Tickets kundenspezifisch (keine Cross-Tenant-Zugriffe)

API

  • CRUD-Endpoints für Kunden: GET/POST/PUT/DELETE /api/customers
  • CRUD-Endpoints für Odoo-Instanzen: /api/customers/{id}/odoo
  • CRUD-Endpoints für GitLab-Instanzen: /api/customers/{id}/gitlab
  • Alle bestehenden Endpoints (/api/tickets, /api/repos, /api/stats) filtern nach Kundenkontext
  • Kundenkontext wird über JWT-Token oder Query-Parameter transportiert

Frontend

  • Kundenselektor (Dropdown) im Dashboard-Header
  • Kunden-Verwaltungsseite (Admin: Kunden anlegen, Instanzen konfigurieren)
  • Dashboard-Stats werden pro Kunde berechnet und angezeigt
  • Ticket-Liste, Repo-Registry und Triage-Seite filtern nach aktivem Kunden

Sicherheit & Isolation

  • Kein Ticket/Repo eines Kunden A ist über die API von Kunde B abrufbar
  • Credentials (Odoo-Passwörter, GitLab-Tokens) werden verschlüsselt gespeichert
  • Admin-User können alle Kunden sehen, Operator nur zugewiesene

Tests

  • pytest: Customer-CRUD + Validierung
  • pytest: Ticket-Import mit korrektem customer_id
  • pytest: API-Filter — Kunde A sieht keine Tickets von Kunde B
  • pytest: Pipeline-Durchlauf mit kundenspezifischer GitLab-Instanz
  • pytest: Scoring mit kundengefilterten Repos
  • pytest: Auth — Operator ohne Kundenzuordnung bekommt 403

Technische Hinweise

  • Betroffene Dateien:
    • Neu: backend/models/customer.py (Customer, OdooInstance, GitLabInstance Models)
    • Neu: backend/api/customers.py (Kunden-Verwaltung Endpoints)
    • Neu: frontend/src/pages/Customers.tsx (Kunden-Verwaltung)
    • Neu: frontend/src/components/CustomerSelector.tsx (Header-Dropdown)
    • Ändern: backend/models/ticket.py (+ customer_id FK)
    • Ändern: backend/models/repo.py (+ customer_id FK)
    • Ändern: backend/models/user.py (+ Customer-Zuordnung m:n)
    • Ändern: backend/services/odoo_poller.py (Multi-Instance Polling)
    • Ändern: backend/services/gitlab_service.py (Multi-Instance Client)
    • Ändern: backend/services/scoring_engine.py (Repo-Filter nach Kunde)
    • Ändern: backend/services/preparation_engine.py (Repo-Filter nach Kunde)
    • Ändern: backend/services/pipeline.py (customer_id Threading)
    • Ändern: backend/config.py (Default-Customer Fallback)
    • Ändern: backend/api/tickets.py (Kundenfilter)
    • Ändern: backend/api/repos.py (Kundenfilter)
    • Ändern: backend/api/pipeline.py (Stats pro Kunde)
    • Ändern: backend/api/auth.py (Customer-Kontext in JWT)
    • Ändern: frontend/src/App.tsx (CustomerSelector + Route)
    • Ändern: frontend/src/api/client.ts (Customer-Header mitsenden)
  • Ansatz: Schrittweiser Umbau — zuerst DB-Schema + Models, dann Services,
    dann API, dann Frontend. Bestehende Single-Tenant-Instanzen migrieren
    über Default-Customer.
  • Migration nötig: Ja, umfangreiche Schema-Migration + Datenmigration
  • Ersetzt/vereint: #14 (Multi-Ticketsystem), #31 (Plugin-System)

Aufwand: XL

## Beschreibung Bruno um eine Multi-Tenant-Architektur erweitern, sodass mehrere Kunden (z.B. verschiedene Systemhäuser/Software-Projekte) jeweils eigene Ticketsysteme, Git-Hosts, Repos und Pipeline-Konfigurationen nutzen können — mit vollständiger Datenisolation im selben System. ## Hintergrund Bruno ist aktuell Single-Tenant: eine Odoo-Instanz, ein GitLab, ein globaler Repo-Pool. Für den Einsatz als Systemhaus-Tool müssen mehrere Kunden parallel bedient werden, ohne dass Tickets, Repos oder Configs vermischt werden. Dieses Issue vereint und ersetzt die Teilaspekte aus #14 (Multi-Ticketsystem) und #31 (Plugin-System). ## Akzeptanzkriterien ### Datenmodell - [ ] Neue Tabelle `customers` mit Name, Slug und Konfigurationsreferenzen - [ ] Neue Tabelle `odoo_instances` (URL, DB, User, Password, Poll-Intervall pro Kunde) - [ ] Neue Tabelle `gitlab_instances` (URL, Token, Assignee pro Kunde) - [ ] FK `customer_id` auf `tickets`, `repos`, `appsignal_apps` - [ ] User-Customer-Zuordnung (User kann 1..n Kunden sehen/verwalten) - [ ] Alembic-Migration für alle Schema-Änderungen ### Backend-Services - [ ] Odoo-Poller iteriert über alle aktiven `odoo_instances` und setzt `customer_id` beim Ticket-Import - [ ] AppSignal-Poller ordnet Tickets dem richtigen Kunden zu - [ ] Scoring-Engine filtert Repos nach `customer_id` bei Repo-Matching - [ ] Preparation-Engine wählt nur kundeneigene Repos zur Vorbereitung - [ ] GitLab-Service nutzt pro Ticket die korrekte GitLab-Instanz des Kunden - [ ] Pipeline routet Tickets kundenspezifisch (keine Cross-Tenant-Zugriffe) ### API - [ ] CRUD-Endpoints für Kunden: `GET/POST/PUT/DELETE /api/customers` - [ ] CRUD-Endpoints für Odoo-Instanzen: `/api/customers/{id}/odoo` - [ ] CRUD-Endpoints für GitLab-Instanzen: `/api/customers/{id}/gitlab` - [ ] Alle bestehenden Endpoints (`/api/tickets`, `/api/repos`, `/api/stats`) filtern nach Kundenkontext - [ ] Kundenkontext wird über JWT-Token oder Query-Parameter transportiert ### Frontend - [ ] Kundenselektor (Dropdown) im Dashboard-Header - [ ] Kunden-Verwaltungsseite (Admin: Kunden anlegen, Instanzen konfigurieren) - [ ] Dashboard-Stats werden pro Kunde berechnet und angezeigt - [ ] Ticket-Liste, Repo-Registry und Triage-Seite filtern nach aktivem Kunden ### Sicherheit & Isolation - [ ] Kein Ticket/Repo eines Kunden A ist über die API von Kunde B abrufbar - [ ] Credentials (Odoo-Passwörter, GitLab-Tokens) werden verschlüsselt gespeichert - [ ] Admin-User können alle Kunden sehen, Operator nur zugewiesene ### Tests - [ ] pytest: Customer-CRUD + Validierung - [ ] pytest: Ticket-Import mit korrektem `customer_id` - [ ] pytest: API-Filter — Kunde A sieht keine Tickets von Kunde B - [ ] pytest: Pipeline-Durchlauf mit kundenspezifischer GitLab-Instanz - [ ] pytest: Scoring mit kundengefilterten Repos - [ ] pytest: Auth — Operator ohne Kundenzuordnung bekommt 403 ## Technische Hinweise - Betroffene Dateien: - Neu: `backend/models/customer.py` (Customer, OdooInstance, GitLabInstance Models) - Neu: `backend/api/customers.py` (Kunden-Verwaltung Endpoints) - Neu: `frontend/src/pages/Customers.tsx` (Kunden-Verwaltung) - Neu: `frontend/src/components/CustomerSelector.tsx` (Header-Dropdown) - Ändern: `backend/models/ticket.py` (+ customer_id FK) - Ändern: `backend/models/repo.py` (+ customer_id FK) - Ändern: `backend/models/user.py` (+ Customer-Zuordnung m:n) - Ändern: `backend/services/odoo_poller.py` (Multi-Instance Polling) - Ändern: `backend/services/gitlab_service.py` (Multi-Instance Client) - Ändern: `backend/services/scoring_engine.py` (Repo-Filter nach Kunde) - Ändern: `backend/services/preparation_engine.py` (Repo-Filter nach Kunde) - Ändern: `backend/services/pipeline.py` (customer_id Threading) - Ändern: `backend/config.py` (Default-Customer Fallback) - Ändern: `backend/api/tickets.py` (Kundenfilter) - Ändern: `backend/api/repos.py` (Kundenfilter) - Ändern: `backend/api/pipeline.py` (Stats pro Kunde) - Ändern: `backend/api/auth.py` (Customer-Kontext in JWT) - Ändern: `frontend/src/App.tsx` (CustomerSelector + Route) - Ändern: `frontend/src/api/client.ts` (Customer-Header mitsenden) - Ansatz: Schrittweiser Umbau — zuerst DB-Schema + Models, dann Services, dann API, dann Frontend. Bestehende Single-Tenant-Instanzen migrieren über Default-Customer. - Migration nötig: Ja, umfangreiche Schema-Migration + Datenmigration - Ersetzt/vereint: #14 (Multi-Ticketsystem), #31 (Plugin-System) ## Aufwand: XL
Sign in to join this conversation.
No description provided.