Files
company-tool/PLANUNG.md
Torsten Schulz (local) 0e539710c0 feat: Add password reset functionality with request and reset forms
feat: Implement price list import feature with preview and apply options

feat: Create price rules management page with CRUD operations

feat: Develop quotes management page with itemized quotes and status tracking

feat: Introduce organization registration page for new users

feat: Build suppliers management page with detailed supplier information

feat: Create users management page for inviting and managing roles

chore: Add TypeScript configuration for improved type checking

chore: Set up Vite configuration for development server and API proxy

chore: Add Vite environment type definitions for better TypeScript support
2026-06-02 15:28:38 +02:00

65 KiB

Planung Firmen-Software

Stand: 2026-05-22

Zielbild

Die Software wird als mehrplatzfähiges Firmensystem geplant:

  • lokaler Betrieb mit eigenem Server bei einer Firma
  • öffentlicher SaaS-Betrieb mit vielen Firmen auf einer Instanz
  • Backend in Rust
  • PostgreSQL als Datenbank
  • Kommunikation zwischen Clients und Backend per WebSocket für Live-Daten
  • zusätzliche REST-API für externe Zugriffe, Importe und Integrationen
  • Webfrontend für Browser
  • nativer Desktopclient für Linux, Windows und macOS
  • gleiche fachliche Funktionen in Webclient und Desktopclient
  • Live-Aktualisierung der UI, wenn Backend-Daten geändert werden
  • verschlüsselte Kommunikation zwischen Clients und Backend
  • Offline-Fähigkeit im Desktopclient
  • automatische Updates für den Desktopclient

Begriffe

Der Begriff Kunde wird nur für Kunden einer Firma verwendet, also z.B. für Rechnungsempfänger.

Für die Betreiber-/Mandantenebene wird stattdessen Firma verwendet. Eine Firma ist die Organisation, die das System nutzt und ein eigenes PostgreSQL-Schema bekommt.

Technische Begriffe:

  • Firma: fachlicher Mandant, also Nutzerorganisation des Systems
  • organization: technischer Name für eine Firma in Code, API und Datenbank
  • Firmenschema: PostgreSQL-Schema einer Firma, z.B. company_<organization_id>
  • User: globaler Benutzeraccount in public
  • Kunde: Kunde einer Firma innerhalb eines Firmenschemas
  • Vorgang: fachlicher Sammelbegriff für Aktivität, Aufgabe, Wiedervorlage, Termin oder interne Bearbeitung mit Bezug zu Kunden, Lieferanten, Dokumenten oder Belegen
  • activity: technischer Name für einen Vorgang in Code, API und Datenbank

Namensregel:

  • Tabellen, Spalten, API-Felder und Code-Bezeichner sind englisch.
  • Die UI zeigt deutsche Begriffe und Labels.
  • Deutsche UI-Texte, Fehlermeldungen und Dokumentation verwenden echte Umlaute (ä, ö, ü, Ä, Ö, Ü) und ß. ASCII-Umschreibungen wie ae, oe, ue oder ss werden nur in technischen Bezeichnern verwendet, wenn das nötig ist.
  • Beispiel: Datenbank/API organization, UI Firma.

Mandantenmodell

Jede Firma bekommt ein eigenes PostgreSQL-Schema. Das trennt operative Daten im SaaS-Betrieb klar voneinander und funktioniert gleichzeitig für lokale Einzelfirmen-Installationen.

Wichtige Entscheidung:

  • In public liegen nur globale Daten, die für Login und Firmenzuordnung notwendig sind.
  • Alle fachlichen Daten, Rollen, Rechte, Einstellungen, Nummernkreise und Logs liegen im jeweiligen Firmenschema.
  • Ein User kann mehreren Firmen zugeordnet sein.
  • Eine Firma verwaltet nicht mehrere weitere Firmen/Mandanten in derselben Installation.

public-Schema

public bleibt bewusst klein.

Geplante Tabellen:

  • users
  • organizations
  • user_organizations
  • organization_domains, optional für SaaS-Subdomains
  • auth_identities, für Passwortlogin, SSO und externe Identity Provider
  • sessions oder refresh_tokens

Nicht in public:

  • Rollen
  • Rechte
  • Audit-Log
  • Fachmodule
  • Nummernkreise
  • API-Zugangsdaten
  • Firmeneinstellungen

Diese Daten gehören in das jeweilige Firmenschema.

Firmenschema

Schema-Namensvorschlag:

  • company_<organization_id>

organization_id ist eine technische, nicht sprechende Kennung. Schema-Namen enthalten keine Firmennamen.

Geplante Tabellen je Firmenschema:

  • roles
  • permissions
  • role_permissions
  • user_roles
  • settings
  • number_ranges
  • audit_log
  • customers
  • suppliers
  • contacts
  • addresses
  • items
  • item_price_sources
  • item_prices
  • price_rules
  • customer_price_terms
  • supplier_price_terms
  • cash_discount_terms
  • stock_movements
  • quotes
  • quote_versions
  • quote_items
  • incoming_invoices
  • incoming_invoice_items
  • outgoing_invoices
  • outgoing_invoice_items
  • communications
  • activities
  • activity_links
  • tasks
  • document_templates
  • documents
  • document_versions
  • imports
  • import_mappings
  • api_connectors
  • webhooks

Mandantenauflösung

Vorgeschlagener Ablauf:

  1. User meldet sich global an.
  2. Backend liest aus public.user_organizations, welchen Firmen der User zugeordnet ist.
  3. Falls der User mehrere Firmen hat, wählt er eine aktive Firma aus.
  4. Backend erstellt ein Token oder eine Session mit aktiver organization_id.
  5. Jeder REST-Request und jede WebSocket-Verbindung wird gegen diese aktive Firma geprüft.
  6. Datenbankzugriffe setzen kontrolliert das passende Firmenschema.

Für den öffentlichen Betrieb kann zusätzlich eine Subdomain genutzt werden:

  • firma-a.example.com
  • firma-b.example.com

Die Subdomain darf aber nur eine Vorauswahl sein. Die finale Berechtigung kommt aus public.user_organizations.

Betriebsarten

Eigener Server bei einer Firma

  • eine Backend-Instanz
  • eine PostgreSQL-Datenbank
  • genau eine Firma
  • optional mehrere User
  • dieselbe Mandantenarchitektur wie im SaaS-Betrieb
  • Installation per Docker Compose, Systemdienst oder Installationsprogramm
  • keine öffentliche Selbstregistrierung
  • Firmenschema wird während Installation oder beim ersten Start erzeugt
  • erster Firmen-User wird während Installation oder Erstkonfiguration angelegt

Die lokale Version soll bewusst nur eine Firma verwalten können. Dadurch bleibt die lokale Installation einfacher, nutzt intern aber trotzdem dieselbe Firmenschema-Architektur wie der öffentliche Server.

Öffentlicher SaaS-Server

  • Betrieb durch uns
  • eine oder mehrere Backend-Instanzen
  • zentrale PostgreSQL-Datenbank
  • viele Firmen, jeweils eigenes Schema
  • TLS zwingend
  • Backup, Monitoring, Rate-Limits und Mandantentrennung zwingend
  • Benutzer können mehreren Firmen zugeordnet sein
  • öffentliche Registrierung möglich
  • Freischaltung neuer Firmen erfolgt durch einen Administrator
  • vor Freischaltung ist kein produktiver Zugriff auf das Firmenschema möglich

Registrierung und Freischaltung

Öffentliche Registrierung

Für den öffentlichen Server gibt es eine Registrierungsmaske.

Pflichtangaben:

  • Firmenname
  • E-Mail-Adresse

Ablauf:

  1. Interessent gibt Firmenname und E-Mail-Adresse ein.
  2. Server legt einen globalen User in public.users an, falls die E-Mail noch nicht existiert.
  3. Server legt einen Firmeneintrag in public.organizations mit Status pending_approval an.
  4. Server legt die Zuordnung in public.user_organizations an.
  5. Server erzeugt das Firmenschema entweder sofort im gesperrten Zustand oder erst nach Freischaltung. Bevorzugt: Schema erst nach Admin-Freischaltung erzeugen, damit abgelehnte Registrierungen keine operativen Strukturen hinterlassen.
  6. Ein Administrator prüft und schaltet die Firma frei.
  7. Bei Freischaltung erzeugt das Backend das Firmenschema, Basistabellen, Standardrollen, Standardrechte und Grundeinstellungen.
  8. Server erzeugt ein zufälliges Initialpasswort.
  9. Server sendet eine E-Mail an die registrierte Adresse.
  10. User meldet sich mit E-Mail-Adresse und Initialpasswort an.
  11. Beim ersten Login muss das Passwort sofort geändert werden.
  12. Danach kann der User Firmendaten, Einstellungen, Nummernkreise, Vorlagen und weitere Stammdaten festlegen.

Die E-Mail-Adresse ist der Username.

Admin-Freischaltung

Neue Firmenregistrierungen stehen in einer Admin-Oberfläche.

Admin-Aktionen:

  • Registrierung ansehen
  • Firma freischalten
  • Registrierung ablehnen
  • E-Mail erneut senden
  • Firmenschema-Erstellung erneut versuchen, falls ein technischer Fehler auftrat

Statusmodell für public.organizations:

  • pending_approval
  • approved
  • active
  • rejected
  • suspended

Vorgeschlagene Bedeutung:

  • pending_approval: Registrierung eingegangen, aber noch nicht freigegeben
  • approved: durch Admin freigegeben, technische Anlage läuft oder steht bevor
  • active: Firma ist nutzbar
  • rejected: Registrierung wurde abgelehnt
  • suspended: Firma wurde nachträglich gesperrt

Initialpasswort und Passwortwechsel

Initialpasswörter werden zufällig erzeugt und per E-Mail versendet.

