Screen Blueprints — Venues
Status: Active Last reviewed: 2026-11-10
Current-state blueprints for the venues screens, read from the components. Conventions and the screen index live in screen-blueprint.md. History lives in git and rebuild-log.md — not here.
Venue Detail (장소 상세, L2-04)
- Route:
/venues/[id] - Screen:
VenueDetailScreen—packages/features/sessions/src/venue-page/venue-detail-screen.tsx - Shell: DetailShell · title = venue name (dynamic) · header="collapsing" collapsingLook="circles" · actions: 공유 · 저장 (spine venue, signed in) · ⋯ (only when the viewer has a command) · footer: the band
- Design: unreviewed
- Verified: 2026-11-13
- Batch 58 (ST2, 2026-11-13), States: Same set; not found offers 경기 보기.
- Notes: 2026-11-10 (W4 batch 17): one page for a place, built to
flat-v2-detail#vc; it replaces the club's court screen and the directory screen (a court row and a spine row of one place, joined bycourt_venues.venue_id). The route's id is the spine venue's id; the directory screen's old path redirects here. A court id from an older link is resolved once and the route replaced with the spine id (useVenuePageId); a court row never linked to the spine draws alone, with no 저장, no ⋯ commands and no Notice.
Purpose. A place on a page of its own, whether a club plays there or it is only in the directory: its 진행 중 매치, its next public 매치, the clubs that call it home, its photos and one group of facts (L2-04).
Anatomy.
├─ [MediaBand kind=map] the whole band is one button "{name}, 길찾기" (opens the 길찾기 MenuSheet) · pin · bar: 공유 · 저장 · ⋯
├─ [Hero] eyebrow by facility kind (테니스장 / 연습장 / 스크린 / 테니스 샵) · name · 📍 address + Tag 인증됨 (a verified owner only) · distance
├─ [Notice] ▸ one of: closed (title by closureReason, action 재개장 제보) · owner (검토할 제안 N건, 30건 이상 past the inbox's first page) · pending (검토 중인 제안이 N건 있어요)
│ a moved venue also offers a Cell door to where it went (when the destination is known)
├─ [YStack opacity=TERMINAL_MUTE_OPACITY ▸ closed]
│ ├─ 진행 중 [SectionHead count] + [Block kind=match] per 매치 in play (spectator; the whole Block opens its 스코어카드) ▸ not closed
│ ├─ [Shelf compact] 예정된 매치 (≤ 5, no door; a card opens 일정 상세, or 매치 미리보기 when the viewer is not in) ▸ not closed
│ ├─ [Shelf compact] 홈 코트로 쓰는 클럽 (≤ 5, no door; a card opens the club)
│ ├─ [Shelf tile] 사진 (≤ 5, no door; Naver's photos)
│ └─ 정보 [CellGroup]: 코트 구성 · 요금 per scope · 운영 시간 (휴무 in line 2) · 전화 · 평점 · 결제 수단 · [club: 예약 시작 · 예약 사이트] · 편의시설 · 지도 위치 (low confidence only) · [club: 메모] · 정보 출처
└─ [CtaBand] 이 테니스장에서 일정 만들기 (seen from a club) / 이 테니스장에서 매치 만들기 (from the directory) ▸ not closed, not a shopSeen from a club. The viewer is an active member of a club that has a court_venues row of this venue (the club of the court id they came with, else one they officiate, else the first): the 정보 group adds that row's booking Cells and 메모, 코트 구성 reads its own count first, and the band makes a 일정. An official of that club (canManageClub) also has 코트 수 바꾸기 (an Edit Sheet: the count 1..40 and 메모, written at once) and, in a destructive group, 클럽 테니스장에서 삭제 (a Dialog naming the venue; the venue stays).
States.
Write failures (ruling EP-3): a refused venue edit is the court Sheet's error line, a refused delete the remove Dialog's body; never a Toast.
Offline (F1c, the app's root strip says it): offline a cached venue stays (vn-stale); 코트 수 고치기 waits.
loading → the band's gray ground, the Hero, one Shelf and three Cell skeletons, no actions on the bar; cold offline →
EmptyState kind="offline"; error →EmptyState kind="error"(retry); id unknown or venue deleted →EmptyState kind="notfound"with 돌아가기 onlyclosed → the Notice, the list dimmed to
TERMINAL_MUTE_OPACITY, no 매치, no live Block, no band; its clubs and photos staya Shelf with nothing, or whose read has not answered or failed, is not drawn (head included); each Shelf reads alone
quiet venue → the Hero and 정보 only; a shop has no 코트 구성, no fee Cells and no band; a fact the place lacks is not drawn (no 전화, no booking Cells)
예약 알림 has no Cell (no scheduler exists; recorded in the external blockers)
2026-11-13 (UX-7, the state helper): Same set as Session Detail (
PageStateView, offline over error); not found offers 경기 보기.
Actions.
- the band → 길찾기 MenuSheet (네이버 지도 · 카카오맵 · T map · 구글 지도, https handoffs through
MapServicePort.openIn; an app that cannot be opened is said once in a Dialog) - 공유 (the native sheet: name and address until a public venue link exists) · 저장 (the saved-venue toggle)
- ⋯ → 장소 정보 제안 (
routes.newVenueContribution) · 소유권 신청 (routes.newVenueOwnerClaim) · for an official of the club 코트 수 바꾸기 and 클럽 테니스장에서 삭제 - Notice action: closed → 재개장 제보 form; owner → the inbox at 검토할 제안; pending → 내가 보낸 제안
- live Block → 스코어카드; 매치 card → 일정 상세 or 매치 미리보기; club card → 클럽 홈; 전화 / 예약 사이트 / 정보 출처 → outside the app
- the band → 일정 만들기 / 매치 만들기 with the venue filled in; pull to refresh
Gaps.
- A moved venue's destination is not known to the page:
DirectoryVenuedoes not carrysuccessor_venue_id, so the destination door is built but not yet fed. - The photo tiles open nothing: the app has no photo viewer.
- The live Block shows no faces yet (the read returns them under
can_view_face; the Block's photos are not bound). - 공유 sends text, not a link (no public venue link exists).
- The inbox read for the owner's count runs for every viewer (
useVenueContributionshas noenabled); the server returns only what the caller may review.
Venue Contribution Detail (제안 상세, L3-33)
- Route:
/venue-contributions/[id] - Screen:
VenueContributionDetailScreen—packages/features/sessions/src/venue-contributions/detail-screen.tsx(bodyreceipt-body.tsx, sectionsreceipt-sections.tsx, the venue rowreceipt-lead.tsx, the bandreceipt-actions.tsxwithuse-receipt-actions.ts,use-receipt-writes.tsand the purereceipt-band.ts, the reviewer's Sheetreceipt-review-sheet.tsx, the rowscontribution-change-rows.ts/contribution-changes.tsx) - Shell: DetailShell · title
courts.contributions.detailTitle(제안 상세) · back · footer = the band - Design: unreviewed
- Verified: 2026-11-15
- Band: a pending suggestion that can be completed has one main action, 정보 보완하기, and 제안 취소하기 is the band's secondary; a withdrawal that is the only action is the one tonal button.
- Batch 58 (ST2, 2026-11-13), Actions: Dismissing with a result chosen or an explanation typed asks the edit guard; with nothing typed it closes.
- Batch 58 (ST2, 2026-11-13), States: Private reads (hidden class): a warm copy is never drawn offline (offline state instead); not found offers the list.
Purpose. The receipt of one suggestion, a task page (flat-v2-detail#rc): the venue leads as its row with the status, then what changed, on what evidence and what was decided, and the one action the viewer's role allows. A decided suggestion's push and notice open this page.
Anatomy.
├─ [DetailShell] title 제안 상세
├─ status: signedOut [ReceiptWall] | loading [MediaRow skeleton] [SectionHead] [SkeletonKind cell ×3] | error [ReceiptWall error] | offline [OfflineEmptyState] | notfound [ReceiptWall 제안을 찾을 수 없어요 · 돌아가기]
└─ ready →
├─ [Gap 16] [ReceiptVenueRow] map · venue (new venue: its proposed name and pin, no door) · "9월 19일 14:05 보냄" · Tag VenueContributionStatusBadge — the row is the door to 장소 상세
├─ (an accepted report) the reading sentence 신고 승인이 장소 정보 변경을 뜻하지는 않아요
├─ [SectionHead 제안 내용] [CellGroup] one Cell per change, value "before → after" (a court operation: one Cell per field, labelled by the court)
├─ [SectionHead 확인한 근거] [CellGroup] 확인한 날짜 · 확인 방법 (the note) · 참고 링크 (nav)
├─ [SectionHead 검토 이력] [TextRow] per decision: status · day and time · the reviewer's explanation (none while pending)
├─ [CellGroup] 이전 제안 보기 · 새 제안 보기 · 이전한 장소 보기 (only those that exist)
├─ the ask (a receipt that needs more): a reading paragraph
└─ footer [CtaBand] by the server's flags: 검토 | 정보 보완 | 다시 보내기 | 제안 취소 (tonal), a second button when a pending receipt can be both withdrawn and completed
overlays: [Sheet 검토 결과] result (승인 | 거절 | 추가 정보 필요) + 검토 의견 required, footer 검토 결과 보내기 (soft until both) · [Dialog 이 제안을 취소할까요?] (the kit's confirm)States. signed out · loading · error · cold offline · not found · pending (proposer / reviewer) · needs information · declined · accepted (read-only) · superseded / withdrawn (history only) · a stale read draws no band · English sent line · 200% text (the kit's row).
- 2026-11-13 (UX-7, the state helper): Private read (hidden class): a warm copy is never drawn offline (the offline state instead); not found offers the list. The reviewer Sheet asks the edit guard on dismissal when a result is chosen or an explanation typed; with nothing typed it closes.
Actions. The venue row → 장소 상세. 참고 링크 → the public link. 검토 → the Sheet → useReviewVenueContribution (both parts required; no extra Dialog: the Sheet is the commit). 제안 취소 → Dialog → useWithdrawVenueContribution. 정보 보완 → routes.newVenueContribution({ supersedesId }). 다시 보내기 → routes.newVenueContribution({ fromId }) (a fresh form filled from the declined receipt: the server cannot replace a declined one). The chain and destination doors push their receipt or venue. Every write is held to the receipt as it is now (mounted, fresh, still granted).
Gaps. The board draws no history for a pending receipt (kept: none is drawn) and no explanation of a decision (kept: under the history row). The "접수 내역 새로고침" button is gone (the read refetches on every mount and every error state has its retry). The evidence link's label is courts.contributions.reference (공개 참고 링크), the board says 참고 링크.
Venue Contributions Inbox (장소 정보 제안 내역, L3-30)
- Route:
/venue-contributions - Screen:
VenueContributionsScreen—packages/features/sessions/src/venue-contributions/list-screen.tsx(the Feed isreceipts-list.tsx, shared with 소유권 신청 내역; the row model incontribution-row.tsx; the state inreceipt-list-gate.ts) - Shell: DetailShell scroll={false} · title
common.submissionHistory(장소 정보 제안 내역, also the settings door and the finder's door) · back · FAB 테니스장 pinned · no tab bar - Design: unreviewed
- Verified: 2026-11-15
- Batch 58 (ST2, 2026-11-13), States: Private reads (hidden class): a warm copy is never drawn offline (offline state instead); not found offers the list.
Purpose. The suggestions the viewer sent and, for a reviewer, the ones waiting for a decision; built W4 batch 21c to flat-v2-list-b#cn. The page's one filter is the Choice ▾ in the Feed's head; the FAB sends a new suggestion; the Cell that ends the Feed opens 소유권 신청 내역.
Anatomy.
├─ [DetailShell scroll={false}] title 장소 정보 제안 내역
└─ signed out → [ReceiptWall signedOut] 장소 정보를 제안하려면 로그인해 주세요 (no head, no FAB)
signed in →
├─ (cached rows stay under the root strip while the read fails or waits)
├─ [FeedList] header = [Gap 12] [SectionHead first 제안 (`courts.contributions.feedHead`) · Choice ▾ 내가 보낸 제안 | 검토할 제안]
│ ├─ [TextRow 68] × n l1 venue (else the new venue's name, else the kind) · l2 kind + day · Tag VenueContributionStatusBadge
│ ├─ empty → [EmptyState first compact] by scope · loading → [TextRowSkeletons 6] · error → [QueryErrorState] · cold offline → [OfflineEmptyState]
│ └─ footer [FeedEnd] door Cell 소유권 신청 내역 (testID venue.contributions.ownership)
├─ [Fab 테니스장 · spoken 목록에 없는 테니스장 추가] → 장소 정보 제안
└─ [ValueSheet 제안 보기] 내가 보낸 제안 | 검토할 제안States. loading (head real, six skeleton rows, FAB) · error · cold offline · cached under the strip (own history only: useVenueContributions shows its retained rows without actions; the review inbox is withheld whole, so offline it is the cold state) · first run mine / inbox · rows · signed out. The venueId filter narrows the list with no visible cue (as drawn).
- Offline (F1c, the app's root strip says it): offline the viewer's own cached receipts stay with no page strip (a failed refetch also keeps them); the review inbox is staff data and is withheld even when this mount read it; the create FAB waits (cn-stale).
- 2026-11-13 (UX-7, the state helper): Private read (hidden class): a warm copy is never drawn offline; the offline state instead.
Actions. A row → 제안 상세. The Choice → the value Sheet (a tap selects, closes and re-reads). The door → routes.venueOwnerClaims({ venueId }). The FAB → routes.newVenueContribution(). Reaching the end loads the next page (skeleton rows). 로그인 → sign-in. Pull to refresh.
Gaps. The venueId filter has no cue on the board. The status words 취소됨 and 새 제안으로 바뀜 follow the board (the terminology guide's 철회됨 line is the lead's).
New Venue Contribution (장소 정보 제안, L4-07)
- Route:
/venue-contributions/new - Screen:
NewVenueContributionScreen—packages/features/sessions/src/venue-contributions/new-screen.tsx(the link and the walls; the form iscontribution-editor.tsx) - Shell: DetailShell · title = the kind (테니스장 추가 · 정보 수정 · 코트 변경 · 운영 상태 · 문제 신고) via
formTitle· footerCtaBand제안 보내기 · headerRight: none - Design: unreviewed
- Verified: 2026-11-15
- Notes: 2026-11-10 (W4 batch 21c, board
flat-v2-forms#vc): rebuilt on the flat v2 field grammar with the sequential reveal (noWizardShell). The place of a new venue is the app's place search (PlaceSearchTakeover; it returns the coordinates, so the geocode and the pin-drag editor left the form); the observation date is the kitDaySheet(past-only), the sharedEvidenceGroup(evidence-group.tsx, also read by 소유권 신청). 코트 변경, 운영 상태 and 문제 신고 are reached from the 다른 제안 doors inside 정보 수정; every fact editor of 정보 수정 stays behind 다른 정보 (a value Cell opensFactEditSheet).vc-blockedis derived from the viewer's own pending report or closure of the venue only. A form opened withfromIdis filled from that receipt (a resend after a decline) and replaces nothing. The deadVenueCorrectionModalandvenue-correction/**retired.
Purpose. One form with five kinds for suggesting a missing venue or a correction, with what the person saw and when; the sequence of sections is the kind's, and the band stays soft until the form is whole.
Anatomy.
├─ [DetailShell] title=kind onBack footer=[CtaBand] 제안 보내기
│ ├─ ▸ offline → the form stays under the root strip (the band is disabled by the kit)
│ ├─ ▸ not signed in → [ReceiptWall signedOut] · restoring → [SkeletonKind media] + [FieldSkeleton]
│ ├─ ▸ loading → [SkeletonKind media] + [FieldSkeleton n=4]
│ ├─ ▸ failed read → [ReceiptWall error] · no venue in the link / receipt gone → [ReceiptWall notfound]
│ ├─ ▸ cannot be completed → [ReceiptWall permission] · own pending report or closure → [ReceiptWall permission] (blocked)
│ └─ ▸ ready
│ ├─ lead: [ReceiptVenueRow] (the four kinds on a venue) · [Notice] 이전 제안을 보완해요 → 제안 상세 (a replacement / a sent receipt)
│ ├─ the kind's block
│ │ ├─ 테니스장 추가: [SectionHead] 시설 [ChoiceSet] 시설 유형 → [Field] 테니스장 이름 → [SectionHead] 위치 [PickerCell] 도로명 주소 (+ [PlaceMapFace]) → [PlaceSearchTakeover]
│ │ ├─ 정보 수정: [SectionHead] 직접 확인한 정보 [CheckRow check]×N · [Cell disclosure] 다른 정보 → [Cell value]×N → [FactEditSheet] · [SectionHead] 다른 제안 [Cell nav]×3
│ │ ├─ 코트 변경: [SectionHead] 코트 · [Cell value]×N (the courts, then staged adds) · [Button tonal] 코트 추가 → [CourtEditSheet]
│ │ ├─ 운영 상태: [ChoiceSet] 휴장 | 폐업 | 이전 | 재개장 · 이전 → [PickerCell] → [VenueSearchTakeover]
│ │ └─ 문제 신고: [Field] 문제 유형 > [CheckRow radio lead]×6
│ └─ once the block is answered: [EvidenceGroup] [SectionHead] 확인한 근거 · [PickerCell] 확인한 날짜 → [DaySheet]; once picked: [Field] 확인한 내용 [TextArea limit 1000] · [Field] 참고 링크 [Input]States.
Offline (F1c, the app's root strip says it): offline the form stays and the band waits; no page strip.
Untouched: the kind's first section alone (시설 유형, 운영 상태, 문제 유형); 정보 수정 and 코트 변경 open on their own section and the evidence waits for no answer.
Each next section appears as the one above is answered; the band is soft until the form is whole, and a press puts the line on the first thing missing (no summary).
Replacement (a Notice naming the earlier proposal) · resend (
fromId, filled, nothing bound) · submitting (보내는 중...) · server error (the danger helper, the input kept) · offline (strip, band disabled).Walls: signed out, cannot be completed, no venue in the link, blocked by the viewer's own pending report or closure, a failed read.
Leaving a dirty form asks 나갈까요?.
2026-11-13 (UX-7, the state helper): Cold offline is the offline state (it was blank).
Actions.
- 제안 보내기 → submit, then replace to
routes.venueContribution(id); the venue row →routes.venue(id); the Notice door → the earlier receipt; 다른 제안 →routes.newVenueContribution({ kind, venueId }); place search / venue search / day Sheet / edit Sheets as above.
Gaps.
- 휴장 시작일 (board
vc-lifecycle-start) is not asked: the lifecycle payload has no start date and no schema is added in this batch. - The fact editors behind 다른 정보, the court Sheet's long property sets and the 다른 제안 doors are not drawn on the board (the capability is kept; the owner draws them).
Venue Owner Claim Detail (장소 소유권, L3-34)
- Route:
/venue-owner-claims/[id] - Screen:
VenueOwnerClaimDetailScreen—packages/features/sessions/src/venue-owner-claims/detail-screen.tsx(the Feedclaim-feed.tsx, detailsreceipt-details.tsx, evidenceclaim-evidence.tsx, historyclaim-history.tsx, transfer toolstransfer-proposals.tsx, actionsclaim-actions.tsxwithuse-claim-actions.ts,use-claim-start.ts,use-claim-drafts.ts, the pureclaim-band.tsandclaim-action-intent.ts, the access stateuse-claim-access.ts, the verification fieldsreview-editor.tsx) - Shell: DetailShell scroll={false} · title
courts.ownerClaims.receiptTitle(장소 소유권) · back · header ⋯ for an owner or staff · footer = the band - Design: unreviewed
- Verified: 2026-11-15
- History: a history of one 신청함 event draws neither its head nor its row; the list is given no rows when the head is hidden.
- Batch 63 (L12, N7), Actions: the band's buttons are verbs (section 1.19): 다시 신청하기, 양도 동의하기, 양도 동의 철회하기, 신청 취소하기, and the ⋯'s 소유권 취소하기 / 소유권 끝내기.
- Batch 58 (ST2, 2026-11-13), States: Private reads (hidden class): a warm copy is never drawn offline (offline state instead); not found offers the list.
Purpose. The receipt of one ownership application (flat-v2-detail#ow): the venue's row with the status, the evidence, and for an owner the one place to end it. Everything the page could do before stays: the tenure, the transfer link and received proposals, staff revoke, the reviewer's own check.
Anatomy.
├─ [DetailShell] title 장소 소유권 · actions: ⋯ [MenuSheet] (destructive) 소유권 끝내기 (the holder) · 소유권 취소 (staff)
├─ invalid id → [ReceiptWall notfound] 링크를 열 수 없어요 · 테니스장 화면에서 다시 열어 주세요
├─ signed out | scope starting | scope needs a new check (as the list) · loading [MediaRow skeleton] · not found · error (the failure's constant message; a refusal is the permission state) · cold offline
└─ ready → [FeedList]
header: [Gap 16] [ReceiptVenueRow] ("9월 12일 14:05 보냄" · Tag VenueOwnerClaimStatusBadge)
├─ restricted consent view → [Cell 신청자] [SectionHead 양도 동의 상태] (never the evidence)
├─ [SectionHead 소유권 근거] 확인한 날짜 · 확인 방법 · 참고 링크
├─ [SectionHead 별도 인증 확인] method · date · note · link (an accepted application)
├─ [SectionHead 소유권 상태] state · 시작일 · 종료일 · 사유 (the tenure)
├─ [CellGroup] 이전 신청 · 대체 신청 · [SectionHead 양도 동의 상태] state + 현재 소유권 기록 (nav) + hint
├─ [SectionHead 양도 신청 링크] hint + the selectable link + [Cell nav 받은 양도 신청] → [Sheet] paged proposals (the holder)
├─ the ask (needs information) · [SectionHead 변경 내역] (omitted while only "submitted") [TextRow] events + [ExpandToggle 이전 내역 더보기]
footer [CtaBand]: 검토 | 양도 동의 (또는 양도 동의 철회) | 정보 보완 | 다시 신청 | 신청 취소 (tonal)
overlays: [Sheet 검토 결과] (the suggestion's Sheet; 승인 adds method, 인증 확인일, 근거 설명, 참고 링크) · [Sheet 소유권 취소] required 사유 · every send asks first in the kit's confirm Dialog (이 신청을 취소할까요? · 내 소유권을 끝낼까요? · …)States. invalid link · signed out · loading · error · cold offline · not found · applicant pending / needs information / declined · reviewer · outgoing owner (restricted view) · approved owner (header ⋯) · ended tenure · a denied history read hides the receipt until the viewer re-checks it (the page drops every action meanwhile).
- 2026-11-13 (UX-7, the state helper): Private read (hidden class): a warm copy is never drawn offline; not found offers the list.
Actions. As above; each send is an idempotent attempt (useOwnerClaimAttempt) held to the receipt's id and revision, the drafts, the scope and the server's flags, and expires when any moves. 정보 보완 → routes.newVenueOwnerClaim({ supersedesId }); 다시 신청 → { fromId }. The drafts (decision, revoke reason) guard a leave.
Gaps. Ending one's own ownership no longer collects the optional reason (the board's rule: the reason is not collected here); a staff revoke still requires one. The tenure, transfer link and proposals, revoke and the verification fields are not on the board (kept on kit pieces; the owner draws them when reviewing). The evidence link's label is courts.ownerClaims.reference (공개 참고 링크).
Venue Owner Claims List (소유권 신청 내역, L3-31)
- Route:
/venue-owner-claims - Screen:
VenueOwnerClaimsScreen—packages/features/sessions/src/venue-owner-claims/list-screen.tsx(the Feed is the sharedvenue-contributions/receipts-list.tsx; the row inclaim-summary.tsx; the gate inowner-gate-body.tsx; the invalid link inowner-invalid-route-screen.tsx) - Shell: DetailShell scroll={false} · title
courts.ownerClaims.title(소유권 신청 내역) · back · FAB 소유권 신청 pinned - Design: unreviewed
- Verified: 2026-11-13
- Batch 58 (ST2, 2026-11-13), States: Private reads (hidden class): a warm copy is never drawn offline (offline state instead); not found offers the list.
Purpose. The ownership applications the viewer filed and the staff queue (flat-v2-list-b#oc): the stack of 장소 정보 제안 내역 without its door. The route, the session and the owner scope gate it before any private read mounts.
Anatomy.
├─ [DetailShell scroll={false}] title 소유권 신청 내역
├─ route invalid → [ReceiptWall notfound] 소유권 링크를 열 수 없어요 · 링크를 다시 확인해 주세요 (header back is the way out)
├─ session: signed out → [ReceiptWall signedOut] | scope starting → [TextRowSkeletons] | scope needs a new check → [EmptyState error] + retry
└─ ready → [FeedList] header = [SectionHead first 신청 내역 · Choice ▾ 내 신청 | 운영팀 검토]
├─ [TextRow] × n l1 venue · l2 kind (소유권 신청 | 소유권 양도) + day · Tag VenueOwnerClaimStatusBadge
├─ empty by scope · loading · error (the failure's own constant message) · cold offline
│ · the queue refused → [ReceiptWall permission] 운영팀만 볼 수 있는 목록이에요
├─ [Fab 소유권 신청] → 소유권 신청 (with the page's venue) · [ValueSheet 신청 보기]States. invalid link · signed out · scope starting · scope needs a new check · loading · error · cold offline · first run mine / queue · rows · the queue refused (a member who is not staff; the client has no staff flag, the server answers) · cached rows under the strip (private reads are never retained, so this occurs only while a refetch fails or waits).
- Offline (F1c, the app's root strip says it): offline the viewer's own cached applications stay with no page strip (oc-stale); the staff queue (the inbox scope) is not drawn offline, even when this mount read it (oc-hidden); the claim reads are memory-only.
- 2026-11-13 (UX-7, the state helper): Private read (hidden class): a warm copy is never drawn offline; the offline state instead.
Actions. A row → 장소 소유권 (held by the scope boundary). The Choice → the value Sheet. The FAB → routes.newVenueOwnerClaim({ venueId }). Reaching the end loads the next page. The tenure state and the revision the old row printed live on 장소 소유권.
Gaps. The invalid-link screen takes page="list" for the list's own copy; the list route shells still render it without the prop (the lead passes it). oc-stale cannot occur for a private read that keeps nothing (gcTime 0); the strip is wired for the day it does.
New Venue Owner Claim (소유권 신청, L4-08)
- Route:
/venue-owner-claims/new - Screen:
NewVenueOwnerClaimScreen—packages/features/sessions/src/venue-owner-claims/new-screen.tsx(the form isapplication-editor.tsx; its parts areapplication-*.tsx,claim-*.ts,use-claim-target.ts,use-application-form.ts) - Shell: DetailShell (
ApplicationShell) · titlet().common.applyForOwnership("소유권 신청";courts.ownerClaims.form.transferTitle"소유권 양도 신청" for a transfer) ·subheadthe offline strip while offline · footer the CTA band · the venue pick step keepsOwnerFrame list - Design: unreviewed
- Verified: 2026-11-13
- Notes: 2026-11-10 (W4 batch 21c, board
flat-v2-forms#oc): rebuilt on the flat v2 form grammar. The venue is its row (ReceiptVenueRow, it opens the venue: the 장소 보기 button is gone), the evidence block is the sharedEvidenceGroupof 장소 정보 제안 under the head 소유권 근거 (a past-only day Sheet, then the either/or note and link, the note counter to the server's 1000), the band says 신청하기 (it was 신청 제출). Rulings V4 (afromIdform is a fresh application filled from a declined one; asupersedesIdform still replaces), V5 (the venue pick step stays), V9, V11.
Purpose. Ask to be recognised as a venue's owner (or to take it over from the current owner), with dated evidence the staff check separately.
Anatomy. One column under the Header; the route and session walls come first, then the venue, then the form.
├─ invalid route → [ApplicationShell] [EmptyState kind=error] 링크를 열 수 없어요 (돌아가기)
├─ session: restoring → [ClaimLoadingView] · signed out → [ReceiptWall signedOut] · scope failed → [ReceiptWall error] (retries the scope)
├─ no venue and no application → [OwnerFrame list] [ExistingOwnerVenuePicker] = [VenueFinder intent=pick] + a tonal "없는 장소 추가" Button (no board frame)
├─ the application a form is filled from cannot be read or replaced → [EmptyState kind=permission] 더 이상 대체할 수 없는 신청이에요 (replace) · [EmptyState kind=error] 링크를 열 수 없어요 (fromId)
├─ reads settling → [ClaimLoadingView] ([SkeletonKind media ×1], [FieldSkeleton ×3]) · a read failed → [ReceiptWall error] (retries the reads)
└─ form → [ApplicationShell] title, subhead, footer [CtaBand 신청하기]
├─ 16 · [ReceiptVenueRow] (map thumb, name, address; opens 장소 상세)
├─ allowed → [TransferNotice] (transfer only) · [EvidenceGroup head=소유권 근거]: [PickerCell 확인한 날짜] → [DaySheet]; once picked, [Field 확인한 내용 / TextArea ≤1000] and [Field 참고 링크 / Input ≤2000]
├─ not allowed → [Notice attention] 새 신청을 낼 수 없어요 · [Cell nav] 장소 소유권 (the claim under review, else the current ownership; absent when there is neither) — no form, no band
└─ [Cell nav] 운영팀 검토 (only when the context's `canOpenInbox`; not on the board)States. Untouched (the date alone, band soft), 근거 asked (the pair, band soft), pressed (a soft press with neither given puts the line on the note), ready (the ball primary), submitting (spinner, 신청하는 중...; edits are ignored), failed (a danger line at the band with the last send's message), offline (strip, primary disabled), blocked, transfer, loading, the walls above. The leave guard (useLeaveGuard with the kit's 나갈까요? Dialog) holds while the answers differ from their seed and no send is pending. The venue baseline is frozen when the reads first agree; a replacement also needs its application unchanged (same revision, still replaceable).
- Offline (F1c, the app's root strip says it): offline the form stays and the application band waits (the kit holds it).
- 2026-11-13 (UX-7, the state helper): Cold offline is the offline state; loading while offline shows offline.
Actions. Pick a venue; 확인한 날짜 → the day Sheet; type the note and the link; 신청하기 → the send (an idempotent attempt, authorized against the live reads), then replace to 장소 소유권 with the leave guard released; the venue row → 장소 상세; 장소 소유권 → the one record (guarded: the reads and the mutation must still be current); 운영팀 검토 → the venue's inbox.
Gaps. The pick step has no board frame. 운영팀 검토 on the form is not drawn (kept so a venue's staff keep a way to its inbox). A failed send shows the message of the failure, not the board's one fixed sentence. The oc-kb frame (the note above the keyboard) is the shell's keyboardShouldPersistTaps and the band's keyboard inset; the test covers typing, not the lift.