Architekturtests ausführen
SupaCloud erzwingt seine Schichtgrenzen und die Dateigrößen-Obergrenze mit einer
Rust-Testsuite in server/tests/architecture.rs. Diese Tests laufen innerhalb des
normalen cargo test-Frameworks — keine externen Werkzeuge erforderlich. Führe sie
vor jedem Push aus; sie sind das CI-Gate, das verhindert, dass sich Regressionen
ansammeln.
Architekturtests ausführen
Abschnitt betitelt „Architekturtests ausführen“cd servercargo test archCargo filtert Tests nach Namen, daher werden alle Tests ausgeführt, deren Name arch
enthält — derzeit ausschließlich die einzelne Funktion rust_source_architecture_guards_hold.
Die Datei enthält außerdem Hilfs-Unit-Tests
(auth_user_handler_scanner_rejects_handlers_without_scope_guard,
cfg_test_module_discovery_rejects_name_only_test_files) sowie einen Docker-Kontext-Test,
deren Namen jedoch kein arch enthalten — sie werden daher nur bei einem breiteren Filter
wie dem einfachen cargo test ausgeführt. Der Test durchsucht alle .rs-Quelldateien
unter server/src/ und alle .sql-Migrationsdateien unter server/migrations/.
Um die vollständige Testsuite auszuführen (die auch die Architekturtests enthält):
cargo testWas die Tests prüfen
Abschnitt betitelt „Was die Tests prüfen“Der einzelne Einstiegspunkt-Test rust_source_architecture_guards_hold in
server/tests/architecture.rs führt vierzehn unabhängige Guards aus und sammelt
alle Verstöße, bevor er fehlschlägt — du siehst also alle Probleme in einem Durchlauf.
Abhängigkeitsrichtung
Abschnitt betitelt „Abhängigkeitsrichtung“Die grundlegende Regel lautet Interface → Service → Persistence. Vier Guards erzwingen sie:
| Guard | Was er verbietet |
|---|---|
| Interfaces umgehen Services | src/interfaces/** importiert crate::db::queries, db::queries, queries::, sqlx::PgPool, &state.db |
| Services rufen Interfaces auf | src/services/** importiert crate::interfaces oder einen Interface-Adapter-Alias (api, stripe, telegram, management, discord) |
| Runtime/Integrationen umgehen Services | src/runtime/** und src/integrations/** importieren dieselben Persistence-Muster |
| Auth-Module umgehen Services | src/auth/** importiert dieselben Persistence-Muster |
Chat-Adapter-Isolation
Abschnitt betitelt „Chat-Adapter-Isolation“Chat-Adapter (telegram, discord) müssen über die neutrale crate::chat-Oberfläche
kommunizieren. Adapter-übergreifende Imports sind in beide Richtungen verboten, und
src/interfaces/chat darf keinen der konkreten Adapter importieren.
HTTP-Autorisierungs-Guard
Abschnitt betitelt „HTTP-Autorisierungs-Guard“Jede pub async fn-Handler-Funktion in src/interfaces/http, die einen
AuthUser-Extraktor empfängt, muss mindestens einen Autorisierungs- oder
Scope-Guard aufrufen (z. B. resolve_workspace_id(, require_workspace_admin(,
authorize_org( oder einen anderen Eintrag in der Guard-Liste). Authentifizierte Handler, die gemeinsame (nicht mandantenspezifische) Metadaten
zurückgeben und daher keinen weiteren Authz-/Scope-Guard benötigen, haben benannte
Ausnahmen, die in der Testdatei registriert sind (die Liste
HTTP_AUTHZ_AUTHENTICATED_METADATA_EXCEPTIONS).
Management-Services bleiben HTTP-frei
Abschnitt betitelt „Management-Services bleiben HTTP-frei“Dateien unter src/services/management dürfen keine HTTP-Antworten konstruieren
(StatusCode::, IntoResponse, .into_response()). Das Antwort-Mapping gehört
in die Interface-Schicht.
500-Zeilen-Obergrenze
Abschnitt betitelt „500-Zeilen-Obergrenze“Jede Quelldatei unter server/src/ muss unter 500 nicht-leeren,
nicht-kommentierten Code-Zeilen bleiben. Der Test misst die Anzahl nach dem
Entfernen nachgestellter //-Kommentare und Leerzeilen, sodass Dokumentationsvolumen
eine Datei nicht über die Grenze treibt.
Außerdem muss jede Quelldatei mit einem Zweckkommentar beginnen — entweder
// Purpose: oder //! Purpose: — und darf weder include!( noch
allow(dead_code) verwenden.
Migrations-Vokabular (ADR 0040)
Abschnitt betitelt „Migrations-Vokabular (ADR 0040)“Neue Migrationsdateien (Nummer über 168) dürfen keine team_id-Tenancy-Spalte
einführen — verwende stattdessen workspace_id — und dürfen die umbenannten
Tabellen teams, team_members oder team_invites nicht neu erstellen. Bestehende,
erlaubte RENAME COLUMN team_id TO workspace_id-Zeilen sind ausgenommen.
Lokalisierungs-Hygiene
Abschnitt betitelt „Lokalisierungs-Hygiene“Telegram-Adapter müssen app::i18n (Fluent) verwenden statt inline match-Anweisungen
für das Locale. Deutscher Text (Umlaute, ß) muss in .ftl-Dateien unter
server/locales/ stehen, nicht im Rust-Quellcode.
Einen Fehler lesen
Abschnitt betitelt „Einen Fehler lesen“Wenn ein Guard ausgelöst wird, gruppiert die Testausgabe Verstöße nach Regel und
gibt jeden als <Pfad>:<Zeile> gefolgt vom passenden Muster in Backticks aus. Behebe sie alle — der Test
hält nicht bei der ersten Gruppe an.
thread 'rust_source_architecture_guards_hold' FAILED
architecture guards failed:interfaces must call services/use-cases instead of persistence directly:src/interfaces/http/example.rs:42 contains `sqlx::PgPool`Siehe auch
Abschnitt betitelt „Siehe auch“- Architektur-Erklärung — das Schichtmodell und die Abhängigkeitsrichtung in Prosa.
- Eine Datenbankmigration hinzufügen — wie du eine Migration hinzufügst, ohne den Vokabular-Guard zu verletzen.