- Replace dart:js with package:js in health_check_service_web.dart\n- Implement showHealthCheckNotification in web/index.html\n- Pin js dependency to ^0.6.7 for flutter_secure_storage_web compatibility auth: harden AuthInterceptor + tests - Allow overrideAuthRepository injection for testing\n- Normalize imports to package: paths\n- Add unit test covering token attach, 401→refresh→retry, and failure path\n- Add integration test skeleton gated by env vars ui/data: map User.companyName to list column - Add companyName to domain User\n- Map UserDto.company?.name\n- Render companyName in user_list cleanup: remove legacy equipment table + unused code; minor warnings - Remove _buildFlexibleTable and unused helpers\n- Remove unused zipcode details and cache retry constant\n- Fix null-aware and non-null assertions\n- Address child-last warnings in administrator dialog docs: update AGENTS.md session context
12 KiB
12 KiB
Superport AGENTS.md — Working Guide and Current State
This document is the project-wide guide for agents/developers. It describes the Flutter frontend structure, rules, run/test workflows, backend integration principles, technical debt, and improvement items.
- Scope: applies to the entire repo (lib, test, docs, etc.).
- Backend repo:
/Users/maximilian.j.sul/Documents/flutter/superport_api/(Rust/Actix, SeaORM) - Agent doc precedence:
./.claude/agents/→~/.claude/agents/(global) - Project communication/comments can be in Korean, but this file stays in English unless requested otherwise.
1) System Overview
- Stack: Flutter 3.x, Dart 3.x, Provider, get_it, dio, freezed, json_serializable, shadcn_ui
- Architecture: Clean Architecture (recommended) with some legacy Service coexistence
- Data (API/DTO/RemoteDataSource) → Domain (Repository/UseCase) → Presentation (Controller/UI)
- Some features still use legacy Service-based logic
- Data flow: Backend owns business logic; frontend focuses on DTO mapping and presentation
- UI: shadcn_ui components as standard; tables migrating to ShadTable
2) Current Status (Important)
- DI:
lib/injection_container.dartvia get_it- Both ApiClient (env-driven Dio) and a raw Dio existed; now standardized on ApiClient.dio
- Avoid raw Dio; use
ApiClientonly
- Env/config:
.env.development,.env.production,lib/core/config/environment.dartmain.dartmust callEnvironment.initialize()to load .env before DI- Previously, baseUrl was hardcoded in DI; now use Environment + ApiClient consistently
- UI standard: per root
CLAUDE.md, use ShadTable; avoid Flutter base widgets for tables - Tests: multiple unit/integration suites under
test/, includingtest/integration/automated - Docs:
docs/backend.md(backend issues/requests),docs/superportPRD.md(requirements/UI)
3) Directory Map (Essentials)
lib/
core/ # constants/utils/env/storage/theme/errors
data/ # DTOs, RemoteDataSources, Repo impl, ApiClient/Interceptors
domain/ # Entities, Repository interfaces, UseCases
screens/ # UI screens and Controllers (ChangeNotifier)
services/ # legacy/transitional services
models/ # app-side models (Freezed/Json)
utils/ # UI/validators (some moving to core)
- API endpoints:
lib/core/constants/api_endpoints.dart - Env/Config:
lib/core/config/environment.dart - API client:
lib/data/datasources/remote/api_client.dart - DI container:
lib/injection_container.dart
4) Coding Rules (Mandatory)
- Follow Clean Architecture flow:
- API ← Repository (impl in data) ← UseCase ← Controller ← UI
- DTO/field names must match backend exactly
- DTO field mapping (critical)
- Example
@JsonSerializable() class EquipmentDto { @JsonKey(name: 'companies_id') final int? companiesId; // NOT company_id @JsonKey(name: 'models_id') final int? modelsId; // NOT model_id const EquipmentDto({this.companiesId, this.modelsId}); }
- Example
- Error handling
- Domain returns
Either<Failure, T> - Show user-friendly messages in UI (see
AppConstants)
- Domain returns
- State management
- Controllers are ChangeNotifier; inject via Provider
- Wrap dialogs/routes with Provider when needed
- UI components
- Prefer shadcn_ui; tables must use
ShadTable - Theme/color/spacing via
ShadcnThemeand shared constants
- Prefer shadcn_ui; tables must use
- Lint/logging
analysis_options.yamlrelaxes some warnings for dev speed- Use debug logging in dev; minimize in production
5) API/Networking
- Define endpoints in
lib/core/constants/api_endpoints.dart - Use ApiClient (recommended)
- Env-driven Base URL/Timeout/Logging via
.env - Interceptors: Auth, Logging (dev), Response normalization, Error handling
- Tokens read from secure storage/AuthService
- Env-driven Base URL/Timeout/Logging via
- Avoid raw Dio
- For transitional code requiring
Dio, obtain it fromsl<ApiClient>().dio
- For transitional code requiring
- 401 handling
- Refresh token flow implemented in
AuthInterceptorusingAuthService.refreshToken() - On success, original request is retried; on failure, session is cleared
- Refresh token flow implemented in
6) Dependency Injection (DI)
- Container:
lib/injection_container.dart- Order: External → Core → ApiClient/Dio → DataSource → Repository → UseCase → Controller → Services
- Lifecycle: Repository/UseCase as
registerLazySingleton, Controller asregisterFactory - Example
// 1) RemoteDataSource sl.registerLazySingleton<MyFeatureRemoteDataSource>( () => MyFeatureRemoteDataSourceImpl(sl<ApiClient>()), ); // 2) Repository sl.registerLazySingleton<MyFeatureRepository>( () => MyFeatureRepositoryImpl(sl<MyFeatureRemoteDataSource>()), ); // 3) UseCase sl.registerLazySingleton(() => GetMyFeatureUseCase(sl<MyFeatureRepository>())); // 4) Controller sl.registerFactory(() => MyFeatureController(sl<GetMyFeatureUseCase>()));
7) Environment & Running
- Env files:
.env.development,.env.production(sample:.env.example) - Environment class:
lib/core/config/environment.dart- Use
Environment.apiBaseUrl,apiTimeout,enableLogging - Initialization at startup
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Environment.initialize(); await di.init(); runApp(const SuperportApp()); }
- Use
- Web dev with CORS disabled:
./run_web_with_proxy.sh(keep API URL consistent with .env)
8) Backend Integration
- Backend repo:
/Users/maximilian.j.sul/Documents/flutter/superport_api/- Rust (Actix), SeaORM, PostgreSQL, JWT
- See backend README for run/migrations/env
- Frontend policy
- Backend schema/fields = source of truth
- Keep business logic on the backend
- Known issues
- See
docs/backend.md:GET /companieswithsearch+is_activereturns empty (Critical) - When backend responses change, update DTO → RemoteDataSource → Repository in order
- See
9) Build/Test/Quality
- Install deps:
flutter pub get - Static analysis:
flutter analyze(keep ERROR: 0) - Tests:
flutter testor use scripts undertest/integration/automated- Quick API check:
./test_api_integration.sh
- Quick API check:
- Quality script:
./scripts/fix_code_quality.sh
10) Feature Workflow (Checklist)
- Confirm requirements/backend spec (
docs/superportPRD.md, backend README,docs/backend.md) - Add/verify endpoint in
core/constants/api_endpoints.dart - Define DTO with exact
JsonKeymapping - Implement RemoteDataSource (API call/error mapping)
- Add Repository interface/impl (delegate to DataSource)
- Write UseCase (single responsibility; compose in Controller)
- Register in DI (
injection_container.dart) - Add Controller and wire UI (Provider)
- Write tests (errors/edge cases)
- Use shadcn_ui in UI (ShadTable for tables)
11) Legacy Coexistence (Transition)
- Service-based calls remain for some features (e.g., parts of Company/Auth)
- Prefer migrating to Repository/UseCase; gradually remove Service-bound UseCases
- Avoid duplicate implementations; standardize on
ApiClient
12) Improvement Roadmap
- Env/Networking
- Remove raw Dio from DI → standardized on
ApiClient - Ensure
Environment.initialize()runs before DI - Stabilize refresh-token retry flow
- Remove raw Dio from DI → standardized on
- UI
- Continue ShadTable migration; follow
CLAUDE.mdchecklist - Use only design system constants for color/typography/spacing
- Continue ShadTable migration; follow
- Architecture
- Migrate remaining Service-based paths (Company/Auth) to Repos
- Remove interceptor duplication
- Tests
- Strengthen real-API integration suite and wire into CI
13) Frequently Used Paths
- Env:
lib/core/config/environment.dart,.env.* - Endpoints:
lib/core/constants/api_endpoints.dart - API:
lib/data/datasources/remote/api_client.dart - DI:
lib/injection_container.dart - Controllers:
lib/screens/*/controllers/*_controller.dart - Docs:
docs/backend.md,docs/superportPRD.md, rootCLAUDE.md - Global agent docs:
~/.claude/CLAUDE.md,~/.claude/agents/*.md
14) Patterns
// Controller — standard pattern with loading/error states
class ExampleController extends ChangeNotifier {
final GetItemsUseCase _getItems;
bool _loading = false; String? _error; List<Item> _items = [];
ExampleController(this._getItems);
Future<void> fetch() async {
_loading = true; _error = null; notifyListeners();
final result = await _getItems();
result.fold(
(f) { _error = f.message; },
(data) { _items = data; },
);
_loading = false; notifyListeners();
}
}
// RemoteDataSource — using ApiClient
class ItemsRemoteDataSource {
final ApiClient _api;
ItemsRemoteDataSource(this._api);
Future<List<ItemDto>> getItems() async {
final res = await _api.get(ApiEndpoints.items);
final list = (res.data['data'] as List).cast<Map<String, dynamic>>();
return list.map(ItemDto.fromJson).toList();
}
}
Before merging, always verify:
- Patterns in
./.claude/agents/→~/.claude/agents/ - .env setup and API Base URL consistency
- New features use ApiClient + Repository/UseCase
- UI uses shadcn_ui (ShadTable for tables)
- Tests and analysis pass (0 errors)
15) Session Continuation Context (2025-09-08)
This section captures the current in-progress state so another session can resume seamlessly.
-
Environment/DI
lib/main.dart: callsawait Environment.initialize()before DI init.lib/injection_container.dart: unified network stack tosl<ApiClient>().dio; removed rawDioconfig to avoid divergence.
-
Auth flow (migrated to Repository)
- UseCases moved to
AuthRepository:LogoutUseCase,GetCurrentUserUseCase(returnsAuthUser),RefreshTokenUseCase.
AuthRepositoryextended with:getStoredAccessToken(),getStoredRefreshToken(),clearLocalSession().
- Interceptor now repository-based:
lib/data/datasources/remote/interceptors/auth_interceptor.dartreads tokens viaAuthRepository, handles 401 → refresh → retry → clear+navigate.
- Global navigation:
lib/core/navigation/app_navigator.dart(key used inShadApp), enables navigation on 401.
- UseCases moved to
-
UI: ShadTable migration (columns preserved as-is)
- Equipment list:
lib/screens/equipment/equipment_list.dart→_buildShadTableused. Legacy_buildFlexibleTableis deprecated (kept temporarily). - Vendor list:
lib/screens/vendor/vendor_list_screen.dart→ShadTable.list. - Model list:
lib/screens/model/model_list_screen.dart→ShadTable.list. - User list:
lib/screens/user/user_list.dart→ShadTable.list(Company column shows-until backend supplies it). - Inventory history:
lib/screens/inventory/inventory_history_screen.dart→ShadTable.list. - Company list:
lib/screens/company/company_list.dart→ShadTable.list.
- Equipment list:
-
Company UseCases (Repository-based)
GetCompanyDetailUseCase,CreateCompanyUseCase,UpdateCompanyUseCase,DeleteCompanyUseCase,ToggleCompanyStatusUseCase,GetCompanyHierarchyUseCase,UpdateParentCompanyUseCase,ValidateCompanyDeletionUseCasenow useCompanyRepository.
-
Analysis status
flutter analyzeshows 0 errors (non-blocking warnings remain; functionality unaffected).
-
Known remaining warnings (non-blocking)
lib/screens/equipment/equipment_in_form.dart: minor validator consistency; most null-aware warnings resolved.- Other general warnings may persist but do not affect functionality.
-
How to continue
- Optional cleanups (most done):
- Deprecated
_buildFlexibleTableremoved; ShadTable only. - Unused
_showAddressDetailsand_maxRetryCountremoved. - Web health notification uses JS interop; ensure global function exists (added to
web/index.html).
- Deprecated
- User list: map Company name into the “Company” column when backend/DTO supplies it (update DTO + repository mapping).
- Add/extend integration tests for Auth (login → 401 → refresh → retry) and core flows.
- Run
flutter pub getafter dependency adjustment (jspinned to^0.6.7).
- Optional cleanups (most done):
-
Quick verification commands
- Static analysis:
flutter analyze(expect 0 errors). - Sample unit test:
flutter test test/utils/currency_formatter_test.dart. - Dev run (web, with CORS disabled):
./run_web_with_proxy.sh.
- Static analysis:
-
Conventions to uphold when resuming
- Use
ApiClient(env-driven) for all network calls; do not instantiate rawDio. - Keep Clean Architecture boundaries; DTO names match backend exactly (
JsonKey(name: ...)). - UI tables use
ShadTable.list; avoid Flutter default tables. - For navigation from non-UI layers (e.g., interceptor), use
appNavigatorKey. - DI: register Repositories/UseCases as lazy singletons, Controllers as factories.
- Use