Files
Trackeep/backend/models/goals_habits.go
T
Tomas Dvorak d27cf14110 first test
2026-02-08 14:14:55 +01:00

174 lines
6.3 KiB
Go

package models
import (
"time"
"gorm.io/gorm"
)
// Habit represents a habit that can be tracked
type Habit struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
UserID uint `json:"user_id" gorm:"not null;index"`
User User `json:"user,omitempty" gorm:"foreignKey:UserID"`
// Basic habit information
Name string `json:"name" gorm:"not null"`
Description string `json:"description" gorm:"type:text"`
Category string `json:"category" gorm:"default:personal"` // health, productivity, learning, personal
// Habit tracking
TargetFrequency int `json:"target_frequency"` // e.g., 7 times per week
FrequencyUnit string `json:"frequency_unit"` // daily, weekly, monthly
TargetValue float64 `json:"target_value"` // e.g., 30 minutes, 8 glasses
Unit string `json:"unit"` // minutes, glasses, pages, etc.
// Schedule
TimeOfDay string `json:"time_of_day"` // morning, afternoon, evening, night
DaysOfWeek []string `json:"days_of_week" gorm:"serializer:json"` // ["monday", "tuesday", etc.]
// Status and settings
IsActive bool `json:"is_active" gorm:"default:true"`
IsPublic bool `json:"is_public" gorm:"default:false"`
Streak int `json:"streak" gorm:"default:0"`
LongestStreak int `json:"longest_streak" gorm:"default:0"`
CompletionRate float64 `json:"completion_rate" gorm:"default:0"` // percentage
// Relationships
GoalID *uint `json:"goal_id,omitempty"`
Goal *Goal `json:"goal,omitempty" gorm:"foreignKey:GoalID"`
HabitEntries []HabitEntry `json:"habit_entries,omitempty" gorm:"foreignKey:HabitID"`
HabitTags []HabitTag `json:"habit_tags,omitempty" gorm:"foreignKey:HabitID"`
}
// HabitEntry represents a single completion of a habit
type HabitEntry struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
HabitID uint `json:"habit_id" gorm:"not null;index"`
Habit Habit `json:"habit,omitempty" gorm:"foreignKey:HabitID"`
EntryDate time.Time `json:"entry_date" gorm:"not null;index"`
Value float64 `json:"value"` // actual value completed
TargetValue float64 `json:"target_value"` // target value for this entry
Unit string `json:"unit"`
Notes string `json:"notes" gorm:"type:text"`
IsCompleted bool `json:"is_completed" gorm:"default:false"`
Quality int `json:"quality" gorm:"default:3"` // 1-5 rating
TimeSpent int `json:"time_spent"` // minutes spent
Location string `json:"location"`
Mood string `json:"mood"` // happy, neutral, stressed, etc.
}
// GoalTag represents tags for goals
type GoalTag struct {
ID uint `json:"id" gorm:"primaryKey"`
GoalID uint `json:"goal_id" gorm:"not null;index"`
TagID uint `json:"tag_id" gorm:"not null;index"`
Goal Goal `json:"goal,omitempty" gorm:"foreignKey:GoalID"`
Tag Tag `json:"tag,omitempty" gorm:"foreignKey:TagID"`
}
// HabitTag represents tags for habits
type HabitTag struct {
ID uint `json:"id" gorm:"primaryKey"`
HabitID uint `json:"habit_id" gorm:"not null;index"`
TagID uint `json:"tag_id" gorm:"not null;index"`
Habit Habit `json:"habit,omitempty" gorm:"foreignKey:HabitID"`
Tag Tag `json:"tag,omitempty" gorm:"foreignKey:TagID"`
}
// GoalTemplate represents templates for creating goals
type GoalTemplate struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
Name string `json:"name" gorm:"not null"`
Description string `json:"description" gorm:"type:text"`
Category string `json:"category"`
Unit string `json:"unit"`
TargetValue float64 `json:"target_value"`
Duration int `json:"duration"` // suggested duration in days
IsPublic bool `json:"is_public" gorm:"default:false"`
UsageCount int `json:"usage_count" gorm:"default:0"`
// Template milestones
Milestones []GoalTemplateMilestone `json:"milestones,omitempty" gorm:"foreignKey:GoalTemplateID"`
}
// GoalTemplateMilestone represents milestones in goal templates
type GoalTemplateMilestone struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
GoalTemplateID uint `json:"goal_template_id" gorm:"not null;index"`
GoalTemplate GoalTemplate `json:"goal_template,omitempty" gorm:"foreignKey:GoalTemplateID"`
Title string `json:"title" gorm:"not null"`
Description string `json:"description" gorm:"type:text"`
TargetValue float64 `json:"target_value"`
Unit string `json:"unit"`
DayOffset int `json:"day_offset"` // days from start date
SortOrder int `json:"sort_order" gorm:"default:0"`
}
// BeforeCreate hooks
func (h *Habit) BeforeCreate(tx *gorm.DB) error {
if h.Category == "" {
h.Category = "personal"
}
if h.FrequencyUnit == "" {
h.FrequencyUnit = "daily"
}
return nil
}
func (he *HabitEntry) BeforeCreate(tx *gorm.DB) error {
// Set completion based on value vs target
if he.Value >= he.TargetValue {
he.IsCompleted = true
}
return nil
}
// BeforeUpdate hooks
func (h *Habit) BeforeUpdate(tx *gorm.DB) error {
// Update completion rate and streak
h.updateStreakAndRate()
return nil
}
// Helper methods
// updateStreakAndRate calculates current streak and completion rate
func (h *Habit) updateStreakAndRate() {
// This would typically involve querying habit entries
// For now, we'll keep the existing values
// In a real implementation, you'd calculate based on recent entries
}
// GetTodayEntry gets today's habit entry if it exists
func (h *Habit) GetTodayEntry() *HabitEntry {
// This would typically query the database
// For now, return nil
return nil
}
// GetWeeklyStreak gets the current weekly streak
func (h *Habit) GetWeeklyStreak() int {
// This would calculate based on habit entries
// For now, return the stored streak
return h.Streak
}