# Feature Implementer

> Feature Implementation Automation Skill

- Skill: `kandil7/feature-implementer` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add kandil7/feature-implementer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kandil7/feature-implementer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Kandil7 (https://skillmd.com/u/kandil7)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kandil7/feature-implementer

---

# Feature Implementation Automation Skill

## Skill Overview

You are an expert Flutter developer specializing in Clean Architecture implementation. This skill automates the complete implementation of Flutter features from specifications in `IMPLEMENTATION_PLAN.md`, following PRPROMPTS methodology with comprehensive testing and security validation.

**What This Skill Does:**
- Reads feature specifications from IMPLEMENTATION_PLAN.md
- Implements complete Clean Architecture structure (domain/data/presentation layers)
- Generates entities, use cases, repositories, data sources
- Creates BLoC/Cubit state management
- Builds UI components (screens, widgets)
- Writes comprehensive tests (unit, widget, integration)
- Validates security patterns and compliance requirements
- Ensures 70%+ test coverage

**Execution Time:** 3-8 minutes per feature

---

## Prerequisites

Before running this skill, verify:

1. **Flutter Project Initialized:**
   ```bash
   # Check Flutter project exists
   test -f pubspec.yaml || echo "❌ Not a Flutter project"
   ```

2. **IMPLEMENTATION_PLAN.md Exists:**
   ```bash
   # Check implementation plan
   test -f docs/IMPLEMENTATION_PLAN.md || echo "❌ IMPLEMENTATION_PLAN.md not found"
   ```

3. **PRPROMPTS Files Present:**
   ```bash
   # Check PRPROMPTS directory
   test -d PRPROMPTS || echo "❌ PRPROMPTS directory not found"
   ls PRPROMPTS/*.md | wc -l  # Should show 32 files
   ```

4. **Flutter Bootstrapper Completed:**
   - Clean Architecture folder structure exists: `lib/features/`, `lib/core/`
   - Core utilities configured (dependency injection, error handling, network)

**If prerequisites not met:**
- Run `@claude use skill automation/flutter-bootstrapper` first

---

## Step 1: Parse Feature Specification

### 1.1 Read IMPLEMENTATION_PLAN.md

**Read the entire implementation plan:**

```bash
# Display implementation plan
cat docs/IMPLEMENTATION_PLAN.md
```

**Expected Structure:**
```markdown
# Implementation Plan

## Phase 1: Core Features (Week 1-2)

### Feature 1: Authentication
**Priority:** HIGH
**Estimated Time:** 6-8 hours
**Dependencies:** None

**Requirements:**
- Email/password authentication
- JWT token management
- Biometric authentication (iOS/Android)
- Session persistence

**User Stories:**
- As a user, I can register with email/password
- As a user, I can log in with email/password
- As a user, I can use Face ID/Touch ID to log in
- As a user, I stay logged in after closing the app

**Acceptance Criteria:**
- [ ] User can register with valid email/password
- [ ] User receives email verification
- [ ] User can log in with verified credentials
- [ ] JWT token stored securely in FlutterSecureStorage
- [ ] Biometric auth enabled after first login
- [ ] Session persists across app restarts
- [ ] Login screen shows proper validation errors

**Technical Details:**
- Use firebase_auth or custom backend
- Store JWT in FlutterSecureStorage (encrypted)
- Use local_auth package for biometrics
- Implement auto-logout after 30 minutes inactivity
- Hash passwords with bcrypt (backend)

**Security Requirements:**
- NEVER store passwords in plain text
- Use HTTPS for all auth endpoints
- Implement rate limiting (5 attempts/15min)
- JWT expires after 24 hours
- Refresh token rotation

**API Endpoints:**
- POST /api/auth/register
- POST /api/auth/login
- POST /api/auth/refresh
- POST /api/auth/logout
- GET /api/auth/verify-email

**Data Models:**
```dart
class User {
  final String id;
  final String email;
  final String? displayName;
  final String? photoUrl;
  final bool emailVerified;
  final DateTime createdAt;
}

class AuthTokens {
  final String accessToken;
  final String refreshToken;
  final DateTime expiresAt;
}
```

**UI Screens:**
- LoginScreen (lib/features/auth/presentation/pages/login_screen.dart)
- RegisterScreen (lib/features/auth/presentation/pages/register_screen.dart)
- ForgotPasswordScreen (lib/features/auth/presentation/pages/forgot_password_screen.dart)

**Tests Required:**
- Unit tests for use cases (login, register, logout)
- Unit tests for repositories
- Widget tests for login/register screens
- Integration test for complete auth flow
```

### 1.2 Extract Feature Information

**Parse the feature specified in input:**

From `{{feature_name}}` input, extract:
- Feature name (e.g., "authentication")
- Priority level
- Requirements list
- User stories
- Acceptance criteria
- Technical details
- Security requirements
- API endpoints
- Data models
- UI screens
- Test requirements

**Create a feature summary:**

```markdown
# Feature: {{feature_name}}

## Key Information
- **Priority:** [HIGH/MEDIUM/LOW]
- **Estimated Time:** [X hours]
- **Dependencies:** [List or None]

## Requirements
[Bulleted list from plan]

## Security Requirements
[Critical security patterns to implement]

## Architecture Components

### Domain Layer
- Entities: [List entities to create]
- Use Cases: [List use cases to create]
- Repository Contracts: [List repository interfaces]

### Data Layer
- Models: [List data models]
- Data Sources: [Remote/Local data sources]
- Repository Implementations: [Concrete repositories]

### Presentation Layer
- BLoC/Cubit: [State management files]
- Screens: [UI screens to build]
- Widgets: [Reusable widgets]

## Test Strategy
- Unit Tests: [X files]
- Widget Tests: [Y files]
- Integration Tests: [Z files]
- Target Coverage: {{test_coverage_target}}%
```

**Validation:**
- ✅ Feature exists in IMPLEMENTATION_PLAN.md
- ✅ All required sections present
- ✅ Data models defined
- ✅ API endpoints documented
- ✅ Security requirements specified

**If feature not found in plan:**
```markdown
❌ ERROR: Feature "{{feature_name}}" not found in IMPLEMENTATION_PLAN.md

Available features:
[List all features from plan with priorities]

Please specify a valid feature name or update IMPLEMENTATION_PLAN.md.
```

---

## Step 2: Implement Domain Layer

The domain layer contains business logic and is independent of frameworks, UI, and external dependencies.

### 2.1 Create Entities

**Entities are pure Dart classes representing core business objects.**

For each entity in the feature:

**File:** `lib/features/{{feature_name}}/domain/entities/{{entity_name}}.dart`

**Template:**
```dart
import 'package:equatable/equatable.dart';

/// {{Entity description from plan}}
///
/// This entity represents {{business concept explanation}}.
///
/// **Business Rules:**
/// - {{Rule 1}}
/// - {{Rule 2}}
///
/// **Immutability:** This entity is immutable to ensure data consistency
/// and prevent accidental mutations across the application.
class {{EntityName}} extends Equatable {
  /// {{Field description}}
  final {{Type}} {{fieldName}};

  const {{EntityName}}({
    required this.{{fieldName}},
    // ... other fields
  });

  @override
  List<Object?> get props => [{{fieldName}}, /* other fields */];

  @override
  bool get stringify => true;

  /// Creates a copy of this entity with updated fields
  {{EntityName}} copyWith({
    {{Type}}? {{fieldName}},
    // ... other fields
  }) {
    return {{EntityName}}(
      {{fieldName}}: {{fieldName}} ?? this.{{fieldName}},
      // ... other fields
    );
  }
}
```

**Example for Authentication Feature:**

**File:** `lib/features/auth/domain/entities/user.dart`

```dart
import 'package:equatable/equatable.dart';

/// User entity representing an authenticated user in the system.
///
/// This entity contains core user information after successful authentication.
/// It is used throughout the domain layer for authorization and user-specific operations.
///
/// **Business Rules:**
/// - User ID must be unique and non-empty
/// - Email must be verified for full access
/// - Display name is optional but recommended for UX
///
/// **Security Considerations:**
/// - Password is NEVER stored in this entity (authentication backend only)
/// - Sensitive data (email) should be handled according to GDPR/compliance
class User extends Equatable {
  /// Unique identifier for the user (from backend)
  final String id;

  /// User's email address (verified or unverified)
  final String email;

  /// Display name for UI (optional)
  final String? displayName;

  /// Profile photo URL (optional)
  final String? photoUrl;

  /// Whether email has been verified
  final bool emailVerified;

  /// Account creation timestamp
  final DateTime createdAt;

  const User({
    required this.id,
    required this.email,
    required this.emailVerified,
    required this.createdAt,
    this.displayName,
    this.photoUrl,
  });

  @override
  List<Object?> get props => [
        id,
        email,
        displayName,
        photoUrl,
        emailVerified,
        createdAt,
      ];

  @override
  bool get stringify => true;

  /// Creates a copy of this user with updated fields
  User copyWith({
    String? id,
    String? email,
    String? displayName,
    String? photoUrl,
    bool? emailVerified,
    DateTime? createdAt,
  }) {
    return User(
      id: id ?? this.id,
      email: email ?? this.email,
      displayName: displayName ?? this.displayName,
      photoUrl: photoUrl ?? this.photoUrl,
      emailVerified: emailVerified ?? this.emailVerified,
      createdAt: createdAt ?? this.createdAt,
    );
  }
}
```

**File:** `lib/features/auth/domain/entities/auth_tokens.dart`

```dart
import 'package:equatable/equatable.dart';

/// Authentication tokens for session management.
///
/// Contains JWT access and refresh tokens for maintaining authenticated sessions.
///
/// **Security Rules:**
/// - Tokens are stored in FlutterSecureStorage (encrypted)
/// - Access token expires after 24 hours (configurable)
/// - Refresh token rotates on each use
/// - NEVER log tokens in production
class AuthTokens extends Equatable {
  /// JWT access token for API requests
  final String accessToken;

  /// JWT refresh token for obtaining new access tokens
  final String refreshToken;

  /// Expiration timestamp for access token
  final DateTime expiresAt;

  const AuthTokens({
    required this.accessToken,
    required this.refreshToken,
    required this.expiresAt,
  });

  /// Whether the access token has expired
  bool get isExpired => DateTime.now().isAfter(expiresAt);

  /// Time remaining until expiration
  Duration get timeUntilExpiration => expiresAt.difference(DateTime.now());

  @override
  List<Object?> get props => [accessToken, refreshToken, expiresAt];

  @override
  bool get stringify => true;

  AuthTokens copyWith({
    String? accessToken,
    String? refreshToken,
    DateTime? expiresAt,
  }) {
    return AuthTokens(
      accessToken: accessToken ?? this.accessToken,
      refreshToken: refreshToken ?? this.refreshToken,
      expiresAt: expiresAt ?? this.expiresAt,
    );
  }
}
```

### 2.2 Create Use Cases

**Use cases contain single-responsibility business operations.**

For each use case in the feature:

**File:** `lib/features/{{feature_name}}/domain/usecases/{{use_case_name}}.dart`

**Template:**
```dart
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';

import '../../../../core/error/failures.dart';
import '../../../../core/usecases/usecase.dart';
import '../entities/{{entity_name}}.dart';
import '../repositories/{{repository_name}}.dart';

/// {{Use case description}}
///
/// **Business Logic:**
/// {{Explain what this use case accomplishes}}
///
/// **Parameters:**
/// - {{param1}}: {{description}}
///
/// **Returns:**
/// - Success: {{EntityName}} object
/// - Failure: {{FailureType}} with error details
///
/// **Validation Rules:**
/// - {{Rule 1}}
/// - {{Rule 2}}
class {{UseCaseName}} implements UseCase<{{ReturnType}}, {{ParamsType}}> {
  final {{RepositoryName}} repository;

  {{UseCaseName}}(this.repository);

  @override
  Future<Either<Failure, {{ReturnType}}>> call({{ParamsType}} params) async {
    // Input validation
    final validationResult = params.validate();
    if (validationResult != null) {
      return Left(ValidationFailure(validationResult));
    }

    // Call repository
    return await repository.{{methodName}}(
      params.{{field1}},
      params.{{field2}},
    );
  }
}

/// Parameters for {{UseCaseName}}
class {{ParamsName}} extends Equatable {
  final {{Type}} {{fieldName}};

  const {{ParamsName}}({
    required this.{{fieldName}},
  });

  /// Validates parameters before use case execution
  String? validate() {
    // Validation logic
    if ({{fieldName}}.isEmpty) {
      return '{{FieldName}} cannot be empty';
    }
    return null;
  }

  @override
  List<Object?> get props => [{{fieldName}}];
}
```

**Example for Authentication Feature:**

**File:** `lib/features/auth/domain/usecases/login_with_email.dart`

```dart
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';

import '../../../../core/error/failures.dart';
import '../../../../core/usecases/usecase.dart';
import '../entities/user.dart';
import '../repositories/auth_repository.dart';

/// Authenticates a user with email and password.
///
/// **Business Logic:**
/// 1. Validates email format and password strength
/// 2. Sends credentials to authentication backend
/// 3. Stores JWT tokens securely on success
/// 4. Returns authenticated User entity
///
/// **Security Considerations:**
/// - Password is transmitted over HTTPS only
/// - Rate limiting applied (5 attempts per 15 minutes)
/// - Account locked after 10 failed attempts
/// - Passwords are NEVER stored locally
///
/// **Error Handling:**
/// - Invalid credentials: AuthFailure with "Invalid email or password"
/// - Network error: NetworkFailure
/// - Server error: ServerFailure
/// - Account locked: AuthFailure with "Account locked, try again in X minutes"
class LoginWithEmail implements UseCase<User, LoginParams> {
  final AuthRepository repository;

  LoginWithEmail(this.repository);

  @override
  Future<Either<Failure, User>> call(LoginParams params) async {
    // Validate input parameters
    final validationError = params.validate();
    if (validationError != null) {
      return Left(ValidationFailure(validationError));
    }

    // Attempt login via repository
    return await repository.loginWithEmail(
      email: params.email,
      password: params.password,
    );
  }
}

/// Parameters for email/password login
class LoginParams extends Equatable {
  final String email;
  final String password;

  const LoginParams({
    required this.email,
    required this.password,
  });

  /// Validates login parameters
  ///
  /// **Validation Rules:**
  /// - Email must be valid format (regex)
  /// - Password must be at least 8 characters
  /// - Email cannot be empty
  /// - Password cannot be empty
  String? validate() {
    if (email.isEmpty) {
      return 'Email cannot be empty';
    }

    // Email regex validation
    final emailRegex = RegExp(
      r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
    );
    if (!emailRegex.hasMatch(email)) {
      return 'Please enter a valid email address';
    }

    if (password.isEmpty) {
      return 'Password cannot be empty';
    }

    if (password.length < 8) {
      return 'Password must be at least 8 characters';
    }

    return null; // Valid
  }

  @override
  List<Object?> get props => [email, password];
}
```

**File:** `lib/features/auth/domain/usecases/register_with_email.dart`

```dart
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';

import '../../../../core/error/failures.dart';
import '../../../../core/usecases/usecase.dart';
import '../entities/user.dart';
import '../repositories/auth_repository.dart';

/// Registers a new user with email and password.
///
/// **Business Logic:**
/// 1. Validates email format and password strength
/// 2. Checks if email already exists (via backend)
/// 3. Creates new user account
/// 4. Sends email verification link
/// 5. Returns User entity (emailVerified = false)
///
/// **Password Requirements (PRPROMPTS Security Standard):**
/// - Minimum 8 characters
/// - At least 1 uppercase letter
/// - At least 1 lowercase letter
/// - At least 1 number
/// - At least 1 special character
///
/// **Compliance:**
/// - GDPR: User consent obtained during registration
/// - COPPA: Age verification if required
/// - Data minimization: Only collect necessary fields
class RegisterWithEmail implements UseCase<User, RegisterParams> {
  final AuthRepository repository;

  RegisterWithEmail(this.repository);

  @override
  Future<Either<Failure, User>> call(RegisterParams params) async {
    // Validate input parameters
    final validationError = params.validate();
    if (validationError != null) {
      return Left(ValidationFailure(validationError));
    }

    // Attempt registration via repository
    return await repository.registerWithEmail(
      email: params.email,
      password: params.password,
      displayName: params.displayName,
    );
  }
}

/// Parameters for email/password registration
class RegisterParams extends Equatable {
  final String email;
  final String password;
  final String? displayName;

  const RegisterParams({
    required this.email,
    required this.password,
    this.displayName,
  });

  /// Validates registration parameters
  ///
  /// Enforces strong password policy and email format validation
  String? validate() {
    // Email validation
    if (email.isEmpty) {
      return 'Email cannot be empty';
    }

    final emailRegex = RegExp(
      r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
    );
    if (!emailRegex.hasMatch(email)) {
      return 'Please enter a valid email address';
    }

    // Password validation
    if (password.isEmpty) {
      return 'Password cannot be empty';
    }

    if (password.length < 8) {
      return 'Password must be at least 8 characters';
    }

    // Password strength requirements
    final hasUppercase = password.contains(RegExp(r'[A-Z]'));
    final hasLowercase = password.contains(RegExp(r'[a-z]'));
    final hasDigit = password.contains(RegExp(r'[0-9]'));
    final hasSpecialChar = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'));

    if (!hasUppercase) {
      return 'Password must contain at least one uppercase letter';
    }
    if (!hasLowercase) {
      return 'Password must contain at least one lowercase letter';
    }
    if (!hasDigit) {
      return 'Password must contain at least one number';
    }
    if (!hasSpecialChar) {
      return 'Password must contain at least one special character';
    }

    // Display name validation (optional)
    if (displayName != null && displayName!.length > 50) {
      return 'Display name must be 50 characters or less';
    }

    return null; // Valid
  }

  @override
  List<Object?> get props => [email, password, displayName];
}
```

**Create additional use cases:**
- `logout.dart` - Logs out user, clears tokens
- `get_current_user.dart` - Retrieves currently authenticated user
- `refresh_token.dart` - Refreshes expired access token
- `verify_email.dart` - Verifies email with token
- `reset_password.dart` - Initiates password reset flow

### 2.3 Create Repository Interface

**Repository contracts define data access operations without implementation details.**

**File:** `lib/features/{{feature_name}}/domain/repositories/{{repository_name}}.dart`

**Template:**
```dart
import 'package:dartz/dartz.dart';

import '../../../../core/error/failures.dart';
import '../entities/{{entity_name}}.dart';

/// Abstract repository defining data operations for {{feature_name}}.
///
/// This interface is implemented by the data layer and used by use cases.
/// It follows the Repository Pattern and Dependency Inversion Principle.
///
/// **Responsibilities:**
/// - Define contracts for data operations
/// - Return Either<Failure, Success> for error handling
/// - Remain agnostic to data source (API, database, cache)
///
/// **Implementation:**
/// See `lib/features/{{feature_name}}/data/repositories/{{repository_name}}_impl.dart`
abstract class {{RepositoryName}} {
  /// {{Method description}}
  ///
  /// **Parameters:**
  /// - {{param1}}: {{description}}
  ///
  /// **Returns:**
  /// - Right({{ReturnType}}): Success
  /// - Left(Failure): Error occurred
  ///
  /// **Possible Failures:**
  /// - NetworkFailure: No internet connection
  /// - ServerFailure: Backend error
  /// - ValidationFailure: Invalid input
  Future<Either<Failure, {{ReturnType}}>> {{methodName}}({{params}});
}
```

**Example for Authentication Feature:**

**File:** `lib/features/auth/domain/repositories/auth_repository.dart`

```dart
import 'package:dartz/dartz.dart';

import '../../../../core/error/failures.dart';
import '../entities/user.dart';
import '../entities/auth_tokens.dart';

/// Abstract repository for authentication operations.
///
/// Defines the contract for all authentication-related data operations.
/// This interface is implemented by AuthRepositoryImpl in the data layer.
///
/// **Design Principles:**
/// - Dependency Inversion: Domain doesn't depend on data layer
/// - Single Responsibility: Only authentication operations
/// - Interface Segregation: Focused, cohesive interface
///
/// **Error Handling:**
/// All methods return Either<Failure, T> for explicit error handling:
/// - Left(Failure): Operation failed with specific error type
/// - Right(T): Operation succeeded with result
abstract class AuthRepository {
  /// Authenticates user with email and password.
  ///
  /// **Flow:**
  /// 1. Sends credentials to backend via AuthRemoteDataSource
  /// 2. Receives JWT tokens on success
  /// 3. Stores tokens in FlutterSecureStorage via AuthLocalDataSource
  /// 4. Returns User entity
  ///
  /// **Security:**
  /// - Credentials sent over HTTPS only
  /// - Password NEVER stored locally
  /// - Tokens encrypted in secure storage
  ///
  /// **Possible Failures:**
  /// - AuthFailure: Invalid credentials or account locked
  /// - NetworkFailure: No internet connection
  /// - ServerFailure: Backend error (500, 502, etc.)
  Future<Either<Failure, User>> loginWithEmail({
    required String email,
    required String password,
  });

  /// Registers new user with email and password.
  ///
  /// **Flow:**
  /// 1. Sends registration data to backend
  /// 2. Backend creates user account and sends verification email
  /// 3. Returns User entity with emailVerified = false
  ///
  /// **Possible Failures:**
  /// - AuthFailure: Email already exists
  /// - ValidationFailure: Invalid email or weak password
  /// - NetworkFailure: No internet connection
  /// - ServerFailure: Backend error
  Future<Either<Failure, User>> registerWithEmail({
    required String email,
    required String password,
    String? displayName,
  });

  /// Logs out current user and clears stored tokens.
  ///
  /// **Flow:**
  /// 1. Notifies backend to invalidate tokens (optional)
  /// 2. Deletes tokens from FlutterSecureStorage
  /// 3. Clears any cached user data
  ///
  /// **Note:** This should always succeed locally, even if backend call fails
  Future<Either<Failure, void>> logout();

  /// Retrieves currently authenticated user.
  ///
  /// **Flow:**
  /// 1. Checks if tokens exist in secure storage
  /// 2. Validates token expiration
  /// 3. Fetches user profile from backend or cache
  ///
  /// **Possible Failures:**
  /// - AuthFailure: No user logged in or token expired
  /// - NetworkFailure: Cannot reach backend
  /// - CacheFailure: Local data corrupted
  Future<Either<Failure, User>> getCurrentUser();

  /// Refreshes expired access token using refresh token.
  ///
  /// **Flow:**
  /// 1. Retrieves refresh token from secure storage
  /// 2. Exchanges refresh token for new access token
  /// 3. Stores new tokens (refresh token may rotate)
  ///
  /// **Security:**
  /// - Refresh token rotation (new refresh token on each use)
  /// - Old refresh token immediately invalidated
  ///
  /// **Possible Failures:**
  /// - AuthFailure: Refresh token invalid or expired
  /// - NetworkFailure: Cannot reach backend
  Future<Either<Failure, AuthTokens>> refreshAccessToken();

  /// Verifies user's email address with token.
  ///
  /// **Flow:**
  /// 1. Sends verification token to backend
  /// 2. Backend marks email as verified
  /// 3. Returns updated User entity
  ///
  /// **Possible Failures:**
  /// - AuthFailure: Invalid or expired verification token
  /// - NetworkFailure: Cannot reach backend
  Future<Either<Failure, User>> verifyEmail(String token);

  /// Initiates password reset flow.
  ///
  /// **Flow:**
  /// 1. Sends password reset request to backend
  /// 2. Backend sends reset email with token
  /// 3. Returns success (void)
  ///
  /// **Security:**
  /// - Reset token expires after 1 hour
  /// - Email sent to registered address only
  ///
  /// **Possible Failures:**
  /// - AuthFailure: Email not found
  /// - NetworkFailure: Cannot reach backend
  Future<Either<Failure, void>> resetPassword(String email);
}
```

**Domain Layer Summary:**

After Step 2, you should have:
- ✅ Entities (pure business objects)
- ✅ Use Cases (single-responsibility operations)
- ✅ Repository Interface (data access contract)
- ✅ All files in `lib/features/{{feature_name}}/domain/`

---

## Step 3: Implement Data Layer

The data layer handles data retrieval from various sources (API, database, cache) and implements repository contracts.

### 3.1 Create Data Models

**Models are data transfer objects that convert between JSON and entities.**

For each entity, create a corresponding model:

**File:** `lib/features/{{feature_name}}/data/models/{{model_name}}.dart`

**Template:**
```dart
import '../../domain/entities/{{entity_name}}.dart';

/// Data model for {{EntityName}} entity.
///
/// Handles JSON serialization/deserialization for API communication.
/// Extends the domain entity to inherit business logic and properties.
///
/// **Responsibilities:**
/// - Convert JSON to Entity (fromJson)
/// - Convert Entity to JSON (toJson)
/// - Handle nullable fields from API
/// - Provide default values when needed
class {{ModelName}} extends {{EntityName}} {
  const {{ModelName}}({
    required super.{{field1}},
    required super.{{field2}},
    // ... other fields
  });

  /// Creates a {{ModelName}} from JSON received from API.
  ///
  /// **JSON Structure:**
  /// ```json
  /// {
  ///   "{{jsonKey1}}": "{{value}}",
  ///   "{{jsonKey2}}": "{{value}}"
  /// }
  /// ```
  ///
  /// **Null Handling:**
  /// - Required fields throw if null
  /// - Optional fields default to null
  factory {{ModelName}}.fromJson(Map<String, dynamic> json) {
    return {{ModelName}}(
      {{field1}}: json['{{jsonKey1}}'] as {{Type}},
      {{field2}}: json['{{jsonKey2}}'] as {{Type}},
      // ... other fields
    );
  }

  /// Converts this model to JSON for API requests.
  ///
  /// **Output:**
  /// ```json
  /// {
  ///   "{{jsonKey1}}": "{{value}}",
  ///   "{{jsonKey2}}": "{{value}}"
  /// }
  /// ```
  Map<String, dynamic> toJson() {
    return {
      '{{jsonKey1}}': {{field1}},
      '{{jsonKey2}}': {{field2}},
      // ... other fields
    };
  }

  /// Creates a {{ModelName}} from a {{EntityName}} entity.
  factory {{ModelName}}.fromEntity({{EntityName}} entity) {
    return {{ModelName}}(
      {{field1}}: entity.{{field1}},
      {{field2}}: entity.{{field2}},
      // ... other fields
    );
  }
}
```

**Example for Authentication Feature:**

**File:** `lib/features/auth/data/models/user_model.dart`

```dart
import '../../domain/entities/user.dart';

/// Data model for User entity.
///
/// Handles JSON serialization/deserialization for user data from API.
///
/// **API Response Example:**
/// ```json
/// {
///   "id": "user_123456",
///   "email": "john.doe@example.com",
///   "display_name": "John Doe",
///   "photo_url": "https://example.com/avatars/john.jpg",
///   "email_verified": true,
///   "created_at": "2024-01-15T10:30:00Z"
/// }
/// ```
class UserModel extends User {
  const UserModel({
    required super.id,
    required super.email,
    required super.emailVerified,
    required super.createdAt,
    super.displayName,
    super.photoUrl,
  });

  /// Creates UserModel from JSON response.
  ///
  /// **Field Mappings:**
  /// - id: Required string
  /// - email: Required string
  /// - display_name: Optional string (snake_case from API)
  /// - photo_url: Optional string (snake_case from API)
  /// - email_verified: Required boolean (snake_case from API)
  /// - created_at: Required ISO 8601 timestamp (snake_case from API)
  factory UserModel.fromJson(Map<String, dynamic> json) {
    return UserModel(
      id: json['id'] as String,
      email: json['email'] as String,
      displayName: json['display_name'] as String?,
      photoUrl: json['photo_url'] as String?,
      emailVerified: json['email_verified'] as bool,
      createdAt: DateTime.parse(json['created_at'] as String),
    );
  }

