createRouter function

GoRouter createRouter({
  1. required bool supabaseReady,
  2. VoidCallback? onSetupComplete,
})

Creates the app router. When supabaseReady is false, all routes redirect to /setup and the auth listener is not attached.

onSetupComplete is called by the setup screen after Supabase is successfully initialized, triggering an app-level rebuild.

Implementation

GoRouter createRouter({
  required bool supabaseReady,
  VoidCallback? onSetupComplete,
}) {
  _activeRouter = GoRouter(
    initialLocation: supabaseReady ? '/' : '/setup',
    refreshListenable: supabaseReady ? AuthChangeNotifier() : null,
    redirect: (context, state) {
      if (!supabaseReady) {
        if (state.matchedLocation != '/setup') return '/setup';
        return null;
      }
      final session = Supabase.instance.client.auth.currentSession;
      final container = ProviderScope.containerOf(context, listen: false);
      final lastMode = container.read(lastUsedModeProvider).valueOrNull;
      final adminOrgs = container.read(adminEligibleOrgsProvider).valueOrNull;
      final lastActiveOrg = container.read(lastActiveOrgIdProvider).valueOrNull;
      return authRedirect(
        session,
        state,
        lastMode: lastMode,
        adminOrgIds: adminOrgs?.map((o) => o.id).toList(),
        lastActiveOrgId: lastActiveOrg,
      );
    },
    routes: [
      GoRoute(
        path: '/setup',
        builder: (context, state) => DeferredScreen(
          loader: setup.loadLibrary,
          builder: () => setup.SetupScreen(onConnected: onSetupComplete),
        ),
      ),
      GoRoute(
        path: '/login',
        builder: (context, state) => DeferredScreen(
          loader: auth.loadLibrary,
          builder: () => auth.LoginScreen(),
        ),
      ),
      GoRoute(
        path: '/forgot-password',
        builder: (context, state) => DeferredScreen(
          loader: auth.loadLibrary,
          builder: () => auth.ForgotPasswordScreen(),
        ),
      ),
      GoRoute(
        path: '/reset-password',
        builder: (context, state) => DeferredScreen(
          loader: auth.loadLibrary,
          builder: () => auth.ResetPasswordScreen(),
        ),
      ),
      GoRoute(
        path: '/mfa-verify',
        builder: (context, state) => DeferredScreen(
          loader: mfa.loadLibrary,
          builder: () => mfa.MfaVerifyScreen(),
        ),
      ),
      GoRoute(
        path: '/mfa-enroll',
        builder: (context, state) => DeferredScreen(
          loader: mfa.loadLibrary,
          builder: () => mfa.MfaEnrollScreen(),
        ),
      ),
      GoRoute(
        path: '/persona',
        builder: (context, state) => DeferredScreen(
          loader: setup.loadLibrary,
          builder: () => setup.PersonaScreen(),
        ),
      ),
      // First-connection onboarding (Plan 49) — full-screen, no nav bar.
      GoRoute(
        path: '/onboarding/profile',
        builder: (context, state) => DeferredScreen(
          loader: onboarding.loadLibrary,
          builder: () => onboarding.ProfileCompletionScreen(),
        ),
      ),
      GoRoute(
        path: '/onboarding/welcome',
        builder: (context, state) => DeferredScreen(
          loader: onboarding.loadLibrary,
          builder: () => onboarding.OnboardingWelcomeScreen(),
        ),
      ),
      GoRoute(
        path: '/onboarding/why',
        builder: (context, state) => DeferredScreen(
          loader: onboarding.loadLibrary,
          builder: () => onboarding.OnboardingWhyScreen(),
        ),
      ),
      GoRoute(
        path: '/onboarding/session',
        builder: (context, state) => DeferredScreen(
          loader: onboarding.loadLibrary,
          builder: () => onboarding.OnboardingFirstSessionScreen(),
        ),
      ),
      GoRoute(
        path: '/onboarding/review',
        builder: (context, state) => DeferredScreen(
          loader: onboarding.loadLibrary,
          builder: () => onboarding.OnboardingReviewScreen(),
        ),
      ),
      GoRoute(
        path: '/onboarding/mastery',
        builder: (context, state) => DeferredScreen(
          loader: onboarding.loadLibrary,
          builder: () => onboarding.OnboardingMasteryScreen(),
        ),
      ),
      GoRoute(
        path: '/admin-onboarding/org-picker',
        builder: (context, state) => DeferredScreen(
          loader: adminonboarding.loadLibrary,
          builder: () => adminonboarding.AdminOnboardingOrgPickerScreen(),
        ),
      ),
      GoRoute(
        path: '/admin-onboarding/org-basics',
        builder: (context, state) {
          final orgId = state.uri.queryParameters['orgId'] ?? '';
          return DeferredScreen(
            loader: adminonboarding.loadLibrary,
            builder: () =>
                adminonboarding.AdminOnboardingOrgBasicsScreen(orgId: orgId),
          );
        },
      ),
      GoRoute(
        path: '/admin-onboarding/members',
        builder: (context, state) {
          final orgId = state.uri.queryParameters['orgId'] ?? '';
          return DeferredScreen(
            loader: adminonboarding.loadLibrary,
            builder: () =>
                adminonboarding.AdminOnboardingMembersScreen(orgId: orgId),
          );
        },
      ),
      GoRoute(
        path: '/admin-onboarding/curriculum',
        builder: (context, state) {
          final orgId = state.uri.queryParameters['orgId'] ?? '';
          return DeferredScreen(
            loader: adminonboarding.loadLibrary,
            builder: () =>
                adminonboarding.AdminOnboardingCurriculumScreen(orgId: orgId),
          );
        },
      ),
      GoRoute(
        path: '/admin-onboarding/tour',
        builder: (context, state) {
          final orgId = state.uri.queryParameters['orgId'] ?? '';
          return DeferredScreen(
            loader: adminonboarding.loadLibrary,
            builder: () =>
                adminonboarding.AdminOnboardingTourScreen(orgId: orgId),
          );
        },
      ),
      ShellRoute(
        builder: (context, state, child) => EntitlementBootstrap(
          child: TermsGate(
            child: OnboardingGate(child: ScaffoldWithNavBar(child: child)),
          ),
        ),
        routes: [
          GoRoute(
            path: '/',
            pageBuilder: (context, state) =>
                const NoTransitionPage(child: HomeScreen()),
          ),
          GoRoute(
            path: '/domains',
            pageBuilder: (context, state) => NoTransitionPage(
              child: DeferredScreen(
                loader: domains.loadLibrary,
                builder: () => domains.DomainListScreen(),
              ),
            ),
            routes: [
              GoRoute(
                path: 'curriculum-creator',
                builder: (context, state) => DeferredScreen(
                  loader: curriculumcreator.loadLibrary,
                  builder: () => curriculumcreator.CurriculumCreatorScreen(),
                ),
              ),
              GoRoute(
                path: 'upload-curriculum',
                builder: (context, state) => DeferredScreen(
                  loader: curriculumcreator.loadLibrary,
                  builder: () => curriculumcreator.UploadCurriculumScreen(),
                ),
              ),
              GoRoute(
                path: ':domainSlug/topics',
                builder: (context, state) {
                  final domainSlug = state.pathParameters['domainSlug']!;
                  final domainName = state.uri.queryParameters['name'];
                  return DeferredScreen(
                    loader: domains.loadLibrary,
                    builder: () => domains.TopicTreeScreen(
                      domainSlug: domainSlug,
                      domainName: domainName,
                    ),
                  );
                },
                routes: [
                  GoRoute(
                    path: ':topicId/lesson',
                    builder: (context, state) {
                      final domainSlug = state.pathParameters['domainSlug']!;
                      final topicId = state.pathParameters['topicId']!;
                      final topicTitle = state.uri.queryParameters['title'];
                      return DeferredScreen(
                        loader: lesson.loadLibrary,
                        builder: () => lesson.LessonViewerScreen(
                          topicId: topicId,
                          topicTitle: topicTitle,
                          domainSlug: domainSlug,
                        ),
                      );
                    },
                  ),
                ],
              ),
            ],
          ),
          GoRoute(
            path: '/tutor',
            pageBuilder: (context, state) => NoTransitionPage(
              child: DeferredScreen(
                loader: tutor.loadLibrary,
                builder: () => tutor.TutorModeScreen(),
              ),
            ),
            routes: [
              GoRoute(
                path: 'chat',
                builder: (context, state) {
                  final topicId = state.uri.queryParameters['topicId'];
                  final mode = state.uri.queryParameters['mode'] ?? 'socratic';
                  final topicTitle = state.uri.queryParameters['topicTitle'];
                  final from = state.uri.queryParameters['from'];
                  final isValidation =
                      state.uri.queryParameters['isValidation'] == 'true';
                  final validationTarget =
                      state.uri.queryParameters['validationTarget'];
                  return DeferredScreen(
                    loader: tutor.loadLibrary,
                    builder: () => tutor.ChatScreen(
                      topicId: topicId,
                      mode: mode,
                      topicTitle: topicTitle,
                      from: from,
                      isValidation: isValidation,
                      validationTarget: validationTarget,
                    ),
                  );
                },
              ),
            ],
          ),
          GoRoute(
            path: '/review',
            pageBuilder: (context, state) => NoTransitionPage(
              child: DeferredScreen(
                loader: review.loadLibrary,
                builder: () => review.ReviewSessionScreen(),
              ),
            ),
            routes: [
              GoRoute(
                path: 'proposals',
                builder: (context, state) => DeferredScreen(
                  loader: review.loadLibrary,
                  builder: () => review.CardProposalsScreen(),
                ),
              ),
            ],
          ),
          GoRoute(
            path: '/progress',
            pageBuilder: (context, state) {
              final initialTab = state.uri.queryParameters['tab'];
              return NoTransitionPage(
                child: DeferredScreen(
                  loader: progress.loadLibrary,
                  builder: () =>
                      progress.ProgressDashboardScreen(initialTab: initialTab),
                ),
              );
            },
            routes: [
              GoRoute(
                path: 'guide',
                builder: (context, state) => DeferredScreen(
                  loader: progress.loadLibrary,
                  builder: () => progress.LearningGuideScreen(),
                ),
              ),
              GoRoute(
                path: 'overrides',
                builder: (context, state) => DeferredScreen(
                  loader: progress.loadLibrary,
                  builder: () => progress.OverrideHistoryScreen(),
                ),
              ),
              GoRoute(
                path: 'notes/new',
                builder: (context, state) {
                  final topicId = state.uri.queryParameters['topicId'];
                  final sessionId = state.uri.queryParameters['sessionId'];
                  final content = state.uri.queryParameters['content'];
                  return DeferredScreen(
                    loader: notes.loadLibrary,
                    builder: () => notes.NoteDetailScreen(
                      topicId: topicId,
                      sessionId: sessionId,
                      initialContent: content,
                    ),
                  );
                },
              ),
              GoRoute(
                path: 'notes/:noteId',
                builder: (context, state) {
                  final noteId = state.pathParameters['noteId']!;
                  return DeferredScreen(
                    loader: notes.loadLibrary,
                    builder: () => notes.NoteDetailScreen(noteId: noteId),
                  );
                },
              ),
            ],
          ),
          GoRoute(
            path: '/goals',
            pageBuilder: (context, state) => NoTransitionPage(
              child: DeferredScreen(
                loader: progress.loadLibrary,
                builder: () => progress.GoalsListScreen(),
              ),
            ),
          ),
          GoRoute(
            path: '/bookmarks',
            pageBuilder: (context, state) => NoTransitionPage(
              child: DeferredScreen(
                loader: progress.loadLibrary,
                builder: () => progress.BookmarksScreen(),
              ),
            ),
          ),
          // Settings now lives inside the shell so the sidebar persists
          // when the user opens it. Sub-screens stay scoped under
          // `/settings/...` so deep links keep working.
          GoRoute(
            path: '/settings',
            pageBuilder: (context, state) => NoTransitionPage(
              child: DeferredScreen(
                loader: settings.loadLibrary,
                builder: () => settings.SettingsScreen(),
              ),
            ),
            routes: [
              GoRoute(
                path: 'account',
                builder: (_, _) => DeferredScreen(
                  loader: settings.loadLibrary,
                  builder: () => settings.AccountSettingsScreen(),
                ),
              ),
              GoRoute(
                path: 'change-password',
                builder: (_, _) => DeferredScreen(
                  loader: settings.loadLibrary,
                  builder: () => settings.ChangePasswordScreen(),
                ),
              ),
              GoRoute(
                path: 'subscription',
                builder: (_, _) => DeferredScreen(
                  loader: settings.loadLibrary,
                  builder: () => settings.SubscriptionScreen(),
                ),
              ),
              GoRoute(
                path: 'learning',
                builder: (_, _) => DeferredScreen(
                  loader: settings.loadLibrary,
                  builder: () => settings.LearningSettingsScreen(),
                ),
              ),
              GoRoute(
                path: 'notifications',
                builder: (_, _) => DeferredScreen(
                  loader: settings.loadLibrary,
                  builder: () => settings.NotificationsSettingsScreen(),
                ),
              ),
              GoRoute(
                path: 'privacy',
                builder: (_, _) => DeferredScreen(
                  loader: settings.loadLibrary,
                  builder: () => settings.PrivacySettingsScreen(),
                ),
              ),
              GoRoute(
                path: 'ai',
                builder: (_, _) => DeferredScreen(
                  loader: settings.loadLibrary,
                  builder: () => settings.AiSettingsScreen(),
                ),
              ),
            ],
          ),
          // Billing redirect landing pages (after Stripe Checkout completes
          // or is cancelled). Inside the shell so the nav bar stays visible.
          GoRoute(
            path: '/billing/success',
            builder: (context, state) => const _BillingLandingScreen(
              title: 'Thank you!',
              body:
                  'Your subscription is being activated. It should appear '
                  'in your billing page within a few seconds.',
              icon: Icons.check_circle_rounded,
            ),
          ),
          GoRoute(
            path: '/billing/cancel',
            builder: (context, state) => const _BillingLandingScreen(
              title: 'Checkout cancelled',
              body:
                  'No charge was made. You can try again any time from the '
                  'billing page.',
              icon: Icons.cancel_outlined,
            ),
          ),
        ],
      ),
      // Org admin shell — 5 destinations (Dashboard, Members, Assignments,
      // Analytics, Org Settings) shown in OrgShellScaffold's nav rail/bar.
      // `/org` (no orgId) redirects to `/org/:lastActiveOrgId`, falling back
      // to the first admin-eligible org, or `/` if the user has none.
      ShellRoute(
        builder: (context, state, child) => EntitlementBootstrap(
          child: TermsGate(
            child: OnboardingGate(
              child: DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.OrgShellScaffold(child: child),
              ),
            ),
          ),
        ),
        routes: [
          GoRoute(
            path: '/org',
            redirect: (context, state) {
              final container = ProviderScope.containerOf(
                context,
                listen: false,
              );
              final lastOrgAsync = container.read(lastActiveOrgIdProvider);
              // Fast path: lastActiveOrgId already loaded with a value.
              if (lastOrgAsync.hasValue && lastOrgAsync.value != null) {
                return '/org/${lastOrgAsync.value}';
              }

              final adminsAsync = container.read(adminEligibleOrgsProvider);
              final orgsAsync = container.read(myOrganizationsProvider);
              // If any of the three is still loading, stay on /org and let
              // the loading-screen builder watch the providers; it will
              // forward once they settle.
              if (lastOrgAsync.isLoading ||
                  adminsAsync.isLoading ||
                  orgsAsync.isLoading) {
                return null;
              }

              final admins = adminsAsync.valueOrNull;
              if (admins != null && admins.isNotEmpty) {
                return '/org/${admins.first.id}';
              }
              final orgs = orgsAsync.valueOrNull;
              if (orgs != null && orgs.isNotEmpty) {
                return '/org/${orgs.first.id}';
              }
              return '/';
            },
            builder: (context, state) => const _OrgRedirectLoadingScreen(),
          ),
          GoRoute(
            path: '/org/:orgId',
            pageBuilder: (context, state) => NoTransitionPage(
              child: DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.OrgDashboardScreen(),
              ),
            ),
          ),
          GoRoute(
            path: '/org/:orgId/members',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.MemberManagementScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/assignments',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.CurriculumAssignmentScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/analytics',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.OrgAnalyticsScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/settings',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.OrgSettingsScreen(orgId: orgId),
              );
            },
          ),
        ],
      ),
      // Other /org/:orgId/* sub-pages — wrapped uniformly in OrgDetailScaffold
      // so every detail screen gets the same AppBar (with back button) and
      // mobile bottom-nav / desktop NavigationRail chrome. The title is
      // derived from the matched location via `_orgDetailRouteTitle` so
      // adding a new detail route auto-inherits the wrapper.
      ShellRoute(
        builder: (context, state, child) {
          final orgId = state.pathParameters['orgId'] ?? '';
          final title = orgDetailRouteTitle(state.uri.path, orgId);
          return EntitlementBootstrap(
            child: TermsGate(
              child: OnboardingGate(
                child: DeferredScreen(
                  loader: org.loadLibrary,
                  builder: () => org.OrgDetailScaffold(
                    orgId: orgId,
                    title: title,
                    body: child,
                  ),
                ),
              ),
            ),
          );
        },
        routes: [
          GoRoute(
            path: '/org/:orgId/teams',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.TeamManagementScreen(orgId: orgId),
              );
            },
            routes: [
              GoRoute(
                path: ':teamId',
                builder: (context, state) {
                  final orgId = state.pathParameters['orgId']!;
                  final teamId = state.pathParameters['teamId']!;
                  return DeferredScreen(
                    loader: org.loadLibrary,
                    builder: () =>
                        org.TeamDetailScreen(orgId: orgId, teamId: teamId),
                  );
                },
              ),
            ],
          ),
          GoRoute(
            path: '/org/:orgId/reports',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.OrgProgressReportScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/assignments/:assignmentId',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              final assignmentId = state.pathParameters['assignmentId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.AssignmentDetailScreen(
                  orgId: orgId,
                  assignmentId: assignmentId,
                ),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/members/:userId',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              final userId = state.pathParameters['userId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () =>
                    org.MemberDetailScreen(orgId: orgId, userId: userId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/notifications',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.NotificationCenterScreen(orgId: orgId),
              );
            },
            routes: [
              // Per-org preferences for notification channels and types.
              // Reuses the global NotificationsSettingsScreen with the
              // current org pre-selected so the URL is shareable and
              // deep-linkable.
              GoRoute(
                path: 'preferences',
                builder: (context, state) {
                  final orgId = state.pathParameters['orgId']!;
                  return DeferredScreen(
                    loader: settings.loadLibrary,
                    builder: () => settings.NotificationsSettingsScreen(
                      preselectedOrgId: orgId,
                    ),
                  );
                },
              ),
            ],
          ),
          GoRoute(
            path: '/org/:orgId/paths',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.LearningPathsScreen(orgId: orgId),
              );
            },
            routes: [
              GoRoute(
                path: ':pathId',
                builder: (context, state) {
                  final orgId = state.pathParameters['orgId']!;
                  final pathId = state.pathParameters['pathId']!;
                  return DeferredScreen(
                    loader: org.loadLibrary,
                    builder: () =>
                        org.PathDetailScreen(orgId: orgId, pathId: pathId),
                  );
                },
                routes: [
                  GoRoute(
                    path: 'progress',
                    builder: (context, state) {
                      final orgId = state.pathParameters['orgId']!;
                      final pathId = state.pathParameters['pathId']!;
                      return DeferredScreen(
                        loader: org.loadLibrary,
                        builder: () => org.PathProgressScreen(
                          orgId: orgId,
                          pathId: pathId,
                        ),
                      );
                    },
                  ),
                ],
              ),
            ],
          ),
          GoRoute(
            path: '/org/:orgId/skills',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.SkillFrameworkScreen(orgId: orgId),
              );
            },
            routes: [
              GoRoute(
                path: 'gaps',
                builder: (context, state) {
                  final orgId = state.pathParameters['orgId']!;
                  return DeferredScreen(
                    loader: org.loadLibrary,
                    builder: () => org.SkillGapScreen(orgId: orgId),
                  );
                },
              ),
            ],
          ),
          GoRoute(
            path: '/org/:orgId/roles',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.RoleProfilesScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/certifications',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.CertificationsScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/compliance',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.ComplianceDashboardScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/certificates/:certId',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              final certId = state.pathParameters['certId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.CertificateViewScreen(
                  orgId: orgId,
                  certificateId: certId,
                ),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/leaderboard',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.LeaderboardScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/badges',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.BadgesScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/gamification-settings',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.GamificationSettingsScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/sso',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.SsoSettingsScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/api-keys',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.ApiKeysScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/webhooks',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.WebhooksScreen(orgId: orgId),
              );
            },
          ),
          GoRoute(
            path: '/org/:orgId/billing',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: org.loadLibrary,
                builder: () => org.OrgBillingScreen(orgId: orgId),
              );
            },
          ),
        ],
      ),
      // Org-admin lesson viewer. Lives outside the org detail shell so the
      // lesson keeps its own AppBar (no double-AppBar from
      // [OrgDetailScaffold]); the URL prefix preserves the org context so
      // `context.pop()` from the lesson returns to the assignment detail.
      GoRoute(
        path: '/org/:orgId/assignments/:assignmentId/topics/:topicId/lesson',
        builder: (context, state) {
          final topicId = state.pathParameters['topicId']!;
          final topicTitle = state.uri.queryParameters['title'];
          final domainSlug = state.uri.queryParameters['slug'] ?? '';
          return DeferredScreen(
            loader: lesson.loadLibrary,
            builder: () => lesson.LessonViewerScreen(
              topicId: topicId,
              topicTitle: topicTitle,
              domainSlug: domainSlug,
            ),
          );
        },
      ),
      // Backoffice routes (platform admin only)
      GoRoute(
        path: '/backoffice',
        builder: (context, state) => DeferredScreen(
          loader: backoffice.loadLibrary,
          builder: () => backoffice.PlatformAdminGuard(
            child: backoffice.BackofficeScreen(),
          ),
        ),
        routes: [
          GoRoute(
            path: 'users',
            builder: (context, state) => DeferredScreen(
              loader: backoffice.loadLibrary,
              builder: () => backoffice.BackofficeUsersScreen(),
            ),
          ),
          GoRoute(
            path: ':orgId',
            builder: (context, state) {
              final orgId = state.pathParameters['orgId']!;
              return DeferredScreen(
                loader: backoffice.loadLibrary,
                builder: () => backoffice.PlatformAdminGuard(
                  child: backoffice.BackofficeOrgDetailScreen(orgId: orgId),
                ),
              );
            },
          ),
        ],
      ),
    ],
    errorBuilder: (context, state) =>
        _RouteNotFoundScreen(missingPath: state.matchedLocation),
  );
  return _activeRouter!;
}