Zum Hauptinhalt springen
Schneespur
Dokumentation durchblättern

Module entwickeln

Architektur-Überblick

Wie das Schneespur-Modulsystem aufgebaut ist: Tech-Stack, das Zwei-Marken-Modell, die Verzeichnisstruktur und das Registry-Prinzip, auf dem jede Erweiterung beruht.

Bevor Sie ein Modul schreiben, hilft ein Bild davon, woran es sich anlehnt. Schneespur ist eine Laravel-Anwendung, und Module sind keine Fremdkörper darin, sondern reguläre Laravel-ServiceProvider, die ihre Fähigkeiten an klar definierten Stellen anmelden. Diese Seite zeigt diese Stellen.

Tech-Stack

SchichtTechnologie
FrameworkLaravel 11+ (PHP 8.2+)
DatenbankMySQL / MariaDB (Produktion). SQLite :memory: nur für die Test-Suite
FrontendBlade-Templates, Tailwind CSS, Alpine.js
PDFDomPDF (austauschbar über PdfRendererRegistry)
GPSOwnTracks-Anbindung (MQTT/HTTP)
WetterOpenMeteo, BrightSky, Met Norway (austauschbar)
AuthLaravel-Standard + eigener Customer-Guard für das Portal
UpdatesSignierte Pakete vom Update-Server, geprüft mit libsodium

Die meisten dieser Bausteine sind über eine Registry austauschbar — genau das ist der Hebel, an dem Module ansetzen. Welche das im Einzelnen sind, steht weiter unten und ausführlich unter Registries.

Zwei-Marken-Modell

Schneespur und Wintertrace sind dieselbe Codebasis. Die Marke wird zur Installationszeit über die Locale bestimmt:

  • deutsche Locale → Schneespur
  • jede andere Locale → Wintertrace

Die Marke liegt in der Einstellung app_brand und wird über zwei globale Helfer verfügbar gemacht:

brand_slug(); // 'schneespur' oder 'wintertrace'
brand();      // 'Schneespur' oder 'Wintertrace'

Übersetzungsdateien laufen über einen BrandedTranslator, der den Markennamen automatisch einsetzt. Ein Modul muss sich um die Marke nur dann kümmern, wenn es selbst sichtbaren Text mit dem Produktnamen erzeugt — sonst nimmt der Translator die Arbeit ab.

Verzeichnisstruktur der Anwendung

So ist die Laravel-Anwendung aufgebaut. Für die Modul-Entwicklung sind vor allem app/Services/Extension/ (die Registries) und modules/ (das Installationsverzeichnis) relevant:

schneespur/                          ← Laravel-Anwendungswurzel
├── app/
│   ├── Console/Commands/            ← Artisan-Commands (ModulesList, ModulesSync, …)
│   ├── Enums/                       ← UserRole, JobType, WeatherMoment
│   ├── Events/                      ← Domain-Events (JobCompleted, CustomerCreated, …)
│   ├── Exceptions/
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── Admin/               ← Admin-Controller
│   │   │   ├── Auth/                ← Authentifizierung
│   │   │   ├── Driver/              ← Fahrer-Ansichten
│   │   │   ├── Portal/              ← Kundenportal
│   │   │   └── Api/                 ← OwnTracks-API
│   │   ├── Middleware/              ← Auth-Guards, Rollen-Durchsetzung
│   │   └── Requests/                ← Form-Validierung
│   ├── Jobs/                        ← Queue-Jobs (FetchWeather, SendCustomerReportEmail)
│   ├── Listeners/                   ← Event-Listener
│   ├── Mail/                        ← Mailable-Klassen
│   ├── Models/                      ← Eloquent-Modelle
│   ├── Policies/                    ← Autorisierungs-Policies
│   ├── Providers/                   ← AppServiceProvider (Setup der Core-Registries)
│   └── Services/                    ← Geschäftslogik
│       └── Extension/               ← ALLE Erweiterungs-Registries (Kern des Modulsystems)
├── config/
│   └── schneespur_modules.php       ← Konfiguration des Modulsystems
├── modules/                         ← Installationsverzeichnis der Module
│   └── example/                     ← mitgeliefertes Referenzmodul
├── resources/
│   ├── views/layouts/              ← admin.blade.php, driver.blade.php, portal.blade.php
│   └── lang/                        ← Core-Übersetzungen (de, en)
├── public/
│   └── modules/                     ← Symlinks auf die dist/-Verzeichnisse der Module
└── storage/
    └── app/                         ← u. a. der Modul-Katalog-Status

