Files
geutebruck-api/specs/001-flutter-app/tasks.md
Geutebruck API Developer b46403cecb Update Flutter app implementation status and task tracking
- Updated task status to reflect Phase 2 completion (Server Management)
- Added completed features:
  * US-2.5: Create G-Core Server
  * US-2.6: Create GeViScope Server
  * US-2.7: Update Server
  * US-2.8: Delete Server
  * Offline-first architecture with Hive
  * Server sync and download functionality
  * Shared BLoC state across routes
- Documented recent bug fix: "No data" display issue resolved
- Updated last modified date to 2025-12-23

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 00:07:56 +01:00

812 lines
21 KiB
Markdown

# 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<String, dynamic> 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<void> saveToken(String key, String token);
Future<String?> getToken(String key);
Future<void> deleteToken(String key);
Future<void> 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<AuthResponse> login(String username, String password);
Future<AuthResponse> 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<Failure, T>
#### 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<Either<Failure, User>> 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<AuthEvent, AuthState> {
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<ServerListResponse> getServers();
@GET('/servers/gcore')
Future<GCoreServerListResponse> getGCoreServers();
@GET('/servers/geviscope')
Future<GeViScopeServerListResponse> 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<String, String> inputActions,
required List<OutputAction> outputActions,
}) = _ActionMapping;
}
@freezed
class OutputAction with _$OutputAction {
const factory OutputAction({
required String action,
required String caption,
String? server,
required Map<String, String> 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<List<ActionMappingModel>> getActionMappings();
@GET('/action-mappings/{id}')
Future<ActionMappingModel> getActionMapping(@Path() int id);
@POST('/action-mappings')
Future<void> createActionMapping(@Body() ActionMappingCreateRequest request);
@PUT('/action-mappings/{id}')
Future<void> updateActionMapping(
@Path() int id,
@Body() ActionMappingUpdateRequest request,
);
@DELETE('/action-mappings/{id}')
Future<void> 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<List<CameraModel>> getCameras();
@GET('/{id}')
Future<CameraModel> 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.