Add technical check history

A car's mandatory roadworthiness inspections — przegląd techniczny, MOT,
TÜV — had nowhere to live. Log them behind Service history, which this
mirrors minus the odometer: an inspection falls due on a date whatever
the mileage reads.

The cycle is legal rather than mechanical, and it is not constant — a new
car's first check falls due years later than its third. So the car's
technical_check_interval_days only prefills the next date, and any check
overrides it with the valid-until printed on its own certificate. A
failed check derives no next date at all: reading one off a failure would
stamp a reassuring "valid until" on a car that just flunked.

The next-due date and its status are derived on every read rather than
stored, for the same reason documents are — a stored verdict goes stale
as the date passes. The response carries the same expiry shape documents
use, so the web app reuses the existing badge rather than growing a
second one.

Each check records result, cost, station and notes, and holds the
certificate as its single attachment on the same terms as every other
record.

Needs `node scripts/setup-pocketbase.mjs` to create technical_checks and
add the interval to cars. The reformatting in records.go is gofmt
realigning the car struct around a longer field name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-07-17 11:54:26 +02:00
co-authored by Claude Opus 4.8
parent 03738f08dc
commit 21c99ad762
11 changed files with 713 additions and 81 deletions
+24 -2
View File
@@ -236,6 +236,9 @@ const DESIRED = {
F.text("vin"),
F.number("service_interval_days"),
F.number("service_interval_km"),
// Roadworthiness inspection cycle. Only prefills a check's next-due date —
// the legal interval changes as the car ages, so each check can override it.
F.number("technical_check_interval_days"),
F.text("oil_spec"),
F.text("transmission_oil_spec"),
F.text("differential_oil_spec"),
@@ -261,6 +264,20 @@ const DESIRED = {
F.text("notes"),
attachment(), // the workshop receipt / stamped service-book page
],
// Mandatory roadworthiness inspections (przegląd techniczny / MOT / TÜV).
// Like service_records but time-only: a check falls due on a date whatever the
// odometer reads. valid_until is the expiry printed on the certificate; when
// blank the API derives it from the car's interval.
technical_checks: [
F.relation("car", "cars", true),
F.date("date", true),
F.select("result", ["passed", "failed"]),
F.number("cost"),
F.text("station"),
F.date("valid_until"),
F.text("notes"),
attachment(), // the certificate
],
parts: [
F.relation("car", "cars", true),
F.text("name", true),
@@ -390,6 +407,8 @@ const INDEXES = {
maintenance_entries: ["CREATE INDEX `idx_maintenance_entries_car_date` ON `maintenance_entries` (`car`, `date`)"],
car_documents: ["CREATE INDEX `idx_car_documents_car_expiry` ON `car_documents` (`car`, `expiry_date`)"],
reminders: ["CREATE INDEX `idx_reminders_car_due` ON `reminders` (`car`, `due_date`)"],
// Read as "this car's checks, newest first" every time.
technical_checks: ["CREATE INDEX `idx_technical_checks_car_date` ON `technical_checks` (`car`, `date`)"],
};
async function main() {
@@ -411,6 +430,7 @@ async function main() {
"organizations",
"cars",
"service_records",
"technical_checks",
"parts",
"car_shares",
"fuel_entries",
@@ -434,6 +454,7 @@ async function main() {
"users",
"cars",
"service_records",
"technical_checks",
"parts",
"car_shares",
"fuel_entries",
@@ -445,8 +466,9 @@ async function main() {
}
console.log(
"\nDone. Collections ready: organizations, users, cars, service_records, parts,\n" +
"car_shares, fuel_entries, maintenance_entries, car_documents, reminders.",
"\nDone. Collections ready: organizations, users, cars, service_records,\n" +
"technical_checks, parts, car_shares, fuel_entries, maintenance_entries,\n" +
"car_documents, reminders.",
);
console.log(
"Note: the legacy `sessions` collection is no longer used (auth moved to PocketBase\n" +