Files
sundynix-pets/pets-be/internal/model/models.go
T
Blizzard 3175936266
ci-cd / verify (push) Successful in 2m18s
ci-cd / deploy (push) Skipped
feat: support shared pet care tasks and smooth daily page return
2026-10-05 20:20:05 +08:00

199 lines
9.0 KiB
Go

package model
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// Base gives every persisted model a PostgreSQL uuid primary key.
// GORM's naming strategy maps Go fields to snake_case columns.
type Base struct {
ID string `gorm:"type:uuid;primaryKey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (b *Base) BeforeCreate(_ *gorm.DB) error {
if b.ID == "" {
b.ID = uuid.NewString()
}
return nil
}
type File struct {
Base
Bucket string `gorm:"size:128;not null" json:"bucket"`
ObjectKey string `gorm:"size:512;uniqueIndex;not null" json:"object_key"`
MD5 string `gorm:"column:md5;size:32;uniqueIndex;not null" json:"md5"`
URL string `gorm:"size:1024;not null" json:"url"`
Name string `gorm:"size:255;not null" json:"name"`
ContentType string `gorm:"size:128;not null" json:"content_type"`
Size int64 `gorm:"not null" json:"size"`
}
type User struct {
Base
OpenID string `gorm:"size:128;uniqueIndex;not null" json:"-"`
Nickname string `gorm:"size:64;not null" json:"nickname"`
AvatarFileID *string `gorm:"type:uuid;index" json:"avatar_file_id"`
Disabled bool `gorm:"not null;default:false" json:"disabled"`
}
type Admin struct {
Base
Username string `gorm:"size:64;uniqueIndex;not null" json:"username"`
PasswordHash string `gorm:"size:255;not null" json:"-"`
}
// RefreshSession stores only a hash of the rotating refresh credential.
type RefreshSession struct {
Base
ActorID string `gorm:"type:uuid;index;not null" json:"-"`
Role string `gorm:"size:16;index;not null" json:"-"`
TokenHash string `gorm:"size:64;uniqueIndex;not null" json:"-"`
ExpiresAt time.Time `gorm:"index;not null" json:"-"`
Revoked bool `gorm:"not null;default:false" json:"-"`
}
type Breed struct {
Base
LifeSpan string `gorm:"size:128" json:"life_span"`
Exercise string `gorm:"size:255" json:"exercise"`
Grooming string `gorm:"size:255" json:"grooming"`
EditorialLocked bool `gorm:"not null;default:false" json:"editorial_locked"`
FieldSources map[string]string `gorm:"serializer:json;type:jsonb" json:"field_sources"`
References []BreedReference `gorm:"foreignKey:BreedID" json:"references,omitempty"`
Origin string `gorm:"size:128" json:"origin"`
BreedGroup string `gorm:"size:255" json:"breed_group"`
FCINumber string `gorm:"size:16" json:"fci_number"`
Height string `gorm:"size:128" json:"height"`
Weight string `gorm:"size:128" json:"weight"`
Summary string `gorm:"type:text" json:"summary"`
Temperament string `gorm:"size:255" json:"temperament"`
Traits string `gorm:"type:text" json:"traits"`
CareNotes string `gorm:"type:text" json:"care_notes"`
EncyclopediaUpdatedAt string `gorm:"size:10" json:"encyclopedia_updated_at"`
Name string `gorm:"size:128;uniqueIndex;not null" json:"name"`
EnglishName string `gorm:"size:128" json:"english_name"`
Aliases string `gorm:"size:512" json:"aliases"`
Pinyin string `gorm:"size:1024;index;not null" json:"pinyin"`
PinyinInitials string `gorm:"size:128" json:"pinyin_initials"`
Initial string `gorm:"size:1;index;not null" json:"initial"`
Enabled bool `gorm:"not null;default:true" json:"enabled"`
Source string `gorm:"size:128" json:"source"`
SourceKey *string `gorm:"size:128;uniqueIndex" json:"source_key"`
SourceURL string `gorm:"size:512" json:"source_url"`
}
// Facts contain short structured facts, never copied articles or remote images.
type BreedReference struct {
Base
BreedID string `gorm:"type:uuid;uniqueIndex:idx_breed_provider;not null" json:"breed_id"`
Provider string `gorm:"size:32;uniqueIndex:idx_breed_provider;not null" json:"provider"`
ExternalID string `gorm:"size:128;not null" json:"external_id"`
URL string `gorm:"size:512;not null" json:"url"`
RetrievedAt string `gorm:"size:10;not null" json:"retrieved_at"`
Facts map[string]string `gorm:"serializer:json;type:jsonb;not null" json:"facts"`
}
type Pet struct {
Base
UserID string `gorm:"type:uuid;index;not null" json:"user_id"`
Name string `gorm:"size:64;not null" json:"name"`
Species string `gorm:"size:16;not null;default:dog" json:"species"`
Breed string `gorm:"size:128" json:"breed"`
BreedID *string `gorm:"type:uuid;index" json:"breed_id"`
Gender string `gorm:"size:16" json:"gender"`
BirthDate *time.Time `gorm:"type:date" json:"birth_date"`
WeightKg float64 `gorm:"type:numeric(6,2)" json:"weight_kg"`
AvatarFileID *string `gorm:"type:uuid;index" json:"avatar_file_id"`
Coat string `gorm:"size:64" json:"coat"`
Allergies string `gorm:"size:255" json:"allergies"`
CareNotes string `gorm:"size:1000" json:"care_notes"`
Archived bool `gorm:"not null;default:false" json:"archived"`
}
type CareTask struct {
Base
UserID string `gorm:"type:uuid;index;not null" json:"user_id"`
PetID *string `gorm:"type:uuid;index" json:"pet_id"` // nil applies to all of the user's pets.
Title string `gorm:"size:128;not null" json:"title"`
Category string `gorm:"size:32;not null" json:"category"`
TimeOfDay string `gorm:"size:5;not null" json:"time_of_day"`
RepeatRule string `gorm:"size:16;not null;default:daily" json:"repeat_rule"`
ReminderEnabled bool `gorm:"not null;default:false" json:"reminder_enabled"`
}
type TaskCompletion struct {
Base
TaskID string `gorm:"type:uuid;uniqueIndex:idx_task_date;not null" json:"task_id"`
UserID string `gorm:"type:uuid;index;not null" json:"user_id"`
Date time.Time `gorm:"type:date;uniqueIndex:idx_task_date;not null" json:"date"`
CompletedAt time.Time `gorm:"not null" json:"completed_at"`
}
type Walk struct {
Base
UserID string `gorm:"type:uuid;index;not null" json:"user_id"`
Status string `gorm:"size:16;index;not null" json:"status"`
StartedAt time.Time `gorm:"not null" json:"started_at"`
SegmentStartedAt time.Time `gorm:"not null" json:"segment_started_at"`
PausedAt *time.Time `json:"paused_at"`
PausedSeconds int `gorm:"not null;default:0" json:"paused_seconds"`
EndedAt *time.Time `json:"ended_at"`
DurationSeconds int `gorm:"not null;default:0" json:"duration_seconds"`
DistanceMeters float64 `gorm:"type:numeric(12,2);not null;default:0" json:"distance_meters"`
ShareEnabled bool `gorm:"not null;default:false" json:"share_enabled"`
ShareToken string `gorm:"type:uuid;uniqueIndex" json:"-"`
ShareExpiresAt *time.Time `json:"share_expires_at"`
}
type WalkPet struct {
Base
WalkID string `gorm:"type:uuid;uniqueIndex:idx_walk_pet;not null" json:"walk_id"`
PetID string `gorm:"type:uuid;uniqueIndex:idx_walk_pet;index;not null" json:"pet_id"`
}
type WalkPoint struct {
Base
WalkID string `gorm:"type:uuid;index;not null" json:"walk_id"`
Latitude float64 `gorm:"type:numeric(10,7);not null" json:"latitude"`
Longitude float64 `gorm:"type:numeric(10,7);not null" json:"longitude"`
RecordedAt time.Time `gorm:"index;not null" json:"recorded_at"`
}
type Meetup struct {
Base
HostUserID string `gorm:"type:uuid;index;not null" json:"host_user_id"`
Title string `gorm:"size:128;not null" json:"title"`
Description string `gorm:"size:1000" json:"description"`
PlaceName string `gorm:"size:255;not null" json:"place_name"`
Latitude float64 `gorm:"type:numeric(10,7)" json:"latitude"`
Longitude float64 `gorm:"type:numeric(10,7)" json:"longitude"`
StartsAt time.Time `gorm:"index;not null" json:"starts_at"`
MaxPeople int `gorm:"not null;default:8" json:"max_people"`
Status string `gorm:"size:16;index;not null;default:open" json:"status"`
CoverFileID *string `gorm:"type:uuid;index" json:"cover_file_id"`
}
type MeetupParticipant struct {
Base
MeetupID string `gorm:"type:uuid;uniqueIndex:idx_meetup_user;not null" json:"meetup_id"`
UserID string `gorm:"type:uuid;uniqueIndex:idx_meetup_user;index;not null" json:"user_id"`
}
type MeetupPet struct {
Base
ParticipantID string `gorm:"type:uuid;uniqueIndex:idx_participant_pet;not null" json:"participant_id"`
PetID string `gorm:"type:uuid;uniqueIndex:idx_participant_pet;index;not null" json:"pet_id"`
}
func All() []any {
return []any{
&File{}, &User{}, &Admin{}, &RefreshSession{}, &Breed{}, &BreedReference{}, &Pet{}, &CareTask{}, &TaskCompletion{},
&Walk{}, &WalkPet{}, &WalkPoint{}, &Meetup{}, &MeetupParticipant{}, &MeetupPet{},
}
}