  /// Converts UserModel to JSON for API requests.
  ///
  /// Used when updating user profile or sending user data to backend.
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'email': email,
      'display_name': displayName,
      'photo_url': photoUrl,
      'email_verified': emailVerified,
      'created_at': createdAt.toIso8601String(),
    };
  }

  /// Creates UserModel from User entity.
  ///
  /// Useful when converting domain entities back to models for API calls.
  factory UserModel.fromEntity(User user) {
    return UserModel(
      id: user.id,
      email: user.email,
      displayName: user.displayName,
      photoUrl: user.photoUrl,
      emailVerified: user.emailVerified,
      createdAt: user.createdAt,
    );
  }
}
```

**File:** `lib/features/auth/data/models/auth_tokens_model.dart`

```dart
import '../../domain/entities/auth_tokens.dart';

/// Data model for AuthTokens entity.
///
/// Handles JSON serialization for JWT tokens from authentication API.
///
/// **API Response Example:**
/// ```json
/// {
///   "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
///   "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
///   "expires_at": "2024-01-16T10:30:00Z"
/// }
/// ```
///
/// **Security Note:**
/// Tokens are immediately stored in FlutterSecureStorage and cleared from memory.
class AuthTokensModel extends AuthTokens {
  const AuthTokensModel({
    required super.accessToken,
    required super.refreshToken,
    required super.expiresAt,
  });

