eVorgang Projektplanung

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

Modulkarte

Modulkarte eVorgang Oben Eingänge per Mail und Antragsmaske, in der Mitte der Vorgangskern, um ihn sechs Fachmodule, unten die Dienst-Container für PDF, Modell und künftig Siegel und eCore als Unterbau. FunktionspostfächerGraph oder IMAP, je Postfach Antragsmaske DezernateFormular aus der Vorgangsart PosteingangMail zu Vorgang, Antworten PartnerAnbieter, Ansprechpersonen BeschaffungVergabeakte, Zuschlag VorgangskernVorgangsarten · Phasen-Automat · Feldkatalog · BeteiligteAkteneinträge · Fristen · hash-verkettetes ProtokollEreignisse bei jedem Phasenwechsel DokumenteAblage, Vorlagen, Briefkopf SignaturZeichnung, Ausfertigung, Wächter VertragRegister, Laufzeiten, Fristen GotenbergHTML zu PDF OllamaVorschläge, selbst gehostet SealSiegel, ab Etappe 7 eCoreKonto, Mandant, Verwaltung
Durchgezogen: Fachmodul spricht mit dem Kern (Verträge und Ereignisse). Gestrichelt: interner HTTP-Aufruf eines Dienst-Containers mit Anmeldung.

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

Paketdarf importierendarf nicht
evorgang (Kern)Calhelp\Ecore\, Laravel, Symfony Workflowjedes Fachmodul
FachmoduleKern-Verträge aus Calhelp\Evorgang\Contracts und Kern-Ereignisse, eCoreandere Fachmodule, Kern-Interna außerhalb von Contracts und Events
Oberflächen-Layerecore-ui, ecore-admin-ui, eigener Modul-Layer, Kern-LayerLayer 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.

TabelleInhaltHinweise
evorgang_vorgangsartenSchlüssel, Name, aktive Phasen, Übergänge, Feldschema, Antragsmaske, Aktenzeichen-Muster, Aufbewahrung, Fristvorgabenversioniert; ein laufender Vorgang behält die Fassung, mit der er angelegt wurde
evorgang_vorgaengeAktenzeichen, Vorgangsart und Fassung, Phase, Status, Team, zuständige Person, Organisationseinheit, ElternvorgangAktenzeichen eindeutig je Mandant, etwa D7-2027-00042
evorgang_felddefinitionenFeldkatalog: Schlüssel, Typ, Bezeichnung, Pflicht je Phase, personenbezogen ja oder neinpersonenbezogene Felder werden verschlüsselt gespeichert
evorgang_feldwerteWert je Vorgang und Feld, Quelle (Modul), geändert von, Zeitpunktmit Feldhistorie; Vorlagen lesen {{ auftragssumme }} hier
evorgang_beteiligteRolle (Antragsteller, Anbieter, Auftragnehmer, Unterzeichner), Konto oder Partner-KennungPartner als Kennung ohne Fremdschlüssel, damit der Kern das Partnermodul nicht kennt
evorgang_akteneintraegeZeitleiste: Typ (Mail, Kommentar, Dokument, Entscheidung, Zeichnung), Modul, Verweis, Sichtbarkeitjede Akte ist ohne Modulwissen lesbar
evorgang_fristenTyp, Fälligkeit, Vorlauf, Eskalationsziel, Quelle, erledigt am, letzter Laufein Job für alle Fristen, idempotent je Tag
evorgang_protokollFolge je Vorgang, Aktion, Kontext ohne Inhalte, vorheriger Hash, Hashnur anhängend; Postgres-Trigger sperrt UPDATE und DELETE auf hash-relevante Spalten
evorgang_organisationseinheitenDezernate und Referate als AntragstellerTeams 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:

VertragAufgabe
VorgangRepositoryVorgang anlegen (Art, Team, Startfelder), über Aktenzeichen finden, Kindvorgang anlegen
PhasenwechselÜbergang anwenden mit Begründung; Zustandswechsel, Protokolleintrag und Ereignis in einer Transaktion
FeldkatalogFelder lesen und schreiben, mit Quelle und Historie; prüft Typ und Pflicht der aktuellen Phase
AktenbuchEintrag in die Zeitleiste anhängen (Mail, Kommentar, Dokument, Entscheidung, Zeichnung)
BeteiligteBeteiligte mit Rolle hinzufügen und abfragen
FristServiceFrist setzen, verschieben, erledigen; Vorlauf und Eskalation aus der Vorgangsart
ProtokollEintrag 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.

Ereignisausgelöst vonreagiertWirkung
MailEingegangenPosteingangKernVorgang anlegen oder Eintrag anhängen, Team zuweisen
FreigabeErteiltBeschaffungDokumenteAuftragsschreiben oder Vertrag aus Vorlage vorschlagen
UnterlagenNachgefordertBeschaffungPosteingang, KernMail an das antragstellende Dezernat, Frist setzen
ZuschlagErteiltBeschaffungKernAuftragnehmer im Feldkatalog festschreiben
DocumentSubmittedForSignature (DokumentZurZeichnung)Signatur, beim Start eines LaufsDokumente, synchron nach dem CommitFassung 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 istkeinsKennung 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ückzugDokumenteSperre 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 liegtDokumente; ab Etappe 6 VertragSperre aufheben, Schreiben als „gezeichnet“ führen; Fassung und Hash sind die der Ausfertigung. Kein Siegel in Etappe 4 (Entscheidungen)
FristFaelligKernPosteingang, BenachrichtigungErinnerung an Zuständige, Eskalation nach Ablauf

Die Fachmodule

