Files
teamwallet/docs/superpowers/specs/2026-08-05-env-indicator-design.md
Bastian Wagner ed365db283 docs: add design spec for environment indicator banner
Captures the brainstormed design for a dev-environment banner shown
app-wide, plus the height-compensation needed so it doesn't reintroduce
the double-scrollbar class of bug just fixed in Shell/public pages.
2026-08-05 12:20:02 +02:00

5.8 KiB

Umgebungs-Indikator (Entwicklungsumgebung-Banner)

Status: approved Datum: 2026-08-05

Kontext

Beim Arbeiten und Testen kann leicht unklar sein, ob man gerade in der lokalen Entwicklungsumgebung (ng serve, environment.development.ts) oder in der echten, produktiven App unterwegs ist — beide sehen optisch identisch aus. Ziel: ein visueller Indikator, der überall in der App sofort erkennbar macht, wenn man sich in der Entwicklungsumgebung befindet, damit man sich beim Testen nicht vertut.

Entscheidungen aus dem Brainstorming

  • Betroffene Umgebungen: Es gibt drei Angular-Build-Konfigurationen (myteamwallet_frontend_modern/angular.json): production (Standard, environment.ts, echte API auf myteamwallet.de), development (environment.development.ts, nur lokal via ng serve, localhost:3999) und container (environment.container.ts, npm run build:container). Der container-Build ist der reguläre Deploy-Weg der echten Produktion (z. B. self-hosted per Docker) — kein Staging-System — und setzt bereits selbst production: true. Der Indikator muss also nur environment.production === false erkennen; kein neues Feld in den Environment-Dateien nötig.
  • Darstellung: dünner Banner-Streifen ganz oben über der gesamten App (nicht nur im Header), warme Warnfarbe (Amber/Orange, bewusst nicht das App-Grün), Text „⚠ Entwicklungsumgebung", zentriert, klein, kein Dismiss-Button (der Zweck ist ja gerade, ihn nicht wegzuklicken und zu vergessen).
  • Inhalt: nur der Umgebungsname, keine zusätzlichen technischen Details (API-URL o. ä.).
  • Platzierung im Code: einmalig in app.html vor <router-outlet />, statt in jeder Seite einzeln — automatisch auf jeder Route (Shell, Public-Seiten, Login, Register, Users, Logs, …) sichtbar, single source of truth.

Architektur / Komponenten

1. Neue Komponente EnvBanner

Ordner: myteamwallet_frontend_modern/src/app/shared/env-banner/

Standalone-Komponente nach dem Muster bestehender Shared-Komponenten (context-help, skeleton) — kein Modul/Barrel, keine Inputs.

  • env-banner.ts: importiert environment aus ../../../environments/environment und exponiert protected readonly showBanner = !environment.production;. Exportiert außerdem die Konstante export const ENV_BANNER_HEIGHT_PX = 28; (wird von App für die Höhen-Kompensation wiederverwendet, siehe unten — ein einziger Ort für die Pixel-Zahl).
  • env-banner.html: @if (showBanner) { <div class="env-banner" role="status">⚠ Entwicklungsumgebung</div> } — rendert in Produktion buchstäblich nichts (kein leeres DOM-Element).
  • env-banner.scss: .env-banner { height: 28px; display:flex; align-items:center; justify-content:center; background: #f4a300; color:#20251F; font-weight:700; font-size: 0.75rem; letter-spacing:0.04em; text-transform:uppercase; flex-shrink:0; } (die 28px müssen mit ENV_BANNER_HEIGHT_PX übereinstimmen — als Kommentar im SCSS vermerkt).
  • env-banner.spec.ts: rendert Text wenn environment.production === false, rendert nichts wenn true (Environment-Objekt im Test gemockt/überschrieben).

2. Einbau in app.html / app.ts

app.html bekommt vor <router-outlet /> ein <app-env-banner />. App importiert EnvBanner in seine imports-Liste.

3. Höhen-Kompensation für height: 100dvh-Layouts

Der Banner nimmt echten Platz im normalen Fluss ein. Für Seiten, die nur min-height:100dvh nutzen und sich auf bodys eigenen Scrollbar verlassen (Login, Register, Forgot/Reset-Password, Confirm-Email, Users, Logs), ist das unproblematisch — body gleicht das automatisch aus, kein Änderungsbedarf.

Aber shell.scss, public-team.scss und public-player.scss nutzen height: 100dvh als feste Zusage „genau ein Bildschirm hoch" (siehe docs/superpowers/plans/-Historie zum Doppel-Scrollbar-Fix vom selben Tag). Ohne Anpassung würde die Shell/Public-Seite exakt um die Banner-Höhe über den sichtbaren Bereich hinausragen (Bottom-Nav leicht abgeschnitten) — derselbe Bugtyp wie der kürzlich gefixte.

Fix: App (Root-Komponente) bindet eine CSS-Custom-Property auf ihr eigenes Host-Element. Host-Bindings werten Ausdrücke gegen die Komponenten-Instanz aus, daher als Instanz-Property vorhalten:

host: {
  '[style.--env-banner-height.px]': 'bannerHeight',
}
// ...
protected readonly bannerHeight = environment.production ? 0 : ENV_BANNER_HEIGHT_PX;

Da <app-root> ein gemeinsamer Vorfahre von EnvBanner und allen Routen-Komponenten (Shell, Public-Seiten, …) ist, vererbt sich die Property automatisch nach unten. Die drei betroffenen SCSS-Dateien ändern:

// vorher: height: 100dvh;
height: calc(100dvh - var(--env-banner-height, 0px));

In Produktion ist die Property 0px, calc(100dvh - 0px) verhält sich identisch zu vorher — keine Verhaltensänderung außerhalb der Entwicklungsumgebung.

Testing

  • env-banner.spec.ts (neu): Sichtbarkeit abhängig von environment.production.
  • app.spec.ts: Erweiterung um Assertion, dass --env-banner-height korrekt 0px bzw. 28px auf dem Host gesetzt wird (je nach gemocktem environment.production).
  • Bestehende Tests (shell.spec.ts, public-team.spec.ts, public-player.spec.ts) bleiben unverändert grün — die calc()-Änderung ist rein visuell/CSS, keine Verhaltensänderung.
  • Manuelle Verifikation: ng serve (development) zeigt den Banner, ng build (production) und ng build --configuration=container zeigen ihn nicht; Shell/Public-Seiten scrollen mit Banner weiterhin korrekt ohne abgeschnittene Bottom-Nav (per Chrome DevTools nachprüfen).

Out of Scope

  • Kein neues environmentName-Feld in den Environment-Dateien (nicht nötig, siehe oben).
  • Kein Dismiss/Ausblenden des Banners.
  • Keine Anzeige zusätzlicher technischer Details (API-URL, Build-Hash) im Banner-Text.