Zum Inhalt

Architektur-Überblick

KCForms besteht aus drei Teilen: einem Frontend, das im Browser läuft, einem Spring-Boot-Backend, das Formulare definiert, ausliefert, validiert, druckt und speichert, und einer Haupt-Datenbank, in der sowohl die Formular-Definitionen als auch die ausgefüllten Datensätze liegen.

Als Haupt-Datenbank kann KCForms MySQL 8, PostgreSQL 16, Oracle oder Microsoft SQL Server nutzen. Welche es ist, erkennt das Backend beim Start an der JDBC-Adresse. Details stehen unter Datenbank.

Für die Entwicklung kommen dazu:

  • MailPit als lokaler SMTP-Fänger — Mail-Skripte erreichen in der Entwicklung nie echte Empfänger.
  • Bind-Mounts für Logs, das Skript-Dateisystem, Assets, Datei-Bibliotheken und den Formular-Export. Alles, was im Container entsteht, ist direkt im Explorer bzw. Finder sichtbar.

Komponentenbild

flowchart LR
    subgraph Browser
        FE["Frontend<br/>React + Vite<br/>TypeScript, Tailwind"]
    end
    subgraph Server
        BE["Backend<br/>Spring Boot 3.3<br/>Java 21, GraalVM JS<br/>PDFBox + Batik"]
    end
    DB[("Haupt-Datenbank<br/>MySQL / PostgreSQL /<br/>Oracle / SQL Server")]
    FS[["Bind-Mounts<br/>logs · fs · assets ·<br/>script-libs · forms-export"]]
    MAIL["MailPit (SMTP)<br/>UI :8025"]
    EXT["Externe Systeme<br/>LDAP · JDBC · HTTP/SOAP"]

    FE -- "HTTPS / JSON" --> BE
    BE -- JDBC --> DB
    BE --- FS
    BE -- SMTP --> MAIL
    BE <--> EXT

Im Betrieb gibt es zwei Varianten:

  • Docker: ein fertiges Paket mit Tomcat und Datenbank — siehe Installation mit Docker.
  • WAR auf Tomcat 10: Frontend und Backend in einer Datei ROOT.war (gebaut mit Dockerfile.war); das Backend liefert die Oberfläche unter / selbst aus.

Welche Daten liegen wo?

KCForms folgt dem Prinzip „eine Tabelle pro Formular". Beim Anlegen oder Speichern einer Formular-Definition gleicht das Backend die zugehörige Tabelle mit den Feldern des Schemas ab (fehlende Spalten kommen dazu). Das hat zwei Vorteile:

  1. SQL-Direktzugriff — die ausgefüllten Daten lassen sich ohne Umweg über JSON-Spalten auswerten.
  2. Änderungen bleiben lokal — ein neues Feld betrifft nur die Tabelle dieses einen Formulars.
Tabelle Inhalt
form_<id> ausgefüllte Datensätze eines Formulars
form_<id>_<feld> Detail-Tabellen (kc:childTable); bei tiefer Verschachtelung form_<id>_<feld>_<unterfeld>
form_definition Schema, Skripte, Metadaten der Formulare
form_version_snapshot eingefrorene Formular-Stände (Versionierung)
form_attachment Datei-Anlagen
form_property Properties je Formular und global
section_def, section_snapshot Section-Repository (zentrale Feldgruppen)
USERS, GROUPS, USER_GROUPS Benutzer und Gruppen
permissions, group_permissions, form_acl Rechte
auth_script Skripte für die Anmeldung per Skript
app_settings Laufzeit-Einstellungen (Mail, Anmeldung, Vorgaben)
audit_event, form_audit_log Protokoll (Anmeldungen, Änderungen)
admin_script gespeicherte Skripte der Skript-Konsole
mail_outbox E-Mail-Ausgang (Warteschlange mit Wiederholung)
scheduled_job, scheduled_job_run Zeitplaner
id_encoder Tokens für Ad-hoc-Links

