package model import ( "time" "github.com/golang-jwt/jwt/v5" ) // ── Work Order ──────────────────────────────────────────────────────────────── type WorkOrder struct { ID int `db:"id" json:"id"` WONumber string `db:"wo_number" json:"wo_number"` Title string `db:"title" json:"title"` Description string `db:"description" json:"description"` Instructions string `db:"instructions" json:"instructions"` Status string `db:"status" json:"status"` Priority string `db:"priority" json:"priority"` ScheduledStart *time.Time `db:"scheduled_start" json:"scheduled_start"` ScheduledEnd *time.Time `db:"scheduled_end" json:"scheduled_end"` ActualStart *time.Time `db:"actual_start" json:"actual_start"` ActualEnd *time.Time `db:"actual_end" json:"actual_end"` SiteName string `db:"site_name" json:"site_name"` Address string `db:"address" json:"address"` Lat *float64 `db:"lat" json:"lat"` Lng *float64 `db:"lng" json:"lng"` AccessNotes string `db:"access_notes" json:"access_notes"` ParentType *string `db:"parent_type" json:"parent_type"` ParentID *int `db:"parent_id" json:"parent_id"` CreatedBy string `db:"created_by" json:"created_by"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` ClosedAt *time.Time `db:"closed_at" json:"closed_at"` ClosedBy *string `db:"closed_by" json:"closed_by"` } type WorkOrderListItem struct { ID int `db:"id" json:"id"` WONumber string `db:"wo_number" json:"wo_number"` Title string `db:"title" json:"title"` Status string `db:"status" json:"status"` Priority string `db:"priority" json:"priority"` SiteName string `db:"site_name" json:"site_name"` ScheduledStart *time.Time `db:"scheduled_start" json:"scheduled_start"` StepCount int `db:"step_count" json:"step_count"` StepsDone int `db:"steps_done" json:"steps_done"` PhotoCount int `db:"photo_count" json:"photo_count"` } // ── Steps / Resources / Attachments / Accounting ───────────────────────────── type Step struct { ID int `db:"id" json:"id"` WOID int `db:"wo_id" json:"wo_id"` StepOrder int `db:"step_order" json:"step_order"` Title string `db:"title" json:"title"` Description string `db:"description" json:"description"` Required bool `db:"required" json:"required"` StepType string `db:"step_type" json:"step_type"` TypeConfig string `db:"type_config" json:"type_config"` Completed bool `db:"completed" json:"completed"` CompletedBy *string `db:"completed_by" json:"completed_by"` CompletedAt *time.Time `db:"completed_at" json:"completed_at"` Notes string `db:"notes" json:"notes"` } type AssignedResource struct { ID int `db:"id" json:"id"` WOID int `db:"wo_id" json:"wo_id"` ResourceType string `db:"resource_type" json:"resource_type"` ResourceID int `db:"resource_id" json:"resource_id"` Name string `db:"name" json:"name"` Quantity *float64 `db:"quantity" json:"quantity"` Notes string `db:"notes" json:"notes"` AssignedAt time.Time `db:"assigned_at" json:"assigned_at"` } type Attachment struct { ID int `db:"id" json:"id"` WOID int `db:"wo_id" json:"wo_id"` StepID *int `db:"step_id" json:"step_id"` FileName string `db:"file_name" json:"file_name"` FilePath string `db:"file_path" json:"file_path"` FileType string `db:"file_type" json:"file_type"` FileSize int64 `db:"file_size" json:"file_size"` Caption string `db:"caption" json:"caption"` Phase string `db:"phase" json:"phase"` Lat *float64 `db:"lat" json:"lat"` Lng *float64 `db:"lng" json:"lng"` UploadedBy string `db:"uploaded_by" json:"uploaded_by"` UploadedAt time.Time `db:"uploaded_at" json:"uploaded_at"` URL string `db:"-" json:"url"` } type AccountingCode struct { ID int `db:"id" json:"id"` WOID int `db:"wo_id" json:"wo_id"` CodeType string `db:"code_type" json:"code_type"` CodeValue string `db:"code_value" json:"code_value"` Description string `db:"description" json:"description"` } // ── Resource Registry ───────────────────────────────────────────────────────── type RegistryPerson struct { ID int `db:"id" json:"id"` Name string `db:"name" json:"name"` Role string `db:"role" json:"role"` Email string `db:"email" json:"email"` Phone string `db:"phone" json:"phone"` Active bool `db:"active" json:"active"` } type RegistryVehicle struct { ID int `db:"id" json:"id"` UnitNumber string `db:"unit_number" json:"unit_number"` Description string `db:"description" json:"description"` VehicleType string `db:"vehicle_type" json:"vehicle_type"` Active bool `db:"active" json:"active"` } type RegistryEquipment struct { ID int `db:"id" json:"id"` Name string `db:"name" json:"name"` AssetTag string `db:"asset_tag" json:"asset_tag"` Category string `db:"category" json:"category"` Active bool `db:"active" json:"active"` } type RegistryMaterial struct { ID int `db:"id" json:"id"` Name string `db:"name" json:"name"` Unit string `db:"unit" json:"unit"` PartNumber string `db:"part_number" json:"part_number"` Active bool `db:"active" json:"active"` } type AuditEntry struct { ID int `db:"id" json:"id"` Action string `db:"action" json:"action"` OldValue string `db:"old_value" json:"old_value"` NewValue string `db:"new_value" json:"new_value"` PerformedBy string `db:"performed_by" json:"performed_by"` PerformedAt time.Time `db:"performed_at" json:"performed_at"` } // ── Work Order Profiles ─────────────────────────────────────────────────────── type Profile struct { ID int `db:"id" json:"id"` Name string `db:"name" json:"name"` Description string `db:"description" json:"description"` Category string `db:"category" json:"category"` DefaultPriority string `db:"default_priority" json:"default_priority"` DefaultDurationHours *int `db:"default_duration_hours" json:"default_duration_hours"` DefaultInstructions string `db:"default_instructions" json:"default_instructions"` Active bool `db:"active" json:"active"` StepCount int `db:"step_count" json:"step_count"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` Steps []ProfileStep `db:"-" json:"steps,omitempty"` } type ProfileStep struct { ID int `db:"id" json:"id"` ProfileID int `db:"profile_id" json:"profile_id"` StepOrder int `db:"step_order" json:"step_order"` Title string `db:"title" json:"title"` Description string `db:"description" json:"description"` Required bool `db:"required" json:"required"` StepType string `db:"step_type" json:"step_type"` TypeConfig string `db:"type_config" json:"type_config"` } // ── Users & Auth ────────────────────────────────────────────────────────────── type User struct { ID int `db:"id" json:"id"` Username string `db:"username" json:"username"` Email string `db:"email" json:"email"` DisplayName string `db:"display_name" json:"display_name"` PasswordHash string `db:"password_hash" json:"-"` Role string `db:"role" json:"role"` AvatarURL *string `db:"avatar_url" json:"avatar_url,omitempty"` Active bool `db:"active" json:"active"` LastLogin *time.Time `db:"last_login" json:"last_login"` CreatedAt time.Time `db:"created_at" json:"created_at"` } // LocalClaims is the JWT payload for locally-issued tokens. type LocalClaims struct { jwt.RegisteredClaims UserID int `json:"uid"` Username string `json:"username"` Email string `json:"email"` DisplayName string `json:"name"` Role string `json:"role"` } // UserClaims is stored in request context after token validation. type UserClaims struct { UserID int `json:"user_id"` Username string `json:"username"` Email string `json:"email"` DisplayName string `json:"display_name"` Role string `json:"role"` } type CtxKey string const CtxUserKey CtxKey = "user"