main function Overview

void main()

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)));
}