Users
Manage admin accounts — profiles, languages, password resets, soft-delete.
Basic, on purpose
The user model is intentionally minimal in v0.1.0 — enough for content editing and admin work, not yet a full identity platform. Manage at /admin/users. Every user is a row in users with one or more roles attached; capabilities and content access derive from the assigned roles, not from a user-level flag.
Profile fields
- Name — first + last, both optional, displayed in node author bylines and in the admin's user picker.
- Email — unique, case-insensitive, used for login and as the recipient address for password resets and notifications.
- Password — hashed with bcrypt at the kernel default cost. Plain-text passwords are never logged or echoed back through the admin API.
- Language preference — pre-selects the editing-language switcher when this user logs in. Falls back to the site's default language if unset.
- Roles — multi-role assignment; capabilities are unioned across all assigned roles. See Roles & Permissions.
- Active — toggle. Inactive users cannot log in but their authored content links remain valid.
Lifecycle
Create
Click New user at /admin/users. The admin can either set a password directly or send an invite email through the email-manager extension; the invite includes a one-time setup link with a short TTL that resolves to the password-set form. If no email provider is active, the inline-password path stays open as a fallback.
Soft-delete
Toggling Active off removes login access but preserves authored-content references and revision history. Hard-delete (the Delete action) reassigns or nulls authored references depending on the relation — nodes get their created_by/updated_by set to null, audit-log entries keep the user id verbatim because audit data is append-only by policy.
Password reset
Two paths, both routing through the email-manager and whichever extension declares email.provider:
- From the admin — click Send reset link on a user row; email-manager dispatches the
password_resettemplate to that user's address. - By the user — "Forgot password" on the login page. Same dispatch path; the user enters their email and receives the same template.
The reset link is a one-time token stored in password_reset_tokens with a TTL (default 1 hour). Used or expired tokens cannot be replayed. The login form's "Forgot password" link is hidden when no email provider is active — the kernel won't dangle a button that has no possible follow-through.
docker compose exec app squilla reset-password <email> <new-password>. It runs against the database without needing a server and uses the same password hasher as signup. Idempotent. Works without SMTP or any email provider configured. The ADMIN_PASSWORD env var only takes effect during first-boot seed (when no admin exists yet); it does not reset an existing user's password.MCP tokens
API tokens for the MCP server are managed at /admin/security/mcp-tokens (the legacy /admin/mcp-tokens URL still redirects). Tokens are created by the admin, carry a scope (read | content | full), and are shown exactly once on creation — capture the token before navigating away. Each token records last-used timestamp and total-call count for usage auditing.
Tokens are not yet user-scoped. They are administrative artefacts created by an admin, used by an external agent. The audit log records the token id and the agent's IP, not the user-as-identity. Per-user tokens are on the roadmap.
Email subscriptions per user
Every user can subscribe to lifecycle events on top of any subscriptions inherited from their roles. Manage these from the user's profile sheet, or via role-level subscriptions for bulk wiring. The email-manager rules engine pairs with these subscriptions when a rule's recipients are set to from-role-subscription or from-user-subscription.
Events available: block-type, layout / layout-block, menu, node (filterable per node type), user. Per event, subscribe to create, update, delete, or all. Multi-verb selections render as comma-separated chips on the profile.
What's not in v0.1.0
- SSO / OAuth / SAML — password-only login today. The session layer is a clean abstraction so adding an OIDC handler is a contained piece of work; it just hasn't been done.
- 2FA / TOTP — roadmap; the user table has placeholder columns reserved for the secret and recovery codes.
- Per-user MCP tokens — tokens are admin artefacts today; per-user issuance with scoped permissions is planned.
- Per-user audit log of admin actions — there's an audit log of MCP calls, but not of every admin REST action. Coming alongside the per-user-token work.
- Profile photos — the schema has the column; the upload UI is not yet wired.
None of these are blocked by architecture; they're just not in this release. Most can be added by an extension without touching the kernel.