Owner review 46 — lane B: clubs, sessions, venues and 대항전 on the Feed item grammar (2026-10-19)
Status: Reference · Date: 2026-10-19
Read-only research for owner review 46, marks M12, M13, M18, M21, M22. Paths are repo-relative; board files drop the flat-v2- prefix (docs/twomore_design_system/wireframes/); "library" = docs/design/flat-v2-component-library-2026-10-09.md.
Bottom line
- Nearly every missing fact is already in the schema; the flat v2 rows just do not read it. The old app ClubCard prints composition, age band, rhythm, join policy and dues (
packages/features/clubs/src/shared/club-card.tsx:187-206). - "Which courts" is already modelled and enterable:
sessions.used_courts(00499),court_venues.used_courts(00454),club_regular_meets.used_courts(00529), entered throughCourtUsagePanel(packages/app/src/presentation/components/court-usage-panel.tsx:77; used by create-session step 2 and the courts-edit sheet). The boards dropped it three times (create-session editors forms.jsx:817-927; create-club row menu forms.jsx:2033; 테니스장 관리 list-a.jsx:3063-3090), andSessionInfoModelkeeps counts only (packages/app/src/domain/session-info-model/types.ts:148-151). Design plus one model field; no migration. (Checked 2026-10-19: no seeded session setsused_courts, 0 of 503 locally.) - 대항전 cannot fully match: it has no venue, time, format or level.
- The library forbids the change today: "A Feed of one kind uses that kind's own row" (library :1779, :291).
Now
The Feed item: HubFeedItem hub.jsx:518 (library §5 :1777) — 96 thumb, overline, title, up to two facts, footer = 128 tall.
- Club (내 클럽, 탐색):
FvkMediaRow kind=club(kit-content.jsx:1595) viaclubRowlist-a.jsx:115 → :274, :301 (also 소속 클럽 detail.jsx:5539): 56 logo, name, region | 멤버 N명, 탐색 adds the NTRP band, Count or Tag at right; 80 tall (96 in 탐색). App: ClubCard (packages/features/clubs/src/shared/club-card.tsx:126): 3:1 cover, tier band and 모집 중 on the photo, emoji-led rows for region, composition + age band, rhythm, join policy, dues; ≈ 230–280 tall (arithmetic). - Session (번개 찾기, 내 경기, 저장됨, search):
sesRowlist-a.jsx:201 → :591, :666, :696, :717 (pickers forms.jsx:996): 56 map, venue, time range, format | NTRP | 친구 N명, n/m or one Tag; 96 / 80. App: SessionCardV2 (packages/app/src/presentation/components/sessions/session-card-v2.tsx). - Club sessions (모집 중, 진행 중, 지난 일정):
ClubSessionsSectionlist-a.jsx:2542 (live :2600, past :2607): the same row; Tags 입금 확인 N건, 게스트 N명, Live. App:useClubSessionCardRow→ SessionCardV2. - Venue (경기 › 테니스장):
vnRowlist-b.jsx:2545 (search :2902): photo/map/court thumb, name, district | 코트 N면 | 영업 중, 80. Club 테니스장 관리 list-a.jsx:3039. App: DirectoryVenueCard, VenueRow. - 대항전 (관리 › 도전 과제):
chRowlist-a.jsx:3282: opponent logo, "vs …", rule | dates, score, 승/패 or 받은 신청 Tag; 80 under a Strip. App: ChallengeBlock (packages/features/clubs/src/club-challenges-screen.tsx:356).
Data (exists / missing)
- Clubs:
member_compositionNULL|male_only|female_only|mixed|any (00040, a declared policy, not measured);min_tier/max_tier(00093);preferred_format(00040); region slugs (00456);active_member_count,open_slot_count,max_members(00003, 00256);regular_meet_days(00266-67);last_activity_at, age band with k ≥ 3 (00446);dues_amount+dues_cycle(00003, 00490);join_policy(00213);focus,tagline(00255);guests_allowed(00479). Missing: a measured gender mix; the viewer's pending request in the list payload. - Sessions:
event_typeregular|pickup|tournament|league|interclub (00657);format; tier band (00500, own ?? club); composition (00500);participation_fee(00298);max_players, RSVPs + waitlist; venue + free-text location;court_count+used_courts[{number, name}] (00499); recorded vs casual =is_friendly(00047); host,rsvp_deadline. SessionInfoModel lacksusedCourts. - Venues:
venues(00283):court_count(fromvenue_courtsonce rostered, 00529), surface, indoor/lighting, parking/shower (00370), hours, fees (00358), booking URL, rating; finder facets (00579).venue_courtsstable ids (00606). Booked numbers:sessions.used_courts,matches.court_number(00162). - 대항전:
inter_club_challenges(00098): two clubs,challenge_typetotal_wins|win_rate|elo_gain|matches_played, dates, status, scores. No venue, time, format, level or capacity; the score counts each club's own matches in the range, not head-to-head (00098:89-130).sessions.event_type = 'interclub'is a bare label (owner review 39 removed 교류전 for this reason).
References (fetched 2026-10-19 unless noted)
- Meetup event card: date/time first, title, organising group, attendee count, one status badge (seats left or Waitlist); a group shows image, name, member count. https://www.meetup.com/find/?keywords=tennis&source=EVENTS
- 소모임: group card = thumb, name, intro, one meta line (next meeting, category, district); event card = group + district, venue, date/time, n/m. Gender, age and fee only in free intro text. https://www.somoim.co.kr/
- 플랩풋볼 (filter panel only): scarcity status, start time, 5vs5/6vs6, gender, level, indoor, parking. https://www.plabfootball.com/
- 서울시 공공서비스예약 (listings dated 2026-10-15): status and fee tags, 선착순, the court number inside the title (1번코트, B면). https://yeyak.seoul.go.kr/web/search/selectPageListDetailSearchImg.do?code=T100&dCode=T108
- Spond Club events overview: type, title, start, group, organiser, participants, location. https://help.spond.com/club/en/articles/174499-overview-of-app-events-in-spond-club · Strava events tab (July 2026): https://9to5mac.com/2026/07/09/strava-gets-an-events-tab-with-upcoming-races-group-runs-more/
- Playtomic (help-centre text; page fetch blocked): gender open/female/male/mixed, level range, price per player, court assigned later. https://help.playtomic.com/en/articles/5689294-friendly-vs-competitive-open-matches
- In-repo benchmark (
docs/design/research/visual-benchmark-2026-10-08/lane-b-category.md:26, 33-34, 70-78): Smash tags composition, NTRP band and capacity; level on 7 of 8 racket apps; urgency = one chip.
Pattern: level and gender are structured on racket-match cards; capacity is n/m; no source read lists court numbers as a fact (Seoul: in the title; Playtomic: after assignment).
Proposal
Keep the slots and "nothing on the thumb, no Tag, no control". Add a second facts row ("who") for objects with eligibility. Each facts row costs 24: one = 128, two = 144, three = 168. Recommend two, one 144 item app-wide (thumb 112; a post gets a third text line) so the pitch stays even; fallback 128 in the mixed 소식 Feed and 144 in single-kind lists. A wrapping name adds 24.
- Club (144). Thumb: logo tile (탐색: featured photo, else logo). Overline 강남구 | 친목형. Facts A 혼성 | 복식 | NTRP 3.0–4.0. Facts B 주 2회 저녁 | 월 3만원 | the deciding fact (신청 중/게스트, else 승인제/초대 전용, else 모집 중 n자리; in 내 클럽: 다음 일정 토 19:00 | 참석). Footer 2시간 전 활동 … 42/60. Top three: level, composition + format, rhythm.
- Session (144). Thumb: venue map. Overline 일정|번개|대회|리그|대항전 | club or host. Facts A time | the viewer's state (참석, 호스트; 예비 n번, 입금 전 in warn), else D-n deadline, else n자리 남음 (two or fewer). Facts B 복식 | 혼성 | NTRP 3.0–4.0 | 3~4번 코트 (a segment equal to an active filter drops). Footer posted time … 친구 2, 6/8. Live = 진행 중 + round n/m; full = 마감 ink3; past = date, then the 결과 grammar when recorded; 취소됨. Club sessions: the same item under the three Tabs; officer attention (입금 확인 3건) takes the deciding slot in warn.
- Venue (144). Thumb: photo, map or court tile. Overline 테니스장 | 송파구. Facts A 코트 12면 | 하드 | 실내. Facts B 영업 중 | 12,000원/시간 (club venues: 예약 오픈 매월 1일 10:00). Footer 1.2km … 4.3. 테니스장 관리 adds 우리 클럽 3~5번 코트.
- 대항전 (144). Thumb: two club logos. Overline 대항전 | 총 승수. Title "vs 반포 한강 테니스". Facts A 9.14~9.28 | D-5 종료. Facts B the standing 2-1, final 승 3-2 (success), 받은 신청 (warn). A real two-club event (venue, time, format) needs a migration and a ruling.
- Booked courts. 일정 만들기 gets a 코트 Cell under 장소 opening a Sheet of multi-select Choices over the venue's court numbers (venue_courts when rostered, else 1..court_count; a stepper above 12, as CourtUsagePanel does), preselected from the club's
used_courtsor the 정기 일정; it writesused_courtsandcourt_count. Shown as 3~4번 코트 (consecutive ~, else 1, 3번 코트; scattered beyond three = 코트 5면) in facts B, the session detail and the club venue row; a count only when numbers are unknown, never invented. Model: addwhere.usedCourts.
Migrations: none for the grammar. Optional: a measured gender mix beside the age band (as 00446), the viewer's pending request in the list payload, a 대항전 session link.
Tensions: peers use one scarcity chip but the Feed forbids Tag pills (review 35), so urgency is warn text; 144 everywhere reopens review 36's 128; 대항전 is either the challenge page or sessions labelled interclub.
Not verified: Playtomic, Strava, TeamSnap, 문토, 당근 모임, 네이버 예약 card layouts; 플랩풋볼 cards (filters only); app heights (estimates); venue_courts population in the live DB.