Die App wird nach thematischen/geschäftlichen Domänen geschnitten, nicht nach technischen Schichten. Statt „alle Controller hier, alle Stores dort“ wird gruppiert, was zu einem Feature gehört und als Modul definiert. Module kapseln Controller, Stores, Modelle und Repositories; der zentrale Context stellt sie bereit, steuert Navigation und hält die UI schlank. Das erleichtert Erweiterungen, hält Abhängigkeiten gering und sorgt für konsistente, testbare Datenflüsse.
Idee #
- Fachlich geschnittene Einheiten: Features werden als Module gedacht und implementiert. Jedes Modul bündelt Controller, Stores, Modelle und Repositories für seinen Fachbereich.
- Klare Grenzen: UI konsumiert Module über den zentralen Controller, statt quer über einzelne Services zu greifen. Das erhöht Übersicht, Testbarkeit und Austauschbarkeit.
Struktur #
- Konfiguration: Die aktive Modullandschaft ist in
@configs/moduleConfigdefiniert. Routen stehen in@configs/routeConfig. - Bereitstellung: Der
ContextControllererzeugt und lädt Module beim App‑Start. Über den Provider providers/ContextControllerProvider.tsx stehen sie global zur Verfügung. - Zugriff in der UI: Screens greifen per useContextControllerProvider() auf modules zu, z. B.
modules.core.controllers.authControlleroder zugehörige Stores/Repos.
Lebenszyklus #
- Beim Start liest der
ContextControllermoduleConfig, initialisiert Module (Controller, Stores, Repos) und setztloaded, sobald alles bereit ist. - Der Provider gate’t das Rendering bis
loadedtrue ist. Erst dann nutzt die UI die modularen APIs.
Navigation und Routen #
- Routen verweisen logisch auf Module (z. B. Auth‑Bereich unter
app/auth/). - Navigation läuft bevorzugt über den zentralen
routeController(injizierte Expo‑Router‑Funktionen), der modulübergreifend Guards, Tracking und Regeln anwenden kann.
Kommunikation zwischen Modulen #
- Inter‑Modul‑Aufrufe erfolgen über den
ContextControllerbzw. klar definierte Controller‑APIs. - Stores liefern nur beobachtbaren Zustand; fachliche Abhängigkeiten werden über Controller‑Schnittstellen gekapselt, nicht über direkte Store‑Kopplung.
Vorteile #
- Isolation: Änderungen bleiben im Modul; geringere Seiteneffekte.
- Skalierbarkeit: Neue Features entstehen als neue Module ohne Berührung mit bestehenden.
- Wartbarkeit: Einheitliche Orte für Logik (Controller), Zustand (Stores), Datenzugriff (Repositories).
- Ownership: Teams können Module unabhängig warten und deployen (Backendschnittstellen via Directus bleiben stabil).
Neues Modul hinzufügen (High‑Level) #
- 1. Konfiguration: Eintrag in
@configs/moduleConfig(Name, Controller/Store/Repo‑Wiring). - 2. Routen: Dateien/Ordner in
app/<modul>/anlegen; falls nötig gemeinsames Layout _layout.tsx. - 3. Implementierung: Controller (Use‑Cases, Navigation), Stores (MobX‑State), Repositories (Directus‑Zugriff), Modelle (Typen).
- 4. Integration: Über useContextControllerProvider() in Screens auf
modules.<modul>.*zugreifen. - 5. Tests: Controller/Repos modular testen; UI als
observer‑Komponenten gegen Mock‑Controller laufen lassen.
Kurzbeispiel Zugriff (konzeptionell) #
// In einem Screen
const { modules, routeController } = useContextControllerProvider();
await modules.core.controllers.authController.onPressLogin();
routeController.navigateToNext("(home)");