  /// Creates AuthTokensModel from JSON response.
  factory AuthTokensModel.fromJson(Map<String, dynamic> json) {
    return AuthTokensModel(
      accessToken: json['access_token'] as String,
      refreshToken: json['refresh_token'] as String,
      expiresAt: DateTime.parse(json['expires_at'] as String),
    );
  }

  /// Converts to JSON for storage or API requests.
  Map<String, dynamic> toJson() {
    return {
      'access_token': accessToken,
      'refresh_token': refreshToken,
      'expires_at': expiresAt.toIso8601String(),
    };
  }

  /// Creates AuthTokensModel from AuthTokens entity.
  factory AuthTokensModel.fromEntity(AuthTokens tokens) {
    return AuthTokensModel(
      accessToken: tokens.accessToken,
      refreshToken: tokens.refreshToken,
      expiresAt: tokens.expiresAt,
    );
  }
}
```

### 3.2 Create Data Sources

**Data sources handle direct communication with external systems (API, database).**

#### 3.2.1 Remote Data Source (API)

**File:** `lib/features/{{feature_name}}/data/datasources/{{feature_name}}_remote_data_source.dart`

**Template:**
```dart
import 'package:dio/dio.dart';

import '../../../../core/error/exceptions.dart';
import '../models/{{model_name}}.dart';

