Kernarchitektur und ihre Umsetzung
Wie die Anwendung technisch aufgebaut wird: eine Hülle aus der eCore-Vorlage, ein Vorgangskern als gemeinsame Datenbasis, sechs Fachmodule, die nur mit dem Kern sprechen, und geteilte Dienst-Container ohne eigenen Zustand. Betrieben wird sie als mandantenfähiger SaaS-Dienst von calhelp im begleiteten Abo. Diese Seite ist die Bauanleitung für Etappe 1 und der Rahmen für alle folgenden.
Grundsätze
- Eine Vorgangsakte. Alles hängt am Vorgang mit seinem Aktenzeichen. Fachmodule fügen Phasen, Felder, Akteneinträge und Dokumente hinzu, sie führen keine eigene Akte.
- Fachmodule kennen den Kern, nie einander. Beschaffung weiß nicht, dass es Signatur gibt; sie meldet „Freigabe erteilt“. So lässt sich jedes Modul einzeln einführen, und eine Vorgangsart ohne Vergabe startet direkt bei Dokumente.
- Konfiguration statt Code. Vorgangsarten, Vergaberegeln, Zeichnungsregeln, Postfächer, Anmeldung und Vorlagen werden in der Verwaltung gepflegt. Was sich je Kunde unterscheidet, steht nicht im Quelltext.
- Ein Produkt, viele Mandanten. Das Dezernat ist der erste Mandant, nicht der einzige. Nichts Kundenspezifisches steht im Code: Postfächer, Briefkopf, Vorgangsarten, Regeln und Anmeldung sind Einstellungen des Mandanten, und jede Tabelle, jede Datei und jeder Schlüssel gehört genau einem Mandanten.
- eCore-Regeln gelten unverändert. Jeder Endpunkt hinter
capability:<modul>, fail-closed; Personenbezogenes durchEnvelopeCrypto; kein IP- oder User-Agent-Log an Fachdaten; keine Inhalte in Logs; KI schlägt vor, entscheidet nicht. - Arbeitsplatz am Desktop, App am Telefon. Dieselben Seiten zeigen am breiten Bildschirm eine Arbeitsfläche mit Navigation, Liste und Akte nebeneinander und am Telefon die dichte App-Form von eCore. Ein Quelltext, kein zweites Frontend.
- Generisches nach unten. Was jede Hülle brauchen kann (Dokumentablage, Teams, SSO, Fristen-Engine, Desktop-Modus), geht als Minor in eCore, mit dieser App als erstem Abnehmer. Fachliches bleibt in der Hülle.
Modulkarte
Aufbau des Repositorys
Die Hülle entsteht mit dem Werkzeug der eCore-Vorlage. Der App-Schlüssel ist evorgang; daraus werden Composer-Paket, Capability des Kerns, Tabellenpräfix, Mandant, Layer und Image-Namen abgeleitet.
node scripts/neue-app.mjs evorgang Evorgang --ziel=../eVorgang
eVorgang/
├── backend/ Laravel-Anwendung, bindet calhelp/ecore per VCS
├── frontend/ Nuxt, extends ecore-ui, ecore-admin-ui und die Modul-Layer
├── packages/
│ ├── evorgang/ Vorgangskern Calhelp\Evorgang\ capability:evorgang
│ ├── evorgang-ui/ Akte, Vorgangsliste, Zeitleiste
│ ├── evorgang-admin-ui/ Vorgangsarten, Organisation, Feldkatalog
│ ├── posteingang/ Calhelp\Posteingang\ capability:posteingang
│ ├── beschaffung/ Calhelp\Beschaffung\ capability:beschaffung
│ ├── dokumente/ Calhelp\Dokumente\ capability:dokumente
│ ├── signatur/ Calhelp\Signatur\ capability:signatur
│ ├── vertrag/ Calhelp\Vertrag\ capability:vertrag
│ └── partner/ Calhelp\Partner\ capability:partner
│ (jedes Fachmodul mit eigenem -ui und -admin-ui Layer)
├── docker/ Dockerfiles, Caddyfile, Compose-Erweiterung für die Dienste
├── scripts/ Hüllen-Werkzeuge aus der Vorlage
├── docs/ diese Projektplanung (GitHub Pages)
├── ecore.pin.json Fassung von eCore, die diese App nutzt
└── docker-compose.yml
Das generierte Modul wird der Vorgangskern. Die Fachmodule entstehen als weitere Pakete nach demselben Muster: je ein ModuleManifest, eigene Routen hinter capability:<modul>, eigener Limiter, eigene Migrationen mit Modulpräfix. Ein Modul wird freigeschaltet, indem seine Capability im App-Manifest steht; fehlt sie, antworten seine Routen 403 und seine Oberfläche bleibt ausgeblendet. Damit ist jede Etappe eine Freischaltung, kein Umbau.
Abhängigkeitsregel
| Paket | darf importieren | darf nicht |
|---|---|---|
evorgang (Kern) | Calhelp\Ecore\, Laravel, Symfony Workflow | jedes Fachmodul |
| Fachmodule | Kern-Verträge aus Calhelp\Evorgang\Contracts und Kern-Ereignisse, eCore | andere Fachmodule, Kern-Interna außerhalb von Contracts und Events |
| Oberflächen-Layer | ecore-ui, ecore-admin-ui, eigener Modul-Layer, Kern-Layer | Layer anderer Fachmodule |
Die Regel wird in der CI geprüft: der Regelwächter der Vorlage (regeln.config.json) bekommt je Fachmodul eine Importliste, ein Verstoß bricht den Build.
Datenmodell des Kerns
Alle Tabellen tragen organization_id und laufen durch den Mandanten-Scope von eCore. Fachmodule verweisen höchstens auf users, organizations, ecore_media_files und die Tabellen des Kerns.
| Tabelle | Inhalt | Hinweise |
|---|---|---|
evorgang_vorgangsarten | Schlüssel, Name, aktive Phasen, Übergänge, Feldschema, Antragsmaske, Aktenzeichen-Muster, Aufbewahrung, Fristvorgaben | versioniert; ein laufender Vorgang behält die Fassung, mit der er angelegt wurde |
evorgang_vorgaenge | Aktenzeichen, Vorgangsart und Fassung, Phase, Status, Team, zuständige Person, Organisationseinheit, Elternvorgang | Aktenzeichen eindeutig je Mandant, etwa D7-2027-00042 |
evorgang_felddefinitionen | Feldkatalog: Schlüssel, Typ, Bezeichnung, Pflicht je Phase, personenbezogen ja oder nein | personenbezogene Felder werden verschlüsselt gespeichert |
evorgang_feldwerte | Wert je Vorgang und Feld, Quelle (Modul), geändert von, Zeitpunkt | mit Feldhistorie; Vorlagen lesen {{ auftragssumme }} hier |
evorgang_beteiligte | Rolle (Antragsteller, Anbieter, Auftragnehmer, Unterzeichner), Konto oder Partner-Kennung | Partner als Kennung ohne Fremdschlüssel, damit der Kern das Partnermodul nicht kennt |
evorgang_akteneintraege | Zeitleiste: Typ (Mail, Kommentar, Dokument, Entscheidung, Zeichnung), Modul, Verweis, Sichtbarkeit | jede Akte ist ohne Modulwissen lesbar |
evorgang_fristen | Typ, Fälligkeit, Vorlauf, Eskalationsziel, Quelle, erledigt am, letzter Lauf | ein Job für alle Fristen, idempotent je Tag |
evorgang_protokoll | Folge je Vorgang, Aktion, Kontext ohne Inhalte, vorheriger Hash, Hash | nur anhängend; Postgres-Trigger sperrt UPDATE und DELETE auf hash-relevante Spalten |
evorgang_organisationseinheiten | Dezernate und Referate als Antragsteller | Teams selbst kommen als eCore-Minor |
Verträge des Kerns
Fachmodule schreiben nie direkt in Kern-Tabellen. Sie benutzen diese Schnittstellen aus Calhelp\Evorgang\Contracts, die der Kern im Service-Container bindet:
| Vertrag | Aufgabe |
|---|---|
VorgangRepository | Vorgang anlegen (Art, Team, Startfelder), über Aktenzeichen finden, Kindvorgang anlegen |
Phasenwechsel | Übergang anwenden mit Begründung; Zustandswechsel, Protokolleintrag und Ereignis in einer Transaktion |
Feldkatalog | Felder lesen und schreiben, mit Quelle und Historie; prüft Typ und Pflicht der aktuellen Phase |
Aktenbuch | Eintrag in die Zeitleiste anhängen (Mail, Kommentar, Dokument, Entscheidung, Zeichnung) |
Beteiligte | Beteiligte mit Rolle hinzufügen und abfragen |
FristService | Frist setzen, verschieben, erledigen; Vorlauf und Eskalation aus der Vorgangsart |
Protokoll | Eintrag anhängen, Kette prüfen (evorgang:protokoll:pruefen täglich) |
Phasen und Workflow
Jede Vorgangsart beschreibt ihre Phasen und Übergänge. Daraus baut der Kern zur Laufzeit einen Zustandsautomaten mit symfony/workflow. Fachmodule hängen Prüfungen als Guard-Listener an Übergänge, etwa „Zuschlag nur mit der Mindestzahl an Vergleichsangeboten“ (Beschaffung) oder „interne Zeichnung abgeschlossen“ (Signatur). Ein BPMN-System wie Camunda wäre mächtiger, brächte aber einen zweiten Laufzeitdienst und ein Modellierwerkzeug, das im Dezernat niemand pflegen wird.
Rückgabe zur Überarbeitung und Nachforderung von Unterlagen sind gewöhnliche Übergänge zurück in eine frühere Phase, mit Pflichtbegründung und Frist. Nicht jeder Vorgang durchläuft alle Phasen: eine Reisekostenfrage endet nach der Bearbeitung, eine Vertraulichkeitsvereinbarung beginnt bei der Dokumenterstellung.
Ereignisse
Der Kern veröffentlicht bei jedem Phasenwechsel PhaseGewechselt, dazu fachliche Ereignisse, die Module auslösen. Ereignisse sind Laravel-Events, werden erst nach dem Commit zugestellt und von Listenern in der Queue verarbeitet, damit ein fehlschlagender Listener keinen Phasenwechsel zurückrollt. Die Klassen liegen in Calhelp\Evorgang\Events; wo der Code-Name vom Planungsnamen abweicht, steht dieser in Klammern. Die Ereignisse der Zeichnung tragen nur Kennungen und Hashes, nie Inhalte.
| Ereignis | ausgelöst von | reagiert | Wirkung |
|---|---|---|---|
MailEingegangen | Posteingang | Kern | Vorgang anlegen oder Eintrag anhängen, Team zuweisen |
FreigabeErteilt | Beschaffung | Dokumente | Auftragsschreiben oder Vertrag aus Vorlage vorschlagen |
UnterlagenNachgefordert | Beschaffung | Posteingang, Kern | Mail an das antragstellende Dezernat, Frist setzen |
ZuschlagErteilt | Beschaffung | Kern | Auftragnehmer im Feldkatalog festschreiben |
DocumentSubmittedForSignature (DokumentZurZeichnung) | Signatur, beim Start eines Laufs | Dokumente, synchron nach dem Commit | Fassung und SHA-256 sind eingefroren; Dokumente sperrt das Dokument für neue Fassungen und führt ein erzeugtes Schreiben als „in Zeichnung“ |
SignaturePending (ZeichnungAusstehend) | Signatur, je Platz, wenn seine Stufe an der Reihe ist | keins | Kennung von Lauf und Platz für Module, die darauf hören; Frist und Meldung je Platz setzt Signatur selbst über die Verträge des Kerns |
SignatureRunAborted (ZeichnungAbgebrochen) | Signatur, bei Ablehnung oder Rückzug | Dokumente | Sperre aufheben; der Grund bleibt in Signatur |
FullySigned (VollstaendigGezeichnet) | Signatur, erst wenn die Ausfertigung (gezeichnete Fassung, Zeichnungsprotokoll, auf Wunsch Stempel) als neue Fassung in der Akte liegt | Dokumente; ab Etappe 6 Vertrag | Sperre aufheben, Schreiben als „gezeichnet“ führen; Fassung und Hash sind die der Ausfertigung. Kein Siegel in Etappe 4 (Entscheidungen) |
FristFaellig | Kern | Posteingang, Benachrichtigung | Erinnerung an Zuständige, Eskalation nach Ablauf |
Die Fachmodule
| Modul | Aufgabe | eigene Tabellen (Auswahl) | Etappe |
|---|---|---|---|
| Posteingang | Funktionspostfächer abrufen, Mail zuordnen (Aktenzeichen im Betreff, dann In-Reply-To, sonst neuer Vorgang im Team des Postfachs), Antworten aus dem Vorgang senden | posteingang_postfaecher, posteingang_nachrichten | 2 |
| Dokumente | versionierte Ablage mit SHA-256, Volltextsuche, Aufbewahrung, Aktenexport; ab Etappe 4 Vorlagen, Textbausteine, Briefkopf, Angebotsstempel | Dokumente und Fassungen im Dokumentdienst von eCore (ecore_documents, ecore_document_versions); eigene: dokumente_templates, dokumente_template_versions, dokumente_generations, dokumente_text_blocks, dokumente_signing_locks | 2 und 4 |
| Partner | Anbieter, Vertragspartner, Ansprechpersonen einmal erfasst | partner_partner, partner_personen | 3 |
| Beschaffung | Antragsmaske, Vergabeakte mit Anfrage, Anbietern, Angeboten, Bewertung, Freigabe, Zuschlag; Vergaberegeln | beschaffung_anfragen, beschaffung_angebote, beschaffung_bewertungen, beschaffung_regeln | 3 |
| Signatur | Zeichnungsregeln (Stufen nacheinander, Plätze nebeneinander, nach Vorgangsart, Vertragsart und Wertgrenze), interne Zeichnung mit Ausfertigung und Zeichnungsprotokoll, Angebotsstempel, Wächter vor geschützten Phasen; ab Etappe 5 Unterzeichnerseite für Externe | signatur_rules, signatur_settings, signatur_runs, signatur_steps; ab Etappe 5 signatur_invitations | 4 und 5 |
| Vertrag | Register mit Beginn, Ende, Kündigungsfrist, Verlängerung, Zuständigkeit, Rückverweis auf die Vergabeakte; berechnet Fristen | vertrag_vertraege, vertrag_arten | 6 |
Wie sich ein Fachmodul anhängt
Neben den Ereignissen kennt der Kern die Fachmodule nur über Container-Tags und gebundene Verträge. Ohne die Capability eines Moduls beim Mandanten hält sein Wächter nichts an, und sein Abschnitt im Aktenexport sagt, dass es abgeschaltet ist.
| Tag oder Vertrag | Was der Kern fragt | Wer sich einträgt |
|---|---|---|
evorgang.transition_guards (TransitionGuard) | Einwand vor einem Übergang, geprüft an der Zielphase | Beschaffung (Freigabe, Zuschlag), Signatur (erst weiter, wenn intern gezeichnet ist und die Ausfertigung in der Akte liegt; Phasen je Vorgangsart in signatur_settings.guard_phases) |
evorgang.export_contributors (CaseExportContributor) | eigener Ordner und Abschnitt im Aktenexport | Dokumente (jede Fassung), Posteingang, Beschaffung (vergabeakte.txt), Signatur (zeichnung.json) |
evorgang.discard_contributors (DiscardContributor) | Widerspruch und hartes Löschen beim Aussondern | Dokumente, Posteingang, Beschaffung, Signatur (ein offener Lauf hält die Akte) |
CaseDocumentStore | Dokumente einer Akte lesen, beschreiben, als neue Fassung ablegen | Dokumente bindet ihn; ohne Dokumentmodul bleibt er leer. Signatur liest und legt die Ausfertigung nur darüber ab und kennt das Modul Dokumente nicht |
Posteingang: zwei Adapter, eine Schnittstelle
MailboxAdapter mit abrufen(), markieren(), senden() und verbindungTesten(). GraphAdapter spricht Microsoft Graph für Exchange Online (App-Registrierung, Client-Credentials), ImapAdapter deckt Exchange lokal und andere Server ab. Welcher gilt, steht je Postfach in der Verwaltung, die Zugangsdaten liegen verschlüsselt. Der Abruf läuft als Job im Scheduler je Postfach mit eigenem Intervall und merkt sich den Stand, damit kein Mail doppelt zum Vorgang wird. Für Exchange Online registriert calhelp eine mandantenfähige App in Entra ID, der jeder Kunde per Administratorzustimmung den Zugriff auf seine Funktionspostfächer gibt; ein lokales Exchange muss aus dem Internet per IMAP über TLS erreichbar sein oder wird über ein Gateway angebunden.
Signatur: einfache Signatur als Standardweg
Interne Zeichnung durch angemeldete Personen, externe ab Etappe 5 über einen Einmal-Link mit Token im URL-Fragment und optionalem Bestätigungscode per Mail. Die Zeichnung startet im Signaturmodul: beim Start wird der SHA-256 der Fassung eingefroren, jede Entscheidung prüft ihn erneut. Nach der letzten Zeichnung rendert der PdfRenderer von eCore (Gotenberg) das Zeichnungsprotokoll, qpdf hängt es an die unveränderten Bytes der gezeichneten Fassung, auf Wunsch mit dem Stempel „Auftrag erteilt“; das Ergebnis liegt als Ausfertigung in der Akte. Das ist eine einfache elektronische Signatur nach Art. 3 Nr. 10 eIDAS; Siegel und qualifizierte Signatur über einen Vertrauensdiensteanbieter (CSC API v2) kommen in Etappe 7.
Betrieb als SaaS
calhelp betreibt eVorgang als Plattform in einem Rechenzentrum in Deutschland, im begleiteten Abo: calhelp richtet den Mandanten ein, pflegt Vorgangsarten und Regeln mit dem Kunden, spielt Updates ein und betreibt Sicherung und Überwachung. Der Kunde stellt keinen Server. Alles läuft in Docker-Containern; dieselben Images laufen in Entwicklung, Abnahme und Produktion. Für Kunden, die eine eigene Instanz verlangen, lassen sich dieselben Images als dedizierte Instanz betreiben, ohne zweiten Codestand.
Mandantentrennung
| Ebene | Trennung |
|---|---|
| Daten | eine Datenbank, jede Tabelle mit organization_id im Mandanten-Scope von eCore; Mandanten-Isolation ist Pflichttest je Endpunkt |
| Ablage | Dateien unter einem Verzeichnis je Mandant, verschlüsselt mit dem Datenschlüssel des Mandanten; Kontingent je Abo |
| Schlüssel | Datenschlüssel, Postfach-Zugangsdaten, SSO-Zertifikate und Siegel-Identität je Mandant, nie plattformweit |
| Anmeldung | SSO-Konfiguration je Mandant, Zuordnung über Domain oder Mandanten-Adresse; eigene Konten daneben |
| Dienste | pdf und ollama sind geteilt, zustandslos und bekommen je Aufruf nur die Daten eines Mandanten; Warteschlangen und Abrufjobs laufen je Mandant mit eigenem Takt, damit ein großer Mandant die anderen nicht ausbremst |
| Sicherung | Sicherung der ganzen Plattform, Wiederherstellung und Export je Mandant einzeln; bei Vertragsende Übergabe der Akte und hartes Löschen |
Plattform-Verwaltung
Neben der Verwaltung des Mandanten gibt es eine Verwaltung für calhelp: Mandanten anlegen und stilllegen, Abo und freigeschaltete Module (Capabilities) zuweisen, Kontingente, Update-Stand, Überwachung von Abrufjobs, Fristenjob und Protokollprüfung je Mandant. Aus der Abo-Schicht von eCore kommen Pläne und Freischaltung; welche Module ein Abo enthält, bestimmt die Capability je Mandant.
Container
| Container | Herkunft | Aufgabe |
|---|---|---|
db | eCore-Vorlage | PostgreSQL 17 |
migrate | eCore-Vorlage | Migration und Bootstrap vor jedem Start |
api, queue, scheduler | eCore-Vorlage | Anwendung, Listener der Ereignisse, Mail-Abruf, Fristenjob, Protokollprüfung |
frontend, caddy | eCore-Vorlage | Oberfläche, TLS, CSP aus der Anwendung |
ollama | eCore-Vorlage | selbst gehostetes Modell für Vorschläge (Team, Vorgangsart, Antwortentwurf) |
pdf | Gotenberg 8 wie in der eCore-Vorlage, auf den Digest gepinnt | HTML zu PDF über den PdfRenderer von eCore: Schreiben aus Vorlagen, Zeichnungsprotokoll, Stempel. Nur im internen Netz evorgang-pdf mit api und queue, ohne JavaScript, lädt nur aus seinem Arbeitsverzeichnis, mit Anmeldung. Zusammenfügen und Überlagern macht qpdf im api-Image, den Text für die Suche pdftotext |
updater | eforms-cloud | nimmt einen neuen Stand entgegen und schaltet um, nur mit Profil und Token |
Die Dienst-Container sind nur im internen Netz erreichbar und verlangen eine Anmeldung (Bearer-Token, beim PDF-Wandler Basic-Auth). Ein gezeichnetes Dokument wird nie neu gerendert: ein Chromium-Update änderte die Bytes, es gelten nur die abgelegten. Dateien der Ablage gehören in die Sicherung; ob die eCore-Sicherung sie je Mandant erfasst und einzeln wiederherstellt, wird in Etappe 1 geprüft und sonst ergänzt. Erreichbar von außen sind nur caddy und, je nach Kunde, der Abruf der Postfächer nach außen.
Oberfläche: Desktop-Modus
eCore kennt bisher nur die App-Form: eine Spalte von höchstens 480 px (--e-measure), dicht und für den Daumen gemacht. Die Verwaltung ist breiter (1040 px mit Seitenleiste), aber nicht für Massenarbeit gebaut. Wer im Dezernat den ganzen Tag Vorgänge bearbeitet, sitzt am großen Bildschirm und braucht Liste, Akte und Dokument gleichzeitig im Blick. Deshalb bekommt eCore einen Desktop-Modus als Minor; eVorgang ist sein erster Abnehmer.
Wie er sich verhält
- Breite entscheidet, nicht ein Schalter. Ab 64rem (1024 px) zeigt das Gerüst die Arbeitsfläche, darunter die App-Form. Eine Hülle schaltet den Modus beim Anmelden ihres Gerüsts ein (
registerAppShell(layout, { desktop: true })); ohne die Angabe bleibt alles wie heute. Damit ist die Erweiterung additiv. - Ein Quelltext. Seiten setzen sich aus denselben Bausteinen zusammen; die Bausteine ordnen sich je nach verfügbarer Breite an (Container Queries statt nur Media Queries), damit ein Bereich in der Mitte eines dreigeteilten Bildschirms so reagiert wie ein Telefon.
- Dichte nach Zeigegerät. Mit Maus (
pointer: fine) und ab 64rem werden Zeilen und Abstände enger; am Touchscreen bleiben 44 px Trefferfläche. Jede Person kann zusätzlich „kompakt“ oder „normal“ wählen, gespeichert in ihren Einstellungen. - Blätter werden Seitenbereiche. Was am Telefon als Blatt von unten kommt (
ESheet), öffnet am Desktop als Bereich rechts neben dem Inhalt; der nächste Schritt (EActionBar) steht im Kopf des Detailbereichs statt unten klebend. - Tastatur. Kürzel für die häufigsten Wege (nächster Vorgang, zuweisen, kommentieren, Phase wechseln, Suche), mit Übersicht auf ?. Jede Handlung bleibt auch per Maus und Vorlesehilfe erreichbar.
Neue Bausteine in eCore
| Baustein | Wofür | am Telefon |
|---|---|---|
EWorkspace | Gerüst: einklappbare Navigationsleiste links, Kopfzeile mit Suche und Konto, Arbeitsfläche in voller Breite | App-Form mit Leiste unten |
ESplitView | Liste und Detail nebeneinander, Teiler verschiebbar, Breite je Person gemerkt; optional dritter Bereich | Liste, Antippen öffnet das Detail als eigene Seite |
EDataTable | Tabelle mit wählbaren Spalten, Sortierung, Filter, Mehrfachauswahl und Stapelaktionen, Tastaturbedienung, Nachladen bei langen Listen | Zeilen als EList mit beschrifteten Werten, aus denselben Spaltendefinitionen |
EFilterBar | Filter als Chips, gespeicherte Ansichten („Meine offenen“, „Frist diese Woche“) | Filter im Blatt |
EInspector | rechte Seitenleiste für Eigenschaften und Nebenformulare | Blatt von unten |
ETabs | Reiter innerhalb eines Bereichs (Akte, Dokumente, Beteiligte, Protokoll) | segmentierte Auswahl oder Abschnitte |
registerShortcuts | Register für Tastaturkürzel, je Seite und global, mit Übersicht | ohne Wirkung |
Was eVorgang daraus macht
| Ansicht | Desktop |
|---|---|
| Arbeitskorb | Vorgangsliste als Tabelle links, Akte rechts; Wechsel per Pfeiltaste, ohne die Liste zu verlassen |
| Akte | Zeitleiste in der Mitte, Felder und Beteiligte im Inspector, Dokumentvorschau als dritter Bereich |
| Posteingang | Mail links, Zuordnung zum Vorgang rechts, Antwort im selben Blick |
| Vergabeakte | Angebote als Vergleichstabelle nebeneinander |
| Vertragsregister | Tabelle mit Fristspalten, Filter nach Fälligkeit, Export |
Das Fixture beispiel der eCore-Vorlage bekommt die Desktop-Naht zuerst, damit der Vertrag belegt ist, bevor eine Hülle ihn nutzt. Browser-Tests prüfen jede Seite in drei Breiten (Telefon, 1280 px, 1920 px).
Anmeldung und Rechte
- Anmeldung: SSO über SAML oder OIDC und eigene Konten nebeneinander, je Mandant in der Verwaltung mit Verbindungstest. Ein lokales AD wird über ADFS oder Entra ID per SAML/OIDC angebunden; LDAP direkt aus der Cloud gibt es nur mit gesicherter Verbindung zum Kunden. Externe Unterzeichnende brauchen kein Konto.
- Rollen: eCore-Rollen bleiben die Grobstufe (Mitglied, Redaktion, Verwaltung).
- Teams: je Funktionspostfach eins, dazu fachliche Teams. Ein Vorgang ist sichtbar für sein Team, seine Beteiligten und die antragstellende Organisationseinheit.
- Zeichnungsbefugnisse: Regeln nach Betrag und Vertragsart im Signaturmodul; die Werte kommen aus dem Anforderungsworkshop.
Querschnitt
| Thema | Umsetzung |
|---|---|
| Revision | jede Freigabe, jeder Zuschlag, jede Zeichnung im hash-verketteten Protokoll; täglicher Prüfjob meldet Brüche |
| Datenschutz | calhelp ist Auftragsverarbeiter (Art. 28 DSGVO) mit Vertrag, technischen und organisatorischen Maßnahmen und Verarbeitung in Deutschland; personenbezogene Felder und Inhalte durch EnvelopeCrypto mit dem Datenschlüssel des Mandanten; Geschäftsdaten bleiben durchsuchbar und sind über Rechte geschützt; kein IP- oder User-Agent-Log an Fachdaten; keine Inhalte in Logs |
| Aufbewahrung | Frist je Vorgangsart; nach Ablauf hartes Löschen mit Protokolleintrag ohne Inhalt; gesetzliche Fristen für Vergabe- und Rechnungsunterlagen werden in Etappe 0 festgelegt |
| Auskunft und Löschung | Export- und Lösch-Beitrag je Modul über das ModuleManifest |
| KI | nur Vorschläge über den Prompt-Katalog von eCore; das Modell läuft auf der Plattform von calhelp, solange AI_REQUIRE_SELF_HOSTED gilt; je Mandant abschaltbar |
| Updates | laufend für alle Mandanten, ohne Bruch innerhalb einer Hauptversion; neue Module bleiben aus, bis ein Abo sie freischaltet; Vorgangsarten sind versioniert, damit laufende Vorgänge ihre Fassung behalten |
| Schnittstellen | REST je Modul hinter der Capability; Finanzbuchhaltung später über E-Rechnung und Bestelldaten |
Qualitätssicherung
- Tests je Endpunkt mit den eCore-Pflichtfällen: Auth-Pflicht, Happy Path, Capability-Gate, Mandanten-Isolation.
- Kern-Tests für Automat, Feldkatalog, Fristen und Protokollkette; Vertragstests, die jedes Fachmodul gegen die Kern-Schnittstellen fährt.
- CI aus der Vorlage: Pint, PHPStan, PHPUnit gegen PostgreSQL, ESLint, Typecheck, Vitest, Regelwächter,
docker compose config. - Je Mail-Adapter ein Testpostfach in der Entwicklung; Graph und IMAP verhalten sich bei Ordnern, Lesestatus und Anhängen unterschiedlich.
- Wiederherstellung von Datenbank und Ablage wird vor dem Produktivstart in Etappe 2 geprobt, für die ganze Plattform und für einen einzelnen Mandanten.
- Mandanten-Isolation zusätzlich als eigene Testreihe: zwei Mandanten mit gleichen Aktenzeichen, Postfächern und Vorlagen dürfen einander in keiner Liste, Suche, Datei oder Ereignis sehen.
- Weil Coding-Agenten den Code schreiben, trägt die Automatik die Grundprüfung: Abnahmekriterien als Tests vor dem Code, Vertragstests gegen den Kern, Regelwächter für die Abhängigkeitsregel, Browser-Tests in drei Breiten. Der Mensch prüft im Review Fachlichkeit, Sicherheit und Architektur.
- Repository-Regeln (
CLAUDE.md, Abhängigkeitsregel, Pflichtfälle) stehen im Repository, damit jeder Agent sie mit dem Code liest.