feat(auth): guest login with random telegraph operator name

No email required — players pick male/female/mystery, get assigned
a humorous period-appropriate operator name (e.g. "Dusty Clicksworth",
"Ada Dottsworth", "The Phantom Sender"), can reroll, then hit
"Begin Transmitting!" for instant play. Email/magic link moved to
a collapsible section for cross-device access only.

- server: POST /api/auth/guest creates guest profile + session
- server/db: profiles.email now nullable, is_guest column added,
  migration recreates table for existing installs
- client: names.ts with 15 names per gender category
- client: LoginPage redesigned — gender picker → name display → play
- client: useAuth gains setAuth() for direct session injection
- 55 server + 44 client tests pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-30 04:22:05 +00:00
parent 8232e75fa9
commit fe5cbaec2b
7 changed files with 341 additions and 39 deletions
+13 -2
View File
@@ -1,6 +1,11 @@
import { useState, useEffect, useCallback } from 'react'
type Profile = { id: number; email: string; display_name: string | null }
export type Profile = {
id: number
email: string | null
display_name: string | null
is_guest: boolean
}
type AuthState = { profile: Profile | null; token: string | null; loading: boolean }
export function useAuth() {
@@ -50,5 +55,11 @@ export function useAuth() {
setState({ profile: null, token: null, loading: false })
}, [])
return { ...state, logout }
// Used by guest login to inject a session without a round-trip
const setAuth = useCallback((token: string, profile: Profile) => {
localStorage.setItem('session', token)
setState({ profile, token, loading: false })
}, [])
return { ...state, logout, setAuth }
}