From 3efa3cdb46529f9270358a0a85ed4b1713b4a9c2 Mon Sep 17 00:00:00 2001 From: Moheeb Zara Date: Sat, 16 May 2026 22:25:11 -0700 Subject: [PATCH] docs: fix audit-found drift (status enum, env, limitations, action layout) Audit follow-up. ARCHITECTURE: status now 'In production', authoritative note that server actions are per-domain under lib/actions/* (no monolithic lib/actions.ts), rewrote stale Known Limitations (test suite exists; PayPal sync route; social auth wired; webhooks signing-only; single-space assumption), fixed env table (removed phantom SUPABASE_JWT_SECRET, added SECRETS_ENCRYPTION_KEY/OAuth). DATABASE_SCHEMA/DB_SCHEMA_MAP: ~43 tables / migrations through 038; space_members.status is member_status enum default 'unverified' (was wrongly 'active'); fixed the active/pending flow text. README: webhook wording matches WEBHOOKS.md. API_REFERENCE: real lib/actions/* path + 4 previously-undocumented actions. createSecret docs were already correct (ADMIN_ROLES = admin+board) -- left as-is. --- DB_SCHEMA_MAP.md | 4 ++-- README.md | 2 +- docs/API_REFERENCE.md | 8 +++++++- docs/ARCHITECTURE.md | 31 ++++++++++++++++++++----------- docs/DATABASE_SCHEMA.md | 13 +++++++------ 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/DB_SCHEMA_MAP.md b/DB_SCHEMA_MAP.md index ca986b1..bda6370 100644 --- a/DB_SCHEMA_MAP.md +++ b/DB_SCHEMA_MAP.md @@ -62,7 +62,7 @@ | `email` | text | nullable | | `handle` | text | nullable | | `phone` | text | nullable | -| `status` | text | default `'active'` | +| `status` | member_status enum (`current`,`late`,`inactive`,`unverified`) | default `'unverified'`; "active" = `current`/`unverified`/`late` | | `payment_status` | text | nullable | | `payment_note` | text | nullable | | `joined_at` | timestamptz | | @@ -301,7 +301,7 @@ Default channels created by trigger on space INSERT: `general`, `announcements`, ### Login 1. `/login` → `signIn(email, password)` → Supabase auth 2. Middleware checks session cookie -3. App layout RSC calls `getCurrentMembership()` → queries `space_members` WHERE `user_id = auth.uid()` AND `status IN ('active', 'pending')` +3. App layout RSC resolves the member → queries `space_members` WHERE `user_id = auth.uid()` AND `status IN ('current','unverified','late')` (the `ACTIVE_STATUSES` set in `lib/permissions.ts`) 4. If no membership found → redirect `/signup` ### Dashboard diff --git a/README.md b/README.md index db7b34f..01f065b 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ A multi-tenant operating system for hackerspaces, makerspaces, and member-run sh - **Governance.** Proposals with quorum, vote tracking and expiry; incident reports with anonymous reporter tracking by token; versioned policy library; member forum with polymorphic comments. - **Communications.** Multi-channel chat with realtime delivery. - **Recruitment.** Public-facing recruitment page per space. -- **API.** PostgREST-generated REST for every table, gated by RLS. Optional webhooks with HMAC-signed deliveries. +- **API.** PostgREST-generated REST for every table, gated by RLS. Webhook HMAC signing contract + secret rotation are defined; per-event delivery is a follow-up (see [docs/WEBHOOKS.md](./docs/WEBHOOKS.md)). ## Stack diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index da4a842..1592659 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -196,7 +196,7 @@ async function joinSpace(formData: { ## 3. Task Actions -**File**: `lib/actions.ts` +**File**: `lib/actions/tasks.ts` (server actions are split per-domain under `lib/actions/*.ts`, re-exported from `lib/actions/index.ts`; there is no monolithic `lib/actions.ts`) ### `createTask(formData)` @@ -945,3 +945,9 @@ No permission code; any active member. All writes are self-only — the member i - `getMyVisits()` — the caller's own recent visits (the `/me` history). - `listAttendance()` — any member (org-wide attendance history is all-members by product decision); last 250 visits with computed status. No new permission code; managers are not special here. Surfaced as the "Who's here" panel on the dashboard (present list + self check-in/out + host + note), the `/attendance` page (all members), and "My recent visits" on `/me`. + +### Previously-undocumented actions (audit addendum) +- `updateMyProfile(input)` — `members.ts`; any member edits their own profile fields (self-scoped). +- `discloseAffiliations(input)` — `members.ts`; the member records their own conflict-of-interest affiliations. +- `updateSpaceVisibility(input)` — `settings.ts`; admin toggles space/member-directory visibility. +- `listDoorCards(input)` — `door.ts`; `door.operate`, service client; active cards for a connection's grant/revoke UI, returning only the masked `last4` (raw UID never returned). diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 0aab57f..fe8339c 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,8 +1,15 @@ # Hackerspace.sh - Architecture Documentation -> **Last Updated**: 2026-03-10 +> **Last Updated**: 2026-05-17 > **Version**: 1.0.0 -> **Status**: Pre-Production Audit +> **Status**: In production (serving live traffic) +> +> Note: Sections 7 and 13 and the project tree describe an earlier layout. +> Server actions are split per-domain under `lib/actions/*.ts` (re-exported +> from `lib/actions/index.ts`); there is no monolithic `lib/actions.ts`. The +> per-module behavior is current; the module-feature sections later in this +> document (Certifications, Classes, Equipment, Door, Presence, etc.) are the +> authoritative reference. --- @@ -395,7 +402,10 @@ Integration credentials stored in `integrations.config` (JSONB): | `NEXT_PUBLIC_SUPABASE_URL` | Yes | Supabase project URL | | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Yes | Supabase anon key | | `SUPABASE_SERVICE_ROLE_KEY` | Yes | Admin operations | -| `SUPABASE_JWT_SECRET` | Yes | JWT verification | +| `SECRETS_ENCRYPTION_KEY` | Yes | AES-256-GCM key for the secrets vault | +| `NEXT_PUBLIC_OAUTH_GITHUB` / `NEXT_PUBLIC_OAUTH_GOOGLE` | No | Enable social sign-in buttons | + +`.env.example` and `docs/DEPLOYMENT.md` are the authoritative env list. (`SUPABASE_JWT_SECRET` is not used by the app and was removed from this table.) --- @@ -591,11 +601,10 @@ self-mark host. Surfaced as the dashboard "Who's here" panel, the ## 13. Known Limitations -1. **No test suite** - Unit, integration, and E2E tests needed -2. **Payment integrations** - UI only, no actual OAuth/API -3. **Import feature** - UI only, no file processing -4. **Database connector** - UI only, not implemented -5. **Social auth** - GitHub/Google buttons present but not wired -6. **Webhook endpoint** - URL shown but no actual endpoint -7. **Email notifications** - Not implemented -8. **Search** - Client-side only, no full-text search +1. **Test suite** - Extensive Vitest unit coverage of pure logic (`__tests__/`, run with `pnpm test`) plus Playwright smoke e2e (`e2e/`). Gap: server-action orchestration is not unit-tested (no Supabase mock harness); e2e is mostly page-render checks, not full write/RLS flows. +2. **Payment integrations** - Manual import/CSV reconciliation is the primary path. A PayPal sync endpoint exists (`app/api/paypal/sync/route.ts`); Stripe/other live APIs are not integrated. See `docs/` and the Payments module section. +3. **Social auth** - GitHub/Google sign-in is wired, gated by the `NEXT_PUBLIC_OAUTH_GITHUB`/`NEXT_PUBLIC_OAUTH_GOOGLE` env flags. +4. **Webhooks** - The HMAC signing contract and secret rotation exist; per-event delivery is not implemented (see `docs/WEBHOOKS.md`). +5. **Email notifications** - Not implemented. +6. **Search** - Client-side filtering only, no server-side full-text search. +7. **Single space per user** - The auth resolver assumes one active membership per user; a user in 2+ spaces is not supported (no space switcher). Fails closed. diff --git a/docs/DATABASE_SCHEMA.md b/docs/DATABASE_SCHEMA.md index f25ed88..8811be7 100644 --- a/docs/DATABASE_SCHEMA.md +++ b/docs/DATABASE_SCHEMA.md @@ -1,12 +1,13 @@ # Hackerspace.sh - Database Schema Reference -> **Last Updated**: 2026-05-15 +> **Last Updated**: 2026-05-17 > **Database**: PostgreSQL via self-hosted Supabase -> **Tables**: ~30 +> **Tables**: ~43 > **Source of Truth**: `scripts/schema.sql` (canonical, idempotent); numbered -> migrations `scripts/0NN_*.sql` upgrade existing deployments. The 13-table -> reference below is the original baseline; tables added by migrations -> 014-025 are summarized in the "Migrations 014-025" section at the end. +> migrations `scripts/0NN_*.sql` (through **038**) upgrade existing +> deployments. The 13-table reference below is the original baseline; tables +> added by migrations 014-038 are summarized in the migrations section at the +> end. `DB_SCHEMA_MAP.md` has the per-table quick map. --- @@ -686,7 +687,7 @@ CREATE INDEX idx_activity_space ON activity_log(space_id, created_at); --- -## Migrations 014-035 (additions since the 13-table baseline) +## Migrations 014-038 (additions since the 13-table baseline) `scripts/schema.sql` is the canonical idempotent schema; each numbered migration is mirrored as a section in it. Tables/columns added: