Skip to content

Club Growth Completion Slices

Status: Archived Last audited: 2026-06-11

This is a completed club-growth evidence packet from an earlier implementation batch. Current roadmap execution lives in Roadmap Implementation Plan.

This document records how the earlier Club Growth & Admin Overhaul gaps were closed. Treat it as evidence and history, not as the current queue of work.

Completion Ledger

SliceStatusCheckpoint
1. Backend access proofComplete8941de52 / OTA 6d2ee7a3-6505-4789-ba9e-47aa253d548a
2. Shared card/filter/ranking contractsComplete01cab953 / OTA 467e4164-d656-48f1-8511-b465e9a5257c
3. Compact discovery filtersCompletea64d8e53 / OTA 3049c233-0a4b-4f4f-b9bd-57c10cb9f4a4
4. Admin modal cleanupComplete97dc3f97 / OTA 449e694d-06fb-42a7-80e4-3629864e9a70
5. Public profile/media smoke pathCompleteb28b65fb / OTA a1014d9b-9899-4585-a36a-4da1336c14d5
6. Scenario builder coverageComplete4040c732 / OTA 03ac1823-a236-4298-867d-b7c8ee89f577
7. Hosted club smoke coverageComplete08a9db61 / hosted run 019eb775-10a6-730e-8ff1-2ed44acce621 SUCCESS 2026-06-11 16:48 UTC — 3/3 flows PASSED on device (01-login 28s · 02-main-tabs 41s · 08-club-growth-media 80s), build 8b32e688
8. Final release evidence packetCompleteThis ledger + Evidence Ledger below IS the packet: migrations through 00258 on prod · yarn check 2,547 tests green · lint:pi-schema + lint:strict green · hosted scenario seeding proven in-run · latest app-affecting commit OTA'd (group d5128319) · hosted device smoke green (019eb775)