Sicherheitsregeln:

  • Passwort wird nie im Klartext gespeichert.
  • Passwort-Hash liegt in public.users.password_hash.
  • User bekommt Status must_change_password.
  • Beim ersten Login sind nur Passwortänderung und Logout erlaubt.
  • Initialpasswort sollte zeitlich ablaufen.
  • Nach erfolgreicher Änderung wird must_change_password entfernt.

Optional spätere Verbesserung:

  • Statt Klartextpasswort per E-Mail wird ein einmaliger Set-Password-Link verschickt. Das ist sicherer, aber der aktuell geplante Ablauf ist: zufälliges Passwort per E-Mail.

User zur Firma einladen

Ein berechtigter Firmen-User kann weitere User einladen.

Ablauf:

  1. Firmen-User gibt neue E-Mail-Adresse ein.
  2. Backend prüft Recht, z.B. users.invite.
  3. Falls die E-Mail in public.users noch nicht existiert, wird ein globaler User angelegt.
  4. Backend legt oder aktualisiert public.user_organizations.
  5. Im Firmenschema werden die gewünschten Rollen in user_roles vergeben.
  6. Backend erzeugt ein zufälliges Initialpasswort oder ein neues Initialpasswort, falls der User noch kein aktives Passwort für diese Installation hat.
  7. Backend setzt must_change_password.
  8. Backend sendet eine Einladung per E-Mail.
  9. Eingeladener User meldet sich mit E-Mail und Initialpasswort an.
  10. Passwortänderung ist beim ersten Login zwingend.

Wenn ein User bereits in einer anderen Firma aktiv ist, darf dessen bestehendes Passwort nicht ungefragt überschrieben werden. In diesem Fall sollte die Einladung als Firmenzuordnung erfolgen und der User sich mit seinem bestehenden Login anmelden. Für diesen Fall kann die Einladung einen Hinweis statt eines neuen Passworts senden.

Lokale Erstinstallation

Für lokale Installationen wird ein eigener Erstkonfigurationsprozess geplant.

Ablauf:

  1. Installation richtet Backend und PostgreSQL ein.
  2. Beim ersten Start erkennt das Backend, dass keine Firma existiert.
  3. Setup-Maske fragt Firmenname, Admin-E-Mail und Initialpasswort ab oder erzeugt ein zufälliges Passwort.
  4. Backend erstellt genau eine Firma und genau ein Firmenschema.
  5. Admin-User wird als owner zugeordnet.
  6. Danach wird der Setup-Modus dauerhaft deaktiviert.

Eine zweite Firma darf in der lokalen Version nicht angelegt werden.

Sicherheit

Mindestanforderungen:

  • TLS für öffentlichen Betrieb
  • Zertifikatsverwaltung über Reverse Proxy, z.B. Caddy, Traefik oder Nginx
  • zusätzliche sessionbasierte Nutzdatenverschlüsselung oberhalb von HTTPS/WSS
  • keine fachlichen Nutzdaten unverschlüsselt über das Netzwerk
  • keine fachlichen Nutzdaten unverschlüsselt in PostgreSQL
  • Passwort-Hashing mit Argon2id oder vergleichbar
  • Zwei-Faktor-Authentifizierung
  • Single Sign-On
  • rollenbasierte Rechte
  • Rechte pro atomarer Aktion mit Lesen, Schreiben und Löschen
  • firmenschema-bewusste Datenbankzugriffe
  • Audit-Log je Firmenschema
  • sichere Speicherung von API-Zugangsdaten
  • Backups und Restore-Konzept je Firma
  • Schutz gegen unautorisierte WebSocket-Abos
  • Initialpasswörter laufen ab
  • Passwortwechsel beim ersten Login erzwingen
  • Admin-Freischaltung für SaaS-Registrierungen

Kommunikation und Verschlüsselung

Grundsatz

Alle produktiven Verbindungen zwischen Client und Backend müssen verschlüsselt sein.

Protokolle:

  • REST über HTTPS
  • WebSocket über WSS

Unverschlüsselte Verbindungen sind nicht vorgesehen. Das gilt auch für lokale Installationen. Für Entwicklung können gesonderte Debug-Schalter existieren, sie dürfen aber nicht Teil des produktiven Betriebs sein.

Zusätzlich zu HTTPS/WSS werden fachliche Nutzdaten auf Anwendungsebene verschlüsselt. TLS schützt den Transportkanal, die Anwendungsschicht- Verschlüsselung schützt die eigentlichen Payloads innerhalb der Session.

Grundsatz:

  • keine fachlichen Nutzdaten werden unverschlüsselt übertragen
  • keine fachlichen Nutzdaten werden unverschlüsselt in PostgreSQL gespeichert
  • Metadaten werden nur dann unverschlüsselt gespeichert, wenn sie technisch für Routing, Login, Rechteprüfung, Indizes oder Betrieb zwingend notwendig sind
  • Klartext existiert nur kurzzeitig im Backend-Prozessspeicher während der Verarbeitung

Sessionbasierte Nutzdatenverschlüsselung

Für jede angemeldete Client-Session wird ein eigener Session-Schlüssel ausgehandelt oder vom Backend sicher bereitgestellt.

Ziel:

  • REST-Payloads zusätzlich zu HTTPS verschlüsseln
  • WebSocket-Payloads zusätzlich zu WSS verschlüsseln
  • Replay und Manipulation über AEAD-Verfahren verhindern
  • Session-Schlüssel beim Logout, Passwortwechsel, User-Sperre oder Ablauf ungültig machen

Empfohlenes Verfahren:

  • asymmetrischer Schlüsselaustausch beim Login oder bei Firmenauswahl
  • danach symmetrische Verschlüsselung pro Session
  • AEAD-Verfahren, z.B. AES-256-GCM oder XChaCha20-Poly1305
  • jede Nachricht bekommt Nonce und Authentifizierungstag
  • Nonces dürfen pro Session-Schlüssel nie wiederverwendet werden
  • Protokollversion und Nachrichtentyp werden als Additional Authenticated Data einbezogen

Abstraktes Nachrichtenformat:

{
  "enc": "v1",
  "kid": "session-key-id",
  "nonce": "...",
  "ciphertext": "...",
  "tag": "..."
}

Für WebSocket bedeutet das:

  • hello und Schlüsselaushandlung laufen vor verschlüsselten Fachnachrichten
  • danach sind Subscribe-, Command- und Event-Payloads verschlüsselt
  • technische Hüllfelder dürfen sichtbar bleiben, soweit sie für Routing nötig sind, z.B. enc, kid, nonce

Für REST bedeutet das:

  • Authentifizierung und Sessionaufbau laufen über HTTPS
  • fachliche Request- und Response-Bodies werden danach verschlüsselt
  • Datei-Uploads werden ebenfalls clientseitig oder vor Speicherung verschlüsselt

Datenbankverschlüsselung

PostgreSQL speichert keine fachlichen Nutzdaten im Klartext.

Geplantes Modell:

  • feld- oder dokumentbasierte Verschlüsselung auf Anwendungsebene
  • PostgreSQL sieht für fachliche Felder nur Ciphertext
  • je Firma eigener Data Encryption Key
  • je Datensatz oder je Feld eigene Nonce
  • AEAD mit Authentifizierungstag
  • Schlüsselmaterial liegt nicht im Firmenschema
  • Master-Key kommt aus Server-Konfiguration, Secret Store oder später HSM/KMS

Schlüsselhierarchie:

  1. Master Key, außerhalb der Datenbank
  2. Firmenschlüssel pro Firma
  3. optional Bereichs- oder Tabellenschlüssel
  4. Datensatzverschlüsselung mit eigener Nonce

Konsequenzen:

  • Volltextsuche auf verschlüsselten Feldern ist nicht direkt möglich
  • Sortierung und Filterung auf verschlüsselten Klartextwerten ist eingeschränkt
  • für benötigte Suche braucht es bewusst geplante Such-/Indexwerte
  • solche Suchwerte dürfen keine sensiblen Klartexte enthalten
  • Logs, Audit-Log und Change-Log dürfen keine entschlüsselten Nutzdaten enthalten

Pragmatische Einordnung:

  • Passwörter werden nicht verschlüsselt, sondern gehasht.
  • technische IDs, Statuswerte, Sequenzen und Foreign Keys können als notwendige Metadaten unverschlüsselt bleiben, wenn sie für Betrieb, Routing, Rechteprüfung und referenzielle Integrität nötig sind.
  • besonders sensible Inhalte wie Adressen, Kommunikationsdaten, Rechnungsinhalte, Dokumentmetadaten, API-Secrets und Preise werden verschlüsselt gespeichert.

Öffentlicher Server

Der öffentliche Server läuft hinter einem Reverse Proxy.

Empfohlene Aufgaben des Reverse Proxy:

  • TLS-Terminierung
  • Zertifikatsverwaltung
  • HTTP-zu-HTTPS-Redirect
  • Weiterleitung von WebSocket-Upgrades
  • Rate-Limits für Login und Registrierung
  • Request-Größenlimits für Uploads
  • Security Header

Geeignete Optionen:

  • Caddy
  • Traefik
  • Nginx

Empfehlung für den Start:

  • Caddy oder Traefik, weil automatische Zertifikatsverwaltung einfacher ist.

Backend-intern:

  • Backend lauscht nur im internen Netz oder auf localhost.
  • Extern erreichbar ist nur der Reverse Proxy.
  • Der Reverse Proxy leitet an das Backend weiter.

Zertifikate

Öffentlicher SaaS-Betrieb:

  • Zertifikate automatisch per ACME/Let's Encrypt
  • automatische Erneuerung
  • TLS mindestens Version 1.2, bevorzugt TLS 1.3
  • HSTS nach stabiler Domain- und Zertifikatskonfiguration aktivieren

