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

2.5 KiB

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

// 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

// 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

// 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

// 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.