Modulhandbuch in acht Kapiteln
Die vollständige Fassung bleibt auf dieser Seite erhalten. Für fokussiertes Arbeiten stehen dieselben Inhalte zusätzlich als Kapitel bereit.
Referenzstand: 25. Juli 2026
Beispielmodul: myInvoices
Dieses Kapitel ist der verbindliche Golden Path für ein datenbasiertes dbxapp-Modul. Das vollständige Beispiel verwaltet Rechnungen und deren Artikelpositionen. Es verbindet dbxTPL, dbxDB, DD, FD, dbxForm, dbxReport, Modul-Inclusion, ajax.js und confirm.js in einem zusammenhängenden Ablauf.
Das Beispiel ist nicht nur Pseudocode. Die installierbare Referenz liegt unter dbx/modules/myInvoices/. Die Codeblöcke dieses Kapitels erklären die entscheidenden Verträge; die Moduldateien, Fixtures und ausführbaren Tests sind die maßgebliche, gemeinsam gepflegte Fassung.
Die Wörter MUSS, DARF NICHT, SOLL und DARF sind normativ:
- MUSS und DARF NICHT beschreiben den dbxapp-Vertrag.
- SOLL ist die Standardentscheidung; eine Abweichung braucht einen dokumentierten fachlichen Grund.
- DARF bezeichnet eine unterstützte Variante.
Das Zielbild
Die erste Listenstufe zeigt Rechnungen. Direkt unter jeder Rechnungszeile ruft ein serverseitiger Modulmarker die zweite Listenstufe auf:
Die zweite Stufe zeigt die Artikelpositionen genau dieser Rechnung. Ihr Record-Callback berechnet für jede Position Menge * Einzelpreis, setzt die virtuelle Spalte sum und sammelt Centbeträge. Ihr Footer-Callback setzt die Endsumme und berechnet den benötigten colspan aus der tatsächlich von dbxReport aufgebauten Spaltenzahl.
Der [modul=...]-Aufruf ist kein zweiter Browserrequest. Der dbxInterpreter setzt die angegebenen Parameter als geschützte Modulvariablen, ruft den Modulrouter im aktuellen Owner-Kontext auf und ersetzt den Marker serverseitig durch das Ergebnis. Modulzugriff und DD-Rechte bleiben aktiv.
confirm.js entscheidet nur, ob eine Benutzeraktion fortgesetzt wird. ajax.js transportiert den Request und ersetzt HTML. Berechtigung, Validierung, Transaktion und Mutation bleiben vollständig auf dem Server.
Welche Schicht entscheidet was?
| Frage | Zuständige Schicht | Nicht dort ablegen |
|---|---|---|
| Welche Route läuft? | Modulrouter | SQL, Formularaufbau, Markup |
| Welche fachliche Operation läuft? | Service | Layoutdetails |
| Woher kommen Daten? | dbxDB über DD | PDO oder SQL im Modul |
| Wie sehen Tabellen und Rechte aus? | DD | Controller-Arrays |
| Welche Felder zeigt ein Formular? | FD | zweite Tabellenbeschreibung |
| Wie wird eingegeben und validiert? | dbxForm | direkte $_POST-Speicherung |
| Wie werden beide Stufen gelistet? | je ein dbxReport | eigene Tabellenloops |
| Wie wird eine Unterliste eingebettet? | [modul=...]...[/modul] | interner HTTP-Aufruf |
| Wie wird HTML strukturiert? | dbxTPL-Template | große PHP-HTML-Strings |
| Wie werden Zeilenwerte berechnet? | Record-Callback | Zusatzschleife nach dem Report |
| Wie wird die Endsumme gesetzt? | Footer-Callback | JavaScript-Nachberechnung |
| Wer darf mutieren? | Modulzugriff, DD-Rechte, ggf. Action-Token | Confirm-Dialog |
Warum die großen Kernelklassen nicht nach Größe geteilt werden
dbxDB, dbxDD, dbxForm und dbxReport sind stabile Systemfassaden und Pipelines. Ihre Größe folgt ihrer Fähigkeitstiefe:
- dbxDB vereinheitlicht Server, DD-Auflösung, Rechte, Owner-Filter, Transaktionen, Trace, Fehler und Performance.
- dbxDD erweitert den Datenpfad um Schema-, Backup-, Restore- und Transferprozesse.
- dbxForm hält einen vollständigen Formularzustand von FD/DD bis Validierung, Meldung, Submit-Schutz und Rendern.
- dbxReport erweitert dbxForm um Selection-Felder, Pagination, Zeilenaktionen, Auswahlzustand, Callbacks und mehrere Ausgabemodi.
Eine Kernelaufteilung ist nur mit stabiler Fassade, Regressionstests und einer bewiesenen Verantwortungsgrenze sinnvoll. Fachmodule dürfen dagegen echte Fachlogik in Services oder Repositories gliedern. Sie dürfen Kernel-Funktionen nicht durch eigene Methoden nachbauen, die nur dbx() weiterreichen.
Verzeichnisstruktur des Referenzmoduls
Die zwei Tabellen liegen auf demselben DD-Server. Dadurch kann eine Mehrtabellenmutation über eine gemeinsame dbxDB-Transaktion laufen.
Routen- und Sicherheitsvertrag
| Route | Zweck | Zustand ändert sich? | Schutz |
|---|---|---|---|
| dbx_run1=report | Rechnungen, Filter, Pagination | nein | Modul- und DD-Leserecht |
| dbx_run1=positions&invoice_id=17 | eingebettete Positionen | nein | Modul- und beide DD-Leserechte |
| dbx_run1=form&rid=17 | Rechnungskopf bearbeiten | POST ja | dbxForm plus DD-Schreibrecht |
| dbx_run1=delete&rid=17 | Rechnung samt Positionen löschen | ja | Modulrecht, DD-Löschrecht, Action-Token |
| dbx_run1=install | DD-Sync und idempotente Demo-Fixtures | POST ja | Adminrecht und dbxForm |
Normale Navigation, Filter, Report und Positions-Inclusion bleiben tokenlos. Ein Standardformular erhält keinen zusätzlichen dbx_token, weil dbxForm seinen Submit schützt. Bei der schreibenden Delete-URL erkennt dbxApi::action_url() die Kombination aus delete und rid automatisch, bindet die RID und ergänzt den Token. dbxWebApp prüft ihn vor dem Aufruf des Moduls. Eine action_routes-Konfiguration ist dafür nicht nötig.
DD- und Modulrechte beantworten, wer handeln darf. Der Action-Token beweist zusätzlich, dass der mutierende GET aus dem aktuellen Browserkontext stammt. Er ersetzt keine Rechteprüfung.
1. Modulkonfiguration
Datei cfg/config.php:
Die Konfiguration schützt nur den Moduleinstieg und enthält keine doppelte Beschreibung einzelner Standardaktionen. Die automatische Action-Policy bindet das Token an Route und Rechnungs-ID; ein Token für Rechnung 17 gilt deshalb nicht für Rechnung 18. Fachwerte gehören nicht in eine parallele JSON-Datei oder in JavaScript.
2. DD des Rechnungskopfs
Datei dd/invoice.dd.php. Doxygen bindet die tatsächlich ausgeführte DD direkt ein; Dokumentation und Modul können dadurch nicht auseinanderlaufen:
total_gross ist ein fachlicher Snapshot, kein dbx-Systemfeld. Er wird beim Ändern von Positionen innerhalb derselben Fachtransaktion aktualisiert. Die Reportcallbacks formatieren und summieren ihn, verändern ihn aber nicht.
3. DD der Rechnungspositionen
Datei dd/invoiceItem.dd.php. Auch hier ist die ausführbare DD selbst die einzige Quelle der Dokumentation:
Beide DDs enthalten die Systemfelder create_date, create_uid, owner, update_date und update_uid. Diese Werte werden automatisch von dbxDB gesetzt. Das Modul setzt sie weder beim Insert noch beim Update selbst. Genau das ist ein Vorteil der DD-Nutzung. Die DDs folgen dem dbxapp-Exportformat mit expliziten TABLE-, FIELDS- und INDEXES-Abschnitten. Es gibt darin keine Closure oder Hilfsmethode, welche Feldattribute verbirgt.
4. FD für den Rechnungskopf
Datei fd/invoice-form.fd.php:
Die Dokumentation bindet die tatsächlich ausgeführte FD ein. Dadurch können Meldungsschlüssel, Labels und Sprachvertrag nicht von der Implementierung abweichen:
Die FD wählt und ordnet Formularfelder. Sie dupliziert weder DD-Rechte noch automatische Systemfelder. total_gross ist ebenfalls kein Eingabefeld des Kopfformulars, weil die Rechnungssumme aus den Positionen entsteht.
5. Selection-FD des Rechnungsreports
Datei fd/rpt-invoice-selection.fd.php:
Die Optionsliste ist Komfort, keine Sicherheitsgrenze. Der Service prüft Sortierfeld und Richtung zusätzlich gegen feste Allowlists.
6. Kleiner Router
Datei myInvoices.class.php:
Der Router validiert nur die Route und delegiert. Besonders wichtig: Auch der eingebettete [modul=myInvoices]-Aufruf geht durch dieselbe run()-Methode. Es existiert kein Sonderzugriff auf die Positions-DD.
7. Service: zwei Reports, Callbacks und Transaktion
Datei include/myInvoicesService.class.php:
Der vollständige Quelltext wird direkt eingebunden. Er ist damit die verbindliche Referenz für aktive FD-Meldungen, Spaltenlabels, Confirmtexte, Callback-Defaults, Summen und Transaktionen:
Was die Servicefunktionen bewirken
| Funktion | Aufgabe und Wirkung |
|---|---|
| euro() | Formatiert die im Modul bewusst als Integer-Cent geführten Summen einheitlich für die Ausgabe. |
| url() | Baut eine Modulroute und kodiert ausschließlich Querybestandteile. Sie ist Fachlogik für konsistente Routen, kein Alias auf dbx(). |
| form() | Liest über die Kopf-DD, lässt dbxForm FD, Validierung und Submit ausführen und speichert über save_post(). |
| invoice_report_next_record() | Ist der automatische {fid}_next_record-Callback: formatiert den Snapshot, signiert die Delete-Route, sammelt die Seitensumme per spätem add_rep() und setzt den [modul=...]-Aufruf für Stufe zwei. |
| report() | Führt Selection-FD, Allowlist, Count, paginiertes Select und den äußeren table-Report zusammen. |
| invoice_items_report_next_record() | Ist der automatische Positions-Callback: berechnet quantity * unit_price, setzt die virtuelle Spalte sum und aktualisiert die Endsumme per add_rep(). |
| positions() | Prüft die geschützte invoice_id, liest Kopf und Positionen über DDs und rendert eine eigenständige, nicht paginierte Reportinstanz. |
| delete() | Wird erst nach zentraler Policy-Prüfung aufgerufen, validiert die RID und löscht Positionen plus Kopf unter DD-Rechten atomar über begin(), commit() und rollback(). |
Die Callbackmethoden sind echte Aufbereitungslogik. Sie sind ausdrücklich keine Modulmethoden, die nur dbx()-Funktionen weiterreichen.
Nach einem erfolgreichen Insert übernimmt form() die von dbxForm gesetzte _rid in Action und Titel. Ein weiterer Submit aktualisiert deshalb denselben Datensatz, statt unbeabsichtigt einen zweiten Insert zu versuchen.
Callback-Lebenszyklus
- dbxForm::init() übernimmt den direkten Modul-/Service-Aufrufer als Callback-Owner. set_callback_owner($this) ist im Normalfall unnötig.
- Die Formular-ID wird zur Callback-ID: invoice-report sucht automatisch invoice_report_next_record(), invoice-items-report entsprechend invoice_items_report_next_record().
- Ein expliziter Callback-Setter ist nur nötig, wenn bewusst von dieser Namenskonvention abgewichen wird.
- add_rep() darf auch während des Record-Laufs Werte setzen. Die von dbxForm bereitgestellte replaces()-Pipeline wendet sie im Footer mit dem zuletzt akkumulierten Wert an.
- {rpt:col_count} umfasst alle Reportspalten. {rpt:colspan} umfasst automatisch alle Spalten außer der letzten Wertespalte.
8. Formtemplate
Datei tpl/htm/invoice-form.htm:
Ohne JavaScript funktioniert derselbe Submit normal. Mit dbxAjax ersetzt die Antwort nur dbxForm_{i} und initialisiert die enthaltenen Features neu.
9. Äußerer Rechnungsreport
Datei tpl/htm/invoice-report.htm:
[rpt:row] erzeugt im table-Modus Header und Datenzellen aus _rflds. Die zweite <tr> gehört zur gleichen Rechnung. Ihr colspan="{rpt:col_count}" deckt auch dann alle Spalten ab, wenn sich der Report später ändert. {positions_call} wurde vorher vom Record-Callback gesetzt und wird nach dem Reportlauf vom dbxInterpreter ausgeführt.
Der Footer verwendet {rpt:colspan}. dbxReport berechnet damit automatisch „alle Spalten außer der letzten Wertespalte“. Eine eigene Footer-Methode ist nicht erforderlich; der Record-Callback aktualisiert die Endsumme spät über add_rep().
10. Eingebetteter Positionsreport
Datei tpl/htm/invoice-items-report.htm:
Der Positionsreport enthält bewusst kein eigenes <form>: Er liegt innerhalb des Formulars des äußeren Reports, und verschachtelte HTML-Formulare wären ungültig. Er besitzt trotzdem eine eindeutige {i}-ID und eine vollständige dbxReport-Pipeline.
Weil positions() keine Pagination aktiviert, sieht der automatische invoice_items_report_next_record()-Callback jede Position der Rechnung. Der per add_rep() gesetzte Footerwert ist damit die vollständige Rechnungssumme der geladenen Positionen, nicht nur eine Seitensumme.
11. Zeilenaktionen mit Confirm und Ajax
Datei tpl/htm/invoice-row-action.htm:
Der Ablauf bleibt systemweit einheitlich:
- confirm.js fragt nur bei der markierten Mutation nach.
- Bei „Nein“ entsteht kein Request.
- Bei „Ja“ übernimmt ajax.js den vorhandenen Link.
- dbxWebApp prüft vor dem Modulstart Route, RID-Bindung und Token.
- dbxDB startet eine Transaktion auf dem gemeinsamen DD-Server.
- Positionen und Rechnung werden über ihre DDs gelöscht und getraced.
- Bei einem Fehler rollt rollback() beide Schritte zurück.
- Der neu gerenderte Report ersetzt denselben Ajax-Root.
12. Was die zweistufige Inclusion technisch bewirkt
Für jede sichtbare Rechnung erzeugt invoice_report_next_record() genau einen Marker:
Der Interpreter:
- prüft den Modulzugriff;
- setzt dbx_run1 und invoice_id als geschützte Modulvariablen;
- ruft erneut den kleinen Router auf;
- lässt positions() Kopf und Positionen über dbxDB und DD prüfen;
- ersetzt den Marker durch den fertigen Positionsreport.
Das Muster eignet sich für eine begrenzte äußere Seitengröße. Bei 20 Rechnungen entstehen 20 gezielte Positionsabfragen mit verschiedenen invoice_id-Werten; das sind keine identischen Resultsets, die ein einfacher Ergebniscache zusammenlegen könnte. dbxDB kann weiterhin DD-Metadaten, Verbindungen und dafür vorgesehene DD-Caches zentral nutzen.
Bei sehr großen Seiten SOLL die Unterliste erst beim Öffnen eingebettet oder in einem fachlichen Batch über dbxDB vorgeladen werden. Direkte PDO-Abfragen oder ein zweiter Browser-API-Weg sind keine Optimierung.
13. DD-Sync, Fixtures und Installation
Beide DDs werden über den vorhandenen Admin-DD-Sync oder einen explizit geschützten Installationspfad synchronisiert:
Schemaänderungen laufen nicht bei jedem normalen Request. Der ausführbare Service zeigt unter dbx_run1=install zunächst nur ein dbxForm. DD-Sync und Fixtures starten erst nach dessen gültigem POST. Deshalb braucht die Installationsroute keinen zusätzlichen dbx_token: dbxForm schützt bereits den Submit, und die Route verlangt zusätzlich Adminrecht.
include/myInvoicesFixtures.class.php berechnet die Demo-Snapshots aus den zugehörigen Positionen und schreibt sämtliche Fachdaten über dbxDB. Sie übergibt keine Auditfelder. Alle Demo-Rechnungen besitzen eine eindeutige DBX-DEMO-*-Nummer; ein wiederholter Lauf überspringt vorhandene Fixtures und überschreibt keine Benutzerdaten.
Für Automation steht derselbe Installer ohne zweiten Datenpfad per CLI bereit:
14. Direkter Aufruf und Inclusion
Direkt:
Eingebettet:
Der Positionsaufruf wird normalerweise vom Rechnungs-Record-Callback erzeugt, kann für eine reine Detailansicht aber auch bewusst eingesetzt werden:
Templates verwenden {i} für eindeutige Instanzen. Modulparameter werden mit get_modul_var() und passenden Regeln gelesen.
15. Verbindliche Arbeitsanweisung
Für jedes neue oder wesentlich erweiterte datenbasierte Modul gilt:
- Fachzweck, Benutzergruppen, lesende und mutierende Routen aufschreiben.
- Beziehungen und Transaktionsgrenzen der DDs festlegen.
- DDs im direkt lesbaren dbxapp-Exportformat anlegen: TABLE, FIELDS und INDEXES mit expliziten $table[...], $field[...], $fields[]=$field, $index[...] und $indexes[]=$index; keine $addField-Closure.
- Automatische dbxDB-Systemfelder nicht im Modul nachbauen.
- Pro Formularsicht und Reportfilter eine passende FD anlegen. Jede FD besitzt strukturgleiche deutsche, englische und spanische $messages; Formulare und Reports beziehen sichtbare Fachtexte mit load_fd_messages(), get_fd_message() und format_fd_message() daraus.
- Router auf validierte Routenauswahl und Delegation begrenzen.
- Daten ausschließlich über dbxDB und DD lesen oder schreiben.
- Standard-CRUD mit dbxForm::save_post() umsetzen.
- Listen, Unterlisten, Pagination und Selection über dbxReport umsetzen.
- Callback-Defaults {fid}_{event} verwenden; nur bei bewusster Abweichung einen Callback explizit registrieren.
- Berechnete Ausgabefelder im {fid}_next_record-Callback setzen und akkumulierte Footerwerte dort spät per add_rep() aktualisieren.
- {rpt:col_count} für alle Spalten oder {rpt:colspan} für alle Spalten außer der letzten Wertespalte verwenden.
- [modul=...] für serverseitige Modul-Inclusion verwenden; keinen internen HTTP-Request bauen.
- Requestsortierung gegen feste Feld- und Richtungslisten prüfen.
- HTML in dbxTPL-Templates legen. Werte nicht pauschal escapen; nur eine tatsächlich rohe, außerhalb der dbx-Ausgabepipeline liegende Fremdeingabe wird am konkreten HTML-Kontext behandelt.
- Ajax und Confirm deklarativ über vorhandene Klassen und Attribute nutzen.
- Schreibende GETs mit dem Action-Token schützen; lesende GETs bleiben tokenlos.
- Mehrtabellenmutationen über dbxDB::begin(), commit() und rollback() atomar halten.
- Direkten Request, Inclusion, Ajax, Rechte, Summen und Mehrfachinstanzen testen.
- Doxygen, Modul-README und reale Codeverweise gemeinsam aktualisieren.
- In Deutsch, Englisch und Spanisch jeweils Formularlabels, Reportspalten, leere Zustände, Validierungs-, Erfolgs-, Fehler- und Confirmmeldungen prüfen. Gespeicherte Werte einer einsprachigen Tabelle gelten dabei als Daten und nicht als Oberflächenübersetzung.
16. Mindesttestmatrix
| Prüfung | Erwartung |
|---|---|
| Rechnungsreport direkt | korrekte Gesamt- und Trefferzahl |
| Rechnungsreport eingebettet | getrennte Modul- und DOM-Zustände |
| Positionsmarker | richtige invoice_id, keine fremden Requestwerte |
| Positions-DD ohne Recht | keine Daten trotz bekanntem Marker |
| Summenspalte | quantity * unit_price, kaufmännisch auf Cent gerundet |
| Positionsfooter | Summe aller Positionen, dynamischer colspan |
| Rechnungsfooter | Summe der sichtbaren Rechnungsseite |
| gespeicherter Snapshot | total_gross entspricht Positionsendsumme |
| Filter, Sortierung, Pagination | gleiche WHERE für Count und Select |
| Formular ohne JavaScript | normaler Submit funktioniert |
| Formular mit Ajax | nur eigenes dbxForm_{i} wird ersetzt |
| Insert und Update | DD-Rechte, Feldprüfung, automatische Systemfelder, Trace |
| Delete: „Nein“ | kein Request, keine Mutation |
| Delete: „Ja“ | Kopf und Positionen werden gemeinsam gelöscht |
| Fehler beim zweiten Delete | vollständiger Rollback |
| Delete ohne/falschen Token | keine Mutation |
| zwei Reportinstanzen | eindeutige {i}-IDs und getrennte Callback-Summen |
| SQLite/MySQL-Wechsel | kein Fachcode muss geändert werden |
| Doxygen-Build | keine fehlende Seite oder Referenz |
Ausführbare Nachweise des Referenzmoduls
Die Mindestmatrix wird durch zwei versionierte Tests und einen dokumentierten Browserablauf konkretisiert:
Der Architekturtest verbietet direkten PDO-/SQL-Zugriff, triviale dbx()-Wrapper, manuell gesetzte Auditfelder und abstrahierte DD-Feld-Closures. Er verlangt die expliziten TABLE-, FIELDS- und INDEXES-Abschnitte. Der Integrationstest prüft DD-Sync, idempotente Fixtures, automatische Systemfelder, Snapshot- und Callback-Summen, falschen Action-Token, erfolgreichen Mehrtabellen-Delete und einen erzwungenen Rollback nach dem ersten Löschschritt.
Der am 25. Juli 2026 ausgeführte Browsernachweis umfasst:
| Ablauf | Nachweis |
|---|---|
| Installations-POST | dbxForm-Ajax, zweiter Lauf meldet 3 vorhandene Fixtures |
| direkter Report | 3 Rechnungen und 3 serverseitig eingebettete Positionsreports |
| Summen | 47,30, 66,00, 129,50 EUR; Seitenfooter 242,80 EUR |
| Ajax-Insert | Erfolgsmeldung und anschließend gespeicherte RID |
| Submit ohne JavaScript | normaler HTTP-POST speichert und wechselt auf die RID |
| Confirm „Nein“ | Dialog schließt, Testrechnung bleibt vorhanden |
| falscher Token | Ablehnungsmeldung, Testrechnung bleibt vorhanden |
| Confirm „Ja“ | Kopf und Positionen verschwinden gemeinsam |
| Browserkonsole | keine Fehler oder Warnungen im finalen Reportlauf |
Der reproduzierbare Ablauf und seine stabilen Selektoren stehen in dbx/modules/myInvoices/tests/README.md.
17. Häufige Fehlentscheidungen
| Falsch | Richtig |
|---|---|
| PDO oder SQL im Service | dbxDB mit DD-Referenz |
| $addField-Closure in der DD | explizite $field[...]- und $index[...]-Definitionen im dbxapp-Exportformat |
| private db()-/tpl()-Aliasfunktionen | dbx()->get_system_obj(...) direkt am Einsatzort |
| create_date, create_uid, owner manuell setzen | von dbxDB automatisch setzen lassen |
| jeden DD-/Reportwert vorsorglich escapen | vorhandene Ausgabe- und Formatpipeline nutzen |
| Positions-HTML im Callback zusammensetzen | Marker setzen, Struktur in dbxTPL |
| Unterliste per internem HTTP/fetch laden | [modul=...]...[/modul] |
| eigene Schleife für Tabellen und Pagination | dbxReport |
| Summe in JavaScript nachrechnen | {fid}_next_record plus spätes add_rep() |
| unnötige Owner-/Callback-Setter | dbxForm-Owner- und {fid}_{event}-Defaults |
| eigene Footer-Methode nur für str_replace() | add_rep() und geerbte replaces()-Pipeline |
| fester colspan="6" | {rpt:col_count} bzw. {rpt:colspan} |
| alle Positionen nur für den Report doppelt laden | im Record-Callback des vorhandenen Reports summieren |
| Kopf löschen, Positionen stehen lassen | gemeinsame dbxDB-Transaktion |
| window.confirm() | dbxConfirm und confirm.js |
| eigener fetch()-Handler für HTML | dbxAjax und ajax.js |
| Action-Token auf jedem GET | nur mutierende GET-Aktionen tokenisieren |
| ungefiltertes ORDER BY aus dem Request | Allowlist im Service |
| Kernelklasse wegen Zeilenzahl teilen | nur nach bewiesener Verantwortungsgrenze |
Weiterführende Detailkapitel
- Module entwickeln — Modulvarianten und Erweiterungsmuster
- dbxTPL Leitfaden — Templates, Marker, Slots und Inclusion
- dbxDB, dbxDD und FD — Daten-, DD- und FD-Referenz
- dbxForm — vollständige Formularpipeline
- dbxReport — vollständige Reportpipeline
- JavaScript-Systemlibs — Browserlibs und deklarative Attribute
- Sicherheit, Integrität und Performance — Sicherheitsnachweise
- Verbindliche Regeln fuer KI-Agenten — verbindliche Regeln für KI-Agenten