Zugriffsmodell — Multi-User + Kundenzugriff
Zwei Haupt-Szenarien im Bild
Fuer das Verstaendnis reichen zwei Diagramme: wie das Team intern arbeitet, und wie ein Kunde von aussen mit Auth auf seinen Bereich kommt.
Diagramm A — Intern: Team arbeitet am gleichen Repo
Alle Teammitglieder haben vollen Zugriff auf den gesamten Vault. Sync laeuft ueber Git — keine App-Layer dazwischen.
flowchart TB classDef human fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#78350f classDef local fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a classDef server fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#064e3b M["👤 Marvin<br>Laptop"]:::human C["👤 Canay<br>Laptop"]:::human T["👤 weitere Teammitglieder"]:::human subgraph Local["💻 Lokale Obsidian-Vaults"] direction LR MV["Vault Marvin"]:::local CV["Vault Canay"]:::local TV["Vault ..."]:::local end GR["🗄️ Zentrales Git-Repo<br>GitHub Private<br>oder Gitea self-hosted"]:::server M ==> MV C ==> CV T ==> TV MV <==>|git pull / push<br>SSH-Key + 2FA| GR CV <==>|git pull / push<br>SSH-Key + 2FA| GR TV <==>|git pull / push<br>SSH-Key + 2FA| GR
Merkmale:
- Jeder arbeitet lokal in seinem eigenen Obsidian-Vault-Klon — offline-faehig, schnell.
- Git ist der Synchronisations-Mechanismus. Konflikte → Merge.
- Auth passiert beim Repo (SSH-Keys + 2FA auf GitHub / Gitea). Keine App-Layer.
- Alle Rollen (Marvin, Canay, spaeter weitere) sehen alles.
- Obsidian-Git-Plugin kann Auto-Commit + Auto-Pull machen (optional).
Diagramm B — Kunde mit Auth auf seinen Bereich
Der Kunde kommt nie direkt ans Git-Repo. Zwischen Repo und Kunde sitzen zwei Dinge: ein Export-Filter (entfernt interne Notizen, trennt Kunden voneinander) und ein Kunden-Portal mit eigener Auth.
flowchart LR classDef team fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#78350f classDef server fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#064e3b classDef filter fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d classDef portal fill:#ede9fe,stroke:#8b5cf6,stroke-width:2px,color:#4c1d95 classDef kunde fill:#fce7f3,stroke:#ec4899,stroke-width:2px,color:#831843 subgraph Team["Team"] direction TB M["👤 Marvin"]:::team C["👤 Canay"]:::team end Repo["🗄️ Zentrales Repo<br>alle Kunden + _internal/"]:::server Filter["🔒 Export-Filter<br>_internal/ raus<br>visibility:internal raus<br>pro Kunde getrennt"]:::filter subgraph Portal["🌐 Kunden-Portal · HTTPS + Auth"] direction TB Auth["🔑 Auth-Layer<br>Clerk · Supabase · Custom"]:::portal TA["Tenant A<br>nur Kunde-A-Inhalte"]:::portal TB["Tenant B<br>nur Kunde-B-Inhalte"]:::portal end KA["👤 Kunde A"]:::kunde KB["👤 Kunde B"]:::kunde M ==>|voller Zugriff| Repo C ==>|voller Zugriff| Repo Repo ==> Filter Filter ==> Auth Auth --> TA Auth --> TB KA -->|Login + 2FA| Auth KB -->|Login + 2FA| Auth TA -.Freigabe · Kommentar.-> Repo TB -.Freigabe · Kommentar.-> Repo
Merkmale:
- Vier Rollen, drei Grenzen. Team ↔ Repo ist die erste Grenze (Git-Auth). Repo ↔ Portal ist die zweite (Filter). Portal ↔ Kunde ist die dritte (Auth + Tenant).
- Kunde A darf nie Kunde B sehen. Der Filter erzeugt pro Kunde einen separaten Export. Das Portal rendert nur, was zum eingeloggten Tenant gehoert. Zwei Verteidigungslinien.
- Feedback-Loop zurueck ins Repo. Kommentare und Freigaben fliessen zurueck als
feedback.mdim passendenruns/-Ordner — der Kunde schreibt aber nie direkt ins Repo, das Portal vermittelt. - Auth-Anbieter: Clerk, Supabase, Auth0 — alle mit EU-Hosting fuer DSGVO. Eigene Lösung ginge auch, ist aber mehr Aufwand.
- Phase-0/1: Dieses Diagramm zeigt den Zielzustand. Aktuell (kein Kunde im System) laeuft nur Diagramm A.
Drei Nutzungs-Szenarien (textlich)
Das System hat drei voellig unterschiedliche User-Typen mit ganz unterschiedlichen Rechten und Beduerfnissen. Eine Loesung fuer alle funktioniert nicht — wir brauchen zwei getrennte Oberflaechen (wie oben gezeigt).
Szenario 1 — Team intern (Marvin + Canay + spaeter weitere)
- Was sie brauchen: Voller Zugriff. Gleichzeitiges Arbeiten am selben Vault. Versionierung und History.
- Loesung: Privates Git-Repo (empfohlen: GitHub Private, alternative: Gitea self-hosted auf EU-Server).
- UI: Obsidian-Vault lokal. Sync via
git pull/git push. Optional: Obsidian Git Plugin fuer Auto-Sync alle paar Minuten. - Konflikt-Handling: Git-Merge. Bei gleichzeitigem Edit derselben Datei: manuelle Konfliktaufloesung.
Szenario 2 — Kunde sieht seinen Bereich
- Was der Kunde braucht: Seine Posts zur Freigabe sehen, seinen Content-Kalender, seinen Monatsreport, kommentieren koennen, freigeben koennen. Mehr nicht.
- Was der Kunde NICHT sehen darf: Interne Notizen (unsere Strategie, Preise, interne Kommunikation, andere Kunden).
- Loesung: Separates Kunden-Portal (Web-App). Zieht aus dem Vault nur die fuer diesen Kunden freigegebenen Files.
- UI: Web-Oberflaeche mit Login. Kunde sieht: sein Kanban (Posts in Draft / Zur Freigabe / Veroeffentlicht), seine Reports, Kommentar-Funktion.
Szenario 3 — Kunde ↔ Kunde Isolation
- Hard Rule: Kunde A darf NIE Kunde B’s Daten sehen. Auch nicht versehentlich, nicht als Dateiliste, nicht als Link-Vorschau.
- Loesung: Auth-Ebene auf dem Portal trennt komplett. Jeder Kunde hat eine eigene Session/Tenant. Im Portal wird nur das gerendert, was zum eingeloggten User gehoert.
Der Daten-Fluss
sequenceDiagram participant Marvin participant Repo as Git-Repo<br/>(privat) participant Agent as Claude-Agent participant Portal as Kunden-Portal participant Kunde Marvin->>Repo: Scoping in runs/ eintragen Marvin->>Agent: "Bereite Sprint 1 fuer Koehnemann vor, Anfrage-zu-Rechnung" Agent->>Repo: Pipeline ausfuehren, Stage-Outputs schreiben Agent->>Portal: Sprint-Plan + Architektur zur Freigabe pushen Kunde->>Portal: Login + Plan ansehen Kunde->>Portal: Kommentar oder "Freigegeben" Portal->>Repo: Feedback zurueckschreiben (runs/.../feedback.md) Agent->>Repo: Bei Freigabe → Implementation starten, Go-Live in performance.md vermerken
Wichtig: Der Kunde schreibt nie direkt ins Repo. Das Portal vermittelt. So bleibt die Source-of-Truth (das Repo) kontrollierbar.
Rollen-Modell
| Rolle | Kann | Kann NICHT |
|---|---|---|
| Team-Lead (Marvin, Canay) | alles: Repo-Zugriff, Portal-Admin, Kunden anlegen, Skills/Pipelines aendern | — |
| Team-Member | Repo-Zugriff (lesend + schreibend in runs/ und intern/kunden/), keine Skill-/Pipeline-Aenderungen | Rollen verwalten, Kunden loeschen |
| Kunde | Portal-Zugriff auf seinen Tenant, Drafts ansehen, kommentieren, freigeben, Reports ansehen | Repo, andere Kunden, interne Notizen |
| Gast (zeitlich befristet) | nur lesen auf definierte Files im Portal | alles andere |
Rollen-Durchsetzung:
- Repo-Ebene: GitHub Teams / Branch Protection / Deploy Keys.
- Portal-Ebene: eigene Auth (Clerk / Auth0 / Supabase Auth) mit Row-Level-Security auf Tenant-Basis.
Sicherheits-Grundsaetze
- Secrets nie im Repo. API-Keys, Tokens, Passwoerter:
.env.local(in.gitignore) + Secret-Manager (GitHub Secrets, Doppler, 1Password Secrets Automation). - Interne-Only Dateien markieren. Dateien/Ordner mit
_internal/Prefix oder Frontmatter-Flagvisibility: internalwerden vom Portal-Export automatisch ausgeschlossen. - Audit-Log. Jede kundenrelevante Aktion (Freigabe, Kommentar, Login) wird geloggt. Wiederherstellbar.
- DSGVO. Kunden-Daten auf EU-Servern. Data-Processing-Agreement im Template-Vertrag mit Kunden. Recht auf Loeschung umsetzbar.
- 2FA Pflicht fuer Team. Auf Repo + Portal-Admin.
- Rate-Limits + Input-Validation im Portal, Standard-Sicherheits-Hygiene.
- Regular Backups. Repo = Git-History reicht. Portal-DB = taegliches Backup.
Self-hosted Server? Reichen dann SSH + OS-Rechte?
Gute Intuition. Kurzantwort: Fuer die Team-Schicht ja, fuer die Kunden-Schicht nicht. Wir brauchen beides.
Warum OS-Rechte fuer Team reichen
SSH + Unix-User + chmod/chown/ACLs sind battle-tested und viel einfacher als eine Auth-Loesung nachzubauen. Fuer Marvin + Canay (+ ggf. spaeter ein:e Angestellte:r) ist das solide:
- Authentifizierung: SSH-Keys. 2FA via hardware tokens (YubiKey) moeglich.
- Autorisierung: Unix-Groups (
agentur-team) + ACLs auf Ordner-Ebene. - Git-Hosting: eigener Gitea/Forgejo auf dem Server, Git-over-SSH.
- Vorteil: keine GitHub-Abhaengigkeit, Daten liegen bei uns, DSGVO automatisch einfacher.
Warum Kunden das NICHT benutzen koennen
Fuenf Probleme:
- UX: Kunde ist nicht-technisch. SSH-Client, Keys generieren,
cat post.md— keine Chance. - Granularitaet: OS-Rechte sind File/Ordner-level. Wir wollen aber “Kunde darf kommentieren aber nicht editieren”, “Kunde sieht Draft aber nicht die internen Kommentare im gleichen Verzeichnis”. Das ist App-Logik, nicht Dateisystem.
- Collaboration-Features: Kommentar-Threads, Freigabe-Button, @-Mentions, Notifications — das bauen wir uns mit
chmodnicht. - Audit/Business-Logik: “Post freigegeben am X durch Kunde Y” ist ein Geschaeftsereignis, kein OS-Log-Eintrag.
- Isolation-Risiko: Alle Kunden auf demselben FS mit
chmod-Trennung — ein falscheschmod 777, ein Pfad-Traversal-Bug im Skript, ein Symlink zu weit → Datenleck zwischen Kunden. Das ist eine Klasse von Fehlern, die eine Applikations-Layer mit sauberer Tenant-ID viel besser absichert.
Die Loesung: zwei Schichten (Defense-in-Depth)
flowchart TB subgraph OS["Schicht 1 — Server + OS"] SSH[SSH + Keys] Unix[Unix-User/Groups<br/>chmod/ACLs] Git[Gitea/Forgejo<br/>Git-over-SSH] end subgraph App["Schicht 2 — Applikations-Layer"] Auth[Web-Auth<br/>pro Kunde eigener Tenant] API[Portal-API<br/>Row-Level-Security] UI[Kunden-Web-UI] end Team[Marvin + Canay] -->|SSH direkt| OS OS -->|liest Files mit eingeschraenkten Rechten| App Kunde -->|nur via HTTPS + Login| App App -.-|Portal darf NUR sein Tenant-Verzeichnis<br/>lesen — erzwungen durch Unix-User| OS
Das Portal laeuft auf demselben Server als eigener Unix-User (portal-service) mit Zugriff nur auf eine definierte Datei-Wurzel. Falls die App einen Auth-Bug hat, sichert das Dateisystem als zweite Verteidigungslinie ab — Portal kann physisch nicht auf /team-internal/ zugreifen, weil chmod 750 team-internal/ + falscher Unix-User.
Empfehlung fuer den Stack
Phase 0/1 (Dogfooding): Wir fangen mit GitHub Private an — zero setup, sofort produktiv. Wenn wir spaeter auf eigenen Server wollen, migriert man Git-Repos in 10 Minuten zu Gitea.
Phase 2 (Kunden): Eigener Server bei Hetzner EU (DSGVO einfach, guenstig, solide). Darauf:
- Gitea/Forgejo fuer Team
- Next.js-Portal als systemd-Service unter eigenem Unix-User
- Nginx als Reverse-Proxy mit Let’s Encrypt
- Backups auf Hetzner Storage-Box oder offsite
Noch nicht jetzt entscheiden — das kommt mit Phase 2. Wichtig ist nur: wir verbauen uns den Weg nicht. Deshalb: clean Git-History von Tag 1, keine Secrets im Repo, Architektur-Trennung Team ↔ Kunde.
Stack-Entscheidungen (Vorschlag)
Phase 0/1 — noch ohne externe Kunden
Fuer Dogfooding reicht nur das Repo. Portal kommt spaeter.
- Repo: GitHub Private (simpel, Marvin hat da Erfahrung, Canay kann leicht eingeladen werden).
- Sync:
git pull/git pushmanuell oder Obsidian-Git-Plugin fuer Auto-Commits. - Secrets:
.env.local+ GitHub Secrets fuer CI.
Phase 2 — Kunden-Portal
Hier wird’s interessant. Zwei Varianten:
Variante A — Custom Portal (Next.js o.ae.)
- Komplette Kontrolle, maximale Flexibilitaet.
- Aufwand: 2-4 Wochen fuer MVP.
- Stack-Vorschlag: Next.js + Supabase (Auth + DB + Row-Level-Security eingebaut, EU-Region waehlbar).
Variante B — Notion oder Trello als Kunden-Bruecke
- Kunde bekommt Einladung zu einem dedizierten Notion/Trello-Workspace.
- Wir syncen Files/Statuses zwischen Repo und Notion via API.
- Schneller zu launchen, aber abhaengig vom Drittanbieter + Branding leidet.
Variante C — Kunde bekommt eigenes Git-Repo (interessante Abkuerzung)
- Pro Kunde ein privates Repo (auf GitHub oder unserem Gitea). Kunde wird als Collaborator hinzugefuegt mit Read-Rechten + Kommentar-Funktion ueber GitHub Issues/PRs.
- Wir pushen nur sein gefiltertes Subset dorthin (Script macht das automatisch aus dem Haupt-Repo).
- Wann geht das gut: Kunde ist selbst tech-affin (andere Agentur, IT-naher KMU, Developer-Shop, Marketing-Profi mit GitHub-Erfahrung).
- Wann NICHT: Traditionelle KMU (Baeckerei, Autohaus, Handwerker). Die wollen klicken, nicht pullen.
- Vorteile wenn’s passt: Minimaler Bau-Aufwand. Git-History als Audit-Log gratis. Pull-Requests als Freigabe-Mechanismus. Kommentare als Review. Kunde kann Markdown selbst editieren wenn er will.
- Nachteile: Kein schickes UI. GitHub-Branding ueberall. Kunde muss Account haben und Basics kennen.
Vorschlag fuer Phase 2: Wir segmentieren nach Kundentyp:
- Tech-affine Kunden → Variante C (eigenes Repo). Startet sofort, null Portal-Aufwand.
- Traditionelle Kunden → Variante B (Notion). Als Bruecke, bis wir genug haben um C als Option abzuloesen oder ein eigenes Portal (A) zu bauen.
- Variante A (Custom Portal) erst wenn 5+ traditionelle Kunden, die uns das rechtfertigen.
Das ist Pragmatismus: wir bauen kein Produkt-Fundament vor dem ersten Euro. Jede Variante hat einen sauberen Migrationspfad.
Entscheidungen die JETZT anstehen
- Git-Host waehlen: GitHub Private (empfohlen) vs Gitea self-hosted.
- Repo privat einrichten: Branch-Protection, Canay als Collaborator einladen.
-
.gitignore+ Secret-Pattern:.env.local,*.key,secrets/— in Grundstruktur als Datei anlegen. -
_internal/Konvention in conventions.md aufnehmen.
Entscheidungen die in Phase 2 anstehen
- Variante A vs B fuers Portal
- Auth-Anbieter (Clerk / Auth0 / Supabase / Custom)
- Datenschutz: DPA-Vorlage, Auftragsverarbeitungsvertrag
- Feedback/Comment-Mechanismus im Portal (Thread? Inline? Separate Tabelle?)
Related
- CLAUDE.md — Router + Behavior Rules (verweist auf dieses Dokument)
- conventions.md — Struktur-Regeln (
visibility: internal,_internal/Prefix) - zielsystem.md — Gesamt-Architektur, §9 Hosting-Modell
- agent-native-architektur.md — verwandter Denkrahmen
- runner-architektur.md — LLM-Agnostik-Layer