StreamLine: Ein Low-Code-ERP-System, in dem Sie das Geschäft modellieren und die Plattform den Rest baut
Die meisten ERP-Systeme kommen als festes Set von Modulen. Sie passen Ihre Prozesse an die Software an, und alles, was das Standardmodell nicht abdeckt, wird zum Anpassungsprojekt — geschrieben in einer proprietären Skriptsprache, eingeplant hinter dem Backlog des Herstellers und bei jedem Upgrade neu zu testen. StreamLine geht den umgekehrten Weg. Sie beschreiben, woraus Ihr Geschäft besteht — Kunden, Projekte, Rechnungen, Fahrzeuge, Verträge, was auch immer — und die Plattform generiert die Formulare, Tabellen, Dashboards, APIs, die Suche, den Audit-Trail, die Versionierung und die Echtzeit-Zusammenarbeit darum herum. Aufgebaut auf Angular, NestJS und PostgreSQL, läuft es auf Ihrer eigenen Infrastruktur. Dieser Artikel zeigt die Bausteine, die in einem ERP-System wirklich ungewöhnlich sind.
Ein Datenmodell, das Sie entwerfen — kein Schema, das Sie migrieren
StreamLines Kern ist objektorientiert und spiegelt, wie Entwickler ohnehin denken. Eine Klasse ist eine Vorlage (wie eine Tabelle), eine Klasseneigenschaft ein typisiertes Feld (wie eine Spalte) und ein Objekt eine Instanz (wie eine Zeile). All das definieren Sie in einem visuellen Editor — kein SQL, keine Migrationen, keine Schemadateien.
Jede Eigenschaft hat einen Basistyp, der Speicherung, Validierung und das gerenderte Bedienelement bestimmt: Zahlen (mit optionalen Einheiten wie €, kg, PS), Text, Datums- und Zeitwerte, Enums, Dateien, Booleans, Referenzen auf andere Objekte und Referenzen auf Benutzer. Zu jedem Typ gibt es eine Listenvariante mit optionalen Längengrenzen. Jede Eigenschaft trägt zudem Validierungsregeln — required, unique, regex, numerische und Datumsbereiche, setOnce, automatisch incremented vergebene Kennungen — durchgesetzt sowohl im Browser während der Eingabe als auch verbindlich auf dem Server.
Beziehungen zwischen Klassen sind vollwertige Bausteine des Modells. Eine Object-Eigenschaft ist eine Einzelreferenz (1:1 / n:1), eine ObjectList eine Liste (1:n / n:m) — das Äquivalent zu Fremdschlüsseln, vollständig über die Oberfläche konfiguriert. Eine Klasse Garage mit einer Eigenschaft Autos vom Typ ObjectList → Auto lässt Sie beim Bearbeiten einer Garage Autos auswählen; Auto kann mit einer Referenz Stammgarage zurückzeigen. Das gesamte Modell — Abteilung → Mitarbeiter → Auto → Garage — entsteht per Klick, und sobald eine Klasse existiert, hat sie ein funktionierendes Formular, ein filterbares Raster, eine REST-Schnittstelle und einen Platz in der Suche.
Ein Modell, drei Sichten
Jeder Arbeitsbereich zeigt dieselben Daten in drei sich ergänzenden Sichten, zwischen denen Sie frei wechseln, benannte Varianten speichern und teilen können.
- Entity-View — der Formular-Editor für ein einzelnes Objekt. Jede Eigenschaft wird mit dem passenden Steuerelement gerendert, dazu Schutz vor ungespeicherten Änderungen, eine Versionsanzeige, ein eingebettetes Kommentarpanel, ein Audit-Log-Popup und (für Admins) der Klassendesigner selbst.
- Table-View — ein tabellenähnliches Raster mit Inline-Bearbeitung, Spaltenfiltern, einer globalen Query-Leiste, gespeicherten Layouts, Massenoperationen und transaktionalem CSV-Import.
- Node-View — eine Leinwand im Blender-Stil, auf der Objekte Knoten sind und Referenzen als Verbindungen gezeichnet werden. Sie ziehen Knoten, zeichnen Beziehungen und speichern das Layout. Für Prozessdiagramme, Anlagengraphen oder Organigramme ist die räumliche Anordnung die Information.
Ein Node-Graph-Editor auf Live-Geschäftsdaten ist etwas, das man in einem ERP-System fast nie sieht — und es ergibt sich ganz natürlich aus einem Modell, in dem Beziehungen erstklassig sind.
Eine Abfragesprache, überall dieselbe
StreamLine hat eine einzige typisierte Abfragegrammatik, und sie taucht in der Table-View, der Node-View, in Massenoperationen, in Custom Forms, in Triggern und in der Analytik auf — einmal gelernt, überall einsetzbar.
Bedingungen stehen in eckigen Klammern und werden mit &, |, ! und Klammern kombiniert:
[class=Car] & [Power>120] Autos mit mehr als 120 PS
[Birthday~04.04] alle, die am 4. April geboren sind (jedes Jahr)
[Amount>1.000] Betrag über 1000 (deutsches Locale: Punkt = Tausender)
[Married=y] Ja/Nein-Synonyme: yes · true · 1 · y · ja
!([Status=Closed] | [Status=Archived]) nicht geschlossen oder archiviert
[Power~] „Power ist gesetzt“
[class=Car] & ![Last Service~] Autos ohne Datum der letzten Wartung
Zwei Vergleichsmodi koexistieren: typisierter Vergleich, wenn Sie mit einem Operator beginnen (=, <>, <, <=, >, >=) — schnell, exakt, lokalisierungsbewusst — und ansonsten ein Teilstring-Vergleich ohne Beachtung der Groß-/Kleinschreibung gegen den formatierten Anzeigetext samt Einheiten. Derselbe Ausdruck, der eine Tabelle filtert, begrenzt auch ein Dashboard-Widget und speist den queryObjects()-Aufruf eines Triggers. Eine Grammatik, kein Dialekt-Wildwuchs zwischen Modulen.
Automatisierung ohne separate Integrationsschicht
Hier hört StreamLine auf, eine Datenbank mit Formularen zu sein, und wird programmierbar. Trigger sind TypeScript-Handler, die serverseitig in einer Sandbox laufen, und es gibt sie in vier Ausprägungen:
- Synchrone (
onObjectCreated/Updated/Deleted) laufen innerhalb der auslösenden Transaktion und können sie mitcancel()abbrechen — echte Validierung und Vorprüfungen, die einen fehlerhaften Schreibvorgang blockieren, bevor er committet wird. - Asynchrone (
afterObjectCreated/Updated/…) laufen nach dem Commit für Seiteneffekte — abgeleitete Felder, Benachrichtigungen, klassenübergreifende Updates, ausgehende HTTP-Aufrufe. - Geplante (
onSchedule) feuern per Cron-Ausdruck oder einmaligem Zeitstempel, mit expliziten Nachhol-Strategien (skip,runOnce,runAll) für Auslösungen, die während einer Ausfallzeit verpasst wurden. - Externe API (
onApiRequest) stellen authentifizierte HTTP-Endpunkte bereit. Damit wird das ERP-System selbst zum Integrationsserver: Eine Anfrage trifft auf/api/ext/{Äther}/{pfad}, durchläuft Bearer-Token-Authentifizierung, tokenbezogene Ratenbegrenzung, eine CORS-Allowlist und Größenlimits für den Body, und dann liest Ihr Handler den Body und steuert die Antwort.
Ein synchroner Validierungs-Trigger sind nur ein paar Zeilen:
// onObjectDeleted | Invoice
const status = ctx.event.old?.['Status']?.value;
if (status === 'Active' || status === 'Pending') {
ctx.cancel('Rechnung mit Status "' + status + '" kann nicht gelöscht werden. Erst archivieren.');
return;
}
ctx.continue();
Die Engine erkennt zyklische Trigger-Ketten zur Compilezeit und sichert wiedereintretende Aufrufe zur Laufzeit ab, sodass sich Automatisierung nicht still in einen Ausfall schleifen kann. Handler können Objekte lesen und schreiben, externe APIs mit Timeout und Retry aufrufen, Payloads hashen und in den Audit-Trail schreiben — alles, wofür eine Integration sonst eine eigene Middleware-Schicht braucht, direkt neben den Daten, auf denen sie arbeitet.
Custom Forms stehen neben den Triggern: ein visueller Builder mit bedingter Sichtbarkeit, berechneten Feldern und TypeScript-Submit-Handlern, die Objekte über mehrere Klassen hinweg in einer Transaktion anlegen oder aktualisieren. Ein Formular lässt sich als öffentliche Token-URL-Seite veröffentlichen, sodass Personen ohne Login — Kunden, Bewerber, Außendienst — strukturierte Daten direkt in Ihr Modell übergeben können.
Ende-zu-Ende-Verschlüsselung, die die meisten ERP-Systeme schlicht nicht haben
Jede Eigenschaft kann als verschlüsselbar markiert werden. Dort eingegebene Werte werden im Browser verschlüsselt, bevor sie das Gerät verlassen, als Chiffrat gespeichert und nur in den Browsern benannter Empfänger entschlüsselt. Der Server, die Datenbank und der Dateispeicher auf der Platte sehen niemals Klartext.
Das Verfahren ist Standard-Hybridverschlüsselung — ein Schlüssel pro Wert (AES-256-GCM), der selbst pro Empfänger einmal mit RSA-OAEP-4096 verpackt wird — mit privaten Schlüsseln, die clientseitig per WebCrypto erzeugt und nie hochgeladen werden. Genau die Eigenschaften, auf die es in einem ERP-System ankommt, sind abgedeckt: eine Bankverbindung, ein Gehalt, ein eingescannter Vertrag. Ein geleakter Datenbank-Dump, ein neugieriger Admin oder ein gestohlenes Backup geben nichts preis.
Was das nutzbar macht statt zur Spielerei, ist, wie der Rest der Plattform es respektiert. Verschlüsselte Skalarwerte speichern NULL in der regulären Spalte, sodass Dashboard-Aggregationen (Summe, Durchschnitt, Anzahl) sie überspringen, statt Summen zu verraten; der Volltextindex schließt sie aus; das Audit-Log hält fest, dass sich ein Wert geändert hat, nie den Wert selbst. Sie können Analysen über eine Klasse fahren, in der einige Zeilen verschlüsselt sind, ohne dass diese Zeilen über ein Diagramm Informationen durchsickern lassen. Eine Schlüsselrotation verpackt nur die kleinen Pro-Wert-Schlüssel neu — eine Rotation über zehntausend Werte ist eine einzige Datenbanktransaktion, nicht die Neuverschlüsselung jeder Nutzlast.
Versionierung und Audit — auch des Schemas
Jedes Speichern eines Objekts und jede Änderung an einer Klassendefinition erzeugt eine neue Version. Aus der Entity-View können Sie die Historie über ein schreibgeschütztes Banner durchschreiten, eine Chronik der Änderungen mit Diff-Chips inspizieren und zurückrollen — nicht-destruktiv, wobei aus den alten Daten eine neue Version entsteht. Die Klassenversionierung überträgt dieselbe Idee auf das Schema: Fügen Sie eine Eigenschaft hinzu, befinden Sie sie für falsch, rollen Sie die Klasse zurück — und die Instanzdaten bleiben gemäß den Lebenszyklusregeln der Eigenschaft erhalten. Zeitreisen im Schema sind in betrieblicher Software selten und verändern, wie bereitwillig ein Team sein Modell weiterentwickelt.
Darunter liegt ein Audit-Log, das jedes Anlegen, Ändern, Löschen, Teilen, jede Rechtevergabe und jede Änderung der Verschlüsselungsempfänger mit Akteur, Zeitstempel und einem lesbaren Diff festhält. Für regulierte Kontexte gibt es eine optionale Hash-Kette: Jede finalisierte Rechnung erhält einen SHA-256-Hash aus ihren eigenen unveränderlichen Feldern plus dem Hash der vorherigen Rechnung, sodass die Änderung eines Datensatzes jeden nachfolgenden Hash bricht. Zusammen mit dem Audit-Log und den Flags readOnly / setOnce deckt das die Anforderungen an Unveränderbarkeit und Nachweisbarkeit ab, die die deutschen GoBD an steuerrelevante Dokumente stellen.
Berechtigungen nach dem Prinzip der minimalen Rechte
Der Zugriff ist standardmäßig verweigert und fließt von oben nach unten: Äther → Klasse → Objekt, wobei jede Ebene den geerbten Wert überschreiben kann. Sie können einem einzelnen Benutzer Lesezugriff auf genau ein Objekt geben, ohne ihm die Klasse zu geben — „diesen Vertrag an eine Person senden“ — und Sie können eine gespeicherte Tabellen- oder Node-View mit jemandem teilen, der gar keinen Klassenzugriff hat; die Freigabe ist der Zugriff, beschränkt auf exakt die Zeilen und Spalten, die diese Sicht liefert, und nichts darüber hinaus.
Die Durchsetzung ist Zero-Trust: Berechtigungen werden bei jeder Anfrage geprüft, und jede nicht explizit zugeordnete Route wird abgewiesen statt durchgereicht, damit ein neu hinzugefügter Endpunkt nicht versehentlich zur offenen Tür wird. Eigenschaftsbezogene Rechte gibt es bewusst nicht — sensible Felder schützt man, indem man sie in eine eigene Klasse auslagert und den Zugriff darauf verweigert; danach wird die Referenz überall automatisch ausgeblendet. Eine kleinere Angriffsfläche, die zudem schwerer falsch zu konfigurieren ist.
Analytik auf derselben Engine
Dashboards bestehen aus Widgets, und jedes Widget läuft auf derselben Query-Engine wie die Table-View — ein Filter, dem Sie im Raster vertrauen, bedeutet im Diagramm dasselbe. Über die üblichen Gruppierungs-Dimensionen und Kennzahlen (sum / avg / min / max / Perzentil) hinaus unterstützt das Modell abgeleitete Felder: Arithmetik pro Zeile, berechnet vor der Aggregation — der einzig korrekte Weg, etwas wie SUMME(Stunden × Stundensatz) auszudrücken, denn über das Produkt zweier getrennter Summen kommt man nicht dorthin. Abgeleitete Felder tragen bedingte Logik (IF / THEN / ELSE, Vergleiche, AND / OR / NOT, IS NULL), laufende Summen für kumulative Salden und Pivots, die die Werte einer Dimension in nebeneinanderliegende Spalten verwandeln. Ein Klick auf einen Balken führt direkt zu den Zeilen, die ihn erzeugt haben. Und — wie oben — zählen verschlüsselte Zeilen als NULL, sodass keine Aggregation je preisgibt, was ein Diagramm nicht zeigen darf.
Mehrbenutzer von Haus aus
StreamLine verhält sich wie ein geteilter Arbeitsbereich, nicht wie ein Einzelplatz-Werkzeug. Kommentare hängen an jedem Objekt, mit @Erwähnungen, die benachrichtigen und automatisch abonnieren; Beobachtungslisten, ein In-App-Benachrichtigungsstrom und Live-Präsenz zeigen, wer sonst noch am selben Datensatz arbeitet; und ein pessimistisches Checkout-Locking verhindert, dass zwei Personen sich gegenseitig still überschreiben — Massenoperationen überspringen sogar Zeilen, die ein anderer Benutzer gerade bearbeitet, und melden die Anzahl. Die Massenbearbeitung selbst hat Sicherheitsnetze: alles, was einer Abfrage entspricht, seitenübergreifend aktualisieren oder löschen, mit einer harten Obergrenze, die bei einer zu großen Treffermenge die Ausführung verweigert, mit Rechteprüfung pro Zeile, Lock-Bewusstsein und einem vollständigen Audit-Eintrag pro betroffenem Objekt. Der CSV-Import ist transaktional und pro Zeile validiert — eine fehlerhafte Zeile rollt die ganze Charge zurück.
Gebaut, um dort zu laufen, wo Ihre Daten liegen müssen
Der Stack ist bewusst konventionell — Angular und Tailwind im Client, NestJS auf dem Server, PostgreSQL als Speicher, davor nginx mit TLS. Es lässt sich von einem frischen Debian-Server mit Docker Compose ausrollen; die Datenbank- und Anwendungscontainer bleiben hinter dem Reverse-Proxy an localhost gebunden, und nginx ist der einzige öffentlich erreichbare Prozess. Nichts an der Architektur setzt eine Cloud-Mandantschaft voraus. Für Organisationen, die Kundendaten nicht an Dritte geben dürfen — oder es schlicht vorziehen, es nicht zu tun — läuft StreamLine vollständig on-premise, was genau das ist, was die Ende-zu-Ende-Verschlüsselung und das Zero-Trust-Berechtigungsmodell voraussetzen.
Was unterm Strich bleibt
Standard-ERP-Systeme zwingen Sie, das Geschäft an die Software anzupassen, und behandeln Anpassung, Integration, Verschlüsselung und Audit als separate, später angeflanschte Projekte. StreamLine kehrt das um: Sie modellieren das Geschäft einmal, und Formulare, Abfragen, Dashboards, Automatisierung, Echtzeit-Zusammenarbeit, Versionierung, Audit und Ende-zu-Ende-Verschlüsselung stammen alle aus demselben Kern. Genau die Dinge, die sich nur schwer nachrüsten lassen — Zeitreisen im Schema, clientseitige Verschlüsselung, die selbst Dashboards nicht einsehen können, eine programmierbare Trigger-Schicht mit Compilezeit-Sicherheit, Zero-Trust-Berechtigungen — sind von Anfang an eingebaut.
Wenn Sie abwägen, ob Sie Ihre Prozesse um eine weitere ERP-Plattform mit festen Modulen biegen, oder wenn Sie ein System wollen, das Sie wie Code formen und auf Ihrer eigenen Infrastruktur betreiben können, zeigen wir Ihnen StreamLine gern an Ihrem eigenen Datenmodell. Sprechen Sie uns an.
Gedanken dazu? Einfach direkt schreiben.
Artikel diskutieren