Lokaler Betrieb:

  • ebenfalls HTTPS/WSS
  • möglich über selbstsigniertes Zertifikat oder lokale Zertifizierungsstelle
  • Installationsprogramm kann ein lokales Zertifikat erzeugen
  • Desktopclient muss lokale Zertifikate sauber vertrauen können

Für lokale Installationen muss das Installationsprogramm die Zertifikatsfrage lösen, z.B. durch lokale Zertifizierungsstelle, Zertifikatimport oder klaren Administrationsdialog.

REST-Kommunikation

REST wird für zustandsändernde Befehle, Dateiübertragungen und externe Integrationen verwendet.

Eigenschaften:

  • JSON als Standardformat
  • HTTPS verpflichtend im SaaS-Betrieb
  • Bearer Token im Authorization-Header
  • API-Version im Pfad, z.B. /api/v1/...
  • fachliche Request- und Response-Bodies werden nach Sessionaufbau zusätzlich verschlüsselt
  • idempotente Endpunkte dort, wo Wiederholungen realistisch sind
  • Request-ID pro Anfrage für Logging und Fehlersuche

Beispiel-Header:

Authorization: Bearer <access_token>
X-Request-Id: <uuid>

WebSocket-Kommunikation

WebSocket wird für Live-Updates, Subscriptions und schnelle UI-Aktualisierung verwendet.

Öffentlicher Betrieb:

  • ausschließlich wss://
  • WebSocket-Verbindung erst nach Login und Firmenauswahl
  • Authentifizierung über kurzlebigen Socket-Token oder Access Token
  • aktive Firma ist im Token oder in der Socket-Startnachricht festgelegt
  • jede Subscription wird gegen Rechte geprüft

Empfohlener Verbindungsaufbau:

  1. Client meldet sich per REST an.
  2. Client wählt aktive Firma.
  3. Backend gibt Access Token und optional separaten kurzlebigen WebSocket-Token.
  4. Client öffnet wss://server/ws.
  5. Client sendet eine hello-Nachricht mit Token und gewünschter Protokollversion.
  6. Backend prüft Token, Firma, Userstatus und Rechte.
  7. Backend bestätigt mit hello_ack.
  8. Client abonniert Topics.

Beispielnachrichten:

{
  "type": "hello",
  "protocol_version": 1,
  "token": "<socket_token>"
}
{
  "type": "subscribe",
  "topic": "customers",
  "since_sequence": 12345
}
{
  "type": "event",
  "topic": "customers",
  "sequence": 12346,
  "operation": "updated",
  "entity_id": "..."
}

Token und Sessions

Geplantes Modell:

  • Access Token kurzlebig
  • Refresh Token länger gültig, aber serverseitig widerrufbar
  • Refresh Token wird nur gehasht gespeichert
  • WebSocket-Token optional separat und sehr kurzlebig
  • Passwortwechsel, User-Deaktivierung oder Firmen-Sperre widerrufen Sessions

Für den Webclient:

  • Access Token möglichst nur im Speicher halten
  • Refresh Token bevorzugt als HttpOnly, Secure, SameSite Cookie
  • bei reinem API-Betrieb alternativ sichere Token-Speicherung bewusst festlegen

Für den Desktopclient:

  • Refresh Token im Betriebssystem-Keychain speichern
  • Linux: Secret Service/KWallet, falls verfügbar
  • Windows: Credential Manager oder DPAPI
  • macOS: Keychain
  • keine Tokens im Klartext in Konfigurationsdateien

Nachrichtenintegrität und Replay-Schutz

TLS schützt Transport und Integrität auf Verbindungsebene. Zusätzlich sollen kritische Operationen nachvollziehbar und wiederholungssicher sein.

Maßnahmen:

  • Request-ID pro REST-Anfrage
  • serverseitige Idempotency Keys für kritische POST-Aktionen, z.B. Rechnungserstellung
  • monoton steigende sequence im change_log
  • WebSocket-Events enthalten sequence
  • Clients können nach Reconnect ab einer bekannten sequence nachladen

E-Mail-Kommunikation

System-E-Mails werden über eine Outbox versendet.

Anwendungsfälle:

  • Initialpasswort nach Admin-Freischaltung
  • Einladung neuer Firmen-User
  • später Passwort-Reset
  • später 2FA-/Sicherheitsbenachrichtigungen

Sicherheitsanforderungen:

  • SMTP-Zugangsdaten nicht im Firmenschema im Klartext speichern
  • zentrale SMTP-Konfiguration für SaaS-Betrieb
  • lokale SMTP-Konfiguration für lokale Installation möglich
  • Versandversuche und Fehler in public.email_outbox protokollieren

API-Zugangsdaten von Lieferanten

Lieferanten-API-Zugangsdaten liegen im Firmenschema, müssen aber verschlüsselt gespeichert werden.

Geplantes Modell:

  • Verschlüsselung vor Speicherung in PostgreSQL
  • Master-Key aus Server-Konfiguration oder Secret Store
  • je Firma optional abgeleiteter Schlüssel
  • Rotation des Master-Keys später einplanen
  • Secrets nie im Audit-Log oder Change-Log im Klartext speichern

Webhooks

Ausgehende Webhooks müssen signiert werden.

Anforderungen:

  • HTTPS-Ziel-URLs bevorzugen
  • HMAC-Signatur pro Webhook
  • Timestamp im Signaturmaterial
  • Retry mit Backoff
  • Dead-Letter-Status nach wiederholtem Fehler
  • kein Mitsenden sensibler Secrets

Lokales Netzwerk und Server-Erkennung

Für den nativen Desktopclient müssen lokale Server auffindbar oder konfigurierbar sein.

Optionen:

  • manuelle Server-URL
  • gespeicherte Serverprofile
  • spätere automatische LAN-Erkennung

Empfehlung für den Start:

  • manuelle Server-URL
  • klare Anzeige, ob Verbindung verschlüsselt ist
  • Warnung bei Zertifikats- oder Vertrauensproblemen

Fehlerfälle und Reconnect

Clients müssen robuste Verbindungslogik haben.

Vorgaben:

  • automatischer Reconnect mit Backoff
  • Token-Refresh vor erneutem WebSocket-Aufbau
  • nach Reconnect Sync über since_sequence
  • sichtbarer Offline-/Verbindungsstatus in der UI
  • keine stillschweigenden Datenverluste bei abgebrochenen Schreiboperationen

Rollen und Rechte

Es gibt feste Standardrollen. Die Rechte selbst sind granular aufgebaut.

Rechtemodell:

  • jedes fachliche Atom bekommt eigene Rechte
  • mindestens read, write, delete
  • Rechte werden im Firmenschema gespeichert
  • feste Rollen bündeln Rechte
  • die erste Person einer Firma ist der Besitzer (owner) und erhält beim Anlegen der Firma alle initial vorgesehenen Rollen/Rechte
  • nur der Besitzer darf Benutzer einladen und Rollen/Rechte für andere Benutzer vergeben oder ändern
  • alle weiteren Firmenbenutzer erhalten Rechte nicht automatisch, sondern erst durch manuelle Freischaltung im Admin-Fenster Benutzerrechte
  • jede größere Funktion bekommt eigene atomare Rechte, z.B. Kunden, Lieferanten, Artikel, Angebote, Eingangsrechnungen, Ausgangsrechnungen, Aktivitäten, Kommunikation, Preislistenimporte, Preis-API-Abgleiche, Einstellungen, Benutzerverwaltung, Nummernkreise, Dokumente, Berichte und Audit-Log

Beispielrollen:

  • owner
  • admin
  • sales
  • accounting
  • purchasing
  • warehouse
  • viewer

Beispielrechte:

  • customers.read
  • customers.write
  • customers.delete
  • activities.read
  • activities.write
  • activities.delete
  • quotes.read
  • quotes.write
  • quotes.delete
  • outgoing_invoices.read
  • outgoing_invoices.write
  • outgoing_invoices.delete
  • items.read
  • items.write
  • items.delete
  • price_rules.write
  • imports.write
  • settings.write

Fachmodule

Dashboard

Die Startmaske ist ein Dashboard mit Übersicht über laufende und offene Vorgänge.

Inhalte:

  • offene Angebote
  • fällige Aufgaben
  • offene Eingangsrechnungen
  • offene Ausgangsrechnungen
  • aktuelle Importläufe
  • Preisänderungen
  • Warnungen aus Lagerbestand oder Preisberechnung
  • offene/fällige Vorgänge
  • Wiedervorlagen

Kunden

Verwaltung von Firmen- und Privatkunden der jeweiligen Firma.

Geplante Daten:

  • Kundennummer
  • Name/Firma
  • Kundentyp
  • Rechnungsadresse
  • Lieferadresse
  • Ansprechpartner
  • Kommunikationsdaten
  • Zahlungsbedingungen
  • Standardrabatt
  • Skonto-Regel, falls abweichend von den Firmeneinstellungen
  • USt-IdNr.
  • Notizen
  • Status

Lieferanten

Verwaltung von Bezugsquellen und Einkaufskonditionen.

Geplante Daten:

  • Lieferantennummer
  • Name/Firma
  • Adressen
  • Ansprechpartner
  • Zahlungsbedingungen
  • Skonto-Regel, falls vom Lieferanten vorgegeben
  • Artikelreferenzen
  • Preislistenquellen
  • API-Zugangsdaten

Artikel und Lager

Zentrale Artikelverwaltung mit Preisberechnung und Lagerbestand.

Geplante Daten:

  • Artikelnummer
  • Bezeichnung
  • Beschreibung
  • Einheit
  • Einkaufspreis
  • Verkaufspreis
  • Steuersatz
  • Lieferant
  • Herstellerartikelnummer
  • EAN/GTIN
  • Preisgültigkeit
  • Lagerbestand
  • Mindestbestand
  • Lagerbewegungen

