Commit Graph

233 Commits

Author SHA1 Message Date
adlee-was-taken
420928f11e Reconcile docker-compose.prod.yml drift with droplet (INC-0001/AI-10)
The droplet copy of this file had drifted from the repo across
multiple sessions. This commit brings the repo in line with what
is actually running in production.

Changes landing from the droplet:
- Add restart: unless-stopped to app, postgres, and redis services
  (the deploy.restart_policy block was swarm-only and silently
  ignored by compose v2; top-level restart: is the correct form)
- Drop the dead deploy.replicas: 1 and deploy.restart_policy:
  subfields from the app service (swarm-only noise)
- Remove the traefik: service block entirely; Traefik now runs as
  its own stack at /opt/traefik from the adlee-traefik repo
- Remove the letsencrypt: volume declaration (owned by adlee-traefik
  now via the external golfgame_letsencrypt volume)
- Change web network from "driver: bridge" to
  "name: traefik_web, external: true" so this stack attaches to the
  shared ingress network created by the traefik stack

This closes INC-0001/AI-10 and unblocks future deploys of this repo.

The other uncommitted client/*, tui_client/* changes in the working
tree are unrelated and intentionally left alone.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:27:14 -04:00
adlee-was-taken
bc9445f06e Relicense project under GPL-3.0-or-later
Replaces the previous MIT license with GPL-3.0-or-later. Adds the full
GPL-3.0 license text at LICENSE, updates pyproject.toml metadata and
classifier, updates the README, and adds SPDX-License-Identifier headers
to all first-party server Python and client JavaScript sources.
Third-party anime.min.js is left untouched.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 09:26:06 -04:00
adlee-was-taken
ea34ddf8e4 Fix swap animation stutter and remove 1s server-side dead delay
- Remove unused card_revealed broadcast + 1s asyncio.sleep in swap handler
  (client never handled this message, causing pure dead wait before game_state)
- Defer swap-out (opacity:0) on hand cards to onStart callback so overlay
  covers the card before hiding it — eliminates visual gap for all players
- Defer heldCardFloating visibility hide to onStart — held card stays visible
  until animation overlay replaces it
- Thread onStart callback through animateUnifiedSwap → _runUnifiedSwap

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 23:47:26 -05:00
adlee-was-taken
5408867921 Harden .gitignore and add detect-secrets baseline
Add 19 missing secret file patterns to .gitignore (.env.* variants,
private keys, certificates, credentials, SSH keys). Add detect-secrets
baseline for pre-commit hook secret scanning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:47:02 -05:00
adlee-was-taken
a8b521f7f7 Fix two production crashes and bump to v3.2.0
1. Fix IndexError in current_player() when player leaves mid-game
   - remove_player() now adjusts current_player_index after popping
   - current_player() has safety bounds check as defensive fallback

2. Fix AssertionError in StaticFiles catching WebSocket upgrades
   - Wrap static file mount to reject non-HTTP requests gracefully
   - Starlette's StaticFiles asserts scope["type"] == "http"

Both crashes were observed in production on 2026-02-28 during a
multi-player session. The IndexError cascaded into reconnection
attempts that hit the StaticFiles assertion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:30:08 -05:00
adlee-was-taken
7f0f580631 Add client-side card reveal before swap and YOUR TURN badge update
Reveal face-down cards briefly (1s) before swap completes, using
client-side state diffing instead of a separate server message.
Local player reveals use existing card data; opponent reveals use
server-sent card_revealed as a fallback. Defers incoming game_state
updates during the reveal window to prevent overwrites.

Also update YOUR TURN badge to cyan with suit symbols.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:35:49 -05:00
adlee-was-taken
215849703c Add inline comments across client and server codebase
Full-codebase commenting pass focused on the tricky, fragile, and
non-obvious spots: animation coordination flags in app.js, AI decision
safety checks in ai.py, scoring evaluation order in game.py, animation
engine magic numbers in card-animations.js, and server infrastructure
coupling in main.py/handlers.py/room.py. No logic changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:17:19 -05:00
adlee-was-taken
72eab2c811 TUI visual polish: felt table, status bar, scoreboard delay
- Dark green felt background for game screen
- Status bar: dark brown bg with amber text instead of blue
- YOUR TURN badge: green bg with white text instead of bright gold
- 3s delay before hole-complete scoreboard overlay
- Dealer indicator changed from Ⓓ to (D)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:56:01 -05:00
adlee-was-taken
dfb3397dcb Overhaul TUI navigation, quit handling, and scoreboard tags
- Replace [esc][esc] quit with [q] quit globally (immediate on login,
  confirmation prompt elsewhere)
- [esc] is now consistently "back": signup→login, lobby→log out (with
  confirm), in-room host→leave (with confirm), in-room guest→leave
- Extract ConfirmScreen to shared screens/confirm.py
- Move dealer Ⓓ indicator to bottom-left corner of player box border
- Scoreboard now tags OUT (went out first) and  (lowest score)
- Send finisher_id and player id in round_over server message
- Room code moved inside in-room section with amber border
- Lobby title uses branded 🏌️ GolfCards.club ♠♥♣♦
- Amber borders and dark green backgrounds on login/lobby containers
- Deck preview renders actual card-back shapes (▓▒▓/▒▓▒)
- Help/standings panels close only with [esc], hint updated
- Game footer: s[⇥]andings [h]elp on left, [q]uit on right

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:41:45 -05:00
adlee-was-taken
b1d3aa7b77 Add session persistence, splash screen, and TUI polish
Save JWT token to ~/.config/golfcards/session.json after login so
subsequent launches skip the login screen when the session is still
valid. A new splash screen shows the token check status (SUCCESS /
NONE FOUND / EXPIRED) before routing to lobby or login.

Also: move OUT indicator to player box bottom border, remove checkmark,
center scoreboard overlay, use alternating shade blocks (▓▒▓/▒▓▒) for
card backs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:35:03 -05:00
adlee-was-taken
67d06d9799 Mark stale games as abandoned in DB during cleanup and on startup
- Periodic room cleanup now updates games_v2 status to 'abandoned'
- Server startup marks all orphaned active games as abandoned
- Prevents stale games from accumulating in the admin portal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 12:25:03 -05:00
adlee-was-taken
82aa3dfb3e Add auto-cleanup of stale game rooms after 5 minutes of inactivity
Rooms that sit idle (no player actions or CPU turns) for longer than
ROOM_IDLE_TIMEOUT_SECONDS (default 300s) are now automatically cleaned
up: CPU tasks cancelled, players notified with room_expired, WebSockets
closed, and room removed from memory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 12:17:57 -05:00
adlee-was-taken
7001232658 Add single-escape navigation: back from signup/lobby, leave room
- Single Esc: goes back one step (signup→login, lobby→connect, room→lobby)
- Double Esc: still quits the app
- Footer bar shows [Esc] Back and [Esc][Esc] Quit hints on all screens

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 20:17:10 -05:00
adlee-was-taken
13e98d330a Add TUI signup flow, quit/help/standings modals, and UI refinements
- Add signup with invite code support, remove guest login
- Add quit confirmation (q), help screen (h), standings tab
- Unified footer: [h]elp [q]uit | action text | [tab] standings
- Amber card highlighting persists through entire initial flip phase
- Player box border only highlights on turn (green) or knock (red)
- Play area gold border only during player's actual turn
- Game end returns to lobby create/join instead of login screen
- Lobby reset_to_pre_room for replayability without reconnecting
- Dynamic opponent layout fits all in one row when terminal is wide enough
- Hole emoji () in status bar, branded title with suits on connect screen
- DECK label spacing, Hole terminology in scoreboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 20:14:04 -05:00
adlee-was-taken
bfe29bb665 Add TUI lobby settings, clickable cards, and UI polish
- Lobby: collapsible Game Settings, House Rules, Deck Style sections
- Lobby: CPU profile picker via [+], random CPU via [?], remove via [-]
- Lobby: all settings (rounds, decks, flip mode, house rules, deck colors)
  sent to server on start_game instead of hardcoded defaults
- Game: clickable cards (hand positions, deck, discard pile)
- Game: immediate visual feedback on initial card flips
- Game: action bar shows escaped keyboard hints (Keyboard: Choose [d]eck...)
- Game: play area uses fixed-width rounded box instead of horizontal lines
- Game: position numbers on card top-left corner (replacing ┌) on all states
- Game: deck color preview swatches next to style dropdown
- Fix opponent box height mismatch when match connectors present
- Rebrand to GolfCards.club
- Add spacing between status bar/opponents and above local hand

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 19:23:27 -05:00
adlee-was-taken
e601c3eac4 Add DAILY_OPEN_SIGNUPS and DAILY_SIGNUPS_PER_IP to compose env vars
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 14:38:25 -05:00
adlee-was-taken
6461a7f0c7 Add metered open signups, per-IP limits, and auth security hardening
Enables public beta signup metering: DAILY_OPEN_SIGNUPS env var controls
how many users can register without an invite code per day (0=disabled,
-1=unlimited, N=daily cap). Invite codes always bypass the limit.

Also adds per-IP signup throttling (DAILY_SIGNUPS_PER_IP, default 3/day)
and fail-closed rate limiting on auth endpoints when Redis is down.

Client dynamically fetches /api/auth/signup-info to show invite field
as optional with remaining slots when open signups are enabled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 14:28:28 -05:00
adlee-was-taken
3d02d739e5 Set prod log level default to WARNING
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 02:00:33 -05:00
adlee-was-taken
3ca52eb7d1 Bump version to 3.1.6, update docs
Update version across pyproject.toml, FastAPI app, HTML footers,
and V3.17 doc. Mark kicked-ball bug as resolved in docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:59:54 -05:00
adlee-was-taken
3c63af91f2 Bump mobile logo-golfer gap from 12px to 15px
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:56:43 -05:00
adlee-was-taken
5fcf8bab60 Fix logo-golfer spacing: source order bug, tighten landscape, widen mobile
Base .golfer-container rule was after the mobile @media override,
clobbering it. Moved base rule before the media query. Landscape
gets -2px (snug), mobile gets 12px.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:55:28 -05:00
adlee-was-taken
8bc8595b39 Adjust logo-golfer spacing: tighter landscape, more room on mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:54:08 -05:00
adlee-was-taken
7c58543ec8 Tighten landscape logo-golfer gap, alternate suit colors on ball logo
Reduce golfer-container margin from 10px to 4px in landscape (2-row)
mode while keeping 10px on mobile. Swap bottom suits to checkerboard
pattern: club/diamond on top, heart/spade on bottom.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:52:25 -05:00
adlee-was-taken
4b00094140 Add spacing between logo ball and golfer container
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:48:44 -05:00
adlee-was-taken
65d6598a51 Fix kicked ball launching from golfer's back foot at narrow viewports
Wrap golfer+ball in a positioned container so the ball is absolutely
anchored to the golfer's front foot, independent of inline flow/viewport.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:47:06 -05:00
adlee-was-taken
baa471307e Tune lobby header: 2x2 suit grid, mobile spacing, tighter row gap
- Rearrange golf ball SVG suits from single row to 2x2 grid
- Add even spacing between logo, golfer, and title in mobile view
- Remove row-gap between logo row and title row in landscape view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:35:25 -05:00
adlee-was-taken
26778e4b02 Fix lobby header: use inline-grid for logo/title layout
The 749px media query was triggering at mid-range widths, collapsing
the two-row logo+title into a single line. Fix by:
- Using inline-grid on h1 for bulletproof two-row layout
- Lowering single-line breakpoint from 749px to 500px
- Widening lobby container to 550px for title to fit naturally
- Constraining game controls to 400px max-width

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:22:34 -05:00
adlee-was-taken
cce2d661a2 Fix logo-row centering at mid-range widths (750-1120px)
Change .logo-row from inline-block to block so the golf ball logo
always left-aligns flush with the G, regardless of viewport width.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:26:52 -05:00
adlee-was-taken
1b748470a0 Use width:fit-content on h1 for bulletproof logo-title alignment
The h1 shrinks to its widest child (GolfCards.club), centers via
margin auto, and text-align left aligns both lines within it.
No breakpoint-dependent transforms needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:14:56 -05:00
adlee-was-taken
d32ae83ce2 Nudge mobile header line 18px left via text-indent
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:07:58 -05:00
adlee-was-taken
e542cadedf Bump mobile single-line breakpoint to 749px to cover all phones
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:06:39 -05:00
adlee-was-taken
cd2d7535e3 Replace translateX hack with text-align left on h1 for logo alignment
Logo and title naturally left-align within the centered lobby box.
Mobile (<480px) gets text-align center + inline display for single line.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:02:17 -05:00
adlee-was-taken
4dff1da875 Only trigger single-line mode at <=449px, shift everywhere else
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:59:51 -05:00
adlee-was-taken
8f21a40a6a Make logo-row inline on mobile for single-line header layout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:58:28 -05:00
adlee-was-taken
0ae999aca6 Revert flex approach, use default translateX with max-width reset for mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:57:49 -05:00
adlee-was-taken
a87cd7f4b0 Use inline-flex column on h1 to left-align logo row with title
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:56:38 -05:00
adlee-was-taken
eb072dbfb4 Set logo-row shift to 750px breakpoint (mobile ends ~750px)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:54:10 -05:00
adlee-was-taken
4c16147ace Set logo-row shift breakpoint to 900px to match actual layout break
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:51:40 -05:00
adlee-was-taken
cac1e26bac Split the difference: logo-row shift at 600px breakpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:49:21 -05:00
adlee-was-taken
31dcb70fc8 Bump logo-row shift breakpoint to 768px so mobile stays centered
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:47:31 -05:00
adlee-was-taken
15339d390f Use min-width breakpoint for logo shift, tighten logo-title gap
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:45:38 -05:00
adlee-was-taken
c523b144f5 Tighten logo-golfer gap and shift row further left on landscape
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:40:52 -05:00
adlee-was-taken
0f3ae992f9 Wrap logo+golfer in .logo-row and translateX left on landscape
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:36:00 -05:00
adlee-was-taken
ce6b276c11 Increase logo left shift to -3.5rem to align with GolfCards text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:33:16 -05:00
adlee-was-taken
231e666407 Fix logo shift direction: move left on landscape, not right
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:31:38 -05:00
adlee-was-taken
7842de3a96 Shift logo+golfer group right on landscape via margin-left
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:29:47 -05:00
adlee-was-taken
aab41c5413 Restore logo-golfer-ball order in header
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:23:49 -05:00
adlee-was-taken
625320992e Move golfer emoji left of logo, make .club inline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:22:53 -05:00
adlee-was-taken
61713f28c8 Style GolfCards title with .club on second line
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:13:40 -05:00
adlee-was-taken
0eac6d443c Rename lobby title from Golf to GolfCards.Club
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:11:39 -05:00