Files
Moheeb Zara 8edc9da611 docs: audit corrections, coverage pages, screenshots, and em-dash removal
Finalizes the docs section after an adversarial audit (code review + per-page
fact-check + coherence critic) and two content requests.

- Accuracy: fixed 10 invented cross-link slugs, the admin-vs-board gating claims
  the verifiers caught (permissions matrix, /settings, invites, onboarding,
  connect-payments, proposal withdraw, Stripe reconciliation, member fields,
  door.operate), and 2 issues in the new pages (project area-at-creation, forum
  thread-delete role).
- Coverage: added 5 how-to pages so every module is documented (recurring Stripe
  dues, tasks & chores, projects, comms & forum, ops knowledge base + secrets
  vault). 34 pages total.
- Screenshots: 12 captioned app screenshots under public/docs-media/, embedded
  as figures. Each tutorial now has 2-3 step screenshots.
- Style: removed all em-dashes/en-dashes/ellipses from the docs (natural ASCII
  punctuation).
- Handoff (docs/HANDOFF-audit-cleanup.md) updated with the current state.

typecheck 0 · lint 0 errors · build ok (all 34 /docs pages prerendered)
2026-08-05 03:15:07 -07:00

5.1 KiB

A member is one person's record in your space, stored in the space_members table. This page lists every member status and tier, the fields on the member record, and the settings that control who can see the directory. Manage members at /members; members edit their own record at /me.

The member roster with tier, status, and per-member actions.

Statuses

status is the member_status enum. It defaults to unverified. It governs whether a member can act in the app and whether they hold their role's privileges.

Status Can use the app Holds role privileges Shown on
current Yes Yes All members
late Yes Yes All members (dues lapsed)
unverified Yes No, pending approval Pending Approval tab
inactive No, blocked from all actions No Inactive tab

Notes:

  • The active set is current, unverified, and late. Only these three are loaded as a member's active membership; inactive members are blocked from every server action.
  • late is a dues state, not an authorization downgrade, a late member keeps their role and privileges.
  • unverified is the approval gate. In a require_approval space, a new member stays unverified and holds no privileged capability until an admin approves them, even if they redeemed a role-bearing invite. Approving sets status to current and approved to true.
  • The /members page tabs are All, Payment Issues, Pending Approval (unverified), and Inactive. The All tab hides inactive members.

Tiers

tier is the member_tier enum. It defaults to basic and records the membership level. It is set by an admin when adding or editing a member; it does not by itself grant permissions (roles do that).

Tier
plus
basic
associate

Record fields

Key columns on space_members. user_id is nullable on purpose: admins can add "offline" members who have no auth account.

Field Type Notes
id uuid Primary key
space_id uuid Owning space
user_id uuid, nullable Auth account; null for offline members
role member_role Default member; see roles
tier member_tier Default basic
tier_id uuid, nullable FK to space_tiers; canonical custom-tier reference
status member_status Default unverified
approved boolean Default true; set true on approval
display_name text Self- or admin-editable
handle text Self- or admin-editable
email text Unique per space when present
phone text
bio text Self-editable
avatar_url text
has_card_access boolean Door access flag
payment_status text Non-current value drives the Payment Issues tab
payment_note text
last_payment_at / last_paid_at timestamptz
dues_paid_until timestamptz Dues coverage end
joined_at timestamptz Sort key on /members
stripe_customer_id text
skills / interests / willing_to / affiliations text[] Self-editable profile arrays
coi_last_disclosed_at timestamptz Set when affiliations are disclosed
onboarding_completed_at timestamptz, nullable Set when onboarding is finished or skipped
onboarding_progress jsonb Default {}; tracks completed onboarding step IDs
created_at / updated_at timestamptz

Constraints: unique on (space_id, user_id), and a partial unique index on (space_id, email) when email is present.

Who edits what

  • Self (at /me): display_name, handle, phone, bio, skills, interests, willing_to, and affiliations. Changing affiliations re-runs conflict-of-interest disclosure and updates coi_last_disclosed_at.
  • Admin (at /members): email, display_name, phone, handle, role, tier, status, has_card_access, payment_status, and payment_note. joined_at is only set when adding a member; updateMember does not accept it.

On the /members page, some per-member panels are gated by capability rather than role: the access-cards panel (card UID) requires door.manage, the certifications panel requires certifications.grant, and the submitted-forms panel requires forms.manage.

Directory visibility

Who can see the member directory is set per space by member_directory_visibility (the directory_visibility enum) under Member directory visibility in /settings. It defaults to members_visible.

Value Who sees the directory
members_visible Any authenticated member (default)
public_members_visible Any authenticated member; behaves identically to members_visible (there is no public, unauthenticated directory route)
board_only Elevated roles only (admin, board, treasurer)
member_count_visible Elevated roles only; treated identically to board_only, non-elevated members get the same restricted notice (no count is shown)

When a member is not permitted to see the directory, /members shows a "restricted in this space" notice instead of the table.