Preisberechnung:

  • Einkaufspreis fest festlegen
  • Einkaufspreis aus Quelle übernehmen
  • Einkaufspreis mal Multiplikator
  • Staffelpreise
  • kundenspezifische Preise
  • kundenbezogener Standardrabatt
  • positionsbezogener Sonderpreis oder Sonderrabatt
  • Skonto-Regeln für Zahlung innerhalb definierter Fristen
  • Projektpreise
  • Rundungsregeln
  • Preisgültigkeit
  • Preisänderungshistorie

Preis- und Zahlungsbedingungen:

  • Kunden können einen festen Standardrabatt erhalten.
  • Lieferanten können eigene Skonto- und Zahlungsbedingungen haben.
  • Firmeneinstellungen definieren Standard-Skonto und Standard-Zahlungsziele.
  • Kunden- oder Lieferanteneinstellungen überschreiben die Firmenstandards.
  • Rechnungspositionen übernehmen zunächst den aktuellen Artikelpreis und die anwendbaren Rabattregeln.
  • Der Einzelpreis einer Rechnungsposition darf manuell überschrieben werden, z.B. wegen Sonderabsprachen, Kulanz oder Spezialrabatt.
  • Preisüberschreibungen müssen als solche gespeichert werden, inkl. optionalem Grund und User.

Geplante Tabellen:

  • customer_price_terms: kundenspezifische Rabatte und Preisbedingungen
  • supplier_price_terms: lieferantenspezifische Einkaufs-/Zahlungsbedingungen
  • cash_discount_terms: Skonto-Regeln mit Prozent, Frist und Gültigkeit

cash_discount_terms ist bewusst eine eigene Tabelle, damit Firmeneinstellung, Kunde, Lieferant und später ggf. einzelne Belege auf dieselben strukturierten Skonto-Regeln verweisen können.

Angebote

Angebote erstellen, versionieren, verwalten und in Rechnungen überführen.

Geplante Funktionen:

  • frei konfigurierbarer Angebotsnummernkreis
  • Kunde auswählen
  • Positionen aus Artikeln oder Freitext
  • Rabatte
  • Steuern
  • Zahlungs-/Lieferbedingungen
  • Status: Entwurf, in Freigabe, freigegeben, gesendet, angenommen, abgelehnt, abgelaufen
  • Angebotsversionen
  • Angebotsvorlagen je Firma
  • optionaler Freigabeprozess je nach Firmeneinstellung
  • E-Mail-Versand aus dem System
  • PDF-Erzeugung
  • Umwandlung in Ausgangsrechnung

Ausgangsrechnungen

Rechnungen an Kunden.

Geplante Funktionen:

  • aus Angebot erzeugen
  • direkt erstellen
  • frei konfigurierbarer Rechnungsnummernkreis mit Pflicht-Platzhalter für Counter
  • Positionen ausschließlich mit Artikelreferenz
  • keine freien Text-/Freipositionen in Ausgangsrechnungen
  • aktueller Artikelpreis wird beim Hinzufügen übernommen
  • Einzelpreis und Rabatt pro Rechnungsposition dürfen überschrieben werden
  • kundenbezogener Standardrabatt wird vorgeschlagen
  • Skonto aus Firmeneinstellung oder Kundenregel wird vorgeschlagen
  • Steuern passend für Deutschland
  • Preisüberschreibungen mit Grund und User nachvollziehbar speichern
  • Zahlungsstatus
  • Mahnstatus
  • PDF-Erzeugung
  • revisionssichere Ablage nach Erstellung
  • spätere Erweiterung für DATEV oder E-Rechnung möglich, aber nicht in der ersten Stufe

Eingangsrechnungen

Rechnungen von Lieferanten.

Geplante Funktionen:

  • Lieferant zuordnen
  • Rechnungsdaten erfassen
  • Positionen erfassen
  • Dokument/PDF ablegen
  • Zahlungsstatus
  • Zahlungsziel und Skonto aus Lieferantenregel vorschlagen
  • Kostenstellen oder Projekte, falls später benötigt
  • Abgleich mit Artikeln und Lieferantenpreisen
  • revisionssichere Ablage

Kommunikation, Vorgänge, Aufgaben und Wiedervorlagen

Keine direkte E-Mail- oder Telefonie-Synchronisation in der ersten Stufe.

Begriffliche Entscheidung:

  • UI-Hauptbegriff: Vorgänge
  • technischer Name: activities
  • Aktivität bleibt als Typ oder Kategorie möglich, ist aber als Hauptbegriff zu unscharf

Ein Vorgang beschreibt etwas, das fachlich passiert ist, gerade passiert oder geplant ist. Dadurch lassen sich Kommunikationsnotizen, Aufgaben, Termine, Wiedervorlagen und Bearbeitungsschritte in einer gemeinsamen Timeline anzeigen.

Geplante Vorgangstypen:

  • E-Mail-Notiz
  • Telefonnotiz
  • interne Notiz
  • Aufgabe
  • Wiedervorlage
  • Kalendertermin
  • Systemereignis, z.B. Angebot angenommen oder Rechnung erstellt
  • manueller Bearbeitungsschritt, z.B. Rückfrage geklärt

Geplante Daten:

  • Titel
  • Beschreibung/Notiz
  • Vorgangstyp
  • Status: offen, in Bearbeitung, erledigt, storniert
  • Priorität: niedrig, normal, hoch, kritisch
  • Fälligkeitsdatum
  • Start-/Endzeit für Termine
  • zuständiger User
  • erstellt von
  • erledigt von
  • Tags/Kategorien
  • Sichtbarkeit, z.B. intern oder für alle berechtigten User
  • Bezug auf Kunde, Lieferant, Kontakt, Angebot, Rechnung, Artikel, Dokument oder Importlauf
  • versionierte Anhänge
  • technische Systemquelle, falls automatisch erzeugt

Verknüpfungen:

  • Ein Vorgang kann mehrere Bezüge haben, z.B. Kunde + Angebot + Dokument.
  • Bezüge werden nicht als viele optionale Spalten modelliert, sondern über eine Link-Tabelle.
  • Beispiel: activity_links(activity_id, entity_type, entity_id).

Live-Verhalten:

  • neue oder geänderte Vorgänge erzeugen WebSocket-Events
  • Dashboard zeigt offene/fällige Vorgänge
  • Detailmasken zeigen eine Timeline der zugehörigen Vorgänge
  • erledigte Vorgänge bleiben nachvollziehbar erhalten

Abgrenzung zu communications:

  • communications speichert strukturierte Kommunikation, sobald echte E-Mail-/Telefonie-Integration oder Nachrichtenarchivierung implementiert wird.
  • activities bildet die nutzbare Timeline und Aufgaben-/Wiedervorlagefunktion schon in der ersten Stufe ab.
  • In der ersten Stufe können E-Mail- und Telefonnotizen direkt als Vorgänge geführt werden.

Dokumente und Vorlagen

Dokumente werden auf dem Filesystem gespeichert. Metadaten und Versionen liegen in PostgreSQL.

Geplante Funktionen:

  • PDF-Ablage
  • Uploads
  • versionierte Anhänge
  • editierbare Dokumentvorlagen
  • Vorlagen je Firma
  • Verknüpfung mit Kunden, Lieferanten, Angeboten und Rechnungen

Keine Volltextsuche in Dokumenten in der ersten Stufe.

Artikelpreislisten und APIs

Dateiimport

Unterstützte erste Formate:

  • CSV
  • XML
  • JSON

XLSX bleibt eine mögliche spätere Erweiterung.

Import-Pipeline:

  1. Datei hochladen
  2. Format erkennen oder manuell auswählen
  3. Spalten/Felder zu Zielfeldern mappen
  4. Vorschau und Validierung
  5. Import ausführen
  6. Importbericht speichern
  7. Einkaufspreise aktualisieren
  8. Verkaufspreise neu berechnen
  9. betroffene Clients per WebSocket informieren

Frei konfigurierbare Preislisten

Da Lieferantenpreislisten frei konfigurierbar sein sollen, braucht das System Mapping-Vorlagen:

  • Lieferant
  • Format
  • Feldzuordnung
  • Identifikationsfeld, z.B. EAN, Artikelnummer oder Herstellerartikelnummer
  • Währungsfeld
  • Preisfeld
  • Mengen-/Staffelfeld
  • Gültigkeitsdatum
  • Konfliktregel

Frei konfigurierbare API-Connectoren

Geplante Connector-Konfiguration:

  • Lieferant
  • Basis-URL
  • Authentifizierung
  • Header
  • Query-Parameter
  • Abrufintervall
  • Request-Template
  • Response-Mapping
  • Fehlerprotokoll
  • Testabruf

Komplexere APIs werden wahrscheinlich dennoch einzelne Spezialadapter brauchen. Die freie Konfiguration sollte daher einfache REST/JSON- und REST/XML-Fälle abdecken, aber nicht als vollständiger Ersatz für jede Lieferanten-API geplant werden.

Rechnungen, Steuern und Archivierung

Zielmarkt ist Deutschland.

Erste Stufe:

  • deutsche Steuersätze
  • Steuerwerte so erfassen, dass eine spätere Übertragung oder Auswertung für Elster möglich ist
  • frei konfigurierbare Nummernkreise
  • Nummernkreis muss mindestens einen Counter-Platzhalter enthalten
  • Rechnungen nach Erstellung unveränderlich behandeln
  • Korrekturen über Storno/Korrekturrechnung statt Bearbeitung finaler Rechnung

Spätere Ausbaustufen:

  • DATEV-Export
  • XRechnung
  • ZUGFeRD
  • direkte Buchhaltungsintegration

Backend-Architektur

