Skip to content

Private player profile with match history #255

Description

@0xferit

Problem

A signed-in player can see their live balance, the current-match summary, and the public leaderboard, but they cannot return later and inspect their own past matches. Once the live summary is gone or the page is refreshed, there is no durable in-app history surface.

That makes it hard to answer basic player questions:

  • How have I been doing over time?
  • What were my last few matches?
  • Which prompts do I usually win or miss?
  • Did that AI-assisted run count or not?

Goal

Add a private player profile/history surface for the authenticated account.

This should let a player:

  • see their current account stats in one place
  • browse recent completed matches
  • reopen a past match and inspect the same kind of summary they saw live
  • distinguish official on-record matches from AI-assisted off-record matches

Why this fits the current architecture

The existing backend already stores most of the data needed for an MVP:

  • accounts for identity, balance, and leaderboard eligibility
  • player_stats for official aggregate stats
  • matches for match metadata and ai_assisted
  • match_players for per-match start/end balances and final result
  • vote_logs for per-game outcomes, deltas, prompt ids, revealed labels/text, coordination credit, and void state

The client also already has a post-match summary UI that can likely be reused as the basis for historical match detail.

Scope

In scope

  • add an authenticated Profile / History view inside the app shell
  • show private account stats for the signed-in player
  • show a recent-match list for matches that include the signed-in player
  • show historical detail for a selected completed match
  • clearly mark AI-assisted matches as off the record

Out of scope

  • public player profile pages
  • exposing one player's history to other players
  • changing leaderboard policy or gameplay rules
  • adding social/follow features
  • adding prompt-performance analytics beyond basic match/game history in the first pass

UX

Entry point

Add a signed-in navigation entry in public/app.html, likely Profile or History, alongside the existing queue/leaderboard navigation.

Profile overview

Show the current authenticated player's private profile card with at least:

  • display name
  • wallet/account id (possibly truncated in UI)
  • token balance
  • leaderboard eligibility
  • current leaderboard rank if available
  • matches played
  • games played
  • coherent games / coherent %
  • current streak
  • longest streak

These should reflect the official stats already tracked in player_stats and leaderboard state, not recomputed ad hoc from history rows.

Match history list

Show recent completed matches newest-first.

Each row/card should include at least:

  • match id
  • started / ended time
  • player count
  • game count
  • on-record vs off-record badge
  • starting balance
  • ending balance
  • net delta
  • final result / placement summary if derivable

MVP should paginate or cursor recent results rather than attempting to render all history at once.

Match detail

Clicking a historical match should open a detail view that reuses the existing summary concepts where possible:

  • match headline / status
  • off-record banner for AI-assisted matches
  • final standings table
  • game-by-game timeline
  • per-game outcome for the signed-in player

For each game, show at least:

  • game number
  • prompt id and resolved prompt text if available
  • prompt type (select / open_text)
  • the player's revealed answer label/text
  • whether the player won
  • whether the game earned coordination credit
  • net delta
  • void reason if the game was voided

Backend/API shape

Introduce authenticated read endpoints rather than overloading the existing PATCH /api/me/profile route.

Proposed MVP routes:

  • GET /api/me/history
    • returns paginated completed matches for the authenticated account
  • GET /api/me/history/:matchId
    • returns one completed match's detail, but only if the authenticated account participated in that match

Possible response fields:

GET /api/me/history

  • matches
  • nextCursor

Per match item:

  • matchId
  • startedAt
  • endedAt
  • status
  • playerCount
  • gameCount
  • aiAssisted
  • startingBalance
  • endingBalance
  • netDelta
  • result

GET /api/me/history/:matchId

  • match-level metadata from matches + match_players
  • players for final standings
  • games derived from vote_logs for that match

Important constraint: this endpoint must authorize by participation. If the authenticated account did not play in the match, return 404 or 403.

Data notes / implementation details

  • Prefer to show only completed matches in the history view for the first version.
  • AI-assisted matches should still appear in history, but they must be visibly marked as off the record.
  • Official aggregate stats should continue to come from player_stats; do not accidentally include AI-assisted history in leaderboard/streak aggregates.
  • Prompt text can be resolved from prompt_id via the canonical prompt catalog. If a prompt id no longer resolves, fall back gracefully to something like Unknown prompt (id 1234) instead of failing the whole history page.
  • The history feature should not duplicate or redefine game rules outside docs/game-design.md.

Acceptance criteria

  • A signed-in player can open a private profile/history view from the app UI.
  • The profile view shows current account data and official aggregate stats for the authenticated account.
  • The profile view lists recent completed matches involving the authenticated account, ordered newest-first.
  • AI-assisted matches appear in history and are clearly marked as off the record.
  • Selecting a historical match shows a durable post-match detail view with final standings and a game-by-game timeline.
  • Historical match detail is available after refresh/relogin; it is not limited to the live in-memory summary state.
  • History endpoints only return matches for the authenticated account.
  • Empty-state UX exists for accounts with no completed matches.
  • Existing leaderboard behavior and gameplay rules remain unchanged.

Follow-ups (not required for MVP)

  • filter history by on-record vs off-record
  • search by match id
  • prompt-level performance breakdowns
  • CSV export for a player's own history
  • shareable read-only match recap URLs if we later decide that completed matches should be publicly linkable

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions