From 9068773ba7dbf7854253e044b0175073e09f7460 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 6 Mar 2026 16:01:50 -0500 Subject: [PATCH] refactor(skills): remove krow-mobile-data-connect skill - Deleted .agents/skills/krow-mobile-data-connect/ directory - Updated README.md to remove all references - Now maintaining 4 core mobile skills instead of 5 --- .agents/skills/README.md | 35 +- .../skills/krow-mobile-data-connect/SKILL.md | 894 ------------------ 2 files changed, 2 insertions(+), 927 deletions(-) delete mode 100644 .agents/skills/krow-mobile-data-connect/SKILL.md diff --git a/.agents/skills/README.md b/.agents/skills/README.md index 86d992d8..b25a74f6 100644 --- a/.agents/skills/README.md +++ b/.agents/skills/README.md @@ -9,7 +9,6 @@ These skills help AI agents contribute effectively to mobile application develop - **Architecture patterns** for Clean Architecture implementation - **Design system rules** for consistent UI implementation - **Release procedures** for version management and deployment -- **Data access patterns** for backend integration ## Available Skills @@ -116,31 +115,6 @@ These skills help AI agents contribute effectively to mobile application develop - Source: `docs/MOBILE/05-release-process.md` - Comprehensive: `docs/RELEASE/mobile-releases.md` (900+ lines) -### 5. krow-mobile-data-connect - -**Purpose:** Centralized backend query management via connectors pattern - -**Covers:** -- Data Connect connectors pattern rationale -- Connector structure (mirroring backend) -- Clean Architecture in connectors (domain/data layers) -- Feature integration pattern -- Adding queries to existing connectors -- Creating new connectors -- Benefits and anti-patterns -- Current implementation (staff, shifts connectors) - -**Use When:** -- Integrating backend queries into mobile features -- Creating new connector repositories -- Adding queries to existing connectors -- Preventing duplicate backend queries -- Implementing feature repositories that use connectors -- Understanding data layer architecture - -**Key Documentation:** -- Source: `docs/MOBILE/03-data-connect-connectors-pattern.md` - ## Skill Organization Each skill follows this structure: @@ -153,9 +127,7 @@ Each skill follows this structure: │ └── SKILL.md ├── krow-mobile-design-system/ │ └── SKILL.md -├── krow-mobile-release/ -│ └── SKILL.md -└── krow-mobile-data-connect/ +└── krow-mobile-release/ └── SKILL.md ``` @@ -175,7 +147,6 @@ Each skill includes a description in its frontmatter that helps AI agents determ 2. **Skills can be combined** - multiple skills may be relevant: - Development rules + Architecture (implementing features) - Architecture + Design System (creating UI with proper structure) - - Development rules + Data Connect (backend integration) - Release + Development rules (preparing releases) 3. **Reference documentation** when needed: @@ -217,7 +188,7 @@ docs/MOBILE/ ├── 00-agent-development-rules.md → krow-mobile-development-rules ├── 01-architecture-principles.md → krow-mobile-architecture ├── 02-design-system-usage.md → krow-mobile-design-system -├── 03-data-connect-connectors-pattern.md → krow-mobile-data-connect +├── 03-data-connect-connectors-pattern.md (not in skills) ├── 04-use-case-completion-audit.md (not in skills yet) └── 05-release-process.md → krow-mobile-release @@ -230,7 +201,6 @@ docs/RELEASE/ These skills encode **NON-NEGOTIABLE** standards. When AI agents: - Create features → Must follow development rules - Implement UI → Must use design system -- Access backend → Must use connectors pattern - Prepare releases → Must follow release process - Structure code → Must maintain Clean Architecture @@ -257,7 +227,6 @@ These skills transform documentation into actionable, contextual guidance for AI - Clean Architecture with strict boundaries - Feature isolation via zero cross-feature imports - Immutable design system -- Centralized backend access via connectors - Semantic versioning and structured releases - Localization-first user interfaces diff --git a/.agents/skills/krow-mobile-data-connect/SKILL.md b/.agents/skills/krow-mobile-data-connect/SKILL.md deleted file mode 100644 index fbd0ce3c..00000000 --- a/.agents/skills/krow-mobile-data-connect/SKILL.md +++ /dev/null @@ -1,894 +0,0 @@ ---- -name: krow-mobile-data-connect -description: KROW Data Connect connectors pattern for centralized backend query management. Use when integrating backend queries, creating connector repositories, adding queries to existing connectors, implementing feature repositories, preventing query duplication, or understanding Clean Architecture data layer. Covers connector structure, repository pattern, feature integration, and benefits over feature-specific repositories. ---- - -# KROW Mobile Data Connect Connectors Pattern - -This skill describes the Data Connect Connectors pattern used in KROW mobile apps to centralize all backend query logic by mirroring backend connector structure. - -## When to Use This Skill - -- Integrating backend queries into mobile features -- Creating new connector repositories -- Adding queries to existing connectors -- Understanding data layer architecture -- Preventing duplicate backend queries -- Implementing feature repositories that use connectors -- Refactoring feature-specific queries to connectors -- Debugging Data Connect integration issues -- Understanding session management and token refresh - -## Problem Statement - -### Without Connectors Pattern - -Each feature creates its own repository implementation, leading to: - -**❌ Query Duplication:** -``` -staff_main/ - └── data/repositories/profile_completion_repository_impl.dart ← queries staff connector -profile/ - └── data/repositories/profile_repository_impl.dart ← also queries staff connector -onboarding/ - └── data/repositories/personal_info_repository_impl.dart ← also queries staff connector -``` - -**Issues:** -- Multiple features query the same backend connector -- When backend queries change, updates needed in multiple places -- No reusability across features -- Code duplication and maintenance burden - -### With Connectors Pattern - -All backend connector queries implemented once: - -**✅ Centralized:** -``` -data_connect/ - └── connectors/ - └── staff/ - ├── domain/ - │ ├── repositories/staff_connector_repository.dart - │ └── usecases/get_profile_completion_usecase.dart - └── data/ - └── repositories/staff_connector_repository_impl.dart - -# Features use connector repositories -staff_main/ → uses StaffConnectorRepository -profile/ → uses StaffConnectorRepository -onboarding/ → uses StaffConnectorRepository -``` - -**Benefits:** -- ✅ Single implementation per query -- ✅ Reused across all features -- ✅ Backend change → update one place -- ✅ No duplication - -## 1. Connector Structure - -### Package Organization - -**Location:** `apps/mobile/packages/data_connect/lib/src/connectors/` - -**Structure:** -``` -data_connect/lib/src/connectors/ -├── staff/ # Mirrors backend/dataconnect/connector/staff/ -│ ├── domain/ -│ │ ├── repositories/ -│ │ │ └── staff_connector_repository.dart # Interface -│ │ └── usecases/ -│ │ ├── get_profile_completion_usecase.dart -│ │ └── get_staff_by_id_usecase.dart -│ └── data/ -│ └── repositories/ -│ └── staff_connector_repository_impl.dart # Implementation -├── order/ # Mirrors backend/dataconnect/connector/order/ -│ ├── domain/ -│ │ ├── repositories/ -│ │ │ └── order_connector_repository.dart -│ │ └── usecases/ -│ └── data/ -│ └── repositories/ -│ └── order_connector_repository_impl.dart -├── shifts/ # Mirrors backend/dataconnect/connector/shifts/ -│ ├── domain/ -│ │ ├── repositories/ -│ │ │ └── shifts_connector_repository.dart -│ │ └── usecases/ -│ │ ├── list_shifts_usecase.dart -│ │ └── apply_for_shifts_usecase.dart -│ └── data/ -│ └── repositories/ -│ └── shifts_connector_repository_impl.dart -└── user/ # Mirrors backend/dataconnect/connector/user/ - ├── domain/ - └── data/ -``` - -**Mirroring Backend:** -``` -backend/dataconnect/connector/ -├── staff/ -│ ├── queries/ -│ │ └── profile_completion.gql -│ └── mutations/ -├── order/ -├── shifts/ -│ ├── queries/ -│ │ └── list_shift_roles_by_vendor.gql -│ └── mutations/ -│ └── apply_for_shifts.gql -└── user/ -``` - -**Key Principle:** Mobile connector structure mirrors backend connector structure. - -## 2. Clean Architecture in Connectors - -Each connector follows Clean Architecture with three layers. - -### Domain Layer (`connectors/{name}/domain/`) - -**Repository Interface:** - -Define contract (what operations are available): - -```dart -// staff_connector_repository.dart -abstract interface class StaffConnectorRepository { - /// Returns true if staff profile is complete. - /// - /// Checks: personal info, emergency contacts, tax forms, experience. - Future getProfileCompletion(); - - /// Fetches staff entity by ID. - /// - /// Returns Staff entity or throws exception if not found. - Future getStaffById(String id); - - /// Updates staff profile. - Future updateStaff(Staff staff); -} -``` - -**Use Cases:** - -One use case per query or related query group: - -```dart -// get_profile_completion_usecase.dart -class GetProfileCompletionUseCase extends UseCase { - final StaffConnectorRepository _repository; - - GetProfileCompletionUseCase({ - required StaffConnectorRepository repository, - }) : _repository = repository; - - @override - Future> call(NoParams params) async { - try { - final result = await _repository.getProfileCompletion(); - return Right(result); - } on DataConnectException catch (e) { - return Left(ServerFailure(e.message)); - } - } -} -``` - -```dart -// get_staff_by_id_usecase.dart -class GetStaffByIdUseCase extends UseCase { - final StaffConnectorRepository _repository; - - GetStaffByIdUseCase({ - required StaffConnectorRepository repository, - }) : _repository = repository; - - @override - Future> call(String staffId) async { - try { - final staff = await _repository.getStaffById(staffId); - return Right(staff); - } on DataConnectException catch (e) { - return Left(ServerFailure(e.message)); - } - } -} -``` - -**Characteristics:** -- Pure Dart (no Flutter dependencies) -- Stable, business-focused contracts -- One interface per connector domain -- One use case per query or logical query group - -### Data Layer (`connectors/{name}/data/`) - -**Repository Implementation:** - -Implements domain interface using `DataConnectService`: - -```dart -// staff_connector_repository_impl.dart -class StaffConnectorRepositoryImpl implements StaffConnectorRepository { - final DataConnectService _service; - - StaffConnectorRepositoryImpl({ - DataConnectService? service, - }) : _service = service ?? DataConnectService.instance; - - @override - Future getProfileCompletion() async { - return await _service.run(() async { - // Get current staff ID from session - final staffId = await _service.getStaffId(); - - // Execute Data Connect query - final response = await _service.connector - .getStaffProfileCompletion(id: staffId) - .execute(); - - // Check completion criteria - return _isProfileComplete(response); - }); - } - - @override - Future getStaffById(String id) async { - return await _service.run(() async { - final response = await _service.connector - .getStaffById(id: id) - .execute(); - - // Map Data Connect model to Domain entity - return _mapToStaff(response.data.staff); - }); - } - - @override - Future updateStaff(Staff staff) async { - return await _service.run(() async { - await _service.connector - .updateStaff( - id: staff.id, - name: staff.name, - email: staff.email, - // ... other fields - ) - .execute(); - }); - } - - /// Maps Data Connect staff model to Domain Staff entity - Staff _mapToStaff(dynamic dataConnectStaff) { - return Staff( - id: dataConnectStaff.id, - name: dataConnectStaff.name, - email: dataConnectStaff.email, - status: _mapStatus(dataConnectStaff.status), - ); - } - - /// Checks if profile is complete based on business rules - bool _isProfileComplete(dynamic response) { - final data = response.data.staff; - - return data.personalInfo != null && - data.emergencyContacts.isNotEmpty && - data.taxForms != null && - data.experience != null; - } -} -``` - -**Key Features of `_service.run()`:** -- ✅ Auto validates user is authenticated -- ✅ Refreshes token if <5 minutes to expiry -- ✅ Executes the query -- ✅ 3-attempt retry with exponential backoff (1s → 2s → 4s) -- ✅ Maps exceptions to domain failures -- ✅ Consistent error handling - -**Characteristics:** -- Implements domain repository interface -- Uses `DataConnectService` to execute queries -- Maps backend response types to domain entities -- Contains mapping/transformation logic only -- Handles type safety with generated Data Connect types - -## 3. Feature Integration Pattern - -### Step 1: Feature Needs Data - -Feature (e.g., `staff_main`) needs profile completion status. - -### Step 2: Register Connector in Feature Module - -Instead of creating a local repository, feature uses connector: - -```dart -// staff_main_module.dart -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:krow_data_connect/krow_data_connect.dart'; - -class StaffMainModule extends Module { - @override - void binds(Injector i) { - // Register connector repository from data_connect - i.addSingleton( - StaffConnectorRepositoryImpl.new, - ); - - // Feature creates its own use case wrapper if needed - // Or uses connector use case directly - i.addSingleton( - () => GetProfileCompletionUseCase( - repository: i.get(), - ), - ); - - // BLoC uses the use case - i.addSingleton( - () => StaffMainCubit( - getProfileCompletionUsecase: i.get(), - ), - ); - } - - @override - void routes(RouteManager r) { - r.child( - '/', - child: (_) => StaffMainPage(), - ); - } -} -``` - -### Step 3: BLoC Uses Connector via Use Case - -```dart -// staff_main_cubit.dart -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:krow_data_connect/krow_data_connect.dart'; - -class StaffMainCubit extends Cubit { - final GetProfileCompletionUseCase _getProfileCompletionUsecase; - - StaffMainCubit({ - required GetProfileCompletionUseCase getProfileCompletionUsecase, - }) : _getProfileCompletionUsecase = getProfileCompletionUsecase, - super(const StaffMainState()) { - _loadProfileCompletion(); - } - - Future _loadProfileCompletion() async { - emit(state.copyWith(isLoading: true)); - - final result = await _getProfileCompletionUsecase(NoParams()); - - result.fold( - (failure) => emit(state.copyWith( - isLoading: false, - error: failure.message, - )), - (isComplete) => emit(state.copyWith( - isLoading: false, - isProfileComplete: isComplete, - )), - ); - } -} -``` - -### Step 4: UI Reacts to State - -```dart -// staff_main_page.dart -class StaffMainPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state.isLoading) { - return const LoadingIndicator(); - } - - if (state.isProfileComplete) { - return CompleteProfileView(); - } - - return IncompleteProfileView(); - }, - ); - } -} -``` - -## 4. Export Pattern - -### Exporting from Data Connect Package - -Connectors are exported from `krow_data_connect` for easy access: - -```dart -// lib/krow_data_connect.dart -library krow_data_connect; - -// Data Connect Service -export 'src/services/data_connect_service.dart'; - -// Session Stores -export 'src/session/staff_session_store.dart'; -export 'src/session/client_session_store.dart'; - -// Staff Connector -export 'src/connectors/staff/domain/repositories/staff_connector_repository.dart'; -export 'src/connectors/staff/domain/usecases/get_profile_completion_usecase.dart'; -export 'src/connectors/staff/domain/usecases/get_staff_by_id_usecase.dart'; -export 'src/connectors/staff/data/repositories/staff_connector_repository_impl.dart'; - -// Shifts Connector -export 'src/connectors/shifts/domain/repositories/shifts_connector_repository.dart'; -export 'src/connectors/shifts/domain/usecases/list_shifts_usecase.dart'; -export 'src/connectors/shifts/data/repositories/shifts_connector_repository_impl.dart'; - -// Order Connector -export 'src/connectors/order/domain/repositories/order_connector_repository.dart'; -export 'src/connectors/order/data/repositories/order_connector_repository_impl.dart'; -``` - -### Features Import - -Features import with single statement: - -```dart -import 'package:krow_data_connect/krow_data_connect.dart'; - -// Now have access to: -// - StaffConnectorRepository -// - GetProfileCompletionUseCase -// - DataConnectService -// - StaffSessionStore -// etc. -``` - -## 5. Adding New Queries to Existing Connector - -When backend adds `getStaffById()` query to staff connector: - -### Step 1: Add to Interface - -```dart -// staff_connector_repository.dart -abstract interface class StaffConnectorRepository { - Future getProfileCompletion(); - - // NEW: Add method signature - Future getStaffById(String id); -} -``` - -### Step 2: Implement in Repository - -```dart -// staff_connector_repository_impl.dart -class StaffConnectorRepositoryImpl implements StaffConnectorRepository { - // ... existing methods ... - - // NEW: Implement method - @override - Future getStaffById(String id) async { - return await _service.run(() async { - final response = await _service.connector - .getStaffById(id: id) - .execute(); - return _mapToStaff(response.data.staff); - }); - } -} -``` - -### Step 3: Create Use Case (Optional) - -```dart -// get_staff_by_id_usecase.dart -class GetStaffByIdUseCase extends UseCase { - final StaffConnectorRepository _repository; - - GetStaffByIdUseCase({ - required StaffConnectorRepository repository, - }) : _repository = repository; - - @override - Future> call(String staffId) async { - try { - final staff = await _repository.getStaffById(staffId); - return Right(staff); - } on DataConnectException catch (e) { - return Left(ServerFailure(e.message)); - } - } -} -``` - -### Step 4: Export - -```dart -// krow_data_connect.dart -export 'src/connectors/staff/domain/usecases/get_staff_by_id_usecase.dart'; -``` - -### Step 5: Use in Features - -```dart -// Any feature can now use it -final staff = await i.get().getStaffById(id); - -// Or via use case -final result = await i.get()(staffId); -``` - -## 6. Creating New Connector - -When backend adds new connector (e.g., `notifications`): - -### Step 1: Create Directory Structure - -```bash -mkdir -p apps/mobile/packages/data_connect/lib/src/connectors/notifications -mkdir -p apps/mobile/packages/data_connect/lib/src/connectors/notifications/domain/repositories -mkdir -p apps/mobile/packages/data_connect/lib/src/connectors/notifications/domain/usecases -mkdir -p apps/mobile/packages/data_connect/lib/src/connectors/notifications/data/repositories -``` - -### Step 2: Define Domain Interface - -```dart -// notifications_connector_repository.dart -abstract interface class NotificationsConnectorRepository { - Future> getNotifications(String userId); - Future markAsRead(String notificationId); - Future getUnreadCount(String userId); -} -``` - -### Step 3: Create Use Cases - -```dart -// get_notifications_usecase.dart -class GetNotificationsUseCase extends UseCase, String> { - final NotificationsConnectorRepository _repository; - - GetNotificationsUseCase({ - required NotificationsConnectorRepository repository, - }) : _repository = repository; - - @override - Future>> call(String userId) async { - try { - final notifications = await _repository.getNotifications(userId); - return Right(notifications); - } on DataConnectException catch (e) { - return Left(ServerFailure(e.message)); - } - } -} -``` - -### Step 4: Implement Repository - -```dart -// notifications_connector_repository_impl.dart -class NotificationsConnectorRepositoryImpl - implements NotificationsConnectorRepository { - final DataConnectService _service; - - NotificationsConnectorRepositoryImpl({ - DataConnectService? service, - }) : _service = service ?? DataConnectService.instance; - - @override - Future> getNotifications(String userId) async { - return await _service.run(() async { - final response = await _service.connector - .getNotifications(userId: userId) - .execute(); - - return response.data.notifications - .map(_mapToNotification) - .toList(); - }); - } - - @override - Future markAsRead(String notificationId) async { - return await _service.run(() async { - await _service.connector - .markNotificationAsRead(id: notificationId) - .execute(); - }); - } - - @override - Future getUnreadCount(String userId) async { - return await _service.run(() async { - final response = await _service.connector - .getUnreadNotificationCount(userId: userId) - .execute(); - return response.data.count; - }); - } - - Notification _mapToNotification(dynamic data) { - return Notification( - id: data.id, - title: data.title, - message: data.message, - isRead: data.isRead, - createdAt: DateTime.parse(data.createdAt), - ); - } -} -``` - -### Step 5: Export from Package - -```dart -// krow_data_connect.dart -export 'src/connectors/notifications/domain/repositories/notifications_connector_repository.dart'; -export 'src/connectors/notifications/domain/usecases/get_notifications_usecase.dart'; -export 'src/connectors/notifications/data/repositories/notifications_connector_repository_impl.dart'; -``` - -### Step 6: Features Use Immediately - -```dart -// feature_module.dart -i.addSingleton( - NotificationsConnectorRepositoryImpl.new, -); - -i.addSingleton( - () => GetNotificationsUseCase( - repository: i.get(), - ), -); -``` - -## 7. Benefits Summary - -### ✅ No Duplication -**Before:** -- `staff_main/data/repositories/` → implements profile completion query -- `profile/data/repositories/` → duplicates same query -- `onboarding/data/repositories/` → duplicates same query - -**After:** -- `data_connect/connectors/staff/` → implements once -- All features use same connector repository - -### ✅ Single Source of Truth -**Backend Change:** `getStaffProfileCompletion` query updated - -**Before:** -- Update in 3+ feature repositories -- Risk of missing updates -- Inconsistent implementations - -**After:** -- Update once in `StaffConnectorRepositoryImpl` -- All features automatically use new implementation - -### ✅ Clean Separation -- **Connector Logic:** Query backend, map responses -- **Feature Logic:** Use cases, business rules, UI state - -### ✅ Reusability -**Any feature can use any connector:** -```dart -// Feature A -i.get().getProfileCompletion() - -// Feature B -i.get().getStaffById(id) - -// Feature C -i.get().updateStaff(staff) -``` - -### ✅ Testability -**Mock connector repository to test features:** -```dart -class MockStaffConnectorRepository extends Mock - implements StaffConnectorRepository {} - -final mockRepo = MockStaffConnectorRepository(); -when(mockRepo.getProfileCompletion()).thenAnswer((_) async => true); - -final useCase = GetProfileCompletionUseCase(repository: mockRepo); -``` - -### ✅ Scalability -Easy to add new connectors as backend grows: -- Backend adds `payments` connector → Mobile adds `payments/` folder -- Backend adds `messaging` connector → Mobile adds `messaging/` folder -- Pattern scales indefinitely - -### ✅ Mirrors Backend -Mobile structure mirrors backend structure, making it intuitive: -``` -backend/dataconnect/connector/staff/ - ↕️ -data_connect/connectors/staff/ -``` - -## 8. Anti-Patterns to Avoid - -### ❌ DON'T: Implement Queries in Feature Repositories - -```dart -// ❌ BAD: Feature-specific repository querying backend directly -class ProfileRepositoryImpl implements ProfileRepositoryInterface { - Future getProfile() async { - // Directly querying Data Connect - final response = await FirebaseDataConnect.instance - .getStaffById(id: id) - .execute(); - return Staff(...); - } -} -``` - -**Problem:** Duplicated across multiple features, no reusability. - -### ❌ DON'T: Duplicate Queries Across Features - -```dart -// ❌ BAD: Same query in multiple features -// staff_main/data/repositories/profile_repository_impl.dart -Future checkProfileCompletion() { /*...*/ } - -// profile/data/repositories/profile_repository_impl.dart -Future checkProfileCompletion() { /*...*/ } - -// onboarding/data/repositories/onboarding_repository_impl.dart -Future checkProfileCompletion() { /*...*/ } -``` - -**Problem:** 3x duplication, 3x maintenance, 3x bug risk. - -### ❌ DON'T: Put Mapping Logic in Features - -```dart -// ❌ BAD: Feature doing data transformation -class ProfileCubit extends Cubit { - Future loadProfile() async { - final response = await connector.getStaff(); - - // Mapping logic in BLoC - final staff = Staff( - id: response.data.staff.id, - name: response.data.staff.name, - ); - } -} -``` - -**Problem:** Violates Clean Architecture, duplicated mapping logic. - -### ❌ DON'T: Call DataConnectService Directly from BLoCs - -```dart -// ❌ BAD: BLoC bypassing repository layer -class ProfileCubit extends Cubit { - Future loadProfile() async { - final response = await DataConnectService.instance.connector - .getStaffById(id: id) - .execute(); - } -} -``` - -**Problem:** No abstraction, no testability, tight coupling. - -### ✅ DO: Use Connector Repositories Through Use Cases - -```dart -// ✅ GOOD: Clean Architecture flow -Feature BLoC → Use Case → Connector Repository → Data Connect Service → Backend -``` - -## 9. Current Implementation - -### Staff Connector - -**Location:** `apps/mobile/packages/data_connect/lib/src/connectors/staff/` - -**Available Queries:** -- `getProfileCompletion()` - Returns bool indicating if profile complete - - Checks: personal info, emergency contacts, tax forms, experience - -**Used By:** -- `staff_main` - Guards bottom nav items requiring profile completion -- `profile` - Displays completion status -- `onboarding` - Checks if onboarding needed - -**Backend Queries:** -- `backend/dataconnect/connector/staff/queries/profile_completion.gql` - -### Shifts Connector - -**Location:** `apps/mobile/packages/data_connect/lib/src/connectors/shifts/` - -**Available Queries:** -- `listShiftRolesByVendorId()` - Fetches shifts with status mapping -- `applyForShifts()` - Handles shift application with error tracking - -**Used By:** -- `shifts` feature - Displays available shifts -- `shift_details` feature - Shows shift information - -**Backend Queries:** -- `backend/dataconnect/connector/shifts/queries/list_shift_roles_by_vendor.gql` -- `backend/dataconnect/connector/shifts/mutations/apply_for_shifts.gql` - -## 10. Future Expansion - -As app grows, additional connectors will be added: - -**Planned Connectors:** -- `order_connector_repository` - From `backend/dataconnect/connector/order/` -- `user_connector_repository` - From `backend/dataconnect/connector/user/` -- `emergency_contact_connector_repository` - From `backend/dataconnect/connector/emergencyContact/` -- `documents_connector_repository` - From `backend/dataconnect/connector/documents/` -- `payments_connector_repository` - From `backend/dataconnect/connector/payments/` - -Each following the same Clean Architecture pattern. - -## Summary - -**Core Pattern:** -1. **Mirror Backend:** Connector structure mirrors backend connector structure -2. **Clean Architecture:** Domain interfaces → Data implementations -3. **Centralized:** All backend queries in one place per connector -4. **Reusable:** Any feature can use any connector via dependency injection -5. **Single Source:** Backend change → update one repository -6. **Type Safe:** Uses Data Connect generated types - -**Implementation Flow:** -``` -Feature Module registers connector repository - ↓ -Feature Use Case uses connector repository - ↓ -Connector Repository uses DataConnectService.run() - ↓ -DataConnectService executes Data Connect query - ↓ -Repository maps response to Domain entity - ↓ -Use Case returns Result to BLoC - ↓ -BLoC emits state to UI -``` - -**When implementing features:** -1. Identify which backend connector you need (staff, order, shifts, etc.) -2. Use corresponding connector repository from `data_connect` -3. Register in feature module via dependency injection -4. BLoC uses connector repository through use cases -5. Don't create feature-specific repositories for backend queries - -**When backend adds queries:** -1. Add to appropriate connector repository interface -2. Implement in connector repository implementation -3. Features automatically have access via dependency injection - -The connector pattern eliminates duplication, ensures consistency, and scales as the backend grows. Always use connectors for backend access, never query Data Connect directly from features.