Evidence Ledger

  • Remote Supabase migration state was verified on 2026-06-11 with yarn supabase migration list --linked; local and remote are aligned through 00258.
  • Migration 00258_club_media_growth_access_contract.sql was applied to the linked remote project on 2026-06-11. It contains only access grants, RLS helper/policy refinements, and a PI exemption because it introduces no new personal-data fields or tables.
  • The seed-scenario Supabase function was deployed to project llhvhhpbjnnrfwcczizc after the scenario builder added pending application states and storage retry hardening.
  • node scripts/run-scenario.mjs club_growth has been run against the hosted backend after the final smoke-flow fix and seeded deterministic club growth data including media and pending join requests (users=29, clubs=8, media=10, joinRequests=7).
  • Preview OTA d998a1e1-82af-4c8e-a0fa-a03cbc70b869 was published for c7a9210f after the stable card-selector fix.
  • yarn check, yarn lint:pi-schema, targeted club/app/ui tests, and YAML parsing have passed for the relevant app-affecting slices before each checkpoint commit.
  • Hosted workflow 019eb640-9f51-71cd-97c9-1a47547d7bf0 was canceled after hanging.
  • Hosted workflow 019eb65f-f38b-7a0e-9628-638dabb59123 was started and then canceled as it reported no build progress updates after launch; 8a5fca13-fd9a-4a73-919b-6ed5c66517c1 never moved to finish state.
  • 2026-06-11/12 hosted-run arc (Claude session): hosted workflow 019eb6c7-bddd-7739-a0e9-d10b1170f932 COMPLETED for the first time — build SUCCESS (build 93876cc1, commit 2414cfa4), flows 01-login (28s) and 02-main-tabs-smoke (42s) PASSED on the hosted device (first device-level proof for any flow), 08-club-growth-media ran 91s deep (seeding hook, discovery card selectors, admin navigation all worked) and failed only its final assertions. Failure 1 (run 019eb6c7): the pending-photo caption sits below the fold on club settings and the flow asserted without scrolling — fixed in a53c637b (add scrollUntilVisible). Failure 2 (run 019eb6ec, build 93876cc1-equivalent SUCCESS, 01/02 PASSED again): assertVisible: '승인 대기' is unsatisfiable by construction — the status renders inside ONE composed meta line (승인 대기 · 갤러리 · …, gallery-section.tsx) and Maestro text matchers are full-string regexes, so the bare label never matches; this assertion had never passed on any run. Fixed in 08a9db61 (scroll to the meta line + '승인 대기 ·.*' regex). Verification run 019eb775-10a6-730e-8ff1-2ed44acce621 SUCCEEDED (2026-06-11 16:48 UTC): 3/3 flows PASSED on the hosted device — 01-login 28s, 02-main-tabs-smoke 41s, 08-club-growth-media 80s (build 8b32e688, commit 08a9db61). Slice 7's device-level proof obtained; slices 7+8 closed. Note: an intermediate trigger attempt for this run hung silently overnight during the CLI project upload without ever creating a run — trigger eas workflow:run in the FOREGROUND with a timeout and confirm a run ID before polling (gotcha recorded in docs/maestro-e2e.md). For future flow-only iterations use maestro-e2e-rerun.yml -F build_id=<id> (reuses an existing build, skips the ~28-min rebuild).
  • Lesson recorded: hosted-smoke text assertions must be authored against the RENDERED element tree (composed strings, full-string regex semantics), not the design intent; and a below-the-fold assert always needs its own scrollUntilVisible. When the app is unchanged (test-YAML-only fix), the rebuild step is wasted ~25 min — pointing the Maestro job at the previous run's build_id is a worthwhile workflow optimization.
  • Operational note (same session): the hosted backend had a 19-hour cron auth outage (2026-06-10 ~19:00 → 06-11 13:33 UTC; app_config.service_role_key held a revoked API key → every cron net.http_post 401'd "Unregistered API key"; push + weather down). Repaired and verified during this session — see CLAUDE.md Operational State. The outage did NOT affect the hosted smoke runs (the seeding path authenticates separately), but any smoke flow asserting push/weather-derived UI would have flaked.

Known verification constraints:

  • Local Maestro is unavailable in this environment (maestro: command not found), so the device-level proof for Slice 7 is the hosted EAS Maestro run.
  • yarn check:supabase-types requires SUPABASE_PROJECT_ID and SUPABASE_ACCESS_TOKEN or a local Supabase stack; it remains a type-sync check to run in an environment with those credentials.

Completion Point

The club overhaul is complete when all of these are true:

  • Club data, media, discovery, admin, and analytics models are reachable from real screens without dead controls or hidden-only paths.
  • Public discovery, My Clubs, public profile, club detail, settings, media manager, applications, and growth analytics have deterministic empty and rich scenario states.
  • Media and growth analytics RLS/storage behavior is covered for public, member, admin, and outsider access.
  • Shared discovery/card/filter behavior has focused tests, not only manual inspection.
  • Hosted smoke coverage reaches the new club flows beyond login/main-tabs.
  • yarn check, yarn lint:pi-schema, targeted tests, scenario smoke, and OTA preview pass for the final app-affecting slice.

Slice 1: Backend Access Proof For Club Media And Growth Events

Current state:

  • club_media, club-gallery-media storage policies, and club_growth_events exist in migrations 00255 and 00257.
  • Existing pgTAP coverage in supabase/tests/00010_rls_clubs.test.sql covers clubs and club members, but not media visibility, storage object access, or growth event aggregate access.

Done when:

  • pgTAP coverage proves approved public media is readable by public discovery.
  • pgTAP coverage proves members/admins can read member-only media.
  • pgTAP coverage proves outsiders cannot read member-only, pending, rejected, or archived media.
  • pgTAP coverage proves only admins can approve/reorder/archive media metadata.
  • pgTAP coverage proves growth events can be recorded for visible clubs and only admins can read aggregate analytics.

Verification:

  • supabase test db or the project-local Supabase test command.
  • yarn lint:pi-schema.

Slice 2: Shared Club Card, Filter, And Ranking Contract Tests

Current state:

  • Shared model ownership exists in packages/features/clubs/src/shared/club-card-model.ts.
  • Discovery filter mapping exists in packages/features/clubs/src/shared/discover-filters.tsx.
  • Viewer-aware membership exclusion exists in packages/features/clubs/src/shared/use-viewer-discover-clubs.ts.
  • Feature packages currently run test: "echo 'noop'", so these shared contracts are not covered by focused tests.

Done when:

  • buildClubCardModel is tested for media priority, profile completeness, next-session summary, capacity/open-slot signals, tags, focus, and join policy.
  • sortClubCardModelsForDiscovery is tested for deterministic score, immediacy, and stable fallback ordering.
  • buildDiscoverClubsFilter is tested for search, region/district, tier, format, schedule, and join policy mapping.
  • The test path follows a repo-wide convention: either feature-package Jest is introduced deliberately or the pure contracts are promoted to an already tested package.

Verification:

  • Targeted card/filter tests.
  • yarn check.

Slice 3: Discovery Filter UX Compactness

Current state:

  • The search bar correctly owns the inline filter toggle.
  • Region and district controls are connected.
  • The expanded panel still presents many wrapping chips across format, region, district, tier min/max, day, time, and join policy.

Done when:

  • Default collapsed state shows only search and the compact active-filter summary.
  • Expanded state uses compact grouped controls appropriate to data type: region-to-district cascade, segmented format/join-policy controls, range-like tier control, and compact schedule controls.
  • Active filters are readable without chip wrapping dominating the first viewport.
  • All controls update the existing filter model without bottom sheets.

Verification:

  • yarn check.
  • Visual smoke on Clubs > Discover with empty, normal, and rich scenario data.

Slice 4: Admin Modal And Design-System Cleanup

Current state:

  • Product bottom-sheet primitives are banned by @twomore/no-bottom-sheet-outside-dev-panel, and current club "sheet" files use ModalPanel.
  • Some component/file names still say "Sheet" even though the implementation is ModalPanel.
  • Dues action modals use StyledInput; no raw TextInput remains in that touched file.

Done when:

  • Club modal components are named by behavior, not "Sheet", where touched.
  • Dues action modals use design-system input primitives and no inline style drift.
  • Modal panels have explicit close/cancel actions and no drag-handle/bottom sheet affordances.

Verification:

  • yarn check.
  • ESLint rule no-bottom-sheet-outside-dev-panel remains green.

Slice 5: Public Profile And Media UX Evidence

Current state:

  • Public profile uses approved public media, schedule, profile identity, description, join policy CTA, and inline application panel.
  • Settings exposes gallery upload, caption, alt text, visibility, approval/rejection, feature, reorder, archive, and profile completeness.
  • There is no dedicated visual smoke path proving those states render with rich scenario media.

Done when:

  • Rich club scenario shows media on Discover cards, My Club cards, public profile, and settings gallery.
  • Empty/bare club scenario shows clean fallbacks and useful admin completeness guidance.
  • Approval-required club scenario shows the inline application path.
  • Invite-only club scenario keeps invite code secondary and does not present a misleading open-join CTA.

Verification:

  • Scenario smoke screenshots or Maestro flow for public profile/settings media.
  • yarn check.

Slice 6: Scenario Builder Coverage For Clubs

Current state:

  • Scenario seeding includes club focus, tags, photo policy, join policy, rich media states, growth analytics events, and membership states.
  • Dev panel scenario builder exists, but the club overhaul needs explicit preset coverage guarantees.

Done when:

  • Configurable scenario builder can generate bare, rich social, competitive, beginner-friendly, invite-only, approval-required, full/no-slots, pending media, pending applications, member, non-member, and admin states.
  • Each preset uses shared builders rather than one-off per-scenario data.
  • Build progress and fresh/build-on-existing modes remain intact.

Verification:

  • Targeted scenario-builder tests.
  • Manual dev-panel scenario smoke for at least empty, rich, approval, invite, and admin-pending states.

Slice 7: Hosted Club Smoke Coverage

Current state:

  • Maestro coverage exists for login, tabs, RSVP, scoring, dispute, sharing, and onboarding.
  • Club media/discovery/admin growth flows are not covered by hosted smoke.

Done when:

  • A deterministic smoke flow covers Clubs > Discover filters, club card media, public profile, join/application CTA state, My Clubs card, and club settings media manager entry.
  • The flow uses seeded deterministic scenario data, not incidental production data.
  • The workflow remains affordable: daily/manual hosted run, local smoke command for targeted development.

Verification:

  • Local Maestro flow command for the new club smoke.
  • Hosted/manual EAS Maestro run when actions quota is available.

Slice 8: Final Release Evidence Packet

Current state:

  • Code-level app checks pass, and recent slices have preview OTA commits.
  • The club overhaul is still not release-complete until backend access, UI smoke, and scenario proof are closed.

Done when:

  • Slices 1-7 are complete.
  • Remote Supabase migration status is verified.
  • Worktree is clean and branch has a final checkpoint commit.
  • Preview OTA is published for the final app-affecting commit.
  • Remaining risks are explicitly documented as post-release, not hidden gaps.

Verification:

  • git status --short --branch
  • supabase migration list --linked or equivalent remote migration check.
  • yarn check
  • yarn lint:pi-schema
  • Targeted Supabase/scenario/Maestro checks from slices 1-7.
  • yarn ota:preview

Markdown remains the source of truth. Run yarn docs:check before handoff.