Repository navigation
Manage auth collection accounts in Users - #481
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Account profile saves can silently retain cleared values, alter JSON types, and drop existing relations, while float inputs and unset required booleans can cause validation failures.
4 open issues
What changed in this PR
This PR gives auth collections a single, collection-scoped account workspace in Users, addressing #478 while retaining ordinary record management for data collections.
Changes:
- Groups navigation by collection type, preserves scoped links, and redirects legacy auth-record URLs.
- Extends account forms with shared profile-field editors, validation, and file handling.
- Adds browser regressions and documents the unified workflow.
| File | Description |
|---|---|
tests/admin/test_shell.py |
Updates the built-in account navigation smoke test. |
tests/admin/test_auth_navigation.py |
Adds navigation, account-form, and system-protection regressions. |
src/admin/views/users.js |
Adds collection-scoped Users pages and custom profile fields. |
src/admin/views/collections.js |
Shares field controls and serialization; adds Users handoffs. |
src/admin/lib/api.js |
Enables multipart account creation and updates. |
src/admin/app.js |
Groups sidebar links and routes auth collections to Users. |
docs/framework.md |
Documents account navigation and editing capabilities. |
changelog.d/auth-users-navigation.md |
Records the navigation and account-form changes. |
Review effort: Balanced
b7d81d7 to
d8eb887
Compare
d8eb887 to
62831b8
Compare
62831b8 to
c90b756
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved issues misdirect collection user-management links, block account updates for server-accepted internationalized email addresses, and cause inconsistent numeric validation between JSON and multipart submissions.
3 open issues
2 resolved since last review
Review effort: Balanced
c90b756 to
29d6679
Compare
29d6679 to
0b525f7
Compare
0b525f7 to
c8dd7c9
Compare
c8dd7c9 to
efd2032
Compare
e29f12c to
e37f457
Compare
valthon
left a comment
There was a problem hiding this comment.
This re-review covers e37f4570. I reviewed by reading the code; I did not run it.
All seven issues from the previous review are addressed: changed-fields-only PATCH, no hang on '…', rich-text cleanup on blur, blank username omitted, a shared system-field helper, the zero password minimum, and reuse of the Shell's metadata. Thanks.
Changes requested (blocking). GitHub doesn't allow a formal "Request changes" on your own PR, so this review is a comment, but every item below must be resolved before merge:
- Regression: the record drawer hides
email,username,verifiedandtoken_epochon base collections. This breaks creating and editing_suppressionsand_sender_identitiesrecords. - Correctness: one failed cache-miss refresh leaves
errset, blocking later refreshes and showing a false error on every records page. - Required refactor: replace the Shell's metadata-refresh state machine with a single
refreshCollections()(details inline). Item 2 comes from its complexity, and we don't want to keep that much interdependent state in the admin shell. - Correctness:
RecordsTablenow reads an outdated schema snapshot, so fields added elsewhere are missing from the drawer until a reload. - Correctness:
minPasswordLengthaccepts out-of-range or non-integer values that the server silently drops.
Please add browser regressions for 1, 2 and 4. As CLAUDE.md notes, zig build test won't catch them.
Generated by Claude Code
There was a problem hiding this comment.
🔵 Needs a closer look
Human assessment is needed because an unpublished finding indicates that cached metadata lookup failures can keep New record disabled even after the API recovers.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
e11ca19 to
37abd0d
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Single-select handling conflates empty-string options with null during saves, risking incorrect stored values, while navigation to cached auth collections leaves stale lookup errors visible.
3 open issues
Review effort: Balanced
Forms that submit a whole record exposed gaps in how the API accepts input. Clearing a single-valued select or relation in a multipart update sent an empty string, which was validated as a literal option or target id and rejected. Integral JSON numbers outside the i64 range arrive as number strings, so float fields skipped their bounds check and failed to bind, and such bounds could not round-trip through schema JSON. An invalid minPasswordLength fell back silently. An empty multipart value now clears single-valued selects and relations as it already did for multi-valued ones. A single select declaring "" as an option keeps it as a value, so that select is cleared by the JSON spelling null instead, unless null is an option too. values.floatValue converts typed JSON numbers to a finite float for both validation and binding, so bounds apply to large tokens and non-finite values are refused while ordinary strings keep their type error. Number bounds in schema JSON accept the same tokens and refuse strings and non-finite values. The collection create and update endpoints return a field error unless minPasswordLength is an integer from 0 through 255, instead of a generic bad request or a fallback. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HTAHrkfe1L2hfpLeP1CQAS
37abd0d to
dccea21
Compare
There was a problem hiding this comment.
🟡 Changes recommended
A delayed lookup failure can incorrectly appear on the members page and sidebar after navigation, requiring a current-route guard and a delayed-failure regression test.
1 open issue
3 resolved since last review
Review effort: Balanced
Auth collections sat beside ordinary collections in the admin sidebar and opened the generic Records screen, whose New record form could not collect a password. The Users editor handled credentials but omitted custom profile fields, and it chose its own default collection, so a link could not reliably keep the collection in view. The sidebar now groups collections by type: ordinary ones under Data collections and auth ones by name under Users. Each opens account management at /_/#/users/<collection>, kept across reloads and browser history, and legacy auth record URLs redirect to the same collection. Collection settings and Users link to each other, and _superusers keeps its system protections. Create and edit forms cover credentials together with custom profile fields, including required fields, JSON, rich text, relations, multiple selections and file uploads, using shared accessible controls. Editing sends only changed fields and credentials, so concurrent API or hook updates and untouched legacy gaps survive a credential reset. JSON comparison ignores object-member order but not array order. Valid field names such as constructor stay ordinary keys. Collection metadata has one guarded refresh, so only the latest request publishes results and a failed lookup does not block later routes. It retries when the route is next visited rather than in a loop, and its error shows only on the route it was for. Record and account drawers load the current collection definition when opened and block saves while it is loading or failed, so field and password-policy changes made elsewhere apply immediately. Password length uses UTF-8 bytes to match the server, and a zero minimum is preserved. A select declaring an empty option keeps it distinct from no selection, in JSON and multipart saves alike. Base collections keep their ordinary email and username fields, and schema controls protect system fields by persisted identity rather than by a draft name. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HTAHrkfe1L2hfpLeP1CQAS
dccea21 to
08fe0f5
Compare



Auth collections now have collection-scoped account management at
/_/#/users/<collection>, with credentials and custom profile fields in the same form. The sidebar groups collections by type, and ordinary collections keep the generic record editor.Admin UI
Record and collection input
""as an option keeps it as a value and is cleared withnullinstead, unlessnullis also an option.minPasswordLengthis an integer from 0 through 255.The series is two commits: the input parsing, then the admin UI that depends on it.
Fixes #478.
Validation on Zig 0.16.0, on
mainat7e212f30:zig build test --summary allreturned 0 at both commits.tests/adminwith-n 4: 665 passed, 154 skipped.check-gating, allocator contracts, disabled agent CLI, error-code ledger, doctor ledger and changelog assembly passed.The
zaptransport re-pin, its changelog fragment and thetests/adminfixture and diagnostics work that were previously on this branch are removed, as they do not belong to this issue. The prior head is preserved oncodex-does-too-much-481.🤖 Generated with Claude Code
https://claude.ai/code/session_01HTAHrkfe1L2hfpLeP1CQAS