Vorgeschlagene Hauptbereiche:

  • Authentifizierung
  • öffentliche Registrierung
  • Admin-Freischaltung von Firmen
  • SSO
  • 2FA
  • Firmenauswahl
  • User-Einladungen
  • E-Mail-Outbox
  • Key-Management
  • Session-Schlüsselverwaltung
  • Payload-Verschlüsselung für REST und WebSocket
  • Datenbankverschlüsselung auf Anwendungsebene
  • Firmenschema-Auflösung
  • rollenbasierte Autorisierung
  • Migrationen für public
  • Migrationen je Firmenschema
  • REST-API
  • WebSocket-Verbindungsverwaltung
  • Event-Bus für Live-Updates
  • Fachmodule
  • Dateiimport
  • API-Connectoren
  • Dokumenterzeugung
  • Dokumentablage im Filesystem
  • Audit-Logging je Firmenschema
  • Webhooks

Socket-Kommunikation

Clients verbinden sich nach Login und Firmenauswahl mit dem Backend.

Das Socket-Protokoll ist versioniert. Jede Verbindung beginnt mit einer hello-Nachricht. Ohne gültige Authentifizierung und bestätigte Protokollversion werden keine Subscriptions angenommen.

Beispiele für Topics:

  • dashboard
  • customers
  • suppliers
  • items
  • stock
  • quotes
  • incoming_invoices
  • outgoing_invoices
  • communications
  • tasks
  • imports

Beispiele für Server-Events:

  • snapshot
  • created
  • updated
  • deleted
  • price_recalculated
  • stock_changed
  • import_finished
  • invoice_created_from_quote
  • task_due

Wichtig:

  • jede WebSocket-Verbindung muss authentifiziert sein
  • jede Verbindung hat genau eine aktive Firma
  • jede Verbindung hat eine bestätigte Protokollversion
  • jede Verbindung hat nach dem Handshake einen Session-Schlüssel für verschlüsselte Payloads
  • jede Nachricht wird gegen Rechte im Firmenschema geprüft
  • Events gehen nur an berechtigte User derselben Firma
  • Clients müssen verlorene Verbindungen erkennen und neu synchronisieren können
  • für Offline-Desktopclients braucht es einen Änderungslog oder Sync-Endpunkt
  • Events enthalten eine sequence für Reconnect und Offline-Sync
  • schreibende Aktionen laufen bevorzugt über REST, Events informieren danach alle betroffenen Clients

REST-API und Webhooks

Zusätzlich zum WebSocket-Protokoll wird eine REST-API geplant.

Einsatz:

  • öffentliche Registrierung im SaaS-Betrieb
  • Admin-Freischaltung neuer Firmen
  • Login
  • Passwortwechsel beim ersten Login
  • Firmenauswahl
  • User-Einladungen
  • CRUD-Operationen
  • Dateiimport
  • Dokumentdownload
  • externe Integrationen
  • Export vorhandener Daten

Webhooks:

  • je Firma konfigurierbar
  • Signatur je Webhook
  • Retry-Strategie
  • Ereignisse wie Angebot angenommen, Rechnung erstellt, Import abgeschlossen

Vorgeschlagene erste REST-Endpunkte:

  • POST /api/registration/organization
  • GET /api/admin/organization-registrations
  • GET /api/admin/organization-registrations/{id}
  • POST /api/admin/organization-registrations/{id}/approve
  • POST /api/admin/organization-registrations/{id}/reject
  • POST /api/admin/organization-registrations/{id}/resend-initial-email
  • POST /api/admin/organization-registrations/{id}/retry-provisioning
  • POST /api/auth/login
  • POST /api/auth/change-initial-password
  • GET /api/auth/organizations
  • POST /api/auth/select-organization
  • GET /api/organizations/current/setup
  • PUT /api/organizations/current/setup
  • POST /api/organizations/current/invitations
  • POST /api/organizations/current/invitations/{id}/resend
  • GET /api/organizations/current/users
  • PATCH /api/organizations/current/users/{user_id}/roles
  • POST /api/organizations/current/users/{user_id}/disable

Alle produktiven REST-Endpunkte werden versioniert, z.B. unter /api/v1/.... Kritische POST-Endpunkte wie Rechnungserstellung oder Angebotsumwandlung sollen Idempotency Keys unterstützen.

Desktop-Offline-Konzept

Offline-Fähigkeit ist sinnvoll und wird eingeplant.

Vorgeschlagener Ansatz:

  • lokaler Cache im Desktopclient
  • lokale SQLite-Datenbank oder eingebetteter Speicher
  • schreibende Offline-Aktionen zuerst nur für ausgewählte Bereiche erlauben
  • Sync beim Wiederverbinden
  • Konfliktstrategie pro Modul

Empfohlene erste Offline-Stufe:

  • Lesen zuletzt synchronisierter Daten
  • Vorgänge und Timelines anzeigen
  • neue Notizen/Vorgangsentwürfe lokal speichern
  • Aufgaben/Wiedervorlagen anzeigen
  • Entwürfe lokal speichern
  • keine finale Rechnungserstellung offline

Finale Rechnungen sollten wegen Nummernkreis, Revisionssicherheit und Mehrbenutzerbetrieb nur online erstellt werden.

Frontend-Planung

Webclient und Desktopclient sollen denselben fachlichen Umfang bekommen.

Fensterbasiertes Arbeitsmodell

Die Anwendung wird fensterbasiert geplant. User sollen mehrere Arbeitskontexte parallel offen halten können, z.B. Rechnung, Artikelliste, Kundendetail und Vorgangstimeline.

Grundsätze:

  • Listen, Detailfenster, Suchdialoge und Auswahlfelder sind eigene Fenster oder fensterähnliche Arbeitsbereiche.
  • Mehrere Fenster können gleichzeitig geöffnet sein.
  • Änderungen in einem Fenster müssen andere offene Fenster sofort erreichen.
  • Auswahlfelder und Suchdialoge dürfen keine veralteten Daten anzeigen.
  • Ein Fenster darf lokale Eingaben nicht verlieren, wenn im Hintergrund Daten aktualisiert werden.
  • Bei Konflikten muss der User nachvollziehbar entscheiden können, ob lokale Änderungen beibehalten, neu geladen oder zusammengeführt werden.

Beispiel:

  1. User erstellt eine Ausgangsrechnung.
  2. Beim Hinzufügen einer Position fehlt ein Artikel oder der Preis ist falsch.
  3. User öffnet parallel Artikelfenster oder Vorgangsfenster.
  4. User legt den Artikel/Vorgang an oder korrigiert den Preis.
  5. Das Rechnungsfenster erhält sofort ein Live-Event.
  6. Artikel und Vorgang sind ohne Neuladen in der Rechnung auswählbar.

Technische Anforderungen:

  • Jede Datenänderung erzeugt ein fachliches Live-Event mit Entity-Typ, ID, Änderungsart und Versions-/Sequenznummer.
  • Frontends führen zentrale Stores/Caches je Firma, z.B. für Artikel, Kunden, Vorgänge und Preisregeln.
  • Fenster abonnieren die Store-Änderungen statt eigene isolierte Listen zu halten.
  • Auswahlkomponenten aktualisieren ihre Ergebnislisten bei Store-Updates.
  • Auswahlkomponenten für große Stammdatenmengen, z.B. Kunden, Lieferanten und Artikel, zeigen nicht pauschal alle Datensätze an. Sie bieten eine Suche nach Nummer und Name und begrenzen die sichtbaren Treffer.
  • Bei großen Listen werden nur betroffene Datensätze aktualisiert, nicht die komplette Maske neu gerendert.
  • Detailfenster vergleichen updated_at oder eine Versionsnummer, bevor lokale Änderungen gespeichert werden.
  • WebSocket-Reconnect nutzt since_sequence, damit verpasste Änderungen nachgeladen werden.

Erste betroffene Bereiche:

  • Artikel- und Preisauswahl in Rechnungen und Angeboten
  • Vorgänge/Timelines in Kunden-, Lieferanten-, Artikel- und Belegfenstern
  • Kunden- und Lieferantenauswahl in Belegen
  • Benutzer- und Rechteänderungen in offenen Einstellungsfenstern
  • Importfortschritt und Preisneuberechnung

Gemeinsame Kernmasken:

  • öffentliche Registrierungsmaske, nur SaaS
  • Admin-Maske für Firmenfreischaltungen, nur Betreiber/Admin
  • Login
  • erzwungener Passwortwechsel
  • Firmenauswahl
  • Dashboard
  • Kunden
  • Lieferanten
  • Artikel
  • Lager
  • Angebote
  • Ausgangsrechnungen
  • Eingangsrechnungen
  • Kommunikation
  • Vorgänge
  • Aufgaben/Wiedervorlagen
  • Dokumente
  • Einstellungen
  • Benutzerverwaltung und Einladungen
  • Importassistent

Benutzereinstellungen:

  • Benutzereinstellungen werden je Firma und je Benutzer gespeichert.
  • Die Werte werden wie andere fachliche Einstellungen verschlüsselt abgelegt.
  • Erste Einstellung: Navigationsdarstellung mit den Modi scroll und groups.
  • Standard ist scroll, damit alle Menüpunkte auch bei kleinen Fenstern erreichbar bleiben.

Erste UI-Seiten: Organization und User

Die ersten UI-Seiten bilden den Onboarding-Flow ab. Fachlich geht es um eine Firma, technisch um organization.

Seite: Öffentliche Registrierung

Ziel:

  • Eine neue Organization für den öffentlichen SaaS-Betrieb registrieren.
  • Einen ersten User mit E-Mail-Adresse vormerken.
  • Noch kein produktiver Zugriff vor Admin-Freischaltung.

Route:

  • Web: /register
  • Desktop: nicht erforderlich für öffentliche SaaS-Registrierung in der ersten Stufe

