103 lines
3.7 KiB
Dart
103 lines
3.7 KiB
Dart
/// Laufzeitkonfiguration der App.
|
|
///
|
|
/// Die Werte kommen zur Build-Zeit aus `--dart-define-from-file=env/<stage>.json`
|
|
/// (siehe `app/env/*.example.json`). Secrets gehören nicht ins Repo.
|
|
class AppConfig {
|
|
const AppConfig({
|
|
required this.environment,
|
|
required this.supabaseUrl,
|
|
required this.supabaseAnonKey,
|
|
required this.siteUrl,
|
|
required this.legalPrivacyUrl,
|
|
required this.legalTermsUrl,
|
|
required this.termsVersion,
|
|
});
|
|
|
|
/// Liest die Konfiguration aus den `--dart-define`-Werten.
|
|
///
|
|
/// `String.fromEnvironment` muss mit konstanten Namen aufgerufen werden;
|
|
/// deshalb steht jeder Schlüssel hier einzeln.
|
|
factory AppConfig.fromEnvironment() => const AppConfig(
|
|
environment: String.fromEnvironment(
|
|
keyAppEnv,
|
|
defaultValue: defaultEnvironment,
|
|
),
|
|
supabaseUrl: String.fromEnvironment(keySupabaseUrl),
|
|
supabaseAnonKey: String.fromEnvironment(keySupabaseAnonKey),
|
|
siteUrl: String.fromEnvironment(keySiteUrl, defaultValue: defaultSiteUrl),
|
|
legalPrivacyUrl: String.fromEnvironment(
|
|
keyLegalPrivacyUrl,
|
|
defaultValue: defaultLegalPrivacyUrl,
|
|
),
|
|
legalTermsUrl: String.fromEnvironment(
|
|
keyLegalTermsUrl,
|
|
defaultValue: defaultLegalTermsUrl,
|
|
),
|
|
termsVersion: String.fromEnvironment(
|
|
keyTermsVersion,
|
|
defaultValue: defaultTermsVersion,
|
|
),
|
|
);
|
|
|
|
/// Baut die Konfiguration aus einer Map (Tests, Tooling). Fehlende
|
|
/// optionale Werte erhalten dieselben Platzhalter wie [fromEnvironment].
|
|
factory AppConfig.fromMap(Map<String, String> values) => AppConfig(
|
|
environment: values[keyAppEnv] ?? defaultEnvironment,
|
|
supabaseUrl: values[keySupabaseUrl] ?? '',
|
|
supabaseAnonKey: values[keySupabaseAnonKey] ?? '',
|
|
siteUrl: values[keySiteUrl] ?? defaultSiteUrl,
|
|
legalPrivacyUrl: values[keyLegalPrivacyUrl] ?? defaultLegalPrivacyUrl,
|
|
legalTermsUrl: values[keyLegalTermsUrl] ?? defaultLegalTermsUrl,
|
|
termsVersion: values[keyTermsVersion] ?? defaultTermsVersion,
|
|
);
|
|
|
|
static const keyAppEnv = 'APP_ENV';
|
|
static const keySupabaseUrl = 'SUPABASE_URL';
|
|
static const keySupabaseAnonKey = 'SUPABASE_ANON_KEY';
|
|
static const keySiteUrl = 'SITE_URL';
|
|
static const keyLegalPrivacyUrl = 'LEGAL_PRIVACY_URL';
|
|
static const keyLegalTermsUrl = 'LEGAL_TERMS_URL';
|
|
static const keyTermsVersion = 'TERMS_VERSION';
|
|
|
|
// Platzhalter (Spec #1 § 5.1), bis Chris die echten Werte festlegt.
|
|
static const defaultEnvironment = 'dev';
|
|
static const defaultSiteUrl = 'https://shuffle.cshomelabs.work';
|
|
static const defaultLegalPrivacyUrl =
|
|
'https://shuffle.cshomelabs.work/legal/privacy';
|
|
static const defaultLegalTermsUrl =
|
|
'https://shuffle.cshomelabs.work/legal/terms';
|
|
static const defaultTermsVersion = '2026-11-draft';
|
|
|
|
/// Name der Stage (`dev`, `ci`, `staging`, `prod`).
|
|
final String environment;
|
|
final String supabaseUrl;
|
|
final String supabaseAnonKey;
|
|
|
|
/// Öffentliche Basis-URL der Web-App (Ziel der Mail-Links).
|
|
final String siteUrl;
|
|
final String legalPrivacyUrl;
|
|
final String legalTermsUrl;
|
|
|
|
/// Version der Rechtstexte, die bei der Registrierung gespeichert wird.
|
|
final String termsVersion;
|
|
|
|
/// Namen der Pflichtwerte, die fehlen oder leer sind.
|
|
List<String> get missingKeys => [
|
|
if (supabaseUrl.isEmpty) keySupabaseUrl,
|
|
if (supabaseAnonKey.isEmpty) keySupabaseAnonKey,
|
|
];
|
|
|
|
bool get isValid => missingKeys.isEmpty;
|
|
|
|
/// Wirft einen [StateError], wenn Pflichtwerte fehlen.
|
|
void validate() {
|
|
final missing = missingKeys;
|
|
if (missing.isNotEmpty) {
|
|
throw StateError(
|
|
'Missing app configuration: ${missing.join(', ')}. '
|
|
'Start the app with --dart-define-from-file=env/<stage>.json '
|
|
'(see app/env/dev.example.json).',
|
|
);
|
|
}
|
|
}
|
|
}
|