/// Remote data source for {{feature_name}} via REST API.
///
/// Handles HTTP requests to backend API endpoints.
/// Throws exceptions on errors (converted to Failures in repository).
///
/// **Base URL:** Configured in lib/core/network/api_client.dart
/// **Authentication:** Bearer token in Authorization header
abstract class {{FeatureName}}RemoteDataSource {
  /// {{Method description}}
  ///
  /// **Endpoint:** {{HTTP_METHOD}} {{/api/path}}
  /// **Headers:** Authorization: Bearer {{token}}
  ///
  /// **Throws:**
  /// - ServerException: HTTP 500/502/503
  /// - NetworkException: No internet connection
  /// - AuthException: Invalid credentials or token expired
  Future<{{ModelName}}> {{methodName}}({{params}});
}

class {{FeatureName}}RemoteDataSourceImpl implements {{FeatureName}}RemoteDataSource {
  final Dio dio;

  {{FeatureName}}RemoteDataSourceImpl({required this.dio});

  @override
  Future<{{ModelName}}> {{methodName}}({{params}}) async {
    try {
      final response = await dio.{{httpMethod}}(
        '{{/api/endpoint}}',
        data: {
          '{{key1}}': {{value1}},
          // ... request body
        },
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        return {{ModelName}}.fromJson(response.data);
      } else {
        throw ServerException(
          message: 'Unexpected status code: ${response.statusCode}',
        );
      }
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw NetworkException(message: 'Connection timeout');
      } else if (e.response?.statusCode == 401 || e.response?.statusCode == 403) {
        throw AuthException(
          message: e.response?.data['message'] ?? 'Unauthorized',
        );
      } else if (e.response?.statusCode == 400) {
        throw ValidationException(
          message: e.response?.data['message'] ?? 'Invalid input',
        );
      } else if (e.response?.statusCode != null && e.response!.statusCode! >= 500) {
        throw ServerException(
          message: e.response?.data['message'] ?? 'Server error',
        );
      } else {
        throw NetworkException(message: 'Network error: ${e.message}');
      }
    } catch (e) {
      throw ServerException(message: 'Unexpected error: $e');
    }
  }
}
```

**Example for Authentication Feature:**

**File:** `lib/features/auth/data/datasources/auth_remote_data_source.dart`

```dart
import 'package:dio/dio.dart';

