---
description: "json_serializable conventions for TaskFlow — Pillar 4"
alwaysApply: true
---

# json_serializable Standards — TaskFlow

## Model annotation
```dart
@JsonSerializable(explicitToJson: true)  // explicitToJson for nested objects
class ProductDto {
  final String id;
  final String name;
  @JsonKey(name: 'unit_price')  // snake_case API → camelCase Dart
  final double unitPrice;
  @JsonKey(defaultValue: false)
  final bool isActive;
  final DateTime createdAt;  // auto-converted from ISO 8601 string

  const ProductDto({
    required this.id,
    required this.name,
    required this.unitPrice,
    required this.isActive,
    required this.createdAt,
  });

  factory ProductDto.fromJson(Map<String, dynamic> json) => _$ProductDtoFromJson(json);
  Map<String, dynamic> toJson() => _$ProductDtoToJson(this);
}
```

## Critical rules
- **NEVER** edit `*.g.dart` files
- Use `@JsonKey(defaultValue: ...)` for nullable API fields — API contracts change
- Use `explicitToJson: true` whenever the model has nested objects
- Null safety: API fields not guaranteed to be non-null should be `String?` not `String`
