Warum modulare Software-Architektur ab Tag eins entscheidet, ob ein SaaS-Projekt skaliert
Wenn man eine All-in-One-Plattform für eine bestimmte Branche baut – wie etwa eine gastro-orientierte SaaS-Lösung mit Menü-Managern, Live-Bestellkanälen und dynamischen Admin-Oberflächen –, droht der Code extrem schnell zu einem unübersichtlichen Monolithen zu verschwimmen. Wer hier unsauber strukturiert, zahlt bei jedem neuen Feature doppelt: Jede Anpassung reißt Seiteneffekte in Modulen auf, die eigentlich unabhängig voneinander laufen sollten.
Kunden wollen Flexibilität. Sie buchen Module einzeln per Subscription oder kaufen sie als feste Komponente. Entsprechend dürfen Datenbankschemas, API-Routes und UI-Komponenten nicht hardcodet miteinander verknüpft sein.
Saubere Datenmodelle mit Prisma ORM
Ein modularer Ansatz bricht meistens direkt beim Datenbankschema zusammen. Mit Prisma lässt sich das über relationale Schemas und klar getrennte Entitäten abbilden, statt alles in eine gigantische Tabelle zu pressen:
model Tenant {
id String @id @default(uuid())
name String
subscriptions TenantModule[]
menus Menu[]
createdAt DateTime @default(now())
}
model ModuleDefinition {
id String @id @default(uuid())
code String @unique // z.B. "menu_manager" oder "pos_integration"
name String
tenants TenantModule[]
}
model TenantModule {
tenantId String
moduleDefinitionId String
isEnabled Boolean @default(false)
tenant Tenant @relation(fields: [tenantId], references: [id])
moduleDefinition ModuleDefinition @relation(fields: [moduleDefinitionId], references: [id])
@@id([tenantId, moduleDefinitionId])
}
Über dieses Schema weiß das Backend zu jedem Zeitpunkt exakt, welcher Mandant welches Modul freigeschaltet hat. Die Berechtigungsprüfung greift direkt vor dem Ausführen der API-Endpunkte.
Feature-basierte Ordnerstruktur in Next.js
Statt Code nach technischem Typ (alle Komponenten in einen Ordner, alle Actions in einen anderen) zu sortieren, trennt eine feature-basierte Struktur die Logik nach Anwendungsbereichen:
/src
/modules
/menu
/components # UI-Komponenten nur für den Menü-Manager
/hooks # Custom Hooks für Menü-Daten
/server # Prisma-Abfragen und Server-Actions für das Menü
/pos
/components
/server
/shared # Globale UI-Komponenten und Utilities
Jedes Modul bringt seine eigene Server-Logik und seine eigenen Komponenten mit. Wenn ein Modul Daten eines anderen benötigt, läuft das über definierte interne Schnittstellen – nicht über direkte SQL-Abfragen in fremden Tabellen.
Fazit
Modularität kostet am Anfang mehr Disziplin und saubere Planung. Aber wenn das System wächst, lassen sich Features wie passgenaue Zahnräder einsetzen, ohne dass das Fundament ins Wanken gerät.