timetracker/.tasks/done/TT-003-domain-models-freezed.md
2026-08-03 21:51:48 +02:00

100 lines
2.5 KiB
Markdown

# 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<String, dynamic> 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<String> tags,
required DateTime createdAt,
}) = _TimeEntry;
factory TimeEntry.fromJson(Map<String, dynamic> 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<String, dynamic> 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.