Implement Application Layer with TDD

- Add date utilities for habit scheduling logic
- Implement CreateHabitHandler with full validation
- Implement GetTodaysHabitsHandler with carry-over support
- Implement MarkHabitHandler for completing habits
- All components developed following TDD methodology
- Complete test coverage for commands and queries
This commit is contained in:
2025-11-25 23:54:49 +01:00
parent 0977d3a58b
commit 34ea1f718e
8 changed files with 1002 additions and 0 deletions
@@ -0,0 +1,50 @@
package commands
import (
"context"
"fmt"
"time"
"habit-tracker-api/internal/domain/entities"
"habit-tracker-api/internal/domain/repositories"
)
type MarkHabitCommand struct {
HabitID string
ScheduledDate time.Time
Value *float64
}
type MarkHabitHandler struct {
entryRepo repositories.HabitEntryRepository
habitRepo repositories.HabitRepository
}
func NewMarkHabitHandler(
entryRepo repositories.HabitEntryRepository,
habitRepo repositories.HabitRepository,
) *MarkHabitHandler {
return &MarkHabitHandler{
entryRepo: entryRepo,
habitRepo: habitRepo,
}
}
func (h *MarkHabitHandler) Handle(ctx context.Context, cmd MarkHabitCommand) error {
habit, err := h.habitRepo.FindByID(ctx, cmd.HabitID)
if err != nil {
return err
}
if habit == nil {
return fmt.Errorf("habit not found")
}
if !habit.IsActive() {
return fmt.Errorf("habit is archived")
}
entry := entities.NewHabitEntry(cmd.HabitID, cmd.ScheduledDate, cmd.Value)
return h.entryRepo.Create(ctx, entry)
}