From d0aef9a6aa1577e13af1cac79a428ae90c3dcd41 Mon Sep 17 00:00:00 2001 From: Moheeb Zara Date: Sat, 16 May 2026 22:44:21 -0700 Subject: [PATCH] =?UTF-8?q?docs:=20correct=20ARCHITECTURE=20layout/=C2=A77?= =?UTF-8?q?,=20note=20intentional=20settings=20+=20single-space?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Project tree + section 7 module paths now reflect the per-domain lib/actions/* reality (no monolithic lib/actions.ts); explicit note that /settings admin secret loading is by-design same-space management; getAuthMember single-space invariant documented in code. HANDOFF pass-31. --- docs/ARCHITECTURE.md | 38 +++++++++++++++++++++++--------------- docs/HANDOFF.md | 20 ++++++++++++++++++++ lib/auth-helpers.ts | 5 +++++ 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index fe8339c..9c0bc2f 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -90,15 +90,18 @@ Hackerspace.sh is a comprehensive member management platform designed for hacker │ │ ├── client.ts # Browser client │ │ ├── proxy.ts # Middleware session refresh │ │ └── server.ts # Server Component client -│ ├── actions.ts # All server actions (CRUD) -│ ├── auth-actions.ts # Auth-specific actions -│ ├── types.ts # TypeScript interfaces +│ ├── actions/ # Server actions, one module per domain +│ │ ├── index.ts # Barrel (re-exports every domain module) +│ │ ├── tasks.ts projects.ts members.ts payments.ts … +│ │ └── classes.ts equipment.ts door.ts presence.ts … +│ ├── *-logic.ts # Pure, unit-tested decision logic +│ ├── *-guard.ts # Per-feature server-component guards +│ ├── auth-helpers.ts # requireMember / permission gates │ └── utils.ts # Utility functions (cn) -├── scripts/ # SQL migrations -│ ├── 000_reset_schema.sql # Schema reset (dev only) -│ ├── 001_create_schema.sql # Initial schema -│ ├── 002-011_*.sql # Incremental fixes -│ └── patch-dashboard.mjs # Utility script +├── scripts/ # SQL +│ ├── schema.sql # Canonical, idempotent (source of truth) +│ ├── 0NN_*.sql # Numbered incremental migrations (→ 038) +│ └── seed.sql # Optional seed data ├── middleware.ts # Auth middleware ├── docs/ # This documentation └── [config files] # next.config, tsconfig, etc. @@ -244,7 +247,7 @@ Admin (full access) | `createSpace` | spaceName, spaceSlug, spaceCity, displayName | Authenticated | Create new space | | `joinSpace` | inviteCode, displayName | Authenticated | Join existing space | -### 7.2 Tasks (`lib/actions.ts`) +### 7.2 Tasks (`lib/actions/tasks.ts`) | Action | Parameters | Role Required | |--------|------------|---------------| @@ -253,7 +256,7 @@ Admin (full access) | `completeTask` | taskId | Claimant | | `deleteTask` | taskId | Member | -### 7.3 Projects (`lib/actions.ts`) +### 7.3 Projects (`lib/actions/projects.ts`) | Action | Parameters | Role Required | |--------|------------|---------------| @@ -261,7 +264,7 @@ Admin (full access) | `updateProjectStatus` | projectId, status | Member | | `deleteProject` | projectId | Member | -### 7.4 Members (`lib/actions.ts`) +### 7.4 Members (`lib/actions/members.ts`) | Action | Parameters | Role Required | |--------|------------|---------------| @@ -271,7 +274,7 @@ Admin (full access) | `removeMember` | memberId | Admin | | `importMembers` | rows[] | Admin/Board | -### 7.5 Payments (`lib/actions.ts`) +### 7.5 Payments (`lib/actions/payments.ts`) | Action | Parameters | Role Required | |--------|------------|---------------| @@ -279,7 +282,7 @@ Admin (full access) | `linkPaymentToMember` | paymentId, memberId | Treasurer/Admin | | `importPaymentsCsv` | rows[] | Treasurer/Admin | -### 7.6 Knowledge Base & Secrets (`lib/actions.ts`) +### 7.6 Knowledge Base & Secrets (`lib/actions/knowledge-base.ts`, `lib/actions/secrets.ts`) | Action | Parameters | Role Required | |--------|------------|---------------| @@ -290,7 +293,7 @@ Admin (full access) | `deleteSecret` | secretId | Admin | | `upsertAreaLead` | area_code, area_name, lead_id?, lead_handle?, status? | Admin/Board | -### 7.7 Contacts (`lib/actions.ts`) +### 7.7 Contacts (`lib/actions/contacts.ts`) | Action | Parameters | Role Required | |--------|------------|---------------| @@ -298,7 +301,12 @@ Admin (full access) | `updateContact` | contactId, updates | Member | | `deleteContact` | contactId | Member | -### 7.8 Settings (`lib/actions.ts`) +### 7.8 Settings (`lib/actions/settings.ts`) + +> Note: `/settings` is admin-only and intentionally loads the space's own +> `webhook_secret` and integration `config` so an admin can view/rotate +> them. That is by-design same-space admin secret management, not a leak; +> the page redirects non-admins before any of it is fetched. | Action | Parameters | Role Required | |--------|------------|---------------| diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index f66257a..be4dba4 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -4,6 +4,26 @@ Append-only. Newest entries on top. Keep each entry to one screen. --- +## 2026-05-17 (pass 31) — Audit follow-ups + attendance polish; LOCAL, awaiting deploy + +Branch `main`. Continuation of the pass-30 audit. User: handle the deferred items where confident + properly test/doc; "stick to single space for now". 5 commits `2dc0af5..` (this entry). + +### Done (each gated + own commit, suite 459, build clean) +- **`2dc0af5` PayPal sync**: `payments` has NO unique index on `external_id`, so the `onConflict:'external_id'` upsert was unreliable and fell back to an insert that stripped `external_id` -> duplicate, non-idempotent rows, not tenant-scoped. Replaced with: look up existing `external_id`s in THIS space, insert only new rows (id preserved). No migration, no schema risk. +- **`1e1b93e` door IPv6 pin**: SSRF pin parser did `pinnedHost.split(':')[0]`, mangling any IPv6 pin (failed closed -> IPv6 controllers unusable). New pure exhaustively-tested `normalizeHost` (scheme/userinfo/port/path strip; `[ipv6]`/`[ipv6]:port`/bare-ipv6 unwrap) applied to both request host and pin. ALL prior behavior preserved (verified: IPv4, host:port, userinfo-spoof reject, trailing-dot reject, metadata always blocked, IPv4-mapped-IPv6 vs IPv4 fails closed). 29 door tests. +- **`d5a71c9` /attendance polish** (user ask): client view with a "Here now" section + inline self check-in / check-in-as-host / check-out + note; history with name search, day picker, grouped-by-day headers, per-visit duration/status/notes, live visits/members summary. New pure tested `dayKey` (tz-stable) + `visitDurationMinutes`. +- **docs (this commit)**: ARCHITECTURE project tree + §7 module paths corrected to `lib/actions/*` reality; explicit note that `/settings` admin secret loading is by-design (not a leak); `getAuthMember` single-space invariant documented in code. + +### Decisions / not done (intentional) +- **Single space per user**: kept (user decision). `getAuthMember` `.single()` is intentional and fails closed; documented in code + ARCHITECTURE Known Limitations #7. Not changed. +- **Settings `select('*')`**: NOT narrowed — verified the admin-only client legitimately uses `webhook_secret` + integration `config`; narrowing would be cosmetic and risk breaking the UI. Documented as intentional instead. +- A full ARCHITECTURE §7 prose rewrite remains a nice-to-have (paths now correct; an authoritative top-of-doc note already added pass-30). + +### Open +- LOCAL & undeployed: pass-31 (5 commits) + the pass-30 deploy-state docs. **Awaiting deploy approval** (no migration this pass; app + docs only). Default reverted to ASK-before-deploy (the pass-30 deploy-without-asking was one-time). After push: smoke `/attendance` (search/day filter/check-in), PayPal re-sync idempotency, door IPv6 pin if a controller is ever IPv6. + +--- + ## 2026-05-17 (pass 30) — Presence/attendance feature + full app audit pass Branch `main`. Big session: landing wording fix, a new presence module, a 4-agent read-only audit, and audit fixes. User authorized deploying this work without the per-deploy ask (one-time, for this ready work; default reverts to ASK next session unless reaffirmed). **DEPLOYED**: pushed `4b29280..c12a103`, Actions run `25982428014` success, migration 038 applied. Smoke: `/` `/login` 200; `/dashboard` `/attendance` `/doors` `/classes` `/equipment/manage` 307->login (gated, expected). NOT browser-verified. diff --git a/lib/auth-helpers.ts b/lib/auth-helpers.ts index 64a682d..1e3185f 100644 --- a/lib/auth-helpers.ts +++ b/lib/auth-helpers.ts @@ -43,6 +43,11 @@ export async function getAuthMember(supabase: ServerSupabase): Promise