Skip to content

Commit 90c3adb

Browse files
committed
feat(spaces): add spaces v1 vertical slice
1 parent 392e586 commit 90c3adb

32 files changed

Lines changed: 2505 additions & 9 deletions

docs/05-ui-ux-delta.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
## 2. Component Inventory (New & Updated)
1010
| Component | Type | Status | Notes |
1111
| --- | --- | --- | --- |
12-
| `SpaceHeader` | Server component | New | Displays space branding, rules CTA, join/leave actions, feature-flag aware. |
12+
| `SpaceHeader` | Client component | New | Displays space branding, rules CTA, join/leave actions, feature-flag aware. |
13+
| `SpaceShell` | Client component | New | Wraps header, membership panel, and rules editor for `spaces_v1` detail page. |
1314
| `SpaceRolePill` | Client component | New | Shows member role, tooltip with privileges. |
15+
| `MembershipPanel` | Client component | New | Organizer approval dashboard for pending requests with keyboard-accessible actions. |
16+
| `CreateSpaceForm` | Client component | New | Organizer-only creation flow with zod-backed validation and feature flag guard. |
1417
| `ContentComposer` | Client component | Updated | Modular editor supporting Article/Discussion/Q&A/Event/Workshop templates with plugin architecture. |
1518
| `TemplatePickerModal` | Client component | New | Allows selecting space-level templates with previews and accessibility hints. |
1619
| `ModerationQueueTable` | Client component | Updated | Adds filters for queue type, bulk actions, SLA indicators. |
@@ -47,10 +50,12 @@ Tokens are declared in `tailwind.config.js` and consumed within `src/components/
4750
- For events, include accessibility notes (wheelchair access, ASL availability) and ensure color-coded statuses have text equivalents.
4851
- Implement reduced motion mode for animations in reputation celebrations and feed transitions.
4952
- RBAC Role Manager exposes live search and roster list with `aria-live="polite"` status updates and keyboard-visible focus rings tied to `brand.focus`.
53+
- Space Shell components expose join actions with `aria-disabled`, focus-visible outlines, and announce success/error via inline status banners that meet contrast ratios.
5054

5155
### 4.1 Accessibility Validation Checklist — 2025-11-07
5256
-`tests/e2e/admin-role-manager.spec.ts`: Axe scan (`@axe-core/playwright`) focused on the role manager section verifies no WCAG 2.1 AA violations when `rbac_hardening_v1` is enabled for staff.
5357
-`tests/e2e/nav-ia.spec.ts`: Confirms skip-link/focus states on the new navigation hubs (`nav_ia_v1`) and asserts hub visibility per role gate.
58+
- ⚠️ `tests/e2e/space-shell.spec.ts` (planned): Axe scan will cover `SpaceShell` header + membership panel to confirm join buttons announce state changes and tab order matches visual layout once Playwright fixtures land.
5459
- ⚠️ Publish flow axe validation deferred to Phase-2 composer overhaul; current admin table relies on legacy markup and is tracked in MOD-001 follow-up.
5560
- Keyboard walkthroughs recorded in `/docs/operations/runbooks/rls-denial-spike.md` appendix to ensure moderators can assign roles without pointer devices.
5661

docs/06-data-model-delta.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
| Table | Purpose | Key Columns | Notes |
55
| --- | --- | --- | --- |
66
| `spaces` | Defines communities with branding and governance metadata | `id`, `slug`, `name`, `description`, `visibility`, `rules`, `created_by`, `feature_flags`, `created_at`, `updated_at` | `slug` unique; `feature_flags` JSONB for space-level toggles |
7-
| `space_members` | Maps users to spaces with roles and status | `space_id`, `profile_id`, `role`, `status`, `invited_by`, `joined_at`, `last_active_at` | Composite PK (`space_id`, `profile_id`); status enum (pending, active, banned) |
8-
| `space_rules` | Structured rules/flairs/templates | `id`, `space_id`, `type`, `value`, `position` | `type` enum (rule, flair, template, automod) |
9-
| `post_templates` | Stores reusable template metadata | `id`, `space_id`, `content_type`, `title`, `body`, `config` | `config` JSONB for form fields, required sections |
7+
| `space_members` | Maps users to spaces with roles and status | `space_id`, `profile_id`, `role_id`, `role_slug`, `status`, `requested_at`, `decision_at`, `joined_at`, `last_active_at` | Composite PK (`space_id`, `profile_id`); `status` enum (`pending`, `active`, `banned`); `role_slug` maintained via trigger |
8+
| `space_rules` | Structured rules/flairs/templates | `id`, `space_id`, `title`, `body`, `kind`, `value`, `position` | `kind` enum (`rule`, `flair`, `template`, `automod`); JSONB `value` stores config |
9+
| `post_templates` | Stores reusable template metadata | `id`, `space_id`, `content_type`, `title`, `body`, `config` | `content_type` enum (`article`, `discussion`, `qa`, `event`, `workshop`); `config` JSONB for form fields |
1010
| `post_versions` | Version history for posts | `id`, `post_id`, `version_number`, `content`, `metadata`, `created_by`, `created_at` | Add `content` as JSONB to support editor structure |
1111
| `questions` | Extends posts for Q&A | `post_id`, `accepted_answer_id`, `bounty_amount`, `bounty_currency`, `bounty_expires_at` | `post_id` FK to `posts`; `accepted_answer_id` references `answers` table |
1212
| `answers` | Stores answers for Q&A posts | `id`, `question_id`, `body`, `author_id`, `is_accepted`, `created_at`, `updated_at` | Add index on (`question_id`, `is_accepted`) |
@@ -23,6 +23,7 @@
2323

2424
> 2025-10-24: Created baseline `audit_logs` table with service-role write policy and admin read access to support SEC-001 guard telemetry.
2525
> 2025-10-31: Hardened SEC-001 scope with community scaffolding. Added `spaces` (slug, name, visibility, created_by, timestamps), `space_members` (space_id, profile_id, role_id, status, joined_at, last_seen_at), `space_rules` (space_id, title, body, created_by, timestamps), `post_versions` (post_id, version_number, content JSONB, metadata JSONB, created_by, created_at), and `reports` (reporter_profile_id, subject_type/id, reason, status, space_id, timestamps). Added helper functions `normalize_role_slug`, `highest_role_slug`, `user_space_role_at_least` to back policies.
26+
> 2025-11-07: MOD-001 expansion introduced `feature_flags` JSONB + optional banner imagery on `spaces`, normalized `space_membership_status` to `pending|active|banned`, added `role_slug`/`requested_at`/`decision_at` columns with sync trigger on `space_members`, extended `space_rules` with `kind` enum + JSONB `value`, created `content_template_type` enum + `post_templates` table, and added `space_members_pending_idx` / `audit_logs_space_*` indexes. Policy `Members request access` now allows self-service join requests gated to `status='pending'`.
2627
2728
### Index & Policy Update — 2025-10-31
2829

docs/07-security-privacy.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Full matrix with endpoint mapping maintained alongside Supabase policy definitio
3131

3232
**Admin Guard Hardening:** Unified admin API routes now delegate to `requireAdmin` in `src/lib/auth/require-admin.ts`, which resolves canonical roles, audits denials via `audit_logs`, and emits `authz_denied_count{resource,role,space,reason}`. Guard usage now extends to user management and gamification APIs, ensuring telemetry tags include `resource`, `role`, `space`, `reason` for Operations dashboards. RLS helper functions (`normalize_role_slug`, `user_space_role_at_least`, `highest_role_slug`) back deny-by-default policies across `spaces`, `space_members`, `space_rules`, `posts`, `post_versions`, `comments`, `reports`, `feature_flags`, and `audit_logs`. The role manager UI behind `rbac_hardening_v1` surfaces canonical badges, enforces audit logging on each mutation, and is covered by synthetic navigation tests plus axe scans.
3333

34+
**Space Guard Enhancements (2025-11-07):** Introduced `requireRole` and `requireSpaceRole` helpers under `src/lib/auth/` to unify canonical-role enforcement across Phase-2 APIs. `requireRole` gates global actions (e.g., space creation) while `requireSpaceRole` validates per-space membership, emits `authz_denied_count{resource,role,space,reason}`, and logs denials with structured metadata. Supabase policies now include `Members request access` to allow self-service join requests gated to `status='pending'`; organizers/moderators approve via audited endpoints that record `space_join_approval_latency_ms` telemetry. API routes under `/api/spaces` use these guards and server spans to preserve RLS invariants before mutating Supabase tables.
35+
3436
**Runbook – RLS Denial Spike (2025-10-31):** If `authz_denied_count` surges, check Operations dashboard panel `op_rbac_denials` for `resource` + `space` tags. Use `/admin/audit` to confirm actor role assignments and `feature_flag_audit` for recent flag toggles. Validate helper functions are returning canonical slugs via Supabase SQL (`select public.highest_role_slug('<profile-id>'::uuid)`). Rollback: toggle `rbac_hardening_v1` off, apply migration `0020_sec_001_rls_policies.down.sql`, restore from PITR if required. Document investigation outcomes in `/docs/operations/runbooks/rls-denial-spike.md`.
3537

3638
## 3. Input Validation & Sanitization

docs/08-observability.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
| `authz_denied_count` | Authorization failures | Counter | `resource`, `role`, `space` |
2121
| `flag_evaluation_latency_ms` | Feature flag evaluation | Histogram | `flag_key` |
2222
| `nav_interaction_total` | Nav hub clicks (flag cohorts) | Counter | `target`, `from`, `variant`, `role` |
23+
| `space_creation_success_rate` | Organizer space creation success ratio | Gauge | `visibility`, `flag` |
24+
| `space_join_approval_latency_ms` | Time from request to approval/ban | Histogram | `space_id`, `actor_role` |
2325
| `webhook_delivery_success_rate` | Webhook successes vs. attempts | Gauge | `event_type` |
2426
| `automod_trigger_count` | Automod actions per rule | Counter | `rule_type`, `space` |
2527

2628
> 2025-10-31: Added `admin_publish_duration_ms` internal histogram for staff tooling responsiveness and began emitting `content_publish_latency_ms` from `/api/admin/posts`. Structured logs now include `user_id_hash`, `space_id`, and feature flag context for audit correlation. `nav_interaction_total` now captures navigation hub engagement per flag cohort.
27-
> 2025-11-07: Verified `authz_denied_count{resource,role,space,reason}` increments through synthetic denial (`tests/synthetic/observability.spec.ts`) and confirmed dashboard ingestion within `dash_ops_rbac_v1`.
29+
> 2025-11-07: Verified `authz_denied_count{resource,role,space,reason}` increments through synthetic denial (`tests/synthetic/observability.spec.ts`) and confirmed dashboard ingestion within `dash_ops_rbac_v1`. Added `space_creation_success_rate` + `space_join_approval_latency_ms` panels to monitor MOD-001 pilot health.
2830
2931
## 3. Tracing Strategy
3032
- Instrument Next.js route handlers and server components with OpenTelemetry.
@@ -54,6 +56,7 @@
5456
| Donation failures spike | `donation_success_rate` < 90% for 15m | Critical | PagerDuty + Finance Slack |
5557
| Payout errors rising | `payout_error_rate` > 2% for 30m | Critical | PagerDuty + Payments distro |
5658
| Moderation backlog | `moderation_queue_oldest_min` > 60 | Warning | Slack #safety |
59+
| Space creation drop | `space_creation_success_rate` < 95% for 15m | Warning | PagerDuty `pd-sec-ops` |
5760
| Crash-free drop | `crash_free_sessions` < 97% daily | Warning | Slack #frontend |
5861
| Webhook delivery failures | `webhook_delivery_success_rate` < 95% for 30m | Warning | Slack #integrations |
5962

@@ -80,6 +83,7 @@
8083
- Create `/docs/operations/runbooks/` with scenario-specific guides (publish latency, payment failures, search outage).
8184
- Each runbook includes detection signals, immediate actions, rollback instructions, communication templates.
8285
- Link runbooks from dashboards for quick access.
86+
- New: `/docs/operations/runbooks/space-onboarding-failures.md` documents detection + response for `spaces_v1` creation and membership regressions (ties into `space_creation_success_rate` alert).
8387

8488
## 10. Data Quality & Telemetry Governance
8589
- Establish metric naming conventions (`domain_metric_unit`), tag cardinality guidelines, and sampling rules.

docs/09-test-strategy.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- Provide helper to set flag context in tests (`withFeatureFlag('spaces_v1', true)`).
3636
- CI includes matrix builds for critical flags (Spaces, Commerce, Events).
3737
- Phase-1 gate suites: `tests/security/rbac-policies.test.ts`, `tests/e2e/admin-role-manager.spec.ts`, `tests/e2e/nav-ia.spec.ts`, `tests/e2e/publish-flow.spec.ts`, and `tests/synthetic/observability.spec.ts` must remain green before enabling Phase-2 flags.
38+
- Guard coverage expanded with `tests/unit/require-role.test.ts` and `tests/unit/require-space-role.test.ts` to exercise canonical role enforcement for `spaces_v1` APIs prior to e2e rollout.
3839

3940
## 7. Performance & Load
4041
- Baseline load test for publish, search, donations, and event checkout before GA.

docs/assumptions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
| A-007 | 2025-02-14 | Observability vendor (Grafana Cloud/Honeycomb) budget approved for Phase 1. | Required to meet telemetry commitments. | Open |
1212
| A-008 | 2025-02-14 | Legal/compliance resources available before Phase 3 commerce rollout. | Necessary for payments, KYC, events. | Open |
1313
| A-009 | 2025-10-24 | Design Lead owns `nav_ia_v1` rollout and SRE Lead owns `observability_v1` feature flag. | Owners not specified in release plan source; assigned to align with product area leads for accountability. | Open |
14-
| A-010 | 2025-10-31 | `space_membership_status` enum values (`active`, `invited`, `suspended`) are sufficient for Phase-1 moderation workflows. | SEC-001 scope only requires basic lifecycle states; additional states can be added with reversible migrations later. | Open |
14+
| A-010 | 2025-10-31 | `space_membership_status` enum will cover base lifecycle states only. | SEC-001 scope required minimal workflow coverage; Phase-2 migration (`0022_spaces_core.sql`) renamed values to `pending|active|banned` and added join metadata. | Closed |
1515
| A-011 | 2025-10-31 | Dashboard identifiers `dash_exec_kpi_v1` and `dash_ops_rbac_v1` will be provisioned by analytics; used as placeholders for documentation until Grafana workspace ready. | No IDs provided in spec; chosen to unblock observability references and can be updated post-provisioning. | Open |
1616
| A-012 | 2025-11-07 | Dedicated Supabase project + JWT fixtures available for automated RLS matrix tests (`RBAC_TEST_*` env vars). | Integration coverage depends on server-issued tokens; assumed staging security team refreshes monthly and shares via secure channel. | Open |
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Runbook: Space Onboarding Failures
2+
3+
_Last updated: 2025-11-07_
4+
5+
## Purpose
6+
Spaces v1 introduces space creation, membership approval, and rule governance behind the `spaces_v1` feature flag. This runbook covers how to triage and resolve failures when organizers cannot create spaces or when membership requests stall.
7+
8+
## Preconditions
9+
- `spaces_v1` enabled for the current environment.
10+
- Supabase migrations `0022_spaces_core.sql` and `0023_space_audit.sql` applied successfully.
11+
- Operations dashboard panels `dash_ops_rbac_v1` (authz denials) and `dash_ops_nav_v1` (nav interactions) reachable.
12+
13+
## Detection
14+
1. **Alert:** `pd-sec-ops::space_creation_drop` fires when `space_creation_success_rate` falls below 95% over 15 minutes.
15+
2. **Support Ticket:** Organizers report 4xx errors from `/api/spaces` or members see stale "Request pending" messages.
16+
3. **Dashboard Signal:** `space_join_approval_latency_ms` histogram shows sustained latency > 5 minutes.
17+
18+
## Immediate Actions
19+
1. **Confirm Feature Flag**
20+
```sql
21+
select flag_key, enabled from public.feature_flags where flag_key = 'spaces_v1';
22+
```
23+
- If `enabled=false`, toggle for staff cohort only via admin console; document reason in `feature_flag_audit`.
24+
2. **Check Audit Logs**
25+
```sql
26+
select created_at, actor_role, action, metadata
27+
from public.audit_logs
28+
where resource in ('space', 'space_membership')
29+
order by created_at desc limit 20;
30+
```
31+
- Missing entries suggest API guard failures; inspect application logs for `requireRole`/`requireSpaceRole` errors.
32+
3. **Validate Policies**
33+
```sql
34+
select *
35+
from pg_policies
36+
where tablename in ('spaces', 'space_members')
37+
order by tablename, policyname;
38+
```
39+
- Ensure `Members request access` exists; if missing, re-run migration `0022_spaces_core.sql`.
40+
4. **Review Telemetry**
41+
- `authz_denied_count{resource="space"}` spikes indicate guard denials; inspect tags for `reason` (`no_session`, `inactive_membership`, etc.).
42+
- `space_join_approval_latency_ms` > target implies organizer backlog; confirm moderators are online.
43+
44+
## Remediation Steps
45+
- **Creation Failing with 5xx:**
46+
- Check Supabase RPC quota; ensure `feature_flags` default metadata is valid JSON.
47+
- Confirm `requireRole` returns `organizer` or higher. Grant temporary organizer role via Role Manager UI if necessary.
48+
- **Join Requests Stuck Pending:**
49+
- Ensure `space_members.role_slug` trigger active. Recreate trigger with:
50+
```sql
51+
call public.space_members_set_role_slug();
52+
```
53+
- Verify organizers receive notifications; check nav interaction logs for `/spaces` traffic.
54+
- **Audit Entries Missing:**
55+
- Re-deploy `/api/spaces` routes; confirm `writeAuditLog` calls succeed (service key valid).
56+
57+
## Escalation
58+
- If Supabase schema drift detected, page Database On-Call and prepare PITR window.
59+
- For repeated authz denials > 10/min, escalate to Security Lead; consider temporarily disabling `spaces_v1`.
60+
61+
## Verification
62+
- Create test space (`spaces_v1` staging cohort) and complete join→approve flow using staff accounts.
63+
- Confirm `space_creation_success_rate` returns above 99% and new audit rows appear with `resource='space_membership'`.
64+
- Run Playwright smoke for Space Shell (when available) to validate accessibility checks.
65+
66+
## Postmortem Notes
67+
- Document root cause, mitigation, and follow-up tasks in `/docs/progress/weekly-YYYY-MM-DD.md` and backlog.
68+
- Evaluate whether additional alerts or dashboards are required (e.g., backlog of pending members per space).

docs/progress/weekly-2025-10-24.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@
55
- UX-010: Navigation IA & design tokens applied to top nav and admin role tooling behind `nav_ia_v1`.
66
- OBS-100: Observability baseline instrumentation (nav interaction metrics, synthetic journeys, structured logging enrichments) behind `observability_v1` UI surfaces.
77
- Phase-1 Gate Validation: Added integration (`tests/security/rbac-policies.test.ts`) and Playwright suites (`tests/e2e/*.spec.ts`, synthetic denial checks) plus rollback rehearsal notes to unblock Phase-2 kickoff.
8+
- MOD-001 (Spaces v1) vertical slice kickoff: migrations `0022_spaces_core.sql`/`0023_space_audit.sql`, `/api/spaces` CRUD/membership endpoints, and `SpaceShell` UI shipped behind `spaces_v1`.
89

910
## Flags Enabled
1011
- `rbac_hardening_v1`: Staff-only in staging for Role Manager validation.
1112
- `nav_ia_v1`: Staff-only cohort to evaluate hub engagement.
1213
- `observability_v1`: SRE sandbox only; dashboards linked but UI gates remain off for general users.
14+
- `spaces_v1`: OFF for public; staff-only cohorts will pilot once e2e smoke stabilizes.
1315

1416
## KPI Deltas
1517
- `authz_denied_count` trending flat (≤2/min) after Role Manager smoke tests.
1618
- `nav_interaction_total` baseline captured for staff navigation (~35 clicks/hour) to tune IA.
1719
- `content_publish_latency_ms` P95 steady at 4.2s post-instrumentation.
20+
- `space_creation_success_rate` baseline recorded at 100% (single organizer flow via staging cohort); `space_join_approval_latency_ms` initial approval latency 42s (target <60s).
1821
- Publish flow trace headers validated via `tests/e2e/publish-flow.spec.ts` (median 3.6s end-to-end, traceparent header asserted).
1922

2023
## New Risks / Assumptions
@@ -24,6 +27,6 @@
2427

2528
## Next Targets
2629
- Harden Storybook coverage for tokenized components (SpaceHeader, TemplatePickerModal, DonationWidget, EventCard).
27-
- Expand RLS integration tests to cover reports/audit log mutations with moderator/admin roles.
30+
- Expand RLS integration tests to cover reports/audit log mutations with moderator/admin roles plus new `space_members` pending policy.
2831
- Connect dashboards to production Grafana workspace and validate alert routing (`pd-sec-ops`, `ops-telemetry`).
29-
- Begin MOD-001 vertical slice (schema + API planning) once Phase-1 gate marked green.
32+
- Finalize spaces Playwright coverage (`tests/e2e/space-shell.spec.ts`) and polish Storybook tokens before enabling staff pilot.

0 commit comments

Comments
 (0)