---
description: "Freezed code generation conventions for {{PROJECT_NAME}} — Pillar 4"
alwaysApply: true
---

# Freezed Standards — {{PROJECT_NAME}}

## When to use Freezed
- All domain entities and data models — use `@freezed`
- Union types / sealed classes — use `@freezed` with multiple constructors
- BLoC states and events — use `@freezed`

## Model pattern
```dart
@freezed
class Product with _$Product {
  const factory Product({
    required String id,
    required String name,
    required double price,
    @Default(0) int stockCount,
    String? imageUrl,
  }) = _Product;

  factory Product.fromJson(Map<String, dynamic> json) => _$ProductFromJson(json);
}
```

## Union type pattern
```dart
@freezed
sealed class ProductState with _$ProductState {
  const factory ProductState.initial()                          = ProductInitial;
  const factory ProductState.loading()                          = ProductLoading;
  const factory ProductState.loaded(List<Product> products)     = ProductLoaded;
  const factory ProductState.error(String message)              = ProductError;
}

// Usage — exhaustive switch
final widget = state.when(
  initial: () => const SizedBox.shrink(),
  loading: () => const ProductShimmer(),
  loaded:  (products) => ProductList(products: products),
  error:   (msg) => ErrorWidget(message: msg),
);
```

## Critical rules
- **NEVER** edit `.freezed.dart` or `.g.dart` files — they are generated
- Run `dart run build_runner build --delete-conflicting-outputs` after changes
- Run `dart run build_runner watch` during development
- Add `*.freezed.dart` and `*.g.dart` to `.gitignore` (or commit them — team must decide)
- Always define `copyWith` via Freezed — never write manual `copyWith`

## Patterns to avoid
```dart
// ❌ Manual copyWith — replaced by Freezed
Product copyWith({String? name, double? price}) => Product(
  id: id, name: name ?? this.name, price: price ?? this.price,
);

// ✅ Let Freezed generate it
product.copyWith(name: 'New Name', price: 9.99)
```
