# 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.dart` via get_it
  - Both ApiClient (env-driven Dio) and a raw Dio existed; now standardized on ApiClient.dio
  - Avoid raw Dio; use `ApiClient` only
- Env/config: `.env.development`, `.env.production`, `lib/core/config/environment.dart`
  - `main.dart` must call `Environment.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/`, including `test/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
    ```dart
    @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});
    }
    ```
- Error handling
  - Domain returns `Either<Failure, T>`
  - Show user-friendly messages in UI (see `AppConstants`)
- 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 `ShadcnTheme` and shared constants
- Lint/logging
  - `analysis_options.yaml` relaxes 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
- Avoid raw Dio
  - For transitional code requiring `Dio`, obtain it from `sl<ApiClient>().dio`
- 401 handling
  - Refresh token flow implemented in `AuthInterceptor` using `AuthService.refreshToken()`
  - On success, original request is retried; on failure, session is cleared


## 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 as `registerFactory`
  - Example
    ```dart
    // 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
    ```dart
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Environment.initialize();
      await di.init();
      runApp(const SuperportApp());
    }
    ```
- 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 /companies` with `search` + `is_active` returns empty (Critical)
  - When backend responses change, update DTO → RemoteDataSource → Repository in order


## 9) Build/Test/Quality

- Install deps: `flutter pub get`
- Static analysis: `flutter analyze` (keep ERROR: 0)
- Tests: `flutter test` or use scripts under `test/integration/automated`
  - Quick API check: `./test_api_integration.sh`
- Quality script: `./scripts/fix_code_quality.sh`


## 10) Feature Workflow (Checklist)

1. Confirm requirements/backend spec (`docs/superportPRD.md`, backend README, `docs/backend.md`)
2. Add/verify endpoint in `core/constants/api_endpoints.dart`
3. Define DTO with exact `JsonKey` mapping
4. Implement RemoteDataSource (API call/error mapping)
5. Add Repository interface/impl (delegate to DataSource)
6. Write UseCase (single responsibility; compose in Controller)
7. Register in DI (`injection_container.dart`)
8. Add Controller and wire UI (Provider)
9. Write tests (errors/edge cases)
10. 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
- UI
  - Continue ShadTable migration; follow `CLAUDE.md` checklist
  - Use only design system constants for color/typography/spacing
- 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`, root `CLAUDE.md`
- Global agent docs: `~/.claude/CLAUDE.md`, `~/.claude/agents/*.md`


## 14) Patterns

```dart
// 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();
  }
}
```

```dart
// 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`: calls `await Environment.initialize()` before DI init.
  - `lib/injection_container.dart`: unified network stack to `sl<ApiClient>().dio`; removed raw `Dio` config to avoid divergence.

- Auth flow (migrated to Repository)
  - UseCases moved to `AuthRepository`:
    - `LogoutUseCase`, `GetCurrentUserUseCase` (returns `AuthUser`), `RefreshTokenUseCase`.
  - `AuthRepository` extended with:
    - `getStoredAccessToken()`, `getStoredRefreshToken()`, `clearLocalSession()`.
  - Interceptor now repository-based:
    - `lib/data/datasources/remote/interceptors/auth_interceptor.dart` reads tokens via `AuthRepository`, handles 401 → refresh → retry → clear+navigate.
  - Global navigation: `lib/core/navigation/app_navigator.dart` (key used in `ShadApp`), enables navigation on 401.

- UI: ShadTable migration (columns preserved as-is)
  - Equipment list: `lib/screens/equipment/equipment_list.dart` → `_buildShadTable` used. Legacy `_buildFlexibleTable` is 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`.

- Company UseCases (Repository-based)
  - `GetCompanyDetailUseCase`, `CreateCompanyUseCase`, `UpdateCompanyUseCase`, `DeleteCompanyUseCase`, `ToggleCompanyStatusUseCase`, `GetCompanyHierarchyUseCase`, `UpdateParentCompanyUseCase`, `ValidateCompanyDeletionUseCase` now use `CompanyRepository`.

- Analysis status
  - `flutter analyze` shows 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 `_buildFlexibleTable` removed; ShadTable only.
    - Unused `_showAddressDetails` and `_maxRetryCount` removed.
    - Web health notification uses JS interop; ensure global function exists (added to `web/index.html`).
  - 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 get` after dependency adjustment (`js` pinned to `^0.6.7`).

- 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`.

- Conventions to uphold when resuming
  - Use `ApiClient` (env-driven) for all network calls; do not instantiate raw `Dio`.
  - 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.


## 16) Git / Commit Policy

- Commit messages must be written in Korean. (필수)
  - 기술 용어/식별자는 영어 사용 가능하나, 메시지의 기본 문장은 한국어로 작성합니다.
  - PR 제목/설명도 동일한 원칙을 따릅니다.
- 권장 형식
  - 한 줄 요약(명령형, 50자 내외) + 필요 시 본문(이유/영향/추가 작업)
  - 예) "장비 목록 페이지네이션 메타 적용; 서버 total/totalPages 사용"
  - 예) "우편번호 팝업 테이블 컬럼 폭 축소로 수평 스크롤 제거"
