Add Phase 1 MVP: D&D text-adventure server

FastAPI + Postgres backend with fastapi-users auth, games/characters
CRUD, and a WebSocket chat endpoint where an x.ai Grok DM narrates
play, rolls dice, and maintains character sheets via tool calls.
React + Tailwind frontend covers registration/login, game list and
creation, participation-code join flow, character viewer, and a
real-time chat session view. Docker Compose skeleton (Postgres +
backend) included; Caddy/frontend container wiring is deferred to
the deploy milestone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Thorsten
2026-08-31 18:43:08 +02:00
commit f37dc9fa76
75 changed files with 106988 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
import secrets
import time
import uuid
TICKET_TTL_SECONDS = 30
_tickets: dict[str, tuple[uuid.UUID, uuid.UUID, float]] = {} # ticket -> (game_id, user_id, expires_at)
def issue_ticket(game_id: uuid.UUID, user_id: uuid.UUID) -> str:
ticket = secrets.token_urlsafe(32)
_tickets[ticket] = (game_id, user_id, time.monotonic() + TICKET_TTL_SECONDS)
return ticket
def consume_ticket(ticket: str, game_id: uuid.UUID) -> uuid.UUID | None:
"""Single-use: returns the user_id if the ticket is valid for this game and not expired, else None."""
entry = _tickets.pop(ticket, None)
if entry is None:
return None
ticket_game_id, user_id, expires_at = entry
if ticket_game_id != game_id or time.monotonic() > expires_at:
return None
return user_id