Account Pages

Profile, devices/sessions and the admin user console

Once a user is signed in, three pages cover the whole account surface. ProfilePage owns their own profile, addresses, phones and files; DevicesPage manages their active sessions and device approvals; UsersPage is the admin console for managing everyone. ProfilePage and UsersPage are wired to the generated CRUD actions over the system tables (users, profiles, addresses, phones, files, roles); DevicesPage instead calls the dedicated /auth/sessions endpoints. The generic-CRUD write path to user_sessions is godmin-locked (it is in the sensitive-table lock list), but DevicesPage sidesteps that lock entirely by using the dedicated /auth/sessions route (no godmin check): revoke (revoke-one / revoke-all) is user-scoped — it requires an authenticated caller and filters to their own sessions — while device approve/reject are public one-time-token endpoints (POST /auth/sessions/approve|reject, no x-user-id; the token from the approval email authorizes them). Either way no godmin is involved, so these controls work outside the RBAC lock. One caveat on UsersPage: the RBAC tables (roles, claims, user_roles, role_claims) are godmin-write-locked in the generic entity API — reads stay on the claim model, but role assign/remove (addUserRoleAction / deleteUserRoleAction, which write user_roles) goes THROUGH generic CRUD, so it hits the godmin gate and only functions for a godmin caller (unlike the DevicesPage session controls, which sidestep the lock).

Like every component in the library they take their actions as props, drive an h-state store (the library's own createStore), support variants and callbacks, and never navigate for you. You pass the generated actions; the page owns the forms, the optimistic state and the loading skeletons.

ProfilePage#

The signed-in user's self-service profile. It hydrates from the ME action and exposes add/update for the profile plus full add/update/delete for its related records (addresses, phones, files), including avatar upload through the file proxy.

meActionEndpointAction<…, MeSuccessResponse>Optional

Loads the user, profile, addresses, phones, files and roles in one call (the typed MeResponseData bundle) — the page renders its profile subset from this single hydrate.

profile / address / phone CRUDadd* / update* / delete* actionsOptional

addProfileAction + updateProfileAction, and full add/update/delete actions for addresses and phones (AddressCard / PhoneCard sub-components). Each maps to the generated action for that system table.

file actions + fileProxyBasePathuploadFileAction / updateFileAction / deleteFileActionOptional

Avatar and document handling. uploadFileAction posts multipart to storage; fileProxyBasePath is where the stored file is served back from (onProfilePictureChanged fires on a new avatar).

variant + allow* toggles'default' | 'minimal' | 'compact'Optional

The variant prop is accepted on the props type (ProfilePageVariant) but currently has no rendering effect — the component never reads it (DevicesPage likewise only stores it as an unused _variant), so it is inert today. The read-only/editable behavior is driven entirely by allowProfileEdit / allowAddressEdit / allowPhoneEdit / allowFileUpload (each defaulting to true), which show or hide the edit controls per section. changePasswordHref / devicesHref (or onChangePassword / onViewDevices) cross-link to the other account pages.

DevicesPage#

The user-facing view of the multi-device session model from Authentication. Each row is a SessionInfo (aliased locally as DeviceInfo) — device, browser, OS, IP, last-active — with revoke controls and, optionally, the new-device approval queue.

sessionsActionSessionsActionOptional

Lists the user's active sessions (DeviceInfo = the session record). showStats renders an activeSessions / uniqueDevices / uniqueIpAddresses summary from sessionsStatsAction.

sessionRevokeAction / sessionRevokeAllActionrevokeOptional

Revoke one session by id (with an optional reason) or revoke all — excludeCurrent keeps the present session alive. allowRevokeCurrent / allowRevokeAll gate the buttons; revocation soft-revokes the user_sessions row (isActive=false + revokedAt/revokedReason) rather than hard-deleting it, and the per-request session re-check of isActive signs the device out immediately (refresh tokens are stateless, so revocation is at the session layer, not per-token).

device approvalsessionsPending / approve / rejectOptional

When new-device approval is enabled, showPendingDevices lists devices awaiting approval; sessionApproveAction / sessionRejectAction act on a one-time token to admit or deny them.

UsersPage#

The admin user-management console. It joins each user with their profile, addresses, phones, files and roles into a UserWithDetails, and exposes lifecycle actions in a detail panel.

getUsersAction + related listsEndpointAction<ListResponse<…>>Optional

Only the users list is paginated (fetchUsers / handlePageChange). Their profiles/addresses/phones/files/roles are eagerly prefetched on mount by fetchRelatedData — bulk list calls up to limit 1000 (profiles, addresses, phones, files), plus roles at limit 100 and userRoles at limit 5000 — then joined client-side into UserWithDetails to assemble the UserListItem + UserDetailPanel views.

UserDetailPanel lifecycleverify / lock / reset / magic-linkOptional

Per-user admin actions: verify email, lock / unlock the account, trigger a password reset or magic link, and assign / remove roles (addUserRoleAction / deleteUserRoleAction). Each calls the matching admin or auth action. Note: 'verify email' and 'lock/unlock' are implemented as updateUserAction PATCHes on the users table (verify sets verifiedAt; lock sets only isLocked; unlock clears isLocked + lockedUntil + failedLoginAttempts). Role assign/remove writes the user_roles RBAC table, which — like the other RBAC tables (roles, claims, role_claims) — is hard-locked to godmin in the generic entity API: any non-GET returns 403 'managing roles and claims requires godmin privileges' unless the caller is godmin, so this control is only functional for a godmin caller. This is the opposite of DevicesPage's session controls: user_sessions carries the same kind of generic-CRUD godmin lock, but DevicesPage never uses generic CRUD — it calls the dedicated /auth/sessions route (no godmin check). Revoke is user-scoped to the authenticated caller's own sessions; approve/reject are public one-time-token endpoints. So those controls work outside the RBAC lock, unlike UsersPage role assign/remove.

updateUserActionEndpointAction<Partial<UserInfo> & { id }, MutationResponse<UserInfo>>Optional

Required. The users-table PATCH action UsersPage uses to mutate a user record — it backs the verify-email and lock/unlock lifecycle controls above (there is no separate 'verify' or 'lock' endpoint; they are field updates).

inviteinviteUserActionOptional

Invite a new user by email (the SetPasswordPage invite flow lands them). onUserInvited / onRoleAssigned / onRoleRemoved / onUserUpdated callbacks let you refresh or toast.

Related sections