Skip to content

NavBuilder 2.0: ID-only data model, Vue 3 editor, new item types, security fixes - #24

Open
ynamite wants to merge 20 commits into
masterfrom
v2
Open

NavBuilder 2.0: ID-only data model, Vue 3 editor, new item types, security fixes#24
ynamite wants to merge 20 commits into
masterfrom
v2

Conversation

@ynamite

@ynamite ynamite commented Aug 14, 2026

Copy link
Copy Markdown
Member

NavBuilder 2.0

Vollständige Modernisierung des Addons — Datenmodell, Backend-UI, Frontend-Rendering und Sicherheit.

Breaking Changes (mit automatischer Migration)

  • Datenmodell v2: Artikel-Einträge speichern nur noch die Artikel-ID — Namen und URLs werden zur Laufzeit in der aktuellen Sprache aufgelöst. update.php migriert alle v1-Datensätze automatisch (idempotent) und sichert das ursprüngliche JSON in einer structure_legacy-Spalte.
  • grouptext (ein Decode-Alias hält Altdaten funktionsfähig), getStructure()/get() sind deprecated, funktionieren aber weiter als BC-Shims.
  • Abhängigkeiten yform und phpmailer entfernt. Benötigt REDAXO ≥ 5.18, PHP ≥ 8.1.

Neu

  • Vue-3-Backend-Editor (mitgeliefert in Version 3.5.13, kein Build-Step, kein CDN, kein jQuery): natives Drag & Drop + Tastatursteuerung, Artikel-Combobox mit Live-Suche, intelligentes Link-Feld (automatische Erkennung von URL / E-Mail / Telefon), Medienpool-Auswahl, Typ-Umwandlung direkt im Eintrag (Artikel | Link | Medium | Text) mit Schutz vor Datenverlust.
  • Neue Eintragstypen: media (Medienpool-Datei, per Dateiname gespeichert, umbenennungssicher) und text (Beschriftung + optionaler HTML-Inhalt für Mega-Menüs, gerendert über ein überschreibbares fragments/navbuilder/text.php).
  • Sichtbarkeit pro Eintrag und Sprache (hiddenIn) sowie maximale Tiefe pro Navigation (von Admins gesetzt, serverseitig erzwungen).
  • Fragment-basiertes Rendering (rex_navbuilder::render() / ::tree()) mit active/activePath, überschreibbaren Fragmenten und NAVBUILDER_INIT-Extension-Point (z. B. um einen WYSIWYG-Editor an Text-Einträge anzubinden).

Behoben / Sicherheit

  • CSRF-Schutz für Speichern/Löschen/Duplizieren und alle API-Endpunkte
  • Stored-XSS-Fixes (konsequentes rex_escape), URL-Schema-Allowlist (javascript: etc. wird abgelehnt)
  • Backend-Assets laden nur noch auf der eigenen Addon-Seite
  • Offline-Artikel gelangen nicht mehr über getStructure() nach außen
  • Leere Strukturen zerschießen nicht mehr das JavaScript der Backend-Seite
  • de/en-Übersetzungen (die Sprachdateien waren leer), README neu geschrieben (DE primär, EN enthalten), CHANGELOG ergänzt

Closes #22, closes #23, closes #7.

Die Version bleibt bis zum Tagging 2.0.0-dev.

🤖 Generated with Claude Code

ynamite and others added 20 commits August 14, 2026 18:01
Complete modernization of the addon. Highlights:

- Data model v2: article items store only the article id (names/URLs resolve
  live per language); idempotent v1 migration with structure_legacy backup
- New item types: media (mediapool file by name) and text (label + optional
  HTML body for mega menus, overridable text.php fragment), group->text rename
  with decode alias; in-place type conversion in the editor
- Per-item per-language visibility (hiddenIn) and per-navigation maxDepth
  (admin-set, server-enforced)
- Vue 3 backend editor (vendored 3.5.13, no build step, no CDN, no jQuery):
  native drag & drop, keyboard controls, article combobox with live search,
  smart link input (URL/email/phone), linkmap + mediapool popup bridges
- Security: CSRF on all mutations, consistent escaping, URL scheme allowlist,
  page-scoped assets, offline-article filtering
- Fragment-based rendering with active/activePath; deprecated get()/
  getStructure() kept as BC shims; REX_NAVBUILDER[] still works
- yform/phpmailer dependencies removed; de/en translations; German README

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bind selection handlers to the popup windows returned by the core open functions, preventing missed callbacks and duplicate handlers when popups are reused.
Allow media entries to open in a new window, including editor controls, rendering, validation, and documentation.
Data loss: structure columns are MEDIUMTEXT with a byte guard in save()
(a legal tree overflowed TEXT's 64KB and truncated JSON decoded as an
empty navigation), strict decode rejects unparseable JSON, updating a
deleted row is refused, a failed save returns the posted tree verbatim
(including the refused item) and keeps the posted name, and page-Save
applies every open edit form first — an invalid form blocks the submit.

Upgrade path: update.php preflights v1 names (aborts on >191 chars,
logs non-slug names) and the migration reports its dropped-item count;
the silent item-overflow drop is logged now.

Hardening: navbuilder[] permission on the autocomplete API, mediapool
declared as dependency, CSP nonce on the init script, request-ID guard
against out-of-order autocomplete responses.

Structure: pure editor logic extracted to navbuilder-core.js (frozen
window.NavBuilderCore, Node-testable) — which caught that the client
refused host:port urls the server accepts; PHPUnit suite for the schema
surface with REDAXO stubs; CI workflow (PHP lint + PHPUnit, node checks
+ tests); unused Navigation::all() removed; Vue bumped to 3.5.41.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adopted from block_peek: builds a cleaned release archive (dev tooling
excluded), attaches it to the GitHub release, then publishes to
redaxo.org via installer-action. No composer step — the addon has no
runtime dependencies.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The seo blob may store non-ASCII raw or as \u-escapes depending on the
writer's json_encode flags — search now tries both forms. url 2.x stores
scheme-relative URLs; the `absolute` shape borrows the configured
server's scheme so sitemap/feed consumers get a full URL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update interne Links im navbuilder Versionsbedingung verhindert Update von YForm auf v5.0 Abgleich / Artikel (Kategorie) entfernt - Whoops

1 participant