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
This commit is contained in:
Achintha Isuru
2026-03-06 16:01:50 -05:00
parent f359439a6b
commit 9068773ba7
2 changed files with 2 additions and 927 deletions

View File

@@ -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

View File

@@ -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<bool> getProfileCompletion();
/// Fetches staff entity by ID.
///
/// Returns Staff entity or throws exception if not found.
Future<Staff> getStaffById(String id);
/// Updates staff profile.
Future<void> updateStaff(Staff staff);
}
```
**Use Cases:**
One use case per query or related query group:
```dart
// get_profile_completion_usecase.dart
class GetProfileCompletionUseCase extends UseCase<bool, NoParams> {
final StaffConnectorRepository _repository;
GetProfileCompletionUseCase({
required StaffConnectorRepository repository,
}) : _repository = repository;
@override
Future<Either<Failure, bool>> 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<Staff, String> {
final StaffConnectorRepository _repository;
GetStaffByIdUseCase({
required StaffConnectorRepository repository,
}) : _repository = repository;
@override
Future<Either<Failure, Staff>> 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<bool> 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<Staff> 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<void> 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<StaffConnectorRepository>(
StaffConnectorRepositoryImpl.new,
);
// Feature creates its own use case wrapper if needed
// Or uses connector use case directly
i.addSingleton(
() => GetProfileCompletionUseCase(
repository: i.get<StaffConnectorRepository>(),
),
);
// BLoC uses the use case
i.addSingleton(
() => StaffMainCubit(
getProfileCompletionUsecase: i.get<GetProfileCompletionUseCase>(),
),
);
}
@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<StaffMainState> {
final GetProfileCompletionUseCase _getProfileCompletionUsecase;
StaffMainCubit({
required GetProfileCompletionUseCase getProfileCompletionUsecase,
}) : _getProfileCompletionUsecase = getProfileCompletionUsecase,
super(const StaffMainState()) {
_loadProfileCompletion();
}
Future<void> _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<StaffMainCubit, StaffMainState>(
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<bool> getProfileCompletion();
// NEW: Add method signature
Future<Staff> 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<Staff> 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<Staff, String> {
final StaffConnectorRepository _repository;
GetStaffByIdUseCase({
required StaffConnectorRepository repository,
}) : _repository = repository;
@override
Future<Either<Failure, Staff>> 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<StaffConnectorRepository>().getStaffById(id);
// Or via use case
final result = await i.get<GetStaffByIdUseCase>()(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<List<Notification>> getNotifications(String userId);
Future<void> markAsRead(String notificationId);
Future<int> getUnreadCount(String userId);
}
```
### Step 3: Create Use Cases
```dart
// get_notifications_usecase.dart
class GetNotificationsUseCase extends UseCase<List<Notification>, String> {
final NotificationsConnectorRepository _repository;
GetNotificationsUseCase({
required NotificationsConnectorRepository repository,
}) : _repository = repository;
@override
Future<Either<Failure, List<Notification>>> 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<List<Notification>> 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<void> markAsRead(String notificationId) async {
return await _service.run(() async {
await _service.connector
.markNotificationAsRead(id: notificationId)
.execute();
});
}
@override
Future<int> 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<NotificationsConnectorRepository>(
NotificationsConnectorRepositoryImpl.new,
);
i.addSingleton(
() => GetNotificationsUseCase(
repository: i.get<NotificationsConnectorRepository>(),
),
);
```
## 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<StaffConnectorRepository>().getProfileCompletion()
// Feature B
i.get<StaffConnectorRepository>().getStaffById(id)
// Feature C
i.get<StaffConnectorRepository>().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<Staff> 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<bool> checkProfileCompletion() { /*...*/ }
// profile/data/repositories/profile_repository_impl.dart
Future<bool> checkProfileCompletion() { /*...*/ }
// onboarding/data/repositories/onboarding_repository_impl.dart
Future<bool> 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<ProfileState> {
Future<void> 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<ProfileState> {
Future<void> 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.