diff --git a/specs/001-flutter-app/tasks.md b/specs/001-flutter-app/tasks.md new file mode 100644 index 0000000..9bcf867 --- /dev/null +++ b/specs/001-flutter-app/tasks.md @@ -0,0 +1,811 @@ +# Geutebruck API Flutter App - Implementation Tasks + +## Implementation Status (Last Updated: 2025-12-23) + +### ✅ Completed Features (Phase 1 & 2) +- **US-1.1**: User Login - Login screen with authentication ✅ +- **US-1.2**: Token Management - Secure storage with flutter_secure_storage ✅ +- **US-2.1**: View All Servers - Server list with filtering (All/G-Core/GeViScope) ✅ +- **US-2.5**: Create G-Core Server - Full form implementation ✅ +- **US-2.6**: Create GeViScope Server - Full form implementation ✅ +- **US-2.7**: Update Server - Edit functionality with proper state handling ✅ +- **US-2.8**: Delete Server - Delete with confirmation dialog ✅ +- **Navigation**: App drawer with left menu navigation ✅ +- **Offline-First**: Hive local storage with sync capabilities ✅ +- **Server Sync**: Upload dirty changes to remote server ✅ +- **Server Download**: Download latest configuration from server ✅ +- **State Management**: BLoC pattern with shared state across routes ✅ + +### 🐛 Recent Bug Fixes +- Fixed "No data" display issue after server update (2025-12-23) + - Issue: BlocBuilder fallback showing "No data" during state transitions + - Solution: Changed fallback to show loading indicator instead + - File: `lib/presentation/screens/servers/servers_management_screen.dart:268` + +### 🚧 In Progress +- Testing and validation of server management features + +### 📋 Pending (Phase 3-9) +- US-3.x: Action Mapping Management +- US-4.x: Camera Management +- US-5.x: Monitor & Cross-Switching +- US-6.x: Cross-Switch Management +- US-7.x: Configuration Export/Tree View +- US-8.x: Additional UI/UX improvements + +--- + +## Task Organization + +Tasks are organized by user story and marked with: +- `[P]` - Can be done in parallel +- `[✅]` - Completed +- `[🚧]` - In Progress +- File paths indicate where code should be created/modified +- TDD tasks (tests) listed before implementation tasks + +--- + +## Phase 1: Foundation & Setup + +### Task Group: Project Setup + +#### TASK-001 [P] [✅]: Create Flutter Project +**File:** N/A (command line) +```bash +flutter create geutebruck_app +cd geutebruck_app +``` + +#### TASK-002 [P] [✅]: Configure Dependencies +**File:** `pubspec.yaml` +- Add all required dependencies from plan.md +- Set Flutter SDK constraints +- Configure assets folder + +#### TASK-003 [✅]: Setup Folder Structure +**Files:** Create folder structure as defined in plan.md +``` +lib/core/ +lib/data/ +lib/domain/ +lib/presentation/ +``` + +#### TASK-004 [P] [✅]: Configure Analysis Options +**File:** `analysis_options.yaml` +- Add very_good_analysis +- Configure lint rules +- Enable strict mode + +#### TASK-005 [P] [✅]: Setup Build Configuration +**File:** `build.yaml` +- Configure freezed +- Configure json_serializable +- Configure injectable + +--- + +### Task Group: US-1.1 - User Login + +#### TASK-010: Create Auth Entities (Test) +**File:** `test/domain/entities/user_test.dart` +- Test User entity creation +- Test equality +- Test copyWith + +#### TASK-011: Create Auth Entities +**File:** `lib/domain/entities/user.dart` +```dart +@freezed +class User with _$User { + const factory User({ + required String id, + required String username, + required String role, + }) = _User; +} +``` + +#### TASK-012: Create Auth Models (Test) +**File:** `test/data/models/auth_model_test.dart` +- Test JSON deserialization +- Test toEntity conversion + +#### TASK-013: Create Auth Models +**File:** `lib/data/models/auth_model.dart` +```dart +@freezed +class AuthResponse with _$AuthResponse { + factory AuthResponse({ + required String accessToken, + required String refreshToken, + required UserModel user, + }) = _AuthResponse; + + factory AuthResponse.fromJson(Map json) => + _$AuthResponseFromJson(json); +} +``` + +#### TASK-014: Create Secure Storage Manager (Test) +**File:** `test/data/data_sources/local/secure_storage_manager_test.dart` +- Test token storage +- Test token retrieval +- Test token deletion + +#### TASK-015: Create Secure Storage Manager +**File:** `lib/data/data_sources/local/secure_storage_manager.dart` +```dart +@injectable +class SecureStorageManager { + final FlutterSecureStorage _storage; + + Future saveToken(String key, String token); + Future getToken(String key); + Future deleteToken(String key); + Future clearAll(); +} +``` + +#### TASK-016: Create Auth Remote Data Source (Test) +**File:** `test/data/data_sources/remote/auth_remote_data_source_test.dart` +- Mock Dio client +- Test login API call +- Test error handling + +#### TASK-017: Create Auth Remote Data Source +**File:** `lib/data/data_sources/remote/auth_remote_data_source.dart` +```dart +@injectable +class AuthRemoteDataSource { + final Dio _dio; + + Future login(String username, String password); + Future refreshToken(String refreshToken); +} +``` + +#### TASK-018: Create Auth Repository (Test) +**File:** `test/data/repositories/auth_repository_impl_test.dart` +- Mock data sources +- Test login flow +- Test token storage + +#### TASK-019: Create Auth Repository +**File:** `lib/data/repositories/auth_repository_impl.dart` +- Implement repository interface +- Coordinate data sources +- Handle errors with Either + +#### TASK-020: Create Login Use Case (Test) +**File:** `test/domain/use_cases/auth/login_test.dart` +- Mock repository +- Test successful login +- Test failed login + +#### TASK-021: Create Login Use Case +**File:** `lib/domain/use_cases/auth/login.dart` +```dart +@injectable +class Login { + final AuthRepository repository; + + Future> call(String username, String password); +} +``` + +#### TASK-022: Create Auth BLoC (Test) +**File:** `test/presentation/blocs/auth/auth_bloc_test.dart` +- Use bloc_test package +- Test all events and state transitions +- Mock use cases + +#### TASK-023: Create Auth BLoC +**File:** `lib/presentation/blocs/auth/auth_bloc.dart` +```dart +@injectable +class AuthBloc extends Bloc { + final Login login; + final RefreshToken refreshToken; + final Logout logout; +} +``` + +#### TASK-024: Create Login Screen (Widget Test) +**File:** `test/presentation/screens/auth/login_screen_test.dart` +- Test UI rendering +- Test form validation +- Test login button tap + +#### TASK-025: Create Login Screen +**File:** `lib/presentation/screens/auth/login_screen.dart` +- Username and password fields +- Login button +- Loading state +- Error display +- BLoC integration + +--- + +### Task Group: US-1.2 - Automatic Token Refresh + +#### TASK-030: Create Auth Interceptor (Test) +**File:** `test/core/network/interceptors/auth_interceptor_test.dart` +- Test token injection +- Test 401 handling +- Test token refresh flow + +#### TASK-031: Create Auth Interceptor +**File:** `lib/core/network/interceptors/auth_interceptor.dart` +```dart +class AuthInterceptor extends Interceptor { + @override + void onRequest(RequestOptions, RequestInterceptorHandler); + + @override + void onError(DioException, ErrorInterceptorHandler); +} +``` + +--- + +## Phase 2: Server Management + +### Task Group: US-2.1 - View All Servers + +#### TASK-040: Create Server Entities +**Files:** +- `lib/domain/entities/server.dart` +- `lib/domain/entities/gcore_server.dart` +- `lib/domain/entities/geviscope_server.dart` + +#### TASK-041: Create Server Models +**Files:** +- `lib/data/models/server_model.dart` +- Include JSON serialization + +#### TASK-042: Create Server Remote Data Source +**File:** `lib/data/data_sources/remote/server_remote_data_source.dart` +```dart +@RestApi(baseUrl: '/api/v1/configuration') +abstract class ServerRemoteDataSource { + factory ServerRemoteDataSource(Dio dio) = _ServerRemoteDataSource; + + @GET('/servers') + Future getServers(); + + @GET('/servers/gcore') + Future getGCoreServers(); + + @GET('/servers/geviscope') + Future getGeViScopeServers(); +} +``` + +#### TASK-043: Create Cache Manager +**File:** `lib/data/data_sources/local/cache_manager.dart` +- Implement Hive boxes +- Cache servers with expiration +- Cache action mappings + +#### TASK-044: Create Server Repository +**File:** `lib/data/repositories/server_repository_impl.dart` +- Implement all server operations +- Cache-first strategy +- Error handling + +#### TASK-045: Create Get Servers Use Case +**File:** `lib/domain/use_cases/servers/get_servers.dart` + +#### TASK-046: Create Server BLoC +**File:** `lib/presentation/blocs/server/server_bloc.dart` +- Events: LoadServers, CreateServer, UpdateServer, DeleteServer +- States: Initial, Loading, Loaded, Error + +#### TASK-047: Create Server List Screen +**File:** `lib/presentation/screens/servers/server_list_screen.dart` +- AppBar with title and actions +- ListView with ServerCard widgets +- Pull-to-refresh +- Search functionality +- Filter chips (All, G-Core, GeViScope) +- FAB for adding new server + +#### TASK-048: Create Server Card Widget +**File:** `lib/presentation/widgets/server/server_card.dart` +- Display server alias, host, type +- Status indicator (enabled/disabled) +- Tap to view details +- Swipe actions (edit, delete) + +--- + +### Task Group: US-2.4 - View Server Details + +#### TASK-050: Create Server Detail Screen +**File:** `lib/presentation/screens/servers/server_detail_screen.dart` +- Display all server properties +- Edit and Delete buttons +- Connection status indicator + +--- + +### Task Group: US-2.5/2.6 - Create Server + +#### TASK-055: Create Server Form Screen +**File:** `lib/presentation/screens/servers/server_form_screen.dart` +- Use flutter_form_builder +- Dynamic form based on server type +- Validation +- Submit button with loading state + +--- + +### Task Group: US-2.7 - Update Server + +#### TASK-060: Create Update Server Use Case +**File:** `lib/domain/use_cases/servers/update_server.dart` + +#### TASK-061: Update Server Form Screen +**File:** Same as TASK-055 +- Pre-populate form with existing values +- Update mode vs create mode + +--- + +### Task Group: US-2.8 - Delete Server + +#### TASK-065: Create Delete Server Use Case +**File:** `lib/domain/use_cases/servers/delete_server.dart` + +#### TASK-066: Add Delete Confirmation Dialog +**File:** `lib/presentation/widgets/common/confirmation_dialog.dart` +- Reusable confirmation dialog +- Customizable title and message + +--- + +## Phase 3: Action Mapping Management + +### Task Group: US-3.1/3.2 - View Action Mappings + +#### TASK-070: Create Action Mapping Entities +**File:** `lib/domain/entities/action_mapping.dart` +```dart +@freezed +class ActionMapping with _$ActionMapping { + const factory ActionMapping({ + required int id, + required String caption, + required Map inputActions, + required List outputActions, + }) = _ActionMapping; +} + +@freezed +class OutputAction with _$OutputAction { + const factory OutputAction({ + required String action, + required String caption, + String? server, + required Map parameters, + }) = _OutputAction; +} +``` + +#### TASK-071: Create Action Mapping Models +**File:** `lib/data/models/action_mapping_model.dart` + +#### TASK-072: Create Action Mapping Remote Data Source +**File:** `lib/data/data_sources/remote/action_mapping_remote_data_source.dart` +```dart +@RestApi(baseUrl: '/api/v1/configuration') +abstract class ActionMappingRemoteDataSource { + @GET('/action-mappings') + Future> getActionMappings(); + + @GET('/action-mappings/{id}') + Future getActionMapping(@Path() int id); + + @POST('/action-mappings') + Future createActionMapping(@Body() ActionMappingCreateRequest request); + + @PUT('/action-mappings/{id}') + Future updateActionMapping( + @Path() int id, + @Body() ActionMappingUpdateRequest request, + ); + + @DELETE('/action-mappings/{id}') + Future deleteActionMapping(@Path() int id); +} +``` + +#### TASK-073: Create Action Mapping Repository +**File:** `lib/data/repositories/action_mapping_repository_impl.dart` + +#### TASK-074: Create Action Mapping Use Cases +**Files:** +- `lib/domain/use_cases/action_mappings/get_action_mappings.dart` +- `lib/domain/use_cases/action_mappings/create_action_mapping.dart` +- `lib/domain/use_cases/action_mappings/update_action_mapping.dart` +- `lib/domain/use_cases/action_mappings/delete_action_mapping.dart` + +#### TASK-075: Create Action Mapping BLoC +**File:** `lib/presentation/blocs/action_mapping/action_mapping_bloc.dart` + +#### TASK-076: Create Action Mapping List Screen +**File:** `lib/presentation/screens/action_mappings/action_mapping_list_screen.dart` + +#### TASK-077: Create Action Mapping Detail Screen +**File:** `lib/presentation/screens/action_mappings/action_mapping_detail_screen.dart` + +--- + +### Task Group: US-3.3/3.4 - Create/Update Action Mapping + +#### TASK-080: Create Action Mapping Form Screen +**File:** `lib/presentation/screens/action_mappings/action_mapping_form_screen.dart` +- Caption field +- Input parameter builder + - Add/remove parameters + - Key-value pairs +- Output action builder + - Action type selector + - Server selector + - Parameter configuration + - Add/remove actions +- Submit button + +--- + +## Phase 4: Camera Management + +### Task Group: US-4.1/4.2 - Camera List and Details + +#### TASK-090: Create Camera Entities +**File:** `lib/domain/entities/camera.dart` + +#### TASK-091: Create Camera Models +**File:** `lib/data/models/camera_model.dart` + +#### TASK-092: Create Camera Remote Data Source +**File:** `lib/data/data_sources/remote/camera_remote_data_source.dart` +```dart +@RestApi(baseUrl: '/api/v1/cameras') +abstract class CameraRemoteDataSource { + @GET('') + Future> getCameras(); + + @GET('/{id}') + Future getCamera(@Path() String id); +} +``` + +#### TASK-093: Create Camera Repository +**File:** `lib/data/repositories/camera_repository_impl.dart` + +#### TASK-094: Create Camera Use Cases +**Files:** +- `lib/domain/use_cases/cameras/get_cameras.dart` +- `lib/domain/use_cases/cameras/get_camera.dart` + +#### TASK-095: Create Camera BLoC +**File:** `lib/presentation/blocs/camera/camera_bloc.dart` + +#### TASK-096: Create Camera List Screen +**File:** `lib/presentation/screens/cameras/camera_list_screen.dart` + +#### TASK-097: Create Camera Detail Screen +**File:** `lib/presentation/screens/cameras/camera_detail_screen.dart` + +--- + +### Task Group: US-4.3 - PTZ Camera Control + +#### TASK-100: Create PTZ Control Use Cases +**Files:** +- `lib/domain/use_cases/cameras/control_ptz.dart` +- Support all PTZ actions (pan, tilt, zoom, focus) + +#### TASK-101: Create PTZ BLoC +**File:** `lib/presentation/blocs/ptz/ptz_bloc.dart` + +#### TASK-102: Create Camera Control Screen +**File:** `lib/presentation/screens/cameras/camera_control_screen.dart` +- PTZ control pad widget + - Directional buttons (up, down, left, right) +- Zoom controls (+/-) +- Focus controls (near/far) +- Stop button +- Speed slider +- Preset selector +- Save preset button + +#### TASK-103: Create PTZ Control Pad Widget +**File:** `lib/presentation/widgets/camera/ptz_control_pad.dart` + +--- + +## Phase 5: Monitor & Cross-Switching + +### Task Group: US-5.1/5.2 - Monitor Management + +#### TASK-110: Create Monitor Entities +**File:** `lib/domain/entities/monitor.dart` + +#### TASK-111: Create Monitor Models +**File:** `lib/data/models/monitor_model.dart` + +#### TASK-112: Create Monitor Remote Data Source +**File:** `lib/data/data_sources/remote/monitor_remote_data_source.dart` + +#### TASK-113: Create Monitor Repository +**File:** `lib/data/repositories/monitor_repository_impl.dart` + +#### TASK-114: Create Monitor Use Cases +**Files:** +- `lib/domain/use_cases/monitors/get_monitors.dart` +- `lib/domain/use_cases/monitors/get_monitor.dart` + +#### TASK-115: Create Monitor BLoC +**File:** `lib/presentation/blocs/monitor/monitor_bloc.dart` + +#### TASK-116: Create Monitor List Screen +**File:** `lib/presentation/screens/monitors/monitor_list_screen.dart` + +#### TASK-117: Create Monitor Detail Screen +**File:** `lib/presentation/screens/monitors/monitor_detail_screen.dart` + +--- + +### Task Group: US-6.1/6.2 - Cross-Switching + +#### TASK-120: Create Cross-Switch Use Cases +**Files:** +- `lib/domain/use_cases/crossswitch/connect_camera_to_monitor.dart` +- `lib/domain/use_cases/crossswitch/clear_monitor.dart` + +#### TASK-121: Create Cross-Switch BLoC +**File:** `lib/presentation/blocs/crossswitch/crossswitch_bloc.dart` + +#### TASK-122: Create Cross-Switch Screen +**File:** `lib/presentation/screens/crossswitch/crossswitch_screen.dart` +- Camera selector +- Monitor selector +- Preview of current assignments +- Connect button +- Clear button + +--- + +## Phase 6: Configuration Management + +### Task Group: US-7.1 - Export Configuration + +#### TASK-130: Create Export Configuration Use Case +**File:** `lib/domain/use_cases/configuration/export_configuration.dart` + +#### TASK-131: Add Export to Settings Screen +**File:** `lib/presentation/screens/settings/settings_screen.dart` +- Export button +- Save to file dialog +- Share option + +--- + +### Task Group: US-7.2 - View Configuration Tree + +#### TASK-135: Create Configuration Tree Screen +**File:** `lib/presentation/screens/configuration/configuration_tree_screen.dart` +- Expandable tree view +- Search functionality +- Node type indicators + +--- + +## Phase 7: UI & Navigation + +### Task Group: US-8.1 - App Navigation + +#### TASK-140: Setup GoRouter +**File:** `lib/core/router/app_router.dart` +```dart +final router = GoRouter( + routes: [ + GoRoute( + path: '/login', + builder: (context, state) => LoginScreen(), + ), + GoRoute( + path: '/servers', + builder: (context, state) => ServerListScreen(), + ), + // ... other routes + ], +); +``` + +#### TASK-141: Create App Shell with Bottom Navigation +**File:** `lib/presentation/screens/app_shell.dart` +- Bottom navigation bar +- Side drawer +- Route management + +--- + +### Task Group: US-8.2 - Settings Screen + +#### TASK-145: Create Settings Screen +**File:** `lib/presentation/screens/settings/settings_screen.dart` +- API base URL configuration +- Theme selector +- Language selector +- Cache management +- About section + +--- + +### Task Group: US-8.3/8.4 - Error Handling & Loading States + +#### TASK-150: Create Common Widgets +**Files:** +- `lib/presentation/widgets/common/loading_widget.dart` + - Shimmer loading for lists + - Circular progress for buttons +- `lib/presentation/widgets/common/error_widget.dart` + - Error icon and message + - Retry button +- `lib/presentation/widgets/common/empty_state_widget.dart` + - Empty list message + - Illustration + +--- + +## Phase 8: Testing & Polish + +### Task Group: Comprehensive Testing + +#### TASK-160 [P]: Write Unit Tests for All Use Cases +**Files:** `test/domain/use_cases/**/*_test.dart` +- Achieve 80%+ coverage + +#### TASK-161 [P]: Write Widget Tests for All Screens +**Files:** `test/presentation/screens/**/*_test.dart` + +#### TASK-162 [P]: Write Integration Tests +**Files:** `integration_test/app_test.dart` +- Login flow +- Server CRUD +- Action mapping CRUD + +--- + +### Task Group: Performance Optimization + +#### TASK-170: Implement List Pagination +**Files:** Update all list screens +- Infinite scroll +- Page size: 20 items + +#### TASK-171: Optimize Image Loading +**Files:** Update image widgets +- Use cached_network_image +- Progressive loading + +#### TASK-172: Implement Request Debouncing +**Files:** Update search fields +- Debounce duration: 300ms + +--- + +### Task Group: Accessibility + +#### TASK-175: Add Semantic Labels +**Files:** All widgets +- Proper semantic labels for screen readers + +#### TASK-176: Test with Screen Reader +**Files:** N/A (manual testing) + +#### TASK-177: Verify Contrast Ratios +**Files:** `lib/core/theme/colors.dart` + +--- + +## Phase 9: Deployment Preparation + +### Task Group: App Configuration + +#### TASK-180: Configure App Icons +**File:** Run flutter_launcher_icons + +#### TASK-181: Configure Splash Screen +**File:** Run flutter_native_splash + +#### TASK-182: Update App Metadata +**Files:** +- `android/app/src/main/AndroidManifest.xml` +- `ios/Runner/Info.plist` + +--- + +### Task Group: Build & Release + +#### TASK-185: Create Release Build (Android) +```bash +flutter build apk --release +flutter build appbundle --release +``` + +#### TASK-186: Create Release Build (iOS) +```bash +flutter build ipa --release +``` + +--- + +## Dependencies Between Tasks + +``` +Foundation Tasks (001-005) → All other tasks + +Authentication: + 010-011 → 012-013 → 014-015 → 016-017 → 018-019 → 020-021 → 022-023 → 024-025 + 030-031 (depends on 022-023) + +Servers: + 040-041 → 042-043 → 044 → 045 → 046 → 047-048 + 050 (depends on 046) + 055 (depends on 046) + 060-061 (depends on 046) + 065-066 (depends on 046) + +Action Mappings: + 070-071 → 072 → 073 → 074 → 075 → 076-077 + 080 (depends on 075) + +Cameras: + 090-091 → 092 → 093 → 094 → 095 → 096-097 + 100-103 (depends on 095) + +Monitors: + 110-111 → 112 → 113 → 114 → 115 → 116-117 + +Cross-Switching: + 120-122 (depends on 095 and 115) + +Configuration: + 130-131 + 135 + +Navigation: + 140-141 (depends on all screens being created) + +Settings: + 145 + +Common Widgets: + 150 (can be done in parallel, used by many screens) + +Testing: + 160-162 (depends on all implementations) + +Performance: + 170-172 (depends on screens) + +Accessibility: + 175-177 (depends on all widgets) + +Deployment: + 180-186 (depends on everything) +``` + +## Parallel Execution Opportunities + +Tasks marked with `[P]` can be executed in parallel: +- TASK-001, 002, 004, 005 (setup tasks) +- TASK-160, 161, 162 (testing can be distributed) + +Multiple developers can work on different epics simultaneously once foundation is complete.