TwoMore App Functionality Map
Status: Active Last reviewed: 2026-06-28
This document describes what the current app delivers from the user's point of view and from the backend capability point of view. It is not a backlog, not a wireframe, and not a promise that every surface is production-launched.
Use it to answer:
- What does each tab do?
- Which support screens and backend systems make those tabs work?
- Which capabilities are built, scaffolded, or externally gated?
- Where should roadmap and market decisions attach to the real product?
Evidence Floor
| Evidence | What it proves |
|---|---|
| Current Project State | Current versions, migration count, web page count, launch posture, auth/payment gating, and enforcement coverage. |
| Product Spec Sheet | Product definition, personas, success metrics, and launch/non-launch scope. |
apps/mobile/app/(tabs) | Mobile has five user tabs: 홈, 클럽, 경기, 기록, 프로필. The mobile folder for 경기 is (sessions) but it mounts the activity feature. |
apps/web/app/(tabs) | Web mirrors the five-tab model and uses /activity for the 경기 tab route. |
packages/features/*/src/index.ts | Router-agnostic screen packages exported for home, clubs, activity, sessions, records, profile, messaging, and onboarding. |
packages/app/src/presentation/hooks/queries and packages/app/src/presentation/hooks/mutations | Data access and mutation surfaces for clubs, sessions, payments, records, DM, trust, venues, weather, notifications, and profile/account flows. |
packages/app/src/adapters/supabase and packages/app/src/ports | Supabase adapters sit behind repository/service ports rather than being called directly from feature UI. |
supabase/functions | Production-facing edge functions for weather, venue search, push, PortOne verification/webhooks, export, and scenario/dev support. |
Product Shape
TwoMore currently behaves as a Korean amateur-tennis club operating system with a mobile-first app, a web shell, and shareable public routes.
The primary loop is:
- User signs in or uses a dev-login path in non-production contexts.
- User completes onboarding and lands in an intent-aware first action: Home by default, Clubs discovery/create, join club, pickup hosting, a public share receiver, or a safe internal
nextroute when present. - User joins, creates, discovers, or receives a shared club/session/pickup.
- User RSVPs, applies, pays or confirms payment state, attends, plays, records results, and returns for records/profile/trust.
- Organizers manage sessions, members, dues, attendance, guest applications, exceptions, and communication from club/session surfaces.
The current freshness model does not depend on persistent ambient Supabase Realtime channels. It uses freshness contracts, focus/foreground refetch, bounded polling on volatile surfaces, push-triggered invalidation, and mutation invalidation.
Platform Shells
| Surface | Current delivery |
|---|---|
| Mobile | Expo Router app for iOS/Android with five primary tabs, deep-link routes, EAS update support, and native scaffolding for Kakao/notifications/payments. |
| Web | Next App Router shell mounting shared feature screens through router-agnostic packages, plus public share/open-graph routes. |
| Shared app layer | @twomore/app exports domain types, ports, hooks, routes, i18n, registry access, cache helpers, and shared app components. |
| Feature packages | packages/features/* own screens and import only from @twomore/app and @twomore/ui, not from platform routers. |
| UI layer | packages/ui owns Tamagui primitives and reusable layout patterns. |
| Backend | Supabase Postgres/RLS/migrations/storage/edge functions behind adapters and ports. |
Primary Tabs
Home / Clubs / Activity Responsibility Split
The club-admin strategy does not mean every admin surface should become a top-level Home destination. The product split is:
| Surface | Responsibility | Club-admin implication |
|---|---|---|
| 홈 | High-frequency attention router: today, this week, this month, live play, disputed scores, payment/session obligations, and recommendations. | Surface only actionable admin exceptions for admins: payment confirmation, RSVP deadline risk, attendance closeout, join/guest decisions, reports. Do not turn Home into the full admin console. |
| 클럽 | Club identity, membership, discovery, club health, and administration. | This is where the club operating cockpit belongs. The club tab should make club value visible to members and admins, not only to users already inside a club detail admin tab. |
| 경기 | Session and pickup execution: find play, RSVP, manage upcoming play, live session detail, and host/session-specific actions. | Session-level host workflows stay here, but club-level operations should roll up to Clubs and admin exceptions can point back from Home. |
This keeps the current Home design intact: it remains the most frequently visited, action-packed surface with consolidated club/pickup sessions, live match visibility, and weekly/monthly progress. The adjustment is to give club-based activity more prominence in the Clubs tab and use Home as a role-gated alerting layer when a club official has work to do.
홈
User job: understand what matters now without becoming a schedule list.
Home is the present-tense feed. It surfaces today's, this week's, and this month's relevant signals, notifications, disputed-match prompts, recommendations, club/session highlights, and unresolved user attention items. It intentionally does not act as the full scheduled-session list because that belongs to 경기.
| Layer | Current implementation |
|---|---|
| Main screen | HomeFeedScreen from packages/features/home. |
| Mobile route | apps/mobile/app/(tabs)/(home) and related home routes. |
| Web route | apps/web/app/(tabs)/home. |
| Key data | Home data, disputed matches, unread signals, recommendations, notifications, foreground refresh. |
| Backend support | home-signals, signal, match/session/profile adapters, notification service, push-triggered invalidation. |
| Product role | Re-entry surface, exception surfacing, and attention routing. |
Planned admin attention rule: when the viewer has club-admin permissions, Home may show small exception cards for urgent club work. Those cards deep-link to the club admin cockpit or existing admin screens. Home should not list all admin tools.
클럽
User job: find, join, administer, and grow clubs.
The club area separates "my clubs" from discovery. Joined clubs are sorted around what matters next, while discovery supports search, filters, media, stats, and join/apply paths. Club detail surfaces branch into board posts, members, settings, dues, attendance, analytics, venues, sessions, partner suggestions, challenges, and public profile/share flows.
| Layer | Current implementation |
|---|---|
| Main screens | ClubsMyScreen, ClubsDiscoverScreen, ClubDetailScreen, PublicClubProfileScreen. |
| Mobile routes | apps/mobile/app/(tabs)/(clubs), club/[id], clubs/[clubId]/*, join-club, create-club. |
| Web routes | /clubs, /clubs/[clubId]/*, /create-club, public club/share routes. |
| Key data | Club membership, roles, invites, join requests, discovery summaries, media, dues, analytics, attendance, venues, posts, challenges. |
| Backend support | Club, club media, analytics, event, dues, invite, post, venue, member report, inter-club challenge, and guest-application adapters. |
| Product role | Club supply, admin cockpit foundation, and social graph anchor. |
Planned club emphasis rule: the club tab should become the primary destination for club identity and operations. Joined-club cards should expose next sessions, role, club health/activity, and admin-action badges where permissions allow. Non-members should still see discovery/preview flows; private member/admin content remains role gated.
경기
User job: find play, manage upcoming play, and act on session obligations.
The user-facing 경기 tab is implemented by the activity feature. On mobile the folder is named (sessions) for legacy route grouping, but the mounted tab surface is the activity screen. On web the route is /activity.
The activity surface includes active user sessions, pickup discovery, filters, saved sessions, RSVP/payment state, and navigation into session detail. Session detail then becomes the main operational screen for players and hosts: status, logistics, venue/weather, participants, matchups, payments, attendance, host actions, share, GPS check-in, guest applications, and post-session steps.
| Layer | Current implementation |
|---|---|
| Main screens | ActivityScreen, ActivityUpcomingSessionsScreen, ActivityPickupsScreen, SessionDetailScreen, PickupHostDashboardScreen. |
| Mobile routes | apps/mobile/app/(tabs)/(sessions), session/[id], sessions/[sessionId]/*, create-session, courts, venues. |
| Web routes | /activity, /sessions/[sessionId]/*, /create-session, /courts, /venues, public /s/[sessionId]. |
| Key data | RSVP, waitlist, saved sessions, payments, guest applications, live session data, weather/TMI, venue/court context, match board, scorecard. |
| Backend support | Session, RSVP, saved-session, session-payment, guest-application, attendance-record, venue, court-review, weather, match, player-matchup, session-feedback adapters and edge functions. |
| Product role | Core play loop, pickup supply, host workflow, and payment/trust gateway. |
기록
User job: see competitive identity, progress, history, and leaderboards.
Records is the analytics and competitive-history area. It owns ELO/tier display, format stats, partner stats, trend charts, personal records, match history, head-to-head views, leaderboard scopes, and shareable leaderboard/stat surfaces. This is intentionally not a profile-settings surface.
| Layer | Current implementation |
|---|---|
| Main screens | RecordsScreen, RecordsLeaderboardScreen, RecordsHistoryScreen, RecordsDayScreen, HeadToHeadScreen. |
| Mobile routes | apps/mobile/app/(tabs)/(records) and records/*. |
| Web routes | /records, /records/*, public /m/[matchId], /lb/[clubId]. |
| Key data | Ratings, tiers, match history, score calls, achievements, progression, practice logs, milestones, leaderboards, matchup records. |
| Backend support | Match, match-set, match-score-call, club-elo-rating, progression, achievement, practice-log, participation-milestone, player-matchup, season-record adapters. |
| Product role | Retention, identity, competitive trust, and shareable proof of play. |
프로필
User job: manage identity, social graph, privacy, safety, account, and settings.
Profile is the identity and account-management hub. It shows avatar/name/tier, lightweight stats, friends summary, achievements, attendance and manner tags, direct-message entry, share cards, settings, legal/account paths, consent history, privacy controls, blocked users, and account export/delete paths.
| Layer | Current implementation |
|---|---|
| Main screens | ProfileScreen, SettingsScreen, PublicProfileScreen, friends/settings/legal/account screens. |
| Mobile routes | apps/mobile/app/(tabs)/(profile), profile/*, settings, legal/account routes, public /p/[userId]. |
| Web routes | /profile, /settings, /p/[userId], profile/settings subroutes. |
| Key data | Profile, preferences, auth state, consents, friendships, achievements, attendance/manner signals, reports/blocks, export/delete. |
| Backend support | Profile, preferences, auth, consent, friendship, safety, member-report, achievement, attendance-record, manner-tag, edge export function. |
| Product role | Account trust, social graph, privacy compliance, and user identity. |
Supporting Surfaces
| Surface | What it delivers | Notes |
|---|---|---|
| Onboarding | First-run setup for account/profile, consent, play style, and intent-aware app entry. | Mobile root gate owns destination choice; production social auth remains externally gated. |
| Messaging | DM inbox, threads, group creation, add-members, requests, unread state, image support, accept/decline flow. | Keep lightweight; do not rebuild Kakao group chat. |
| Public share routes | Public club/session/match/profile/leaderboard landing and preview routes. | Needed for Kakao/share growth loop and web open graph. |
| Legal/account | Terms, privacy, consent history, contact, delete account, password/profile edit. | Legal text and CPO/contact values remain launch gates. |
| Dev/ops | Dev panel, scenario seeding, simulation, debug login, production guardrails. | Must stay inaccessible to normal production users. |
Backend Capability Map
| Capability group | Current backend support |
|---|---|
| Identity and access | Supabase auth adapter, profile repository, preferences, consent repository, RLS migrations, export-user-data function, account safety paths. |
| Club operations | Club repository, roles/membership, invites, join requests, discovery summaries, media, posts, dues, analytics, alerts, attendance, reports, venues, challenges. |
| Session operations | Session, RSVP, waitlist, saved sessions, templates, payment states, guest applications, attendance, scorecards, match board, feedback, host authority. |
| Payments | Manual fee state, mock checkout, session payment repository, PortOne verify and webhook edge functions, payment service port. |
| Records and ratings | Match/match-set/score-call repositories, club ELO ratings, progression, achievements, milestones, leaderboards, practice logs, head-to-head data. |
| Trust and safety | Reports, blocks, manner tags, attendance/no-show records, consent history, privacy settings, safety repository. |
| Messaging and signals | DM repository, home signals, signal repository, unread counts, notification service, push send and receipt-check functions. |
| Venue and weather | Venue repository, court review, venue search edge function, static map function, weather fetch/warnings/forecast functions, TMI/playability support. |
| Operations and observability | Client error repository, Sentry wrapper, performance events, scenario seed/simulate functions, generated docs and enforcement gates. |
Built, Scaffolded, Gated
| Area | Status | Practical meaning |
|---|---|---|
| Core club/session/records loop | Built | Product direction should harden, test, and sequence existing surfaces before adding speculative feature families. |
| Manual payment state | Built | Supports transfer/manual-fee reality and admin visibility. |
| PortOne production rail | Scaffolded and externally gated | Requires owner/vendor setup, native runtime adapter proof, server verification, webhook smoke, refund/support policy, and audit clarity before charging real users. |
| Kakao auth/share | Auth scaffolded; share paths built | Production IdP credentials and Kakao-native share integration remain launch/growth work. |
| Direct venue booking | Not built as marketplace | Current system supports venue/court context and handoff. Booking marketplace should wait for venue supply validation. |
| Subscriptions | Spec/entity shells | Pilot only after retained clubs and payment trust exist. |
| Coaching/brand marketplace | Planned | Should follow retained user intent and working payment rails. |
| Multi-sport/international | Held | Do not generalize before Korea tennis retention and revenue evidence. |
Development Implications
- Treat this map as the first stop before changing the roadmap, product spec, or market thesis.
- If a new feature adds a user-facing workflow, update the relevant tab/support section in the same docs-only slice.
- If a backend adapter, port, migration family, or edge function changes the product capability set, update the Backend Capability Map.
- If a capability moves from scaffolded to production-ready, update this doc, Product Spec Sheet, Roadmap, Roadmap Implementation Plan, Production Readiness, and the blocker register as needed.
- Keep current-state facts in generated docs. Do not hand-edit generated pages.
Verification
When this document changes, run:
yarn docs:generate
yarn docs:check