subctrl is a Flutter (Cupertino-first) subscription tracker with currency conversion and optional local notifications. Keep changes minimal and aligned with the architecture below.
- Clean Architecture: presentation -> application -> domain. Application may depend on infrastructure. Domain never depends on Flutter or infrastructure.
- Presentation (
lib/presentation/) owns UI, ViewModels, and localization. No Drift or HTTP in this layer. - Application (
lib/application/) is use cases only, UI-agnostic. - Domain (
lib/domain/) is pure business logic. Repository interfaces live inlib/domain/repositories/. - Infrastructure (
lib/infrastructure/) contains Drift DB/DAOs, HTTP clients, and platform services.
lib/main.dartbootstraps the app and tabs.lib/application/app_dependencies.dartwires repositories, use cases, and external clients; disposeProxyCurrencyRatesClientwhen done.
- Drift database in
lib/infrastructure/persistence/database.dart, stored assubctrl.dbin the app documents directory;schemaVersionis 1. - Currency seeds:
lib/infrastructure/persistence/seeds/currency_seed_data.dart. - Currency rates backend lives in
backend/(Cloudflare Workers); the Flutter app usesProxyCurrencyRatesClientandSubscriptionCurrencyRatesClient. - Notifications:
LocalNotificationsService(timezone aware).
lib/presentation/screens/widgets/viewmodels/l10n/themelib/application/use cases and DIlib/domain/entities/repositories/serviceslib/infrastructure/persistence/currency/platform/repositoriesbackend/Cloudflare Worker for currency ratestest/mirrors layers
- Follow
analysis_options.yaml(package imports, trailing commas, prefer const/final, avoid dynamic calls, directive ordering). - Add tests for new behavior (domain, application, presentation viewmodels, infrastructure clients). Use mocktail and avoid real network/DB in unit tests.
- Run
build_runner/drift_devand keeplib/infrastructure/persistence/database.g.dartupdated after schema changes. - No secrets; avoid logging sensitive data; keep external services behind adapters.