# TT-003 — Domain Models (freezed) **Type:** Story **Priority:** High **Labels:** domain, models **Depends on:** TT-001 **Blocks:** TT-004, TT-005, TT-006, TT-007, TT-008 --- ## Summary Define all domain-level models using `freezed`. These are the immutable data classes used throughout the app's business logic and UI layer — distinct from the Drift table companion classes. ## Models to implement ### `Project` ```dart // lib/features/projects/domain/project.dart @freezed class Project with _$Project { const factory Project({ required int id, required String name, required int colorValue, String? description, DateTime? archivedAt, required DateTime createdAt, }) = _Project; factory Project.fromJson(Map json) => _$ProjectFromJson(json); } ``` ### `TimeEntry` ```dart // lib/features/entries/domain/time_entry.dart @freezed class TimeEntry with _$TimeEntry { const factory TimeEntry({ required int id, required int projectId, required DateTime startTime, DateTime? endTime, int? durationSeconds, String? note, @Default([]) List tags, required DateTime createdAt, }) = _TimeEntry; factory TimeEntry.fromJson(Map json) => _$TimeEntryFromJson(json); } ``` ### `Tag` ```dart // lib/features/entries/domain/tag.dart @freezed class Tag with _$Tag { const factory Tag({ required int id, required String name, }) = _Tag; factory Tag.fromJson(Map json) => _$TagFromJson(json); } ``` ### `TimerState` ```dart // lib/features/timer/domain/timer_state.dart @freezed class TimerState with _$TimerState { const factory TimerState.idle() = TimerIdle; const factory TimerState.running({ required int entryId, required DateTime startTime, required Project project, String? note, }) = TimerRunning; } ``` ## Acceptance Criteria - [ ] All models defined with `@freezed` - [ ] `fromJson` / `toJson` generated via `json_serializable` - [ ] `dart run build_runner build` generates `*.freezed.dart` and `*.g.dart` without errors - [ ] Models have no mutable fields - [ ] `TimerState` is a union type (sealed), not a single class ## Files to create - `lib/features/projects/domain/project.dart` - `lib/features/entries/domain/time_entry.dart` - `lib/features/entries/domain/tag.dart` - `lib/features/timer/domain/timer_state.dart` ## Notes - Drift table rows ≠ domain models. Use mapper extension methods to convert between them. - Add `extension ProjectMapper on ProjectData { Project toDomain() {...} }` in the DAO files.