UX-audit residual queue — owner decisions
Status: Active Date: 2026-07-19 Context: The 111-finding UX audit was re-verified against live code, then its 52 canonical/mechanical fixes were shipped (commit 3962e8d7). This file holds the 10 findings that were NOT shipped — each needs a design decision, an external service, owner-supplied content, or data-layer work that shouldn't be coded blind. Per the wireframe-first rule, the feature items are staged for mockup-first iteration, not direct implementation.
Source verdicts: ux-verdicts.json (memory dir). Digest: ux-audit-digest-2026-07.json.
A. New-UI / feature work — wireframe-first (owner)
These have working backends but no (or partial) UI; building the UI is a design decision. Recommend an HTML wireframe pass before code.
| # | Sev | What | Why it's not mechanical |
|---|---|---|---|
| 6 | H | Set/edit a club's monthly dues amount after creation | No UI exists; club-settings-screen's editField union has no duesAmount. The already-written duesAmountNotSet copy is unused. Needs a settings form/section design (inline field vs dedicated DuesSection) + updateClub wiring + gating the generate-dues CTA when amount is 0. |
| 7 | H | Aggregate overdue/unpaid-dues view across months | The dead useOverdueDues hook exists; the R2 admin snapshot already surfaces an overdue COUNT but deep-links to the plain current-month screen. Needs a filtered "연체" list/tab/banner design. |
| 8 | H | Inter-club challenge: propose + decline (currently accept-only) | Repository create()/decline() already implemented; only useAcceptChallenge exists. Needs propose-challenge form (opponent-club picker + type + date range) + decline affordance + two new mutation hooks. |
| 49 | M | Poll post type: create + vote UI | Fully modeled (entity/schema/i18n) but zero UI — unreachable dead feature. Either build the create step + vote widget (5+ files) or strip the dead poll surface. Owner call: ship it or cut it? |
| 99 | M | Format-scoped leaderboard filter (singles/doubles/mixed) | getFormatItems() built but never wired; wiring touches the leaderboard screen + 3 tab components + the ELO query hooks (format param). Owner call: wire it or delete the dead export? |
B. Blocked on external service / owner content
| # | Sev | What | Blocker |
|---|---|---|---|
| 34 | H | Kakao/Google/Apple OAuth sign-in buttons | Port + adapter exist; login screen shows only oauthComingSoon. Needs an EAS build (native module, not OTA-able) + Kakao Developer Console app + Supabase provider config (Native App Key / key hash). Tracked as EXT-11 in docs/external-blockers.md. |
| 103 | L | CPO contact in the privacy policy | The pre-launch TODO in privacy-screen.tsx needs the real CPO name / email / phone — a legal/content asset only the owner can supply. (The name+email are already filled; the TODO comment was made accurate in #107, but the phone remains owner-supplied.) |
C. Deferred — needs data-layer work (agent-surfaced during the fix run)
| # | Sev | What | Why deferred |
|---|---|---|---|
| 59 | M | 코트 surface filter matches directory-created sessions | The directory venue id lives in public.venues; WizardDraft.courtVenueId FKs to the structurally distinct court_venues (bridged one-directionally, migration 00284). A direct assignment would violate sessions_court_venue_id_fkey. Needs a server-side venues→court_venues find-or-create RPC or a surface-code translation threaded through host-pickup-game.usecase.ts. The fix agent correctly self-blocked rather than ship a session-creation regression. |
| 79 | M | Show which policy version a consent was granted under | UserConsent (from getHistoryForUser) carries policyId but not the version string — that's only on UserConsentDisplay (the consent_status RPC). Displaying it in the history row needs a policy_versions JOIN added to getHistoryForUser's select + the entity/mapper. Reverted the blind attempt; the i18n scaffolding was removed. |
D. Stale — optional hygiene
| # | What | Note |
|---|---|---|
| 109 | joinPickup 참여-vs-참가 terminology in home.ftue.* / clubs.moim.* | Dead i18n in orphaned/unwired blocks — never reaches a live screen. The live version of this issue (#108) shipped. Clean up opportunistically with the next dead-i18n sweep. |
Recommended next step: for section A, render phone-frame HTML wireframes (dues editing, overdue view, challenge propose, poll) in the app's visual language and iterate before writing code. Sections B/C/D are unblocked only by the owner / a scoped data-layer task.