The Fastify layer over pgmorbac: permission checks, RLS session context,
management routes, PostgREST data proxy, and the migration loader for the SQL
from @crudy/pgmorbac. The SQL is no longer bundled here.
The public repo shipped with no license, readme, or changelog. Add them
plus standard package metadata (license field, keywords, author,
homepage, repository, bugs) so the Gitea/npm pages present the package
professionally. README and CHANGELOG describe the exports this repo
actually contains.
Postgres-native global search (tsvector + pg_trgm, no external service) with a
config-driven index so any table self-registers. Per-row visibility via morbac
RLS. New reusable @crudy/search package for the spotlight UI; core wires it into
the bar (Ctrl/Cmd K) with no hardcoded command list.
Backend
- 0008_search.sql: app.search_index + GIN indexes, app.searchable_sources
registry, generic trigger, app.search_register/reindex_source helpers, the
app.search(q,limit) RPC (websearch_to_tsquery, word_similarity, RLS), grants.
- BackendModule.searchables: modules declare searchable tables; registered at
boot in syncModules with identifier validation.
- /search data route; org/role reindex via new RoleEventSink + search-reindex.
- Core entities registered: users, orgs, roles, service connectors, emails.
Frontend
- @crudy/search: presentational Spotlight (dialog, hotkey, grouped results,
real anchor links, in-modal shortcut hints).
- command-registry is pure logic; pages/actions derive from core-routes,
the settings tab registry, and module navItems/settingsTabs/crudModels/commands.
- CrudModelDef yields page + create action; generic FrontendModule.commands for
any developer action. Floating-sidebar top-right items render separately.
Modules: dashboard, license-admin (customers, plans), email-templates,
service-connectors register their searchables and CRUD models.
- Extract the profile API-key UI into a shared ApiKeysManager component
(modal create form, full/readonly toggle, and detailed permission-scope
picker). Profile and the service-account detail page both use it, so the
two interfaces stay consistent and the code isn't duplicated.
- Add GET /users/:id/permission-options (service accounts), mirroring
GET /me/permissions, so the scope picker shows exactly the pairs the
account holds; the same query caps the key server-side.
- Service and system accounts never receive notifications: recipient
resolution now targets account_type='user' across explicit, org-wide,
and org-scoped paths (also fixes a stale 'human' literal that matched
nothing).
Permissions view
- Restore the System Accounts listing path and audit related tabs.
- Lock the framework system_users deny rules (is_system_managed) and
system-principal global rules; show them read-only.
System vs service accounts
- Only account_type='system' is immutable. service-bot is no longer a
system principal; ensureInternalAccounts repairs existing rows.
- GET /users now surfaces system/service accounts (gated by
read/system_users, read/service_users) and Type is the first column.
Service accounts
- UI to create/edit/delete service accounts (API-only, no login).
- Admin API-key management: GET/POST/DELETE /users/:id/keys, restricted
to service accounts, scope-capped to the account's own permissions,
with a key-management card on the user detail page.
Password policy
- Admins never set passwords. Creating a user account auto-generates a
strong password (shown once) and forces a change on first login;
admin "Reset password" does the same.
- Forced change flow: login returns password_change_required +
challenge token; POST /auth/change-password validates strength,
clears the flag, issues the session. Enforced after password and MFA.
- Strength: length 12-128, reject common passwords and email/name.
UI
- Lock indicators in action columns use a shared LockBtn (tooltip,
aligned with other action buttons).
- Account-type selection in create is a segmented button selector.