Files
superport/AGENTS.md
JiWoong Sul 655d473413
Some checks failed
Flutter Test & Quality Check / Test on macos-latest (push) Has been cancelled
Flutter Test & Quality Check / Test on ubuntu-latest (push) Has been cancelled
Flutter Test & Quality Check / Build APK (push) Has been cancelled
web: migrate health notifications to js_interop; add browser hook
- 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
2025-09-08 17:39:00 +09:00

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.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
      @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
      // 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());
      }
      
  • 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

// 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: 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.dartShadTable.list.
    • Model list: lib/screens/model/model_list_screen.dartShadTable.list.
    • User list: lib/screens/user/user_list.dartShadTable.list (Company column shows - until backend supplies it).
    • Inventory history: lib/screens/inventory/inventory_history_screen.dartShadTable.list.
    • Company list: lib/screens/company/company_list.dartShadTable.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.