Skip to content

Assigning members to units ​

A member is in a unit when a row exists in member_unit_assignments linking the two. That row is what makes attendance roll up, what scopes shepherd visibility, what lets the map know where to put the pin. Without it a member is a name in a list with no organizational context.

This page covers every path GCM offers for creating those rows.

The one-per-level rule ​

A member can be assigned to one unit at each level. If your levels are Branch β†’ Center β†’ Cell, a member can be in one branch and one center and one cell β€” three rows in member_unit_assignments, one per level. They cannot be in two branches at once.

The database enforces this with a unique index on (member_id, level_index) scoped to organization_id. Trying to add a second row at the same level either replaces the existing one (in the unit-detail flow) or surfaces a duplicate error (raw insert).

If a member legitimately participates in two branches β€” say a worship leader who plays at both campuses β€” pick one as their home branch and use a custom field to note the secondary.

Members panel on a unit detail page

From a unit's detail page ​

This is the most common workflow. Open the unit (drill in from the tree or a level page), scroll to the Members panel, and click Add member.

The dialog shows a searchable dropdown. Type two characters and GCM hits the search_members RPC for live results across the whole org. Pick a member, click Add, and you'll see them appear in the panel immediately.

What happens under the hood:

  1. GCM checks the panel's current member list to bail early if the same member-id is already assigned to this unit (toast: "Member already assigned").
  2. It inserts a row into member_unit_assignments with the member, the unit, and the current org id (RLS enforces this anyway).
  3. The unit's member count badge ticks up across the rest of the app.

The Members panel itself has:

  • A search box that filters by first or last name (case-insensitive, both fields ORed).
  • Pagination at 25 / 50 / 100 rows. Big units load lazily.
  • Member rows with avatar, type badge (visitor / member / regular), phone, and a completeness chip.
  • Remove button on hover for unassigning without leaving the page.

From a member's profile ​

Sometimes you're working from the other side β€” you've just added a member and want to file them. Open their profile, scroll to Org unit assignment, and pick units level by level.

The picker is cascading: choose a level 1 branch first, then the level 2 options narrow to that branch's centers, then level 3 to that center's cells. You're never asked to pick a cell whose branch you didn't select.

If you have only one branch the picker locks to it automatically β€” there's nothing to choose. Same for any level where the member-or-staff scope leaves exactly one option.

In bulk ​

For migrations, big intakes, or a parish-wide restructure, single-row inserts get tedious. Two bulk paths:

Bulk import CSV ​

Members imported via bulk import can include the unit name in their column. The import matches by name (case-insensitive) against org_units at the relevant level and creates assignments in the same transaction. Unmatched names show up in the dry-run preview so you can fix typos before committing.

Bulk actions inside the app ​

From Members, filter the list to the subset you want, hit Bulk actions β†’ Assign to unit, and pick the target. GCM upserts the assignments β€” existing rows at the same level are replaced, not duplicated.

Removing an assignment ​

Three paths:

  • From the Members panel on a unit page β€” hover, click the trash icon, confirm.
  • From the member's profile β€” clear the picker for that level.
  • From bulk actions β€” Unassign from current unit at level N.

Removing an assignment doesn't delete the member. It just removes the row from member_unit_assignments. The member becomes "unassigned at that level" and stops appearing in that unit's rolled-up reports.

What gets counted where ​

Once a member has assignments, every count in the app respects them:

CountCascade rule
Unit-card "N members"Direct assignments only (no descendants)
Subtree total on a branch detail pageMember count + sum of every descendant's direct count
Attendance dashboard filterAll members visible in the selected unit's subtree
Giving dashboard filterSame β€” member's giving rolls up the tree
Map pins per unitEach unit's direct assignments are clustered around the unit's coordinates

The "card" count and the "subtree total" being different is intentional. A branch with three centers and 200 members each shows "0 members" on its own card if nobody is directly assigned to the branch (which is normal β€” people are usually assigned to cells, not branches). The branch detail page shows "600 members" in the subtree stat.

Auto-assignment workflows ​

Workflows can create assignments programmatically. The most common pattern: a visitor follow-up workflow assigns the visitor to the cell whose leader took the first call. See Workflow actions for the Assign to unit node spec.

Workflow assignments use the same one-per-level rule

If the workflow assigns a member to a cell and they're already in a different cell, the existing row is replaced. The audit log records both the unassign and the re-assign.

Common questions ​

What if a member has no unit at all? Then they're "unassigned" and don't roll up to any branch. They appear in the all-members list and the global dashboard but not in any filtered report. This is the default for new members until you (or a workflow) place them.

Can I bulk-move members from one cell to another? Yes β€” filter the list to the source cell, select all, run Bulk actions β†’ Assign to unit with the target cell. The existing assignments get replaced.

Why does a member's profile show two assignments at level 3? It shouldn't β€” the unique index prevents that. If you see it, something legacy is in the data. Reach out to support and reference the member's id.

Next steps ​