main function Overview
App entry point. Boots Supabase, spawns DuTaToApp, and lazily starts Firebase + notification services in the background so the UI paints without waiting on native init.
Implementation
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// -- Web URL strategy --
//
// Use clean path-based URLs (`/progress`) instead of Flutter's default
// hash fragment (`/#/progress`). No-op on iOS/Android — the
// `flutter_web_plugins` public API resolves to a non-web stub off-web, so
// this compiles and runs everywhere without a `kIsWeb` guard.
//
// Without this, only `/#/…` URLs resolve: a bare path leaves the fragment
// empty and GoRouter falls back to Home. That silently breaks path-style
// deep links, shared links, browser refreshes, AND the path URLs the app
// already builds for itself — the Stripe `success_url`/`cancel_url` and
// billing-portal `return_url` in
// `supabase/functions/create-{checkout,portal}-session`, plus the
// `https://dutato.app/org/<id>/billing` link in org_billing_screen.dart.
//
// The host side is already wired: Cloudflare Pages serves `index.html` for
// every unmatched path via `web/_redirects` (`/* /index.html 200`), so the
// SPA boots and GoRouter parses the real path. Both halves of this
// contract are locked down by
// `test/platform/web_url_strategy_config_test.dart`.
usePathUrlStrategy();
// -- Supabase (must be before runApp — auth state drives routing) --
//
// Production builds keep the consent gate: even with compile-time demo
// credentials baked in via --dart-define, the user must click "Use Demo
// Instance" on /setup to opt in. Local dev/audit builds set the
// DUTATO_SKIP_SETUP flag (see tools/dto/dto_cli/shared.py:build_web for the
// localhost-detection logic), which trusts the baked-in demo creds and
// boots the app straight to /login.
const bool skipSetup = bool.fromEnvironment('DUTATO_SKIP_SETUP');
bool supabaseReady = false;
try {
await SupabaseConfig.load();
final modeAllowed =
SupabaseConfig.mode == InstanceMode.custom ||
(skipSetup && SupabaseConfig.mode == InstanceMode.demo);
if (SupabaseConfig.isConfigured && modeAllowed) {
await Supabase.initialize(
url: SupabaseConfig.url,
anonKey: SupabaseConfig.anonKey,
authOptions: const FlutterAuthClientOptions(
authFlowType: AuthFlowType.pkce,
),
);
supabaseReady = true;
}
} catch (e) {
dev.log('Supabase init failed: $e', name: 'main');
}
// -- Local LLM cleanup (one-time, reclaims disk space on devices that
// downloaded GGUF weights before the feature was gated off). Runs only
// when `EnvConfig.enableLocalLlm` is false AND the versioned done-flag
// isn't stamped yet; otherwise no-op. Awaited so storage writes settle
// before the first read in `selectedAiProviderProvider`.
if (!kIsWeb) {
try {
await const LocalLlmCleanupService().run(const FlutterSecureStorage());
} catch (e) {
dev.log('LocalLlmCleanupService failed: $e', name: 'main');
}
}
// Show the UI immediately — Firebase & notifications init in the background.
runApp(ProviderScope(child: DuTaToApp(supabaseReady: supabaseReady)));
}