From 423bc2ab16db2d3ba7340edff50b7c5e60daf35c Mon Sep 17 00:00:00 2001 From: tajniak81 <13187254+tajniak81@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:34:48 +0200 Subject: [PATCH] The charger list sorted by a field the collection never had MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opening Home chargers answered {"status":400,"message":"Something went wrong while processing your request."} — PocketBase's generic refusal, here for an unknown sort field. home_chargers declares its own fields and nothing else: PocketBase adds no created field to a collection defined through the API, which is exactly why control_audit and organizations declare theirs. The list handler sorted by created anyway. It was the only handler in the server that sorts by created — every other one sorts by name, km or date, fields their collections actually declare — so the gap had never had a chance to show. The field is now declared, and reconcile adds it to the collection already standing on the next boot, since home_chargers is in reconcileOrder. Import order is the only order a charger has: it carries no date of its own, and a wallbox bolted to a wall does not accumulate events the way a car does. The list also stops depending on that. A rejected sort now falls back to the unsorted query rather than failing the request: the order is a nicety, the list is not, and an owner reading a database error about a field they cannot see is the worst of both. It also makes the deploy order stop mattering — the page works before the bootstrap has run, and the sorted query wins once it has. Co-Authored-By: Claude Opus 5 --- API Server/internal/api/homechargers.go | 24 +++++++++++++++++++----- API Server/internal/bootstrap/schema.go | 5 +++++ API Server/scripts/setup-pocketbase.mjs | 4 ++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/API Server/internal/api/homechargers.go b/API Server/internal/api/homechargers.go index 2fc0d9f..9617328 100644 --- a/API Server/internal/api/homechargers.go +++ b/API Server/internal/api/homechargers.go @@ -79,11 +79,25 @@ func (s *Server) listHomeChargers(w http.ResponseWriter, r *http.Request) { writeError(w, http.StatusUnauthorized, "not authenticated") return } - res, err := s.pb.List(r.Context(), colHomeChargers, url.Values{ - "filter": {fmt.Sprintf("owner='%s'", me)}, - "sort": {"created"}, - "perPage": {"200"}, - }) + query := func(sort string) url.Values { + q := url.Values{ + "filter": {fmt.Sprintf("owner='%s'", me)}, + "perPage": {"200"}, + } + if sort != "" { + q.Set("sort", sort) + } + return q + } + res, err := s.pb.List(r.Context(), colHomeChargers, query("created")) + if err != nil { + // A collection created before `created` was declared does not have the + // field, and PocketBase rejects the whole query over an unknown sort. The + // order is a nicety; the list is not, so ask again without it rather than + // show the owner an error about a field they cannot see. The bootstrap + // adds the field on the next boot, and the sorted query then wins. + res, err = s.pb.List(r.Context(), colHomeChargers, query("")) + } if err != nil { writePBError(w, err) return diff --git a/API Server/internal/bootstrap/schema.go b/API Server/internal/bootstrap/schema.go index b43d524..86f03ab 100644 --- a/API Server/internal/bootstrap/schema.go +++ b/API Server/internal/bootstrap/schema.go @@ -219,6 +219,11 @@ var collectionsSchema = map[string][]fieldDef{ // Owner. Non-cascading, like a car's: deleting a user must not silently // wipe the records they own. fRelation("owner", "users", false, false), + // A charger carries no date of its own, so the import order is the only + // order there is to list them in. PocketBase adds no created field to a + // collection defined through the API, so it is declared here like the + // audit trail's. + fAutodate("created", true, false), }, // Custom fields layered onto the built-in "users" auth collection. "users": { diff --git a/API Server/scripts/setup-pocketbase.mjs b/API Server/scripts/setup-pocketbase.mjs index 1c6d7c2..3f396ea 100644 --- a/API Server/scripts/setup-pocketbase.mjs +++ b/API Server/scripts/setup-pocketbase.mjs @@ -457,6 +457,10 @@ const DESIRED = { F.text("provider_charger_id"), // Owner. Non-cascading, like a car's: deleting a user must not wipe their records. F.relation("owner", "users", false, false), + // A charger carries no date of its own, so the import order is the only order + // there is to list them in. PocketBase adds no created field to a collection + // defined through the API, so it is declared here like the audit trail's. + F.autodate("created", true, false), ], // Server-wide settings as a single record, keyed "global". Today it holds // pluginSettings: the top (L1) layer of the integration cascade — every