Projekt-Sichtbarkeit: Nutzer-Zuordnung, projektbezogene Filterung und Schreibschutz

- Neues Modell ProjektUser (projekt_users) für projektbezogene Sichtbarkeit
- Migration V01_09 legt Tabelle an (keine Initial-Befüllung)
- CRUD-Logik für Projekt-User-Zuordnungen mit Cross-DB-User-Auflösung
- Serverseitige Sichtbarkeits-Filterung: Projekt-Liste/Get filtert nach
  projekt_users-Zuordnung für Nicht-SysAdmin/Nicht-AppAdmin
- Auto-Assignment: Ersteller wird bei Projektanlage automatisch zugeordnet
- Sichtbarkeits-Filterung auf CallLog und Kontaktadresse erweitert
  (Liste und Einzelabruf)
- Schreibschutz: Alle Schreib-Endpunkte (update/delete) für Projekt,
  Kontaktadresse und CallLog prüfen Projekt-Zuordnung vor der Ausführung
- Hilfsfunktionen _get_visible_user_id() und _require_projekt_access()
  zur Kapselung der wiederkehrenden Prüfungen
- REST-Endpunkte /xhr/projektuser/{list,add,remove};
  Schreib-Endpunkte mit @authorisation_required([]) als Erweiterungspunkt
- Client: Neues Modell projekt_user.ts, Listen-Komponente mit Modal
  (Select-Widget), Button in Projekt-Maske, Route registriert
- Build aktualisiert (tsc + rollup)
- AGENTS.md: Vorgaben für projektbezogene Sichtbarkeit dokumentiert

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
gg committed 2026-09-05 15:45:32 +02:00
1 parent b2f8684afb
commit 4cb0084066
12 files changed
+758 -25

No files matched your search

+35 -1
View File
@@ -12,7 +12,7 @@ erfolgt ausschließlich über __bind_key__.
import datetime
import decimal
from sqlalchemy import Boolean, Column, Date, DateTime, ForeignKey, Index, Integer, String
from sqlalchemy import Boolean, Column, Date, DateTime, ForeignKey, Index, Integer, String, UniqueConstraint
from sqlalchemy.orm import relationship
from db import dbapp
@@ -160,6 +160,40 @@ class Projekt(dbapp.Model):
return result
class ProjektUser(dbapp.Model):
"""
Verknüpfungstabelle zwischen Projekt und User.
Steuert die Sichtbarkeit von Projekten: Ein Nutzer sieht nur Projekte,
denen er über diese Tabelle zugeordnet ist. Die Zuordnung erfolgt durch
den AppAdmin (oder später andere berechtigte Rollen).
Die Tabelle liegt in der CRM-Datenbank (appdb). Die Spalte 'user_id'
referenziert logisch die 'id' in der Auth-Datenbanktabelle 'users', ein
physischer Fremdschlüssel ist aufgrund der zwei getrennten SQLite-Datenbanken
nicht möglich. Die Auflösung von user_id auf username etc. erfolgt zur
Laufzeit durch eine separate Query gegen die Auth-Datenbank.
Das UniqueConstraint stellt sicher, dass jeder Nutzer nur einmal pro
Projekt zugeordnet werden kann.
"""
__tablename__ = 'projekt_users'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_projekt_users_projekt_id', 'projekt_id'),
UniqueConstraint('projekt_id', 'user_id', name='uq_projekt_user'),
)
id = Column(Integer, primary_key=True)
projekt_id = Column(Integer, ForeignKey('projekte.id'), nullable=False)
user_id = Column(Integer, nullable=False)
projekt = relationship('Projekt')
def to_dict(self):
"""Liefert die Projekt-User-Zuordnung als Dictionary."""
return columns2dict(self)
class Kontaktadresse(dbapp.Model):
"""
Akquise-Ziel innerhalb eines Projekts. Jede Kontaktadresse ist genau