MySched

Architecture Overview

MySched is a cross-platform mobile application built with Flutter/Dart and powered by a Supabase backend. The app enables students to scan, manage, and share class schedules with offline-first capabilities and real-time sync.

Tech Stack

LayerTechnology
FrameworkFlutter 3.x (Dart)
BackendSupabase (PostgreSQL, Auth, Edge Functions)
OCRGoogle ML Kit Text Recognition
State ManagementChangeNotifier + Controller pattern
NavigationGoRouter
Local StorageSharedPreferences, SQLite (via Drift)
CI/CDGitHub Actions
AnalyticsFirebase Analytics + Crashlytics

Project Structure

lib/
├── core/
│   ├── auth/           # Authentication pipeline (7 files)
│   ├── observability/  # Logging, analytics, crash reporting
│   ├── resilience/     # Retry logic, offline queue, connectivity
│   ├── ocr/            # Google ML Kit integration, schedule parsing
│   └── platform/       # Platform-specific abstractions
├── models/             # Data models (ClassItem, ReminderEntry, Section)
├── services/           # Service singletons (Supabase, sync, notifications)
├── screens/            # Screen widgets organized by feature
└── ui/
    └── theme/          # Design tokens, colors, typography

Architecture Principles

  1. Offline-first — All data is cached locally. The sync engine handles conflict resolution and retry logic when connectivity returns.

  2. Controller pattern — Each feature has a dedicated controller extending ChangeNotifier. Controllers own business logic; widgets only handle presentation.

  3. Service singletons — Backend communication is abstracted through service classes (SupabaseService, SyncService, NotificationService) initialized once at app startup.

  4. Security by default — Row-Level Security (RLS) on all 28 Supabase tables. Auth state changes are serialized to prevent race conditions.

  5. Modular navigation — GoRouter with 4 primary tabs (Dashboard, Schedules, Reminders, Settings), deep linking via mysched:// scheme, and auth-guarded routes.

Documentation Map

SectionWhat It Covers
Data ModelsCore models, relationships, and database schema
Service LayerState management, controllers, and offline queue
Supabase BackendTables, RLS policies, Edge Functions, API patterns
AuthenticationOAuth flows, session management, error handling
UI SystemComponents, navigation, theming, accessibility
Testing & CI/CDTest strategy, mocking, build pipeline, performance

Remote Configuration

MySched uses RemoteConfigService (singleton) to manage feature flags and forced updates at runtime:

  • Cache duration: 1 hour (fetchTimeout: 10s, minimumFetchInterval: 1h)
  • Forced updates: Controlled via min_app_version — when the installed version is below this value, a blocking update dialog is shown
  • Feature flags: Boolean flags for toggling features without app store releases (e.g., enable_ocr_v2, enable_sharing)
Dart
class RemoteConfigService {
  static final RemoteConfigService _instance = RemoteConfigService._();
  factory RemoteConfigService() => _instance;

  final _remoteConfig = FirebaseRemoteConfig.instance;

  Future<void> initialize() async {
    await _remoteConfig.setConfigSettings(RemoteConfigSettings(
      fetchTimeout: const Duration(seconds: 10),
      minimumFetchInterval: const Duration(hours: 1),
    ));
    await _remoteConfig.fetchAndActivate();
  }

  bool getBool(String key) => _remoteConfig.getBool(key);
  String getString(String key) => _remoteConfig.getString(key);
}