Перейти к содержанию

Admin panel (web)

Overview

Web UI for platform operators to browse all game sessions and inspect detailed per-game logs. Access requires admin authentication via Telegram OTP.

FR: FR-057, FR-058

Routes

Route Auth Description
/admin Admin JWT Redirect to /admin/games
/admin/login Public Login form (username + OTP code)
/admin/games Admin JWT Paginated list of all games
/admin/games/[id] Admin JWT Full timeline log for one game

Unauthenticated access to protected routes redirects to /admin/login.

Login screen (/admin/login)

┌─────────────────────────────────────┐
│  TableTime Admin                    │
│                                     │
│  Username: [Mihaham          ]      │
│  Code:     [______          ]       │
│                                     │
│  [ Войти ]                          │
│                                     │
│  Получите код: напишите боту        │
│  @YourBot /admin login              │
└─────────────────────────────────────┘
  • Username prefilled with Mihaham.
  • On success: store tabletime_admin_token in localStorage, redirect to /admin/games.
  • Error states: invalid code, expired code, wrong username.

Games list (/admin/games)

Table columns:

Column Source
Started game.started_at
Plugin game.plugin_id
Session invite_code (link to session games)
Status playing / finished
Winner participant display name
Actions Link «Лог» → /admin/games/{id}

Filters (query params):

  • plugin_id — dice_board, kontakt, shlyapa
  • status — playing, finished
  • from / to — ISO date range
  • invite_code — session invite code
  • page, limit — pagination (default limit 50)

Game log (/admin/games/[id])

Header: game metadata (plugin, session code, status, started/finished, winner).

Timeline — chronological list merged from game_actions and game_events:

#1  game.started          2026-06-14 12:00:01
    plugin: dice_board
    players: Alice, Bob
    [▼ initial_state JSON]

#2  roll_dice             2026-06-14 12:00:15  Alice  web
    [▼ payload] [▼ result_state]

#3  action.rejected       2026-06-14 12:00:20  Bob  telegram
    NOT_YOUR_TURN
    [▼ payload]

#4  choose_cell           2026-06-14 12:00:25  Alice  web
    row=2, col=3
    [▼ payload] [▼ result_state]

#5  game.finished         2026-06-14 12:05:00
    winner: Alice
    [▼ final_state JSON]

Each entry shows:

  • Sequence number
  • Kind: action or event
  • Human-readable label (plugin-aware where possible)
  • Timestamp (UTC, local display optional)
  • Player name and channel (for actions)
  • Expandable JSON blocks for payload, result_state, event payload

Note for legacy games: lifecycle events (game.started, etc.) exist only from deployment date onward; older games show player actions only.

API client

Admin requests use Authorization: Bearer <admin_token> via adminFetch() in apps/web/lib/api.ts.

Endpoints consumed:

  • POST /api/v1/auth/admin/otp/verify
  • GET /api/v1/admin/games
  • GET /api/v1/admin/games/{id}
  • GET /api/v1/admin/games/{id}/log

Styling

Same Tailwind patterns as /auth/login. No shadcn dependency required — plain forms and tables.