import '../../../../core/error/exceptions.dart';
import '../models/user_model.dart';
import '../models/auth_tokens_model.dart';

/// Remote data source for authentication via REST API.
///
/// **Base URL:** https://api.example.com/v1
/// **Endpoints:**
/// - POST /auth/register
/// - POST /auth/login
/// - POST /auth/logout
/// - POST /auth/refresh
/// - GET /auth/me
/// - POST /auth/verify-email
/// - POST /auth/reset-password
abstract class AuthRemoteDataSource {
  /// Authenticates user with email and password.
  ///
  /// **Endpoint:** POST /auth/login
  /// **Request Body:**
  /// ```json
  /// {
  ///   "email": "user@example.com",
  ///   "password": "SecurePass123!"
  /// }
  /// ```
  ///
  /// **Response:**
  /// ```json
  /// {
  ///   "user": { ...user data... },
  ///   "tokens": { ...tokens... }
  /// }
  /// ```
  ///
  /// **Throws:**
  /// - AuthException: Invalid credentials (401)
  /// - ServerException: Server error (500+)
  /// - NetworkException: Connection error
  Future<Map<String, dynamic>> loginWithEmail({
    required String email,
    required String password,
  });

  /// Registers new user.
  ///
  /// **Endpoint:** POST /auth/register
  Future<Map<String, dynamic>> registerWithEmail({
    required String email,
    required String password,
    String? displayName,
  });