Neben Services/Extension/ liegen weitere Service-Ordner, die jeweils ein Interface plus zugehörige Registry bündeln (etwa Weather/, Storage/, Notification/, Pdf/, Scheduler/, Backup/, Diagnostic/). Diese Interfaces sind die Verträge, gegen die ein Modul implementiert.

Erweiterungs-Architektur

Das Modulsystem beruht auf einem Registry-Muster. Der Core definiert abstrakte Registries und Interfaces; Module liefern konkrete Implementierungen und melden sie während des Boots an.

┌──────────────────────────────────────────────────┐
│                  AppServiceProvider               │
│  (registriert alle Registries als Singletons,     │
│   registriert die Core-Implementierungen)         │
└──────────────┬───────────────────────────────────┘
               │ boot()

┌──────────────────────────────────────────────────┐
│                  ModuleManager                    │
│  discover() → modules/*/module.json               │
│  boot()     → Autoloader → ServiceProvider        │
└──────────────┬───────────────────────────────────┘
               │ für jedes aktivierte Modul

┌──────────────────────────────────────────────────┐
│           Modul-ServiceProvider                   │
│  register() → Services in den Container binden    │
│  boot()     → in die Erweiterungs-Registries      │
│              eintragen; Routen, Views, Events      │
└──────────────────────────────────────────────────┘

Das Kernprinzip

Module verändern nie Core-Dateien. Sie registrieren ihre Fähigkeiten während der boot()-Methode ihres ServiceProviders in den Registries; der Core liest zur Laufzeit aus diesen Registries.

Warum das so gebaut ist: Solange ein Modul nur registriert und nichts am Core patcht, bleiben Updates konfliktfrei. Eine neue Schneespur-Version kann den Core austauschen, ohne die Module zu zerstören — und ein Modul lässt sich entfernen, ohne Spuren im Core zu hinterlassen. Das ist der Unterschied zwischen einem Erweiterungssystem und einer Sammlung von Patches.

Die Core-Registries im Überblick

RegistryZweckzu implementierendes Interface
NavigationRegistryMenüpunkte der Admin-Seitenleiste— (Config-Array)
DashboardWidgetRegistryDashboard-Karten/-Widgets— (Config-Array + Blade-View)
FilterRegistryHook-/Filter-Pipeline (WordPress-Stil)— (Callable)
SlotRegistryTemplate-Einschubpunkte— (Blade-View)
PermissionRegistryBerechtigungen— (Config-Array)
RoleTemplateRegistryvorgefertigte Rollen-Konfigurationen— (Config-Array)
DispatchStrategyRegistryAlgorithmen zur Einsatz-ZuteilungDispatchStrategyInterface
NotificationChannelRegistryBenachrichtigungs-KanäleNotificationChannelInterface
TwoFactorMethodRegistry2FA-VerfahrenTwoFactorMethodInterface
BackupTargetRegistryBackup-ZieleBackupTargetInterface
StorageBackendRegistryDatei-Speicher-BackendsStorageBackendInterface
WeatherProviderRegistryWetter-DatenquellenWeatherProviderInterface
PdfRendererRegistryPDF-EnginesPdfRendererInterface
ReportFormatRegistryExport-FormateReportFormatInterface
ScheduledTaskRegistryCron-AufgabenScheduledTaskInterface
DiagnosticReporterRegistryFehler-/Crash-ReportingDiagnosticReporterInterface
ModuleAssetRegistryLaden von CSS/JS— (manifest.json)
ModuleApiRegistrarREST-API-Routengruppen— (Routen-Closure)

Die vollständige API jeder Registry — mit Methoden und Beispielen — finden Sie unter Registries. Wenn Sie zum ersten Mal ein Modul bauen, ist der schnellste Weg der Schnelleinstieg.