Files
eatvio_app/AGENTS.md

5.0 KiB

AGENTS.md

Flutter/Dart mobile app (iOS + Android, Russian-market nutrition/consulting product). Gitea-hosted; CI is Gitea Actions in .gitea/workflows/ (not GitHub Actions, though it references github.com/actions/*).

Toolchain (trust these over README — README version numbers are stale)

  • CI runs Flutter 3.41.2 stable, Java/JDK 21 (.gitea/workflows/test.yml).
  • pubspec.yaml requires Dart SDK ^3.10.4; app version is 1.3.23+105 (README claims 1.3.0+79 — wrong).
  • Build/test/lint via Flutter directly or the Makefile. The repo has a package.json only to wire a git pre-push hook via simple-git-hooks; it is not a Node project.

CRITICAL: generated code is NOT committed

.gitignore excludes *.g.dart, *.freezed.dart, *.gr.dart, *.mocks.dart. After any checkout / pull / model change you must regenerate before flutter analyze, flutter test, or any build, or they fail on missing files:

dart run build_runner build --delete-conflicting-outputs
# or: make build-generated-files

Generators in use: freezed, json_serializable, retrofit_generator, mockito (build_runner). Exception: lib/generated/ (l10n output from intl_utils / flutter_intl) is committed — don't regenerate-and-clobber it casually.

.env (required for running the app, NOT for unit tests)

  • The app loads .env at startup (lib/core/app_initializer.dart → dotenv.load) and ships it as a Flutter asset (pubspec.yaml assets).
  • There is no env.example in the repo despite README/ENV_SETUP.md saying cp env.example .env. Locally you must obtain .env from the team. In CI it is checked out from a private eatvio/eatvio_app_env repo.
  • flutter test does not need .env: tests seed env via dotenv.loadFromString(...) (see test/core/app_config_test.dart). Access values only through lib/core/env_config.dart (EnvConfig).
  • Build types: AppBuildType { prod, tests, dev } (lib/core/app_initializer.dart). prod → BASE_URL; tests/dev → DEV_BASE_URL. main.dart hardcodes prod.

Commands

make run-analyse              # flutter analyze
make run-tests                # flutter test
make run-checks               # analyze THEN test (also the pre-push hook)
make build-generated-files    # build_runner --delete-conflicting-outputs
make clean-coverage           # strips generated files from coverage/lcov.info

Run a single test file / single test:

flutter test test/core/app_config_test.dart
flutter test test/core/app_config_test.dart --plain-name "creates config with prod build type"

Coverage (must be run with the flag): flutter test --coverage, then make clean-coverage. analyze_coverage.py / analyze_coverage_by_uncovered.py summarize coverage/lcov.info.

CI gate (binding constraint on PRs)

.gitea/workflows/test.yml runs on every PR, in order:

  1. flutter clean → flutter pub get → dart run build_runner build --delete-conflicting-outputs
  2. flutter analyze
  3. flutter test --coverage
  4. Coverage must be ≥ 70% (generated files excluded) or the job fails — keep this in mind when adding untested code.
  5. flutter build apk --release --dart-define=HIDE_PLANS=false --dart-define=BUILD_DATE=...

Note: other workflow files (build.yml, docker-run-tests.yml) are simpler/older and do not run build_runner; test.yml is the authoritative one.

Architecture map

  • Entry: lib/main.dart → AppInitializer.initialize (env → DI → Sentry → Firebase → analytics) → runs app under Sentry.
  • DI: get_it (sl global), registered in lib/core/locator_service.dart via lib/core/di/*_registrations.dart (app_config, external, service, repository, cubit).
  • State: flutter_bloc (Cubits/Blocs). Global providers declared in lib/core/app_config.dart (globalBlocProviders).
  • Routing: go_router (lib/core/app_router.dart), with deep-link/push handling in lib/core/notifications/.
  • Networking: dio + retrofit (→ .gr.dart); auth token interceptor in lib/core/interceptors/.
  • Models: freezed + json_serializable (→ .freezed.dart / .g.dart).
  • Realtime: Pusher channels via lib/core/websockets/ (WsManager).
  • Features: ~40 self-contained folders under lib/features/<feature>/, conventionally .../presentation/bloc/<name>_cubit/<name>_cubit.dart. Tests mirror lib/ under test/ with fixtures in test/fixtures/.
  • Localization: Russian only (ru); strings via generated S class from lib/generated/l10n.dart.

Conventions / gotchas

  • analysis_options.yaml enables flutter_lints + extra prefer_const_* rules and excludes generated + l10n files from analysis. dart_code_metrics is also configured (cyclomatic ≤20, ≤50 lines executable, ≤4 params, nesting ≤5) but metrics exclude test/**.
  • Don't commit secrets: .env, android/key.properties, *.jks keystores are all gitignored.
  • Comments and many code identifiers are in Russian (UI strings, doc comments like /// Загрузка переменных окружения); match surrounding style.