Felder:

  • organization_name, UI-Label Firmenname
  • email, UI-Label E-Mail-Adresse
  • accept_terms, UI-Label Nutzungsbedingungen akzeptieren, falls später nötig

Validierung:

  • Firmenname ist Pflichtfeld
  • Firmenname mindestens 2 Zeichen
  • E-Mail ist Pflichtfeld
  • E-Mail muss formal gültig sein
  • Absenden mehrfach verhindern, solange Request läuft

Primäre Aktion:

  • Registrierung absenden

API:

  • POST /api/v1/registration/organization

Request:

{
  "organization_name": "Muster GmbH",
  "email": "admin@example.com"
}

Erfolgszustand:

  • UI zeigt, dass die Registrierung eingegangen ist.
  • Hinweis: Freischaltung erfolgt durch Administrator.
  • Kein Login-Link mit Zugriff suggerieren.

Fehlerzustände:

  • E-Mail bereits registriert und bereits aktiver User
  • Organization mit ähnlichem Namen existiert bereits
  • Registrierung bereits offen
  • Server nicht erreichbar
  • Validierungsfehler

Sicherheits-/Betriebshinweise:

  • Rate-Limit serverseitig
  • keine Auskunft, ob eine E-Mail bereits bei einer anderen Firma aktiv ist
  • Fehlermeldungen allgemein genug halten, um User Enumeration zu vermeiden

Seite: Admin-Liste Registrierungen

Ziel:

  • Betreiber-Admin sieht neue Organization-Registrierungen.
  • Admin kann prüfen, freischalten oder ablehnen.

Route:

  • Web: /admin/organization-registrations
  • Desktop: später optional, erste Stufe Web

Tabelle:

  • Firmenname
  • E-Mail-Adresse
  • Status
  • Eingegangen am
  • Entschieden am
  • Entschieden von

Filter:

  • offen
  • freigeschaltet
  • abgelehnt
  • gesperrt

Aktionen:

  • Details öffnen
  • Freischalten
  • Ablehnen
  • E-Mail erneut senden, falls bereits freigeschaltet
  • technischen Anlageversuch wiederholen

API:

  • GET /api/v1/admin/organization-registrations

Seite: Admin-Detail Registrierung

Ziel:

  • Eine einzelne Registrierung prüfen und entscheiden.

Route:

  • Web: /admin/organization-registrations/:id

Angezeigte Daten:

  • Firmenname
  • E-Mail-Adresse
  • Status
  • Zeitstempel
  • technische Organization-ID, falls schon erzeugt
  • Schema-Name, falls schon erzeugt
  • Fehler der Schema-Erstellung, falls vorhanden

Aktionen:

  • Freischalten
  • Ablehnen
  • Zurück zur Liste
  • Einladungs-E-Mail erneut senden
  • Schema-Erstellung wiederholen

Freischalten:

  • erzeugt oder aktiviert public.organizations
  • erzeugt company_<organization_id>
  • erzeugt Basistabellen, Standardrollen und Standardrechte
  • ordnet ersten User als owner zu
  • erzeugt Initialpasswort
  • setzt must_change_password
  • legt E-Mail in public.email_outbox

Ablehnen:

  • setzt Status rejected
  • speichert optional internen Entscheidungsvermerk
  • erzeugt kein Firmenschema

API:

  • GET /api/v1/admin/organization-registrations/{id}
  • POST /api/v1/admin/organization-registrations/{id}/approve
  • POST /api/v1/admin/organization-registrations/{id}/reject
  • POST /api/v1/admin/organization-registrations/{id}/resend-initial-email
  • POST /api/v1/admin/organization-registrations/{id}/retry-provisioning

Seite: Erster Login mit Initialpasswort

Ziel:

  • Der erste User meldet sich mit E-Mail und Initialpasswort an.
  • Danach muss sofort das Passwort geändert werden.

Route:

  • Web: /login
  • Desktop: Login-Dialog im nativen Client

Felder:

  • email, UI-Label E-Mail-Adresse
  • password, UI-Label Passwort

API:

  • POST /api/v1/auth/login

Besondere Zustände:

  • must_change_password = true: UI leitet direkt zur Passwortänderung weiter
  • Organization noch nicht aktiv: UI zeigt neutralen Hinweis
  • Initialpasswort abgelaufen: UI zeigt Hinweis auf erneute Einladung oder Support

Seite: Passwort beim ersten Login ändern

Ziel:

  • User ersetzt Initialpasswort durch eigenes Passwort.

Route:

  • Web: /change-initial-password
  • Desktop: eigener Dialog direkt nach Login

Felder:

  • current_password, UI-Label Aktuelles Passwort
  • new_password, UI-Label Neues Passwort
  • new_password_confirm, UI-Label Neues Passwort wiederholen

Validierung:

  • neues Passwort erfüllt Passwortrichtlinie
  • Wiederholung stimmt überein
  • neues Passwort darf nicht dem Initialpasswort entsprechen

API:

  • POST /api/v1/auth/change-initial-password

Erfolgszustand:

  • must_change_password wird entfernt
  • Sessions mit altem Passwortstatus werden ungültig
  • User wird zur Organization-Auswahl oder direkt ins Dashboard geleitet

Seite: Organization-Grunddaten nach erstem Login

Ziel:

  • Der erste User ergänzt nach Freischaltung die Stammdaten der Firma.

Route:

  • Web: /setup/organization
  • Desktop: Setup-Dialog nach Login

Felder erste Stufe:

  • Firmenname
  • Rechtsform
  • Straße und Hausnummer
  • PLZ
  • Ort
  • Land
  • USt-IdNr., optional
  • E-Mail der Firma
  • Telefonnummer, optional
  • Standard-Steuersatz
  • Standard-Zahlungsziel

API:

  • GET /api/v1/organizations/current/setup
  • PUT /api/v1/organizations/current/setup

Erfolgszustand:

  • Organization-Setup wird als abgeschlossen markiert
  • User gelangt zum Dashboard

Seite: User für Organization anlegen/einladen

Ziel:

  • Ein berechtigter Firmen-User lädt weitere User ein.

Route:

  • Web: /settings/users
  • Desktop: Benutzerrechte

Felder Einladung:

  • email, UI-Label E-Mail-Adresse
  • roles, UI-Label Rollen

Aktionen:

  • Einladung senden
  • Einladung erneut senden
  • User deaktivieren
  • Rollen ändern

API:

  • GET /api/v1/organizations/current/users
  • POST /api/v1/organizations/current/invitations
  • PATCH /api/v1/organizations/current/users/{user_id}/roles
  • POST /api/v1/organizations/current/invitations/{id}/resend
  • PATCH /api/v1/organizations/current/users/{user_id}/roles
  • POST /api/v1/organizations/current/users/{user_id}/disable

Besonderheiten:

  • Existierender globaler User bekommt keine Passwortüberschreibung.
  • Neuer User bekommt Initialpasswort und must_change_password.
  • Rollen werden im Firmenschema gespeichert.

UI-Zustände und Komponenten

Gemeinsame Zustände:

  • idle
  • validating
  • submitting
  • success
  • error

Wiederverwendbare Komponenten:

  • Formularfeld mit Validierungsfehler
  • Passwortfeld
  • Statushinweis
  • Tabellenliste mit Filter
  • Bestätigungsdialog
  • Fehlerbanner

Texte:

  • UI-Texte deutsch
  • technische IDs nur in Admin-Detailseiten anzeigen
  • keine internen Schema- oder Security-Details auf öffentlichen Seiten

Erste Implementierungsreihenfolge UI

  1. Öffentliche Registrierungsseite
  2. Login-Seite
  3. Passwortänderung beim ersten Login
  4. Admin-Liste Registrierungen
  5. Admin-Detail mit Freischalten/Ablehnen
  6. Organization-Grunddaten-Setup
  7. Benutzerverwaltung mit Einladungen

Erster Datenmodell-Entwurf

Dieser Abschnitt ist noch kein finales SQL-Schema, aber die Grundlage für die ersten Migrationen.

public.users

Globale Benutzeraccounts.

Felder:

  • id
  • email
  • display_name
  • password_hash, nullable bei reinem SSO-Account
  • is_active
  • must_change_password
  • initial_password_expires_at
  • created_at
  • updated_at
  • last_login_at

public.organizations

Globale Firmenliste zur Zuordnung von Usern zu Firmenschemas.

Felder:

  • id
  • display_name
  • schema_name
  • status
  • registration_email
  • approved_by_user_id
  • approved_at
  • rejected_by_user_id
  • rejected_at
  • rejection_reason
  • created_at
  • updated_at

Der schema_name muss eindeutig sein und darf nur vom Backend erzeugt werden. Vor der Admin-Freischaltung kann schema_name leer bleiben, wenn das Firmenschema erst nach Freigabe erzeugt wird.

public.user_organizations

Zuordnung von Usern zu Firmen.

Felder:

  • user_id
  • organization_id
  • status
  • invited_by_user_id
  • invited_at
  • accepted_at
  • created_at
  • updated_at

Rollen werden hier bewusst nicht gespeichert. Die eigentlichen Rollen liegen im Firmenschema.

Mögliche Statuswerte:

  • pending_invitation
  • active
  • disabled

public.auth_identities

Verknüpfung von Usern mit Login-Methoden.

Felder:

  • id
  • user_id
  • provider
  • provider_subject
  • email_at_provider
  • created_at
  • updated_at

Beispiele für provider:

  • password
  • oidc
  • saml
  • microsoft
  • google

public.refresh_tokens

Session-/Token-Verwaltung.

Felder:

  • id
  • user_id
  • organization_id, nullable solange keine Firma gewählt ist
  • token_hash
  • expires_at
  • revoked_at
  • revoked_reason
  • user_agent
  • created_ip
  • created_at

public.socket_tokens