  /// Logs out user (invalidates refresh token on backend).
  ///
  /// **Endpoint:** POST /auth/logout
  /// **Headers:** Authorization: Bearer {{access_token}}
  Future<void> logout(String accessToken);

  /// Fetches current user profile.
  ///
  /// **Endpoint:** GET /auth/me
  /// **Headers:** Authorization: Bearer {{access_token}}
  Future<UserModel> getCurrentUser(String accessToken);

  /// Refreshes access token.
  ///
  /// **Endpoint:** POST /auth/refresh
  /// **Request Body:**
  /// ```json
  /// {
  ///   "refresh_token": "..."
  /// }
  /// ```
  Future<AuthTokensModel> refreshAccessToken(String refreshToken);

  /// Verifies email with token.
  ///
  /// **Endpoint:** POST /auth/verify-email
  Future<UserModel> verifyEmail(String token);

  /// Initiates password reset.
  ///
  /// **Endpoint:** POST /auth/reset-password
  Future<void> resetPassword(String email);
}

class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
  final Dio dio;

  AuthRemoteDataSourceImpl({required this.dio});

  @override
  Future<Map<String, dynamic>> loginWithEmail({
    required String email,
    required String password,
  }) async {
    try {
      final response = await dio.post(
        '/auth/login',
        data: {
          'email': email,
          'password': password,
        },
      );

      if (response.statusCode == 200) {
        return {
          'user': UserModel.fromJson(response.data['user']),
          'tokens': AuthTokensModel.fromJson(response.data['tokens']),
        };
      } else {
        throw ServerException(
          message: 'Unexpected status code: ${response.statusCode}',
        );
      }
    } on DioException catch (e) {
      _handleDioError(e);
      rethrow; // Unreachable, but required for type safety
    }
  }

  @override
  Future<Map<String, dynamic>> registerWithEmail({
    required String email,
    required String password,
    String? displayName,
  }) async {
    try {
      final response = await dio.post(
        '/auth/register',
        data: {
          'email': email,
          'password': password,
          if (displayName != null) 'display_name': displayName,
        },
      );

      if (response.statusCode == 201) {
        return {
          'user': UserModel.fromJson(response.data['user']),
          'tokens': AuthTokensModel.fromJson(response.data['tokens']),
        };
      } else {
        throw ServerException(
          message: 'Unexpected status code: ${response.statusCode}',
        );
      }
    } on DioException catch (e) {
      _handleDioError(e);
      rethrow;
    }
  }

  @override
  Future<void> logout(String accessToken) async {
    try {
      await dio.post(
        '/auth/logout',
        options: Options(headers: {'Authorization': 'Bearer $accessToken'}),
      );
    } on DioException catch (e) {
      // Logout can fail gracefully - local logout still proceeds
      print('Logout request failed: ${e.message}');
    }
  }

  @override
  Future<UserModel> getCurrentUser(String accessToken) async {
    try {
      final response = await dio.get(
        '/auth/me',
        options: Options(headers: {'Authorization': 'Bearer $accessToken'}),
      );

      if (response.statusCode == 200) {
        return UserModel.fromJson(response.data);
      } else {
        throw ServerException(
          message: 'Unexpected status code: ${response.statusCode}',
        );
      }
    } on DioException catch (e) {
      _handleDioError(e);
      rethrow;
    }
  }

  @override
  Future<AuthTokensModel> refreshAccessToken(String refreshToken) async {
    try {
      final response = await dio.post(
        '/auth/refresh',
        data: {'refresh_token': refreshToken},
      );

      if (response.statusCode == 200) {
        return AuthTokensModel.fromJson(response.data);
      } else {
        throw ServerException(
          message: 'Unexpected status code: ${response.statusCode}',
        );
      }
    } on DioException catch (e) {
      _handleDioError(e);
      rethrow;
    }
  }

  @override
  Future<UserModel> verifyEmail(String token) async {
    try {
      final response = await dio.post(
        '/auth/verify-email',
        data: {'token': token},
      );

      if (response.statusCode == 200) {
        return UserModel.fromJson(response.data);
      } else {
        throw ServerException(
          message: 'Unexpected status code: ${response.statusCode}',
        );
      }
    } on DioException catch (e) {
      _handleDioError(e);
      rethrow;
    }
  }

  @override
  Future<void> resetPassword(S

…(truncated)
