Files
DriverVault/API Server/internal/models/models.go
T
2026-07-06 08:50:52 +02:00

141 lines
5.6 KiB
Go

// Package models defines the domain types for the car maintenance tracker.
//
// The shapes mirror the original "Car Service.xlsx": one Car per sheet, a log
// of ServiceRecords (date + km, plus which parts were changed), and a per-car
// catalog of Parts (cols M/N). Derived fields follow the spreadsheet formulas:
//
// Next Service Date = Service Date + ServiceIntervalDays (Excel: A + 365)
// Next Service Km = Service Km + ServiceIntervalKm (Excel: B + 15000)
package models
import "time"
// Car corresponds to one worksheet in the original spreadsheet.
type Car struct {
ID string `json:"id"`
Name string `json:"name"` // e.g. "Toyota Yaris"
Make string `json:"make"` // e.g. "Toyota"
Model string `json:"model"` // e.g. "Yaris"
Year int `json:"year"` // optional
Registration string `json:"registration"` // optional plate
RegistrationCountry string `json:"registrationCountry"` // optional (country of registration)
VIN string `json:"vin"` // optional
// Maintenance intervals, configurable per car. The spreadsheet hard-coded
// 365 days and 15000 km; here they are stored so each car can differ.
ServiceIntervalDays int `json:"serviceIntervalDays"`
ServiceIntervalKm int `json:"serviceIntervalKm"`
// CurrentKm is the car's present odometer reading, updated by the user. Used
// to flag km-based overdue service (current_km >= last service km + interval).
CurrentKm int `json:"currentKm"`
OilSpec string `json:"oilSpec"` // e.g. "Toyota Advanced Fuel Economy 0W20"
TransmissionOilSpec string `json:"transmissionOilSpec"` // e.g. "Toyota WS"
DifferentialOilSpec string `json:"differentialOilSpec"` // e.g. "SAE 75W-90 GL-5"
BrakeFluidSpec string `json:"brakeFluidSpec"` // e.g. "DOT 4"
CoolantSpec string `json:"coolantSpec"` // e.g. "Toyota Super Long Life Coolant"
FuelType string `json:"fuelType"` // petrol | diesel | hybrid | electric
BuildDate string `json:"buildDate"` // ISO YYYY-MM-DD (date-only)
FirstRegistrationDate string `json:"firstRegistrationDate"` // ISO YYYY-MM-DD (date-only)
// Owner is the user id that owns this car. Access is the requesting user's
// permission on it — "owner", "write", or "read" — computed by the API at
// read time and never persisted (omitempty; not part of the write payload).
Owner string `json:"owner,omitempty"`
Access string `json:"access,omitempty"`
Created string `json:"created,omitempty"`
Updated string `json:"updated,omitempty"`
}
// ServiceRecord is one row of the Service log for a car.
type ServiceRecord struct {
ID string `json:"id"`
Car string `json:"car"` // relation -> Car.ID
Date time.Time `json:"date"` // service date (Excel col A)
Km int `json:"km"` // odometer at service (Excel col B)
// "Changed Parts" checkboxes (Excel cols E/F/G).
ChangedOil bool `json:"changedOil"` // Oil & Oil Filter
ChangedEngineAirFilter bool `json:"changedEngineAirFilter"` // Engine Air Filter
ChangedCabinAirFilter bool `json:"changedCabinAirFilter"` // Cabin Air Filter
Notes string `json:"notes,omitempty"`
// Derived (not stored): filled in by the API on read.
NextServiceDate *time.Time `json:"nextServiceDate,omitempty"` // Excel col C
NextServiceKm *int `json:"nextServiceKm,omitempty"` // Excel col D
Created string `json:"created,omitempty"`
Updated string `json:"updated,omitempty"`
}
// Part is one entry in a car's parts catalog (Excel cols M/N).
type Part struct {
ID string `json:"id"`
Car string `json:"car"` // relation -> Car.ID
Name string `json:"name"` // e.g. "Oil Filter"
PartNumber string `json:"partNumber"` // e.g. "04152-YZZA7"
Category string `json:"category"` // optional: oil|filter|wiper|other
Created string `json:"created,omitempty"`
Updated string `json:"updated,omitempty"`
}
// User is the authenticated account's profile, covering the Settings panel's
// Account/Profile/Appearance sections.
type User struct {
ID string `json:"id"`
Email string `json:"email"`
Verified bool `json:"verified"`
Name string `json:"name"`
Bio string `json:"bio"`
HasAvatar bool `json:"hasAvatar"`
Theme string `json:"theme"` // light | dark | system
Locale string `json:"locale"` // e.g. "en-US"
DateFormat string `json:"dateFormat"` // YMD | DMY | MDY
FontSize string `json:"fontSize"` // small | medium | large
Role string `json:"role"` // user | admin
// Non-empty while an account-deletion request is pending its cooldown.
DeletionRequestedAt *time.Time `json:"deletionRequestedAt,omitempty"`
Created string `json:"created,omitempty"`
}
// Session is one active login (device) for the current user.
type Session struct {
ID string `json:"id"`
DeviceLabel string `json:"deviceLabel"`
IP string `json:"ip"`
Current bool `json:"current"`
Created time.Time `json:"created"`
ExpiresAt time.Time `json:"expiresAt"`
}
// ComputeDerived fills NextServiceDate / NextServiceKm from the car's intervals,
// reproducing the spreadsheet formulas. Intervals of 0 fall back to the
// spreadsheet defaults (365 days, 15000 km).
func (r *ServiceRecord) ComputeDerived(c *Car) {
days := c.ServiceIntervalDays
if days <= 0 {
days = 365
}
km := c.ServiceIntervalKm
if km <= 0 {
km = 15000
}
if !r.Date.IsZero() {
d := r.Date.AddDate(0, 0, days)
r.NextServiceDate = &d
}
if r.Km > 0 {
n := r.Km + km
r.NextServiceKm = &n
}
}