Permissions

How Psalmly decides who can do what — roles, capabilities, and per-user overrides.

The four roles

Every member of a church is one of four roles:

  • Owner — full access to everything, including billing and custom domains. There is usually one owner per church (the person who created it); others can be promoted later. Owners can do anything an admin can.
  • Admin — full operational access: people, scheduling, giving, site content, kids check-in, community, settings. Admins cannot manage billing or custom domains (those are owner-only).
  • Member — read access to scheduling, people, and site content, plus visibility into their own household's kids check-in. Members can join groups, sign up to serve, RSVP to events, give, etc., but cannot edit church-wide data.
  • Visitor — a placeholder role with no permissions by default; used for people who attended but haven't joined the church.

These roles are the answer for ~95% of churches.

When roles aren't enough

Sometimes a church needs to grant one specific person one specific capability without promoting them to admin. Common examples:

  • "Sarah runs kids check-in every Sunday but we don't want her in the giving data."
  • "Mark posts our announcements but isn't a full admin."
  • "Pat sets up our kids rooms + worker schedule each term."

For these, Psalmly layers capability-grained permissions on top of the role. The role gives a baseline; per-user overrides add or remove specific capabilities.

The capability catalog

Each capability is a single dotted string in the form <area>.<verb> (or <area>.<noun>.<verb> for finer-grained ones):

These are the capabilities you can grant or revoke per person. They're the ones actually enforced at the data layer — granting one to a member who isn't an admin really does let them do that one thing. (Most admin areas stay on the four-role system; see below.)

AreaCapabilityWhat it gates
Givinggiving.readView giving records and reports
Site contentsite-content.writeEdit Site content (identity, about, staff, important links, ministry pages, theme)
Announcementsannouncements.writePublish church-wide announcements
Kids check-inkids.checkin.writeRun check-in + pickup from the worker / admin UI
Kids check-inkids.rooms.manageCreate rooms + schedule workers
Kids check-inkids.pickup.overrideOverride a pickup-restriction block
Settingssettings.readView settings pages
Settingssettings.domains.manageAdd/remove custom domains (owner only by default)

How a permission resolves

Every server-side check (RLS policy or route handler) calls has_permission(churchId, capability). The function looks at:

  1. Per-user override — if there's a user_permission_overrides row for (church, user, capability), its granted flag wins. granted = true is an explicit grant; granted = false is an explicit revoke (deny). The override is the final word.
  2. Role default — if no override, the user's church role is looked up in role_permissions. If the role has the capability by default, the answer is yes.
  3. Otherwise — no.

Visitors have no role defaults — they're explicitly opted out of every capability until promoted.

How do I grant a member a specific capability?

  1. Admin sidebar → Directory.
  2. Click the person in the list, then Manage to open their profile.
  3. On their profile, click Manage access in the top-right.
  4. Find the capability in its group (Kids check-in, Giving, etc.).
  5. Click Grant. The optimistic update lands immediately; the subject's effective permission updates by their next page load.

To take it back, click Revoke (explicit deny — blocks even something the role would otherwise allow) or Reset (removes the override entirely; the role default applies).

When to use which

You want to…Use
Promote a long-term partnerChange their role to Admin
Give a focused volunteer one capabilityGrant override on that capability
Take away a specific capability from an adminRevoke override on that capability
Go back to "just the role default"Reset the override

Overrides are loud — they show up on the Access page with an "override grant" / "override revoke" tag so a future admin can see why this person can (or can't) do something specific. The audit log captures every grant/revoke/reset with the admin who made the change and when.

What stayed on the four-role system

Most of the admin UI still gates on the four-role enum (admin / owner can edit; member can read; visitor can do nothing). Only the capabilities in the catalog above are enforced at the finer level: kids check-in (run check-in, manage rooms, pickup override), site content, announcements, custom domains, viewing settings, and viewing giving records. Everything else keeps the simpler role check — scheduling, people management, creating funds

  • editing gifts, community moderation, editing settings, billing, and the admin AI tools are all admin/owner-only and can't be handed to a single person via an override.

Refunds are a special case. Psalmly doesn't issue refunds itself — they're done from the Stripe dashboard, and Psalmly only records the result when Stripe sends the charge.refunded webhook. So there's no in-app refund action to gate, and no per-user "can refund" control; restrict refunds at the Stripe account level instead.

What's deferred

  • Custom named roles ("Kids Coordinator" with a specific capability set as a reusable preset). The current model is per-user overrides; named-role presets are a future enhancement.
  • Capability presets / bulk grants (e.g. "give every Sunday School teacher the kids capabilities at once"). For v1 you grant per-person.
  • Per-resource scoping (e.g. "can only refund gifts < $500" or "can publish pages but not the homepage"). All capabilities are church-wide today.