The org tree and parent-child relationships β
The Org Structure page (/org-structure) is the single best place in GCM to see your church's shape. It's a literal tree β every level 1 unit is a root, every level 2 nests under it, and so on down to the leaves.
This page is about reading and navigating the tree. Creating units lives in Creating units; managing the tier names lives in Defining levels.
Anatomy of a row β
Each unit renders as a row in the tree with these elements, from left to right:
- An expand/collapse chevron if the unit has children. Disabled when there are no descendants.
- An icon β building for active, archive for archived.
- The name. Long names wrap onto a second line instead of truncating to "Downβ¦".
- A level badge ("Branch", "Center") β the singular label of the tier.
- A member-count chip with a
Usersicon. Hover for the exact tooltip. - The leader name if one is assigned, in a smaller line below. Unassigned leaders show a muted amber "No leader assigned" hint when you have manage permission, so you can spot gaps at a glance.
- The address if set.
- An actions row on hover with leader-assign, edit, and archive controls.

Expanding the tree β
Click the chevron on any unit with children to expand it. The children render one indent further with a vertical tree-line connector. Click again to collapse.
Three shortcuts in the toolbar:
- Expand all β opens every row in one shot. Good for spotting gaps.
- Collapse all β closes everything back to level 1.
- Select all β used with bulk actions, see below.
The expand state lives in component state only β refresh the page and you're back to all-collapsed. That's intentional; for orgs with hundreds of units the all-expanded view is unwieldy.
Summary stats β
Above the tree, two pill-shaped stat cards show:
- N units β total active units across every level.
- N members assigned β sum of every unit's member count. (Note: a member assigned at level 1 and level 3 counts twice across the levels, but only once toward the org's total members elsewhere. This stat shows the assignment count, not the distinct member count.)
These pills are color-coded β primary for units, blue for members β and serve as a quick health check.
Drilling into a unit β
Click a unit's row to select it (the row highlights in primary blue). Clicking a child unit name in the breadcrumb at the top of the unit's detail page takes you up one level. The URL pattern is:
/org-structureβ the tree view./hierarchy/:levelIndexβ the level page (card grid of every unit at that level)./hierarchy/:levelIndex/:unitIdβ the unit detail page.
The unit detail page is the heavy-lift view. It includes:
- A hero card with the unit name, leader pill, member count, and parent badge.
- Stat tiles for child unit count, total members in the subtree, average members per child, and "leaders assigned" ratio (e.g. "2 / 7").
- The address card and the embedded map preview if
map_locationorestimated_map_locationis set. - A Child units panel with active and archived tabs, sort controls, and click-through cards.
- A Members panel with searchable, paginated, removable assignment rows.
Breadcrumbs are clickable
At the top of every unit detail page the breadcrumb is Org Structure β <plural level name> β <unit name>. Click any segment to jump back.
Parent-child rules β
Every unit below level 1 has exactly one parent. The rules the UI enforces:
- A unit can't be its own parent. The picker excludes the unit's own id.
- A unit can't be a descendant of itself. Reparenting validates against this implicitly via the level constraint (you can only pick a parent one level up).
- A parent must be at the level immediately above. A level 4 cell can't be parented to a level 1 branch directly β it must go through a level 2 and a level 3.
- Level 1 units have no parent. The picker doesn't show on the create dialog for level 1.
These are UI guards; the database also has a check constraint matching #3.
Bulk operations β
Once any unit's checkbox is ticked, a sticky bulk-action bar appears at the top of the tree with these options:
- Archive β soft-hides the selected units (and all their descendants β the cascade is automatic).
- Delete β opens a reassignment wizard. See below.
- Clear β drops the selection.
On a level page (card grid) you also get Edit parent β reparent multiple peer units to a single new parent in one operation. The picker excludes the selected units to prevent self-parenting.
The delete reassignment wizard β
Deleting a unit that has children or members triggers a guard dialog with two questions:
What should happen to the child units?
- Delete them too (the default β recursive cascade).
- Move them to a sibling unit you pick from a dropdown.
What should happen to the members?
- Unassign them (remove the row from
member_unit_assignments). They stay as members; they just lose their unit link. - Reassign them to a sibling unit you pick.
The wizard counts both before running so you see "12 members assigned" and the list of child unit names before confirming. Once you click Delete permanently the operation runs as a sequence: child reparent β member reassign β user-unit-assignment cleanup β soft-delete on the units.
Hard-delete is irreversible from the UI
Once the wizard runs, the deleted rows have deleted_at set and are invisible to the app. Restoring them requires a direct database fix from support. Prefer Archive for anything you might bring back.
How the tree fetches β
The tree uses two queries:
org_unitsβ every active row for the org, ordered bylevel_indexthenname.org_units_archivedβ same query witharchived_at IS NOT NULL.
Both are cached for 2 minutes via React Query. Mutations (create, edit, archive, delete) invalidate the cache so the tree refreshes automatically. If the badge counts ever look stale, navigate away and back β that forces a refetch.
Next steps β
- Assign members to the units in your tree.
- Assign leaders and shepherds to scope user views.
- Archive and restore when your tree shape changes.