Groß- und Kleinschreibung

USERS, GROUPS und USER_GROUPS heißen aus historischen Gründen in Großbuchstaben. Auf MySQL spielt das keine Rolle; auf den anderen Datenbanken kümmert sich die Dialekt-Schicht darum.

Skripting im Backend

Skripte sind JavaScript und laufen im Backend in einer GraalVM-Sandbox. Ein Skript sieht nur die Objekte, die KCForms ihm mitgibt (ctx, db, mail, fs, http …). Beliebige Java-Klassen nachladen, direkt auf Dateien oder das Netz zugreifen oder Threads starten kann es nicht — Dateien und HTTP gehen nur über die freigegebenen Bindings mit ihren eigenen Grenzen (Sandbox-Ordner, Adress-Freigabeliste). Jeder Lauf hat zudem ein Zeitlimit. Das ist die zentrale Sicherheitslinie.

Hook / Art Wann läuft er?
onLoad Formular wird geöffnet (Vorbelegung, Daten ziehen)
onFieldChange ein Feld hat seinen Wert geändert
onValidate vor dem Speichern — Geschäftsregeln
onBeforeSave / onAfterSave rund um das Speichern (vorher mit Veto, nachher mit ctx.isNew)
onSubmit nach dem Speichern — Mails, PDFs, Dateiausgabe
onBeforeDelete / onAfterDelete rund um das Löschen
eigene Hooks über Schaltflächen (kc:button) aufrufbar
Anmelde-Skripte bei der Anmeldung per Skript (scriptLogin)
Jobs vom Zeitplaner gestartet
REST-Services eigene HTTP-Endpunkte — siehe REST-Services

Reihenfolge und Details: Lifecycle-Hooks und Scripting-Überblick.

Formular-Editor

Der Formular-Editor (im Quelltext „Form-Studio") ist die Oberfläche, in der Formulare entstehen. Damit legt ein Formular-Autor ohne neues Deployment Felder an, ordnet sie, stattet sie mit Lookups, Pickern, Sichtbarkeitsregeln, Berechnungen und Skripten aus und legt das Druckbild fest. Beim Speichern gleicht das Backend sofort die Datenbank-Tabelle ab — ein neues Feld hat unmittelbar seine Spalte.

Sicherheits-Schichten

flowchart TB
    B["Browser"] --> API["/api/**"]
    API --> SS["Spring Security"]
    SS --> AUTH["Anmelde-Strategie<br/>dbLogin · fixedLogin · scriptLogin ·<br/>bankid · oidc"]
    AUTH --> RBAC["Rollen und Rechte<br/>ROLE_* (Gruppen) + PERM_* (Berechtigungen)"]
    RBAC --> ROW["Formular- und Datensatz-Ebene<br/>Formular-Freigaben (form_acl),<br/>eigene Datensätze; Admin mit scope=all"]
  • Anmeldung: austauschbare Strategien — siehe Anmeldung.
  • Autorisierung: Gruppen werden zu Spring-Authorities mit dem Präfix ROLE_*, Berechtigungen zu PERM_*. Ein Admin erhält automatisch alle PERM_*.
  • Datensatz-Ebene: Listen zeigen die eigenen Datensätze; ein Admin sieht mit ?scope=all alle.

Was läuft beim Start?

  1. Die Datenbank ist erreichbar; das Backend erkennt den Hersteller an der JDBC-Adresse.
  2. Flyway spielt das Kern-Schema ein (db/migration/<hersteller>/). Auf MySQL ergänzen schema.sql und SchemaMigrations zusätzlich fehlende Tabellen und Spalten — beides ist idempotent.
  3. Seeder legen Standard-Rechte, Standard-Gruppen, Baukasten-Elemente und — falls eingeschaltet — Demo-Formulare an.
  4. FormTableInitializer legt für jedes Formular die Tabelle an oder ergänzt fehlende Spalten.