Initial commit
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user