Add attachments to service, maintenance, fuel and parts records
Documents already carried a single optional file: upload, download, detach,
access-checked on every request and proxied through this server, so PocketBase's
files are never public URLs. Service records, workshop visits, refills and
catalog parts all want the same thing — a receipt, an invoice, a photo of the
box — so extend it to them.
Rather than copy the document handlers four more times, lift them into one
shared layer. Every attachable collection has a car relation and a file field,
which is what lets a single set of handlers authorize and serve all of them. An
upload finishes by delegating to the collection's own GET handler, so the
response carries the full record — derived fields and all — exactly as a re-read
would. The web side gets the same treatment: one picker component and one
upload-after-save helper behind all five forms. Net effect is five features for
about the cost of the one that was already there.
Alongside:
- parts gain a notes field
- Reminders moves behind Parts catalog in the car detail tabs
- the changed-part labels spell out in full ("Oil & Oil filter" rather than
"Oil & filter"), and the form and table now agree
The PocketBase schema must be migrated before the new attachments work:
scripts/setup-pocketbase.mjs adds the file fields and parts.notes. It is
additive and safe to re-run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e64c89a564
commit
07192f1238
@@ -211,6 +211,19 @@ async function reconcileFields(token, name, defs, format, idByName) {
|
||||
console.log(`✓ ${name} — ${changes.join(", ")}`);
|
||||
}
|
||||
|
||||
// The single optional attachment a record can carry — a scan, a receipt, a
|
||||
// workshop invoice, a photo of a part. The 10MB cap matches maxAttachmentUpload
|
||||
// in the API server, and the file is reached only via the API's own file
|
||||
// endpoint, never as a public URL.
|
||||
const attachment = () =>
|
||||
F.file("file", 10485760, [
|
||||
"application/pdf",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/webp",
|
||||
"image/heic",
|
||||
]);
|
||||
|
||||
// Desired schema. Edit here to evolve collections; re-run the script to apply.
|
||||
const DESIRED = {
|
||||
cars: [
|
||||
@@ -246,12 +259,15 @@ const DESIRED = {
|
||||
F.bool("changed_engine_air_filter"),
|
||||
F.bool("changed_cabin_air_filter"),
|
||||
F.text("notes"),
|
||||
attachment(), // the workshop receipt / stamped service-book page
|
||||
],
|
||||
parts: [
|
||||
F.relation("car", "cars", true),
|
||||
F.text("name", true),
|
||||
F.text("part_number"),
|
||||
F.text("category"),
|
||||
F.text("notes"),
|
||||
attachment(), // a photo of the box, or the part's spec sheet
|
||||
],
|
||||
// Fuel refills. Consumption is NOT stored — the API derives it from the whole
|
||||
// history on read (models.ComputeFuelDerived), so correcting an old fill fixes
|
||||
@@ -269,6 +285,7 @@ const DESIRED = {
|
||||
F.bool("missed_fill"),
|
||||
F.text("station"),
|
||||
F.text("notes"),
|
||||
attachment(), // the pump receipt
|
||||
],
|
||||
// Workshop visits and repairs. Deliberately separate from service_records:
|
||||
// that collection is the routine interval schedule (and drives next-service
|
||||
@@ -288,6 +305,7 @@ const DESIRED = {
|
||||
F.text("invoice_number"),
|
||||
F.date("warranty_until"),
|
||||
F.text("notes"),
|
||||
attachment(), // the workshop's invoice
|
||||
],
|
||||
// Insurance, pollution certificates, registration papers … The expiry date is
|
||||
// the point of the record: it drives the renewal status badges and the
|
||||
@@ -302,15 +320,7 @@ const DESIRED = {
|
||||
F.date("expiry_date"),
|
||||
F.number("cost"),
|
||||
F.text("notes"),
|
||||
// The scan/PDF. 10MB cap, matching maxDocumentUpload in the API server.
|
||||
// Reached only via the API's own file endpoint, never as a public URL.
|
||||
F.file("file", 10485760, [
|
||||
"application/pdf",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/webp",
|
||||
"image/heic",
|
||||
]),
|
||||
attachment(), // the scan/PDF of the paperwork itself
|
||||
],
|
||||
// User-set reminders. The API additionally synthesises read-only ones from
|
||||
// document expiry dates and the next service due — those are derived on read
|
||||
|
||||
Reference in New Issue
Block a user