Kurzlebige Tokens für WebSocket-Verbindungen. Diese Tabelle ist optional, wenn Socket-Tokens als signierte, sehr kurzlebige Tokens ohne serverseitige Speicherung umgesetzt werden.

Felder:

  • id
  • user_id
  • organization_id
  • token_hash
  • expires_at
  • used_at
  • revoked_at
  • created_at

public.session_keys

Metadaten zu aktiven Session-Schlüsseln. Rohes Schlüsselmaterial darf nicht im Klartext in PostgreSQL gespeichert werden.

Felder:

  • id
  • user_id
  • organization_id
  • key_id
  • wrapped_key, falls serverseitige Wiederaufnahme nötig ist
  • algorithm
  • created_at
  • expires_at
  • revoked_at

Wenn Session-Schlüssel nur im Arbeitsspeicher gehalten werden, kann diese Tabelle entfallen oder nur Widerrufs-/Audit-Metadaten enthalten.

public.idempotency_keys

Schutz gegen doppelte Ausführung kritischer REST-Aktionen.

Felder:

  • id
  • user_id
  • organization_id
  • key
  • request_hash
  • response_status
  • response_body_json
  • expires_at
  • created_at

Verschlüsselte Fachfelder

Für fachliche Tabellen wird ein einheitliches Muster verwendet.

Mögliche Feldstruktur:

  • *_ciphertext
  • *_nonce
  • *_tag
  • *_key_id

Alternativ kann ein JSONB- oder BYTEA-Container genutzt werden:

  • encrypted_payload
  • encryption_meta

Entscheidungskriterium:

  • einzelne verschlüsselte Felder sind besser, wenn Teile eines Datensatzes getrennt aktualisiert werden
  • ein verschlüsselter Payload-Container ist einfacher, wenn Datensätze meistens komplett gelesen und geschrieben werden

public.organization_registration_requests

Optional separate Tabelle für SaaS-Registrierungen. Wenn die Registrierung direkt in public.organizations abgebildet wird, ist diese Tabelle nicht zwingend nötig.

Felder:

  • id
  • organization_name
  • email
  • status
  • organization_id
  • requested_at
  • decided_by_user_id
  • decided_at
  • decision_note

Vorteil einer separaten Tabelle:

  • abgelehnte Registrierungen bleiben nachvollziehbar
  • public.organizations enthält nur Firmen, die technisch angelegt werden sollen
  • Admin-Freischaltung ist sauberer auditierbar

public.user_invitations

Einladungen von Firmen-Usern an neue oder bestehende User.

Felder:

  • id
  • organization_id
  • email
  • invited_by_user_id
  • status
  • expires_at
  • accepted_at
  • created_user_id
  • created_at

Mögliche Statuswerte:

  • pending
  • accepted
  • expired
  • revoked

public.email_outbox

Queue für systemseitige E-Mails.

Felder:

  • id
  • recipient_email
  • template
  • payload_json
  • status
  • attempt_count
  • last_error
  • send_after
  • sent_at
  • created_at

Verwendung:

  • Initialpasswort nach Admin-Freischaltung
  • Einladung neuer Firmen-User
  • erneuter Versand durch Administrator
  • spätere Passwort-Reset-Mails

company_*.settings

Firmeneinstellungen.

Felder:

  • key
  • value_json
  • updated_by_user_id
  • updated_at

Beispiele:

  • Freigabeprozess für Angebote aktiv
  • Standard-Steuersatz
  • Standard-Zahlungsbedingungen
  • Dokumentvorlage für Angebote
  • Dokumentvorlage für Rechnungen

company_*.roles

Feste Standardrollen, aber je Firma gespeichert, damit Rechte später erweitert oder angepasst werden können.

Felder:

  • id
  • code
  • name
  • description
  • is_system_role
  • created_at
  • updated_at

company_*.permissions

Atomare Rechte.

Felder:

  • id
  • code
  • description

Beispiele:

  • customers.read
  • customers.write
  • customers.delete
  • quotes.approve
  • invoices.finalize
  • settings.write

company_*.role_permissions

Zuordnung von Rollen zu Rechten.

Felder:

  • role_id
  • permission_id

company_*.user_roles

Zuordnung globaler User zu Rollen in dieser Firma.

Felder:

  • user_id
  • role_id
  • created_at

Der user_id verweist logisch auf public.users.id. Ein echter Foreign Key über Schemas hinweg ist möglich, muss aber bewusst entschieden werden.

company_*.number_ranges

Konfigurierbare Nummernkreise.

Felder:

  • id
  • code
  • pattern
  • counter_value
  • counter_padding
  • reset_rule
  • is_active
  • updated_at

Regeln:

  • pattern muss einen Counter-Platzhalter enthalten.
  • Counter-Erhöhung muss transaktional und konkurrenzsicher erfolgen.
  • Finale Rechnungsnummern dürfen nach Vergabe nicht wiederverwendet werden.
  • Standardformat ist ein Präfix plus neunstelliger, gruppierter Zähler: K000.000.001, L000.000.001, I000.000.001, A000.000.001, R000.000.001.
  • Standard-Nummernkreise: customers = K{counter}, suppliers = L{counter}, items = I{counter}, activities = A{counter}, outgoing_invoices = R{counter}.
  • Ergänzende Nummernkreise nach gleichem Prinzip: incoming_invoices = ER{counter}, quotes = AN{counter}.

company_*.audit_log

Revisions- und Nachvollziehbarkeitslog.

Felder:

  • id
  • actor_user_id
  • action
  • entity_type
  • entity_id
  • before_json
  • after_json
  • created_at

Für sehr große Installationen kann dieses Log später partitioniert werden.

company_*.change_log

Grundlage für Live-Updates und Offline-Synchronisation.

Felder:

  • id
  • sequence
  • entity_type
  • entity_id
  • operation
  • payload_json
  • created_at
  • created_by_user_id

Nutzung:

  • WebSocket-Events werden daraus erzeugt oder darauf gespiegelt.
  • Desktopclients können seit ihrer letzten sequence Änderungen nachladen.
  • Offline-Sync wird dadurch planbar.

company_*.documents und company_*.document_versions

Metadaten für Dateien auf dem Filesystem.

documents:

  • id
  • entity_type
  • entity_id
  • title
  • current_version_id
  • created_at
  • created_by_user_id

document_versions:

  • id
  • document_id
  • version_number
  • storage_path
  • mime_type
  • sha256
  • size_bytes
  • created_at
  • created_by_user_id

Implementierungsreihenfolge

Empfohlene Reihenfolge für die nächsten Entwicklungsschritte:

  1. public-Migrationen für User, Firmen und Zuordnungen
  2. SaaS-Registrierung mit Status pending_approval
  3. Admin-Freischaltung und Backend-Service zur Firmenschema-Erstellung
  4. Mailversand für Initialpasswort und Einladungen
  5. Firmenschema-Basismigrationen für Rollen, Rechte, Settings, Nummernkreise, Audit-Log und Change-Log
  6. Login ohne SSO, aber mit Architektur für spätere Provider
  7. erzwungener Passwortwechsel beim ersten Login
  8. Firmenauswahl nach Login
  9. User-Einladung in bestehende Firma
  10. mandantenbewusste REST- und WebSocket-Basisschicht
  11. erstes Fachmodul customers
  12. Live-Update für customers
  13. Dashboard-Grundlage
  14. Artikelmodul und CSV-Import

SSO, 2FA, Desktop-Offline und automatische Updates sind wichtig, sollten aber nach der mandantenfähigen Grundarchitektur kommen. Andernfalls müssten sie später gegen eine noch instabile Daten- und Sessionstruktur gebaut werden.

TODOs

Erledigte Planungsentscheidungen

  • SaaS-Betrieb mit vielen Firmen auf einer Instanz
  • öffentlicher Server wird selbst betrieben
  • jede Firma bekommt eigenes PostgreSQL-Schema
  • public enthält nur globale User- und Firmenzuordnung
  • Rollen, Rechte und Einstellungen liegen im Firmenschema
  • ein User kann mehreren Firmen angehören
  • Zielmarkt erste Stufe: Deutschland
  • REST-API zusätzlich zum WebSocket-Protokoll
  • Webhooks einplanen
  • Desktopclient mit Offline-Fähigkeit
  • automatische Desktopclient-Updates einplanen
  • Dokumente im Filesystem, Metadaten in PostgreSQL
  • öffentliche Registrierung für SaaS
  • Admin-Freischaltung neuer Firmen
  • Registrierung mit Firmenname und E-Mail-Adresse
  • E-Mail-Adresse ist Username
  • Initialpasswort per E-Mail
  • Passwortwechsel beim ersten Login verpflichtend
  • neue Firmen-User werden per Einladung hinzugefügt
  • lokale Version erlaubt genau eine Firma
  • SaaS-Kommunikation ausschließlich über HTTPS/WSS
  • lokale produktive Kommunikation ebenfalls ausschließlich über HTTPS/WSS
  • Reverse Proxy übernimmt TLS-Terminierung
  • WebSocket-Protokoll wird versioniert
  • WebSocket-Verbindungen werden per Token authentifiziert
  • Webhooks werden signiert
  • fachliche Payloads werden zusätzlich zu HTTPS/WSS sessionbasiert verschlüsselt
  • fachliche Daten werden in PostgreSQL nicht im Klartext gespeichert
  • pro Firma wird ein eigener Datenschlüssel geplant
  • technischer Mandantenname ist organization
  • Schema-Namenskonvention ist company_<organization_id>

