Files
hackerspace.sh/content/docs/reference/members.md
T
Moheeb Zara 16229ae523 feat(docs): add a Diátaxis documentation section to the public site
A new public /docs area covering the whole platform, organized by Diátaxis:
tutorials (learning), how-to guides (tasks), reference (facts), and explanation
(the why). 29 pages, each grounded in the actual routes, actions, schema, and
UI — verified against the code and corrected for accuracy (e.g. admin-only vs
admin+board gating, where the permissions matrix actually lives, how Stripe
reconciliation matches).

Implementation:
- lib/docs/nav.ts is the single source of truth (categories + pages), driving
  the sidebar, static params, and prev/next.
- Content authored as content/docs/<category>/<slug>.md, read at build time
  (the routes are statically generated), rendered by <DocsMarkdown> — reuses the
  existing react-markdown/GFM stack, no new dependencies.
- (docs) route group with its own theme (docs.css) matching the public site's
  dark / monospace / lime aesthetic; sidebar with active-state, breadcrumb,
  prev/next, and a Diátaxis home. Public — signed-in users can read it too.
- "Docs" link added to the landing nav.

typecheck 0 · lint 0 errors · build ok (all /docs pages prerendered)
2026-08-05 00:42:42 -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.

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.