Trust & Reputation System — Specification
Status: Draft v2 Date: 2026-04-04 Related: rating-system-summary.mdSupersedes: v1 (thumbs up/down peer reviews)
Design Principles
- Praise is public, penalties are private — 당근 매너온도 model. No negative UI. Bad behavior = silent demotion.
- Trust tiers unlock privileges — VRChat/Stack Overflow model. Reputation is functional, not vanity.
- Structural verification > honor system — Mutual confirmation of attendance + scores.
- 총무 authority preserved — System informs, never auto-expels.
- Club opt-in — Attendance tracking OFF by default. Each club decides.
Part 1: Trust Tiers (신뢰 등급)
4 Tiers — Social Proof, Not Access Control
Trust tiers are visible badges that signal reliability. They do NOT gate any core feature. See platform-architecture.md for the full feature access model.
| Tier | Badge | How Earned | What It Signals |
|---|---|---|---|
| 🌱 새싹 | (no badge) | Account created | New user — no track record yet |
| 🎾 활동 | Small badge | 5+ sessions confirmed | "This person actually plays" |
| ⭐ 신뢰 | Prominent badge | 20+ sessions, 90%+ att (if tracked), 10+ manner tags | "Reliable, well-liked" |
| 🏅 베테랑 | Gold badge | 50+ sessions, 6+ months, 20+ tags | "Club pillar" |
What tiers do: Profile badge, optional recruitment filter, slight discovery boost. What tiers do NOT do: Block joining clubs, block RSVP, block any core feature.
Progression Algorithm (Hidden — VRChat Model)
Players do NOT see exact progress toward next tier. They see their current tier and a qualitative hint:
🎾 활동 멤버
"신뢰 등급까지 조금 더!" ← vague encouragement, no exact numberWhy hidden: Prevents gaming (e.g., "I need 3 more confirmations to unlock 신뢰"). Players focus on playing tennis, not optimizing metrics.
Inputs to Tier Calculation
| Signal | Weight | Source |
|---|---|---|
| Sessions attended (confirmed) | High | Mutual confirmation |
| Attendance rate (if club tracks) | Medium | Attendance system |
| Manner tags received | Medium | Post-session praise |
| Account age | Low | Registration date |
| Matches with score confirmed by both sides | Medium | Score verification |
| 총무 endorsement | High | Manual boost by admin |
| No-show strikes | Negative | Attendance system |
| Reported by other members | Negative | Report system (hidden) |
Demotion
- Silent — no notification for demotion itself
- Triggered by: 3+ no-shows in rolling window, reported by 3+ unique members, 총무 manual action
- Player sees privileges disappear, not a "you've been demoted" message
- 총무 sees demotion reason in dashboard
Part 2: Manner Tags (매너 태그) — Praise-Only System
The 당근 Insight
당근마켓's 매너온도 only has positive review options. There is no "bad manner" button. Negative signals come from behavioral data (reports, no-shows, disputes) — never from a UI that lets users rate others negatively.
Why this works: In small communities (10-30 person clubs), a visible 👎 system creates hostility and retaliation. Praise-only keeps the social dynamic positive while bad actors are handled through structural mechanisms.
Post-Session Manner Tags
After a session, players can give manner tags to anyone they played with:
| Tag | Korean | What It Signals |
|---|---|---|
| 🤝 | 매너가 좋아요 | Good sportsmanship, respectful |
| ⏰ | 시간 약속을 잘 지켜요 | Shows up on time |
| 🎯 | 실력이 정확해요 | Skill matches their level |
| 💬 | 소통이 잘 돼요 | Good communication, friendly |
| 🔥 | 열정적이에요 | Enthusiastic, brings energy |
How It Works
Session ends
→ 2h later: push notification "오늘 함께한 멤버에게 매너 태그를 남�� 보세요"
→ Tap → lightweight bottom sheet:
[Player 1] 🤝 ⏰ 🎯 💬 🔥 (tap to toggle, multi-select)
[Player 2] 🤝 ⏰ 🎯 💬 🔥
...
→ Submit → done (under 10 seconds)
→ Tags accumulate immediately (no dual-blind needed — it's all positive)Display on Profile
🤝 매너가 좋아요 ×24
⏰ 시간 약속을 잘 지켜요 ×18
🎯 실력이 정확해요 ×15Shown to: the player themselves + club members + 총무. Counts only, not who tagged.
No Negative Feedback UI
If a player has bad manners, the correct flow is:
- Report (신고) — goes to 총무, not public
- 총무 investigates, warns the member privately
- Repeated reports → silent trust tier demotion
- Extreme cases → 총무 removes from club (existing club management feature)
Part 3: Attendance Score (unchanged from v1)
Club Opt-In
| Setting | Default | Description |
|---|---|---|
| 출석 관리 | OFF | Enable attendance tracking |
| 취소 페널티 | OFF | Enable strike system (requires 출석 관리) |
| 무료 취소 기한 | 24h | Free cancellation window (12h / 24h / 48h) |
Key Rule
- Not RSVPing = no impact. People have lives.
- RSVPing "참가" then not showing = the problem this solves.
Cancellation Tiers
| Timing | Classification | Strike Value |
|---|---|---|
| Before free window | Free cancel | 0 |
| Within free window | Late cancel | 0.5 |
| < 12h or no-show | No-show | 1.0 |
| 총무 excused | Excused | 0 |
Consequences (Private, Graduated)
| Strikes (rolling 20 sessions) | Action |
|---|---|
| 1 | Gentle nudge notification |
| 2 | Warning + 1-session RSVP cooldown |
| 3+ | Flagged to 총무 + trust tier demotion signal |
Visibility
- Member: Own rate + streak (private)
- 총무: All members' rates + flagged list
- Other members: Nothing
Part 4: Mutual Confirmation (Structural Verification)
The Core Mechanism
Instead of trusting self-reports, require both sides to confirm key facts:
| What | Who Confirms | If Only One Side | If Both Confirm |
|---|---|---|---|
| Attendance | Player + 총무 (or auto-checkin) | Counts, but lower confidence | Full confidence |
| Match score | Both teams (existing score verification) | Counts with existing K-factor | 1.1× confidence bonus to ELO delta |
| Session happened | 총무 marks session complete | — | Required to trigger reviews |
Auto Check-in (Optional)
If the club's court has a known location, players who are physically present (GPS within 200m at session time) get auto-confirmed attendance. No manual check-in needed.
Privacy: Location check is a one-time ping at session start, not continuous tracking. Opt-in per player.
Part 5: Recruitment Filters (호스트 필터)
When a 총무 or host creates a session or recruiting post, they can set minimum requirements:
| Filter | Options | Use Case |
|---|---|---|
| 실력 (ELO tier) | Minimum tier (e.g., Gold III+) | Skill-appropriate matching |
| 신뢰 등급 | Minimum trust tier (e.g., 활동+) | Filter out brand-new accounts |
| 참석률 | Minimum % (e.g., 80%+) | Ensure reliable attendance for paid courts |
| 성별 | 남성 / 여성 / 전체 | Gender-specific sessions |
How Filters Appear to Applicants
[Session Card]
오픈 복식 경기 · 4/12 토 14:00
🎾 Gold III 이상 · ⭐ 신뢰 등급 이상 · 참석률 85%+If a player doesn't meet the filter, the RSVP button shows: "참가 조건을 확인해 주세요" with the specific requirement they're missing.
Filter Visibility
- Filters are shown on the session card — transparent, not hidden
- Players know exactly why they can't join
- This incentivizes building trust tier + maintaining attendance — because it unlocks access
Part 6: The Integrated Player Profile
Self-View (내 프로필)
[Avatar] 김민수
Gold II · 1,420 (±65)
신인부 ~ 오픈부 · NTRP 3.0-3.5
⭐ 신뢰 멤버 ← trust tier badge
🤝 ×24 ⏰ ×18 🎯 ×15 💬 ×12 ← manner tag counts
참석률 94% · 연속 7회 ← private, only I see thisClub Member View
[Avatar] 김민수
Gold II · 1,420
⭐ 신뢰 멤버
🤝 ×24 ⏰ ×18 🎯 ×15 ← manner tags (public praise)No attendance rate, no negative scores. Just: tier + trust badge + positive tags.
총무 View
[Avatar] 김민수
Gold II · 1,420
⭐ 신뢰 멤버
🤝 ×24 ⏰ ×18 🎯 ×15 💬 ×12 🔥 ×8
참석률 94% · 노쇼 1회/20회
신고: 0건Discovery / Recruitment View
[Avatar] 김민수
Gold II
⭐ 신뢰 멤버
🤝 ×24Minimal — tier + trust badge + top manner tag count.
Part 7: Data Model
trust_tiers (enum, not a table)
'sprout' | 'active' | 'trusted' | 'veteran'profiles (new columns)
ALTER TABLE profiles ADD COLUMN trust_tier TEXT DEFAULT 'sprout'
CHECK (trust_tier IN ('sprout', 'active', 'trusted', 'veteran'));
ALTER TABLE profiles ADD COLUMN trust_tier_updated_at TIMESTAMPTZ;
ALTER TABLE profiles ADD COLUMN total_sessions_confirmed INTEGER DEFAULT 0;
ALTER TABLE profiles ADD COLUMN global_attendance_rate REAL;manner_tags
CREATE TABLE public.manner_tags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
giver_id UUID NOT NULL REFERENCES profiles(id),
receiver_id UUID NOT NULL REFERENCES profiles(id),
session_id UUID NOT NULL REFERENCES sessions(id),
tag TEXT NOT NULL CHECK (tag IN ('manner', 'punctual', 'accurate', 'communicative', 'enthusiastic')),
created_at TIMESTAMPTZ DEFAULT now(),
UNIQUE (giver_id, receiver_id, session_id, tag)
);attendance_records
CREATE TABLE public.attendance_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES profiles(id),
session_id UUID NOT NULL REFERENCES sessions(id),
club_id UUID NOT NULL REFERENCES clubs(id),
rsvp_status TEXT NOT NULL,
final_status TEXT NOT NULL
CHECK (final_status IN ('attended', 'no_show', 'late_cancel', 'free_cancel', 'excused')),
strike_value REAL DEFAULT 0,
confirmed_by TEXT DEFAULT 'self'
CHECK (confirmed_by IN ('self', 'mutual', 'gps', 'admin')),
created_at TIMESTAMPTZ DEFAULT now(),
UNIQUE (user_id, session_id)
);clubs (new columns)
ALTER TABLE clubs ADD COLUMN attendance_tracking_enabled BOOLEAN DEFAULT false;
ALTER TABLE clubs ADD COLUMN attendance_cancel_window_hours INTEGER DEFAULT 24;member_reports (for silent demotion signals)
CREATE TABLE public.member_reports (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
reporter_id UUID NOT NULL REFERENCES profiles(id),
reported_id UUID NOT NULL REFERENCES profiles(id),
club_id UUID NOT NULL REFERENCES clubs(id),
session_id UUID REFERENCES sessions(id),
reason TEXT NOT NULL,
resolved BOOLEAN DEFAULT false,
resolved_by UUID REFERENCES profiles(id),
created_at TIMESTAMPTZ DEFAULT now()
);Part 8: Edge Cases
| Scenario | Handling |
|---|---|
| Player not RSVPing regularly | No impact. System only measures RSVP→no-show. |
| Regular personal absences | No impact as long as they don't RSVP for sessions they can't attend. |
| Club doesn't want attendance tracking | OFF by default. No data collected. |
| New player with 0 manner tags | Shows trust tier (새싹) only. No empty "0 tags" display. |
| Player in multiple clubs | Trust tier is global. Manner tags aggregate across clubs. Attendance per club. |
| 총무 gives manner tags | Counts the same as any member. No special weight in UI. |
| Someone gives all 5 tags to everyone every session | Tags from the same giver to the same receiver cap at 1 per tag per session (UNIQUE constraint). Outlier givers don't skew because counts across many givers. |
| GPS auto-checkin at wrong location | Only triggers within 200m of registered court. Player can manually confirm if GPS fails. |
| Player gets reported but it's a personal dispute | 총무 reviews. Can dismiss report. Dismissed reports don't count toward demotion. |
Part 9: How This Replaces the Honor System
| Problem | Old (Honor System) | New (Structural) |
|---|---|---|
| Skill sandbagging | Trust self-assessment | ELO converges via K=40/48 + strike system |
| No-shows | Social pressure | Attendance tracking + RSVP cooldown + deposit (future) |
| Bad manners | 총�� hears complaints | Report → 총무 dashboard → silent demotion |
| Score disputes | One side enters score | Mutual confirmation (both teams verify) |
| Fake accounts | None | Trust tiers gate privileges (새싹 can't host or recruit) |
| Club hopping to avoid reputation | None | Global trust tier + manner tags follow across clubs |
The key insight: every enforcement mechanism is structural (built into the system's rules) rather than social (dependent on people being honest).
References
- 당근마켓 매너온도: praise-only public feedback, hidden penalty algorithm
- Airbnb Superhost: automated badge with hard metric thresholds, silent loss
- Playtomic: reliability factor, coach-verified ratings
- VRChat: hidden progression, privilege-gated trust tiers
- Stack Overflow: reputation unlocks privileges, not vanity
- Urban Sports Club / Playtomic: tiered cancellation penalties
- Korean 동호회 bylaws: 총무 authority, 2/3 vote expulsion