141 lines
5.6 KiB
Go
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
|
|
}
|
|
}
|