docs(saved-filters,dashboard,system,series): Beam WO3 batch 5 — 15 endpoints + dedupe
Beam drafted 15 frontmatter'd docs (saved-filters CRUD, dashboard
sections/preferences/restore, system config/settings, series list + books);
Claude verified shapes against handlers and pinned the registry:
- saved-filters: SavedFilterResponse pinned by type (RFC3339 timestamps here,
unlike most of the API); create/update share CreateSavedFilterRequest
(resource_type oneof media-items|collections|devices)
- dashboard: preferences GET pin {hidden_collections, collection_order,
items_per_section}; PUT returns full UserDashboardPreferences row; sections
wrapper {sections}
- system: GET+PUT /api/system/config are admin-defined key/value maps — new
AnyJSONObject sentinel (gate shape-checks without key comparison; request
side too). UpdateSystemConfiguration returns {status, message} — verified,
not guessed. GET /api/system/settings returns []SettingEntry.
- series: {series[{name, library_id, book_count, total_in_series,
cover_paths, last_entry_at}], total, limit, offset}; books by
?name=&library_id= with family-lens 403
Dedupe: deleted dashboard.md, system/config.md, system/settings.md — each
covered the same endpoints as Beam's per-endpoint files (content merged by
the gate-verified shapes; old prose recoverable from git).
Beam clarifications confirmed: scanner routes are WO5 (docs exist);
progress/books-match are WO5.
This commit is contained in:
1 parent
7471ca99e8
commit
fa00d6d3cb
20 files changed
+714
-416
No files matched your search
@@ -221,6 +221,15 @@ func validateRequestExample(t *testing.T, doc *APIDoc, schema Schema) {
|
||||
return
|
||||
}
|
||||
|
||||
// AnyJSONObject request: arbitrary keys (config maps). Shape-check only.
|
||||
if _, ok := schema.Request.(AnyJSONObject); ok {
|
||||
var m map[string]json.RawMessage
|
||||
if err := json.Unmarshal(doc.ExampleRequest, &m); err != nil {
|
||||
t.Errorf("%s: example-request must be a JSON object", doc.RelPath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Typo guard: field names must exist on the bind struct.
|
||||
dec := json.NewDecoder(bytes.NewReader(doc.ExampleRequest))
|
||||
dec.DisallowUnknownFields()
|
||||
@@ -257,6 +266,16 @@ func validateResponseExample(t *testing.T, doc *APIDoc, schema Schema) {
|
||||
return
|
||||
}
|
||||
|
||||
// AnyJSONObject: response is an object with arbitrary/dynamic keys
|
||||
// (e.g. map[string]string config). Only shape-check, never key-check.
|
||||
if _, ok := schema.Response.(AnyJSONObject); ok {
|
||||
var m map[string]json.RawMessage
|
||||
if err := json.Unmarshal(doc.ExampleResponse, &m); err != nil {
|
||||
t.Errorf("%s: example-response must be a JSON object", doc.RelPath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
want, isSlice := responseTopLevelKeys(t, schema.Response)
|
||||
|
||||
var got map[string]bool
|
||||
|
||||
Reference in new issue
Block a user