Architektur

  • Alle tabellen/namen sind englisch, werden aber in der UI deutsch angezeigt
  • endgültigen Namen für Mandantenobjekt festlegen: Firma, Organisation oder Company: organization
  • Schema-Namenskonvention final festlegen: company_<organization_id>
  • public-Tabellen detailliert entwerfen
  • Firmenschema-Tabellen detailliert entwerfen
  • Migrationsstrategie für neue und bestehende Firmenschemas festlegen: erst am schluss nötig
  • sichere Kapselung für firmenschema-bewusste Datenbankzugriffe entwerfen
  • Socket-Protokoll versionieren
  • REST-API-Versionierung festlegen
  • Event-Topics und Berechtigungsprüfung definieren
  • Fehler- und Reconnect-Verhalten für Clients definieren
  • fensterbasiertes Live-Refresh- und Store-Konzept final spezifizieren
  • Offline-Sync-Strategie für Desktopclient spezifizieren
  • SaaS-Onboarding-Flow final spezifizieren
  • lokale Erstinstallation final spezifizieren
  • E-Mail-Versandarchitektur festlegen
  • Token-Modell final festlegen: JWT, opaque Tokens oder Hybrid
  • WebSocket-Handshake final spezifizieren
  • Idempotency-Key-Strategie für kritische REST-Aktionen festlegen
  • Secret-Verschlüsselung für Lieferanten-API-Zugangsdaten spezifizieren
  • Reconnect- und since_sequence-Sync formal spezifizieren
  • lokale Zertifikatsstrategie final festlegen
  • Debug-/Entwicklungsmodus klar vom produktiven Verschlüsselungsmodell trennen
  • Session-Key-Aushandlung final spezifizieren
  • AEAD-Algorithmus final auswählen
  • Schlüsselhierarchie für Master Key, Firmenschlüssel und Session-Schlüssel spezifizieren
  • Key-Rotation und Re-Encryption-Konzept planen
  • Such-/Indexstrategie für verschlüsselte Daten planen
  • festlegen, welche technischen Metadaten unverschlüsselt bleiben dürfen

Backend

  • öffentliche Registrierungs-API implementieren
  • Admin-Freischaltungs-API implementieren
  • Organization-Registration-Detail-API implementieren
  • Initial-E-Mail erneut senden implementieren
  • Provisioning-Retry implementieren
  • Admin-Oberfläche für Registrierungsfreigaben anbinden
  • Initialpasswort-Erzeugung implementieren
  • E-Mail-Outbox implementieren
  • Passwortwechsel beim ersten Login erzwingen
  • User-Einladungen implementieren
  • lokalen Setup-Modus für genau eine Firma implementieren
  • Authentifizierung implementieren
  • SSO-Provider-Konzept festlegen
  • 2FA-Verfahren festlegen
  • Firmenauswahl nach Login implementieren
  • Rollen- und Rechtesystem im Firmenschema implementieren
  • Firmenschema-Erstellung implementieren
  • Public-Migrationen implementieren
  • Firmenschema-Migrationen implementieren
  • Live-Event-Bus je Firma einbauen
  • Audit-Logging je Firmenschema ergänzen
  • Datei-Upload und Dokumentablage implementieren
  • PDF-Erzeugung evaluieren
  • REST-API-Grundstruktur implementieren
  • Webhook-Versand implementieren
  • HTTPS/WSS-Betrieb hinter Reverse Proxy dokumentieren
  • Access-/Refresh-Token-Handling implementieren
  • WebSocket-Token oder WebSocket-Auth implementieren
  • WebSocket-Handshake mit Protokollversion implementieren
  • Live-Event-Typen je Entity definieren
  • since_sequence-Nachlade-API für verpasste Live-Events implementieren
  • Idempotency Keys für kritische POST-Endpunkte implementieren
  • Verschlüsselung gespeicherter API-Secrets implementieren
  • Session-Key-Verwaltung implementieren
  • REST-Payload-Verschlüsselung implementieren
  • WebSocket-Payload-Verschlüsselung implementieren
  • Datenbank-Verschlüsselungsservice implementieren
  • Firmenschlüssel-Erzeugung bei Firmenschema-Anlage implementieren
  • Entschlüsselung in Logs, Audit-Log und Change-Log verhindern

Datenmodell

  • Firmenmodell in public detaillieren
  • User- und Firmenzuordnung detaillieren
  • Registrierungsanforderungen detaillieren
  • User-Einladungen detaillieren
  • E-Mail-Outbox detaillieren
  • Passwortstatus und Initialpasswort-Ablauf detaillieren
  • Refresh-Token-Modell detaillieren
  • Socket-Token-Modell detaillieren
  • Session-Key-Metadaten detaillieren
  • Idempotency-Key-Modell detaillieren
  • verschlüsselte Feldstruktur festlegen
  • unverschlüsselte technische Metadaten je Tabelle festlegen
  • Such-/Indexfelder für verschlüsselte Daten modellieren
  • Rollenmodell detaillieren
  • Rechtemodell detaillieren
  • Kundenmodell detaillieren
  • Lieferantenmodell detaillieren
  • Artikelmodell detaillieren
  • Kundenpreisbedingungsmodell (customer_price_terms) detaillieren
  • Lieferantenpreisbedingungsmodell (supplier_price_terms) detaillieren
  • Skonto-Regelmodell (cash_discount_terms) detaillieren
  • Lagerbewegungsmodell detaillieren
  • Angebotsmodell detaillieren
  • Angebotsversionsmodell detaillieren
  • Ausgangsrechnungsmodell detaillieren
  • Rechnungspositionsmodell mit Artikelpflicht und Preisüberschreibung detaillieren
  • Eingangsrechnungsmodell detaillieren
  • Kommunikationsmodell detaillieren
  • Vorgangsmodell (activities) detaillieren
  • Vorgangsverknüpfungen (activity_links) detaillieren
  • Aufgaben-/Wiedervorlagemodell detaillieren
  • Dokument- und Dokumentversionsmodell detaillieren
  • Preisquellen- und Preisregelmodell detaillieren
  • Rabatt- und Skonto-Vererbungsregeln definieren
  • Importmapping-Modell detaillieren

Artikelimporte und Preise

  • Beispielpreislisten sammeln
  • CSV-Import als ersten Importweg implementieren
  • XML-Import planen
  • JSON-Import planen
  • Spalten-/Feldmapping definieren
  • Importvalidierung definieren
  • Importhistorie definieren
  • Preisneuberechnung nach Import spezifizieren
  • Staffelpreise modellieren
  • kundenspezifische Preise modellieren
  • Projektpreise modellieren
  • Lieferanten-API-Connector-Schnittstelle entwerfen
  • Grenzen frei konfigurierbarer API-Connectoren dokumentieren

Frontends

  • gemeinsames UI-Konzept für Web und Desktop definieren
  • Login-Flow für beide Clients planen
  • Firmenauswahl planen
  • öffentliche Registrierungsseite planen
  • Admin-Liste für Organization-Registrierungen planen
  • Admin-Detail für Organization-Freischaltung planen
  • Passwortänderung beim ersten Login planen
  • Organization-Grunddaten-Setup planen
  • Benutzerverwaltung und Einladungen planen
  • Dashboard entwerfen
  • Kundenmaske entwerfen
  • Lieferantenmaske entwerfen
  • Artikelmaske entwerfen
  • Lagermaske entwerfen
  • Angebotsmaske mit Versionierung entwerfen
  • Rechnungsmasken entwerfen
  • Artikelpflicht und Preisüberschreibung in Rechnungsmasken entwerfen
  • Kommunikationsverlauf entwerfen
  • Vorgangstimeline entwerfen
  • Vorgangsmaske mit Typen, Status, Priorität und Verknüpfungen entwerfen
  • Aufgaben-/Wiedervorlagemaske entwerfen
  • Dokumentverwaltung entwerfen
  • Importassistent entwerfen
  • Live-Refresh-Verhalten je Maske festlegen
  • fensterübergreifende Aktualisierung von Listen, Suchdialogen und Auswahlfeldern planen
  • Konfliktverhalten bei parallelen Fensteränderungen planen
  • Offline-Verhalten im Desktopclient je Maske festlegen
  • sichere Token-Speicherung im Desktopclient planen
  • sichere Session-Key-Speicherung im Desktopclient planen
  • Verschlüsselung des lokalen Offline-Caches planen
  • Verbindungsstatus und TLS-Warnungen im Desktopclient planen
  • Update-Mechanismus für Desktopclient auswählen

Betrieb

  • Docker-Setup für Backend und PostgreSQL erweitern
  • TLS/Reverse-Proxy-Konzept für öffentlichen Betrieb definieren
  • Zertifikatsstrategie festlegen
  • Caddy, Traefik oder Nginx als Startoption auswählen
  • lokale Zertifikatserzeugung für Installationsprogramm planen
  • Security Header und HTTPS-Redirect konfigurieren
  • Backup- und Restore-Konzept je Firma erstellen
  • Logging und Monitoring planen
  • Konfiguration für lokalen und öffentlichen Betrieb trennen
  • Update-Strategie für Backend festlegen
  • Update-Strategie für Desktopclient festlegen
  • Dateisystem-Speicherlayout für Dokumente definieren
  • Speicherquoten je Firma planen

Rechtliches und Buchhaltung

  • deutsche Steuerlogik detaillieren
  • Elster-relevante Datenfelder identifizieren
  • Revisionssichere Rechnungsablage konzipieren
  • Storno-/Korrekturrechnungsprozess definieren
  • Nummernkreisregeln und Platzhalter definieren
  • spätere DATEV-Erweiterung vorbereiten
  • spätere E-Rechnungs-Erweiterung vorbereiten

Nächster sinnvoller Schritt

Als nächstes sollte das Datenmodell für public und das Firmenschema konkretisiert werden. Besonders wichtig sind:

  1. users, organizations, user_organizations und Login/SSO/2FA
  2. Rollen und atomare Rechte im Firmenschema
  3. Nummernkreise und revisionssichere Rechnungen
  4. Änderungslog für Live-Updates und spätere Offline-Synchronisation