100 lines
2.5 KiB
Markdown
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.
|