# Architektur der Anwendung Beachte die strukturellen Vorgaben, die in ai-context/AI-operative-Vorgaben.md definiert sind. In den Programmen sollen aussagekräftige Kommentare in deutsch erstellt werden. ## Vorgaben git Versionsverwaltung Ein neuer Branch darf nur auf ausdrückliche Anweisung hin erstellt werden. Ohne diese Anweisung werden Änderungen immer in main gemacht. ## Vorgaben für die Typescript und mithriljs Entwicklung Verwende bei der GUI primar die widgets, die es in client/Components/widgets gibt. Fehler widgets, gib eines Hinweis und erstelle einen Vorschlag für ein entsprechendes neues Widget. Es soll immer ein responsive Design implmentiert werden, da die App sowohl auf PCs als auch auf mobilen Geräten laufen soll. Verwende für Attribute der GUI-Oberfläche nach Möglichkeit Klassen aus NGINX_Server/html/static/w3.css, insbesondere wenn es darum geht, eine Respnosive Design zu implentieren. Für Farben (foreground und background) verwende priorisiert die Klassen aus NGINX_Server/html/static/app-theme.css View-Container werden mit `w3-container.w3-auto` gewrappt, damit sie auf kleinen Bildschirmen 100% und auf großen bis max. 1140px (bzw. 95%) zentriert nutzen. Bei Mithril `m(...)`-Aufrufen mit längeren Attributlisten (z.B. mehrere `style`-Eigenschaften oder mehrere Attribute) schreibe die Attribute untereinander, sobald sie in einer Zeile nicht mehr gut lesbar sind (Faustregel: mehr als 2–3 Attribute oder ein mehrzeiliges `style`-Objekt). Kurze Attributlisten (1–2 Attribute, einzeiliges `style`) dürfen in einer Zeile bleiben. Formatbeispiel: ```typescript m("div.w3-bar-block.w3-border", { style: { width: '95%', 'max-height': '220px', 'overflow-y': 'auto', position: 'absolute', 'z-index': '1000' } }) ``` Für Symbole auf Buttons und ähnlichen Steuerelementen verwende Symbole aus den Google Material Icons. Erstelle die Datenmodelle für die Typescript-Entwicklung im Verzeichnis Client/Models. Erstelle für die verschiedenen Datenmodelle (Kunde, Projekt usw.) eigene .ts-Dateien. Erstelle in der jeweiligen Datei auch den Aufruf der REST-Api für die Server-Seite. Beim Aufruf einer Bearbeitungsmaske werden in den Route-Params nur die ID (und ggf. zum Vorbelegen notwendige Eltern-FKs wie `kunden_id`) übergeben — nicht die vollständigen Felder des Objekts. Die Maske lädt die Daten frisch vom Server via `fetchXxxById(id)` im `oninit`. So wird sichergestellt, dass die Daten aktuell sind und zwischenzeitliche Änderungen anderer Nutzer nicht mit veralteten Werten aus der Liste überschrieben werden. Beim Neuanlegen (`id === -1`) entfällt der Fetch; vorbelegte Werte (z.B. `kunden_id`) kommen aus den Route-Params. Jeder `m.request`-Aufruf (REST-Endpunkt) muss `.catch((e) => showServerError(e))` anhängen, damit Serverfehler (z.B. 401 bei fehlender Autorisierung) dem Nutzer als Modal angezeigt werden. Die Navigation (`m.route.set`) steht im `.then`-Zweig, damit sie bei Fehler nicht ausgeführt wird und der Nutzer auf der Maske bleibt. `showServerError` wird aus `./auth/authmessages` importiert. Bei `m.ClosureComponent` den Closure-Parameter weglassen (`() =>`) und Attribute ausschließlich über das `vnode` des jeweiligen Lifecycle-Hooks (`view`, `oninit`, `onupdate` etc.) lesen. Das `vnode` der Closure-Funktion ist ein Snapshot zum Erzeugungszeitpunkt und wird bei Redraws nicht aktualisiert — daraus gelesene `attrs` sind veraltet. Initialisierung, die `attrs` braucht, gehört nach `oninit`. Beispiel: ```typescript export const Select: m.ClosureComponent = () => { // closure-State ohne Referenz auf attrs let search = "" return { oninit: (vnode) => { // vnode.attrs hier initial lesen search = vnode.attrs.value }, view: (vnode) => { // vnode.attrs enthält die aktuellen Werte je Render-Durchlauf const options = vnode.attrs.options ... } } } ``` Nach jeder Änderung an `.ts`-Dateien unter `Client/` ist der Build-Prozess (tsc + rollup) auszuführen, damit die deploybaren Bundles in `NGINX_Server/html/static/` aktuell sind. Verwende dafür den `client-build`-Skill. ## Vorgaben für die Server-seitige Entwicklung unter Python ### Projektbezogene Sichtbarkeit und Schreibschutz Projekte sind nutzerbezogen: Ein Nutzer sieht nur Projekte, denen er über die Tabelle `projekt_users` zugeordnet ist. Diese Sichtbarkeits-Filterung muss für **jede** projektbezogene Entität (Projekt selbst und alle davon abhängigen Entitäten wie Kontaktadresse, CallLog) in den Lese- und Schreib-Endpunkten umgesetzt werden. Die Prüfung erfolgt rollenbasiert, nicht flagbasiert: SysAdmin und AppAdmin (geprüft via `current_user.is_SysAdmin()` bzw. `current_user.has_permission(app.config["APPID"], [APP_ADMIN])`) sehen alle Projekte. Alle anderen Nutzer werden über ihre `current_user.id` gefiltert. Dafür werden in `crm/routes.py` zwei Hilfsfunktionen bereitgestellt: - `_get_visible_user_id()`: Liefert `None` für SysAdmin/AppAdmin (kein Filter), sonst `current_user.id`. Wird an die Modell-Funktionen der Lese-Endpunkte (list/get) übergeben. - `_require_projekt_access(projekt_id)`: Prüft vor Schreiboperationen (create/update/delete), ob der Nutzer dem Projekt zugeordnet ist. Bei fehlender Zuordnung wird 404 (nicht 403) geworfen, um keine Rückschlüsse auf die Existenz des Projekts zu ermöglichen. Bei neuen projektbezogenen Entitäten muss: 1. Die Modell-Funktion `get_xxx(...)` einen optionalen `user_id`-Parameter erhalten. Ist dieser gesetzt, wird per Subquery auf `projekt_users` gefiltert. 2. Die Modell-Funktion `get_xxx_by_id(id, user_id)` bei gesetztem `user_id` die Projekt-Zuordnung prüfen und bei Fehlen 404 werfen. 3. Die Lese-Endpunkte in `crm/routes.py` `_get_visible_user_id()` aufrufen und das Ergebnis an die Modell-Funktion übergeben. 4. Die Schreib-Endpunkte `_require_projekt_access(projekt_id)` aufrufen, bevor die Änderung durchgeführt wird. Bei create/update steht `projekt_id` im JSON-Body (`request.json["projekt_id"]` bzw. `request.json["id"]`); bei delete muss die Entität ggf. erst mit Sichtbarkeits-Check geladen werden, um die `projekt_id` zu ermitteln. ## Generierte Dateien nicht beachten Das Verzeichnis `Client/tsout/` enthält die JavaScript-Ausgabe der TypeScript-Kompilation und wird durch den Build-Prozess (tsc + rollup) erzeugt. Diese Dateien sind nicht manuell zu bearbeiten und brauchen bei der Codeanalyse nicht berücksichtigt zu werden. Ebenso sind die JavaScript-Dateien in `NGINX_Server/html/static/` (z.B. `kbp_crm_00.00.01.js`) die Ausgabe des Rollup-Builds und nicht zu untersuchen.