ModulAufgabeeigene Tabellen (Auswahl)Etappe
PosteingangFunktionspostfächer abrufen, Mail zuordnen (Aktenzeichen im Betreff, dann In-Reply-To, sonst neuer Vorgang im Team des Postfachs), Antworten aus dem Vorgang sendenposteingang_postfaecher, posteingang_nachrichten2
Dokumenteversionierte Ablage mit SHA-256, Volltextsuche, Aufbewahrung, Aktenexport; ab Etappe 4 Vorlagen, Textbausteine, Briefkopf, AngebotsstempelDokumente und Fassungen im Dokumentdienst von eCore (ecore_documents, ecore_document_versions); eigene: dokumente_templates, dokumente_template_versions, dokumente_generations, dokumente_text_blocks, dokumente_signing_locks2 und 4
PartnerAnbieter, Vertragspartner, Ansprechpersonen einmal erfasstpartner_partner, partner_personen3
BeschaffungAntragsmaske, Vergabeakte mit Anfrage, Anbietern, Angeboten, Bewertung, Freigabe, Zuschlag; Vergaberegelnbeschaffung_anfragen, beschaffung_angebote, beschaffung_bewertungen, beschaffung_regeln3
SignaturZeichnungsregeln (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 Externesignatur_rules, signatur_settings, signatur_runs, signatur_steps; ab Etappe 5 signatur_invitations4 und 5
VertragRegister mit Beginn, Ende, Kündigungsfrist, Verlängerung, Zuständigkeit, Rückverweis auf die Vergabeakte; berechnet Fristenvertrag_vertraege, vertrag_arten6

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 VertragWas der Kern fragtWer sich einträgt
evorgang.transition_guards (TransitionGuard)Einwand vor einem Übergang, geprüft an der ZielphaseBeschaffung (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 AktenexportDokumente (jede Fassung), Posteingang, Beschaffung (vergabeakte.txt), Signatur (zeichnung.json)
evorgang.discard_contributors (DiscardContributor)Widerspruch und hartes Löschen beim AussondernDokumente, Posteingang, Beschaffung, Signatur (ein offener Lauf hält die Akte)
CaseDocumentStoreDokumente einer Akte lesen, beschreiben, als neue Fassung ablegenDokumente 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

EbeneTrennung
Dateneine Datenbank, jede Tabelle mit organization_id im Mandanten-Scope von eCore; Mandanten-Isolation ist Pflichttest je Endpunkt
AblageDateien unter einem Verzeichnis je Mandant, verschlüsselt mit dem Datenschlüssel des Mandanten; Kontingent je Abo
SchlüsselDatenschlüssel, Postfach-Zugangsdaten, SSO-Zertifikate und Siegel-Identität je Mandant, nie plattformweit
AnmeldungSSO-Konfiguration je Mandant, Zuordnung über Domain oder Mandanten-Adresse; eigene Konten daneben
Dienstepdf 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
SicherungSicherung 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

ContainerHerkunftAufgabe
dbeCore-VorlagePostgreSQL 17
migrateeCore-VorlageMigration und Bootstrap vor jedem Start
api, queue, schedulereCore-VorlageAnwendung, Listener der Ereignisse, Mail-Abruf, Fristenjob, Protokollprüfung
frontend, caddyeCore-VorlageOberfläche, TLS, CSP aus der Anwendung
ollamaeCore-Vorlageselbst gehostetes Modell für Vorschläge (Team, Vorgangsart, Antwortentwurf)
pdfGotenberg 8 wie in der eCore-Vorlage, auf den Digest gepinntHTML 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
updatereforms-cloudnimmt 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

Neue Bausteine in eCore

BausteinWofüram Telefon
EWorkspaceGerüst: einklappbare Navigationsleiste links, Kopfzeile mit Suche und Konto, Arbeitsfläche in voller BreiteApp-Form mit Leiste unten
ESplitViewListe und Detail nebeneinander, Teiler verschiebbar, Breite je Person gemerkt; optional dritter BereichListe, Antippen öffnet das Detail als eigene Seite
EDataTableTabelle mit wählbaren Spalten, Sortierung, Filter, Mehrfachauswahl und Stapelaktionen, Tastaturbedienung, Nachladen bei langen ListenZeilen als EList mit beschrifteten Werten, aus denselben Spaltendefinitionen
EFilterBarFilter als Chips, gespeicherte Ansichten („Meine offenen“, „Frist diese Woche“)Filter im Blatt
EInspectorrechte Seitenleiste für Eigenschaften und NebenformulareBlatt von unten
ETabsReiter innerhalb eines Bereichs (Akte, Dokumente, Beteiligte, Protokoll)segmentierte Auswahl oder Abschnitte
registerShortcutsRegister für Tastaturkürzel, je Seite und global, mit Übersichtohne Wirkung

Was eVorgang daraus macht

AnsichtDesktop
ArbeitskorbVorgangsliste als Tabelle links, Akte rechts; Wechsel per Pfeiltaste, ohne die Liste zu verlassen
AkteZeitleiste in der Mitte, Felder und Beteiligte im Inspector, Dokumentvorschau als dritter Bereich
PosteingangMail links, Zuordnung zum Vorgang rechts, Antwort im selben Blick
VergabeakteAngebote als Vergleichstabelle nebeneinander
VertragsregisterTabelle 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

Querschnitt

ThemaUmsetzung
Revisionjede Freigabe, jeder Zuschlag, jede Zeichnung im hash-verketteten Protokoll; täglicher Prüfjob meldet Brüche
Datenschutzcalhelp 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
AufbewahrungFrist 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öschungExport- und Lösch-Beitrag je Modul über das ModuleManifest
KInur 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
Updateslaufend 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
SchnittstellenREST je Modul hinter der Capability; Finanzbuchhaltung später über E-Rechnung und Bestelldaten

Qualitätssicherung