CLAUDE.md: bumped the stale test count (54 -> 76), added "Balance display"
and "Real-time updates (SSE)" sections, and rewrote the DRAW section's
frontend-reveal paragraph to describe the actual current behavior (dual
status/result boxes gated by user_played, closes_at-anchored reveal delay,
localStorage persistence, the last-round-result backstop) instead of the
older single-box design. Refined the "no history endpoints" known gap now
that GET /users/me/last-round-result exists (still not general history).
README.md: same test count fix, expanded coverage list.
docs/: fixed a pre-existing broken link in setup.md (admin-guide.md ->
guida-admin.md), added a note in running-the-server.md that editing the
bind-mounted Caddyfile needs an explicit `docker compose restart caddy`
(discovered while adding the SSE Caddy config in a prior change), and
rewrote guida-utente.md's draw/reveal section plus the balance/withdrawal
sections to match what the UI actually does now. guida-admin.md was
reviewed but needed no changes.
app/static/style.css: dropped `.toast.info`, dead since the toast-based
loss notification it styled was replaced by the persistent result box.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Balance display: place_bet/request_withdrawal spend whole UTXOs and mark
them spent at broadcast time, well before confirmation, so the confirmed-only
balance could drop by far more than the amount actually moving. Add
compute_pending_balance() (app/wallet/balance.py) to fold the unconfirmed
change from in-flight bet/withdrawal PendingTransactions back in; GET
/users/me now returns pending_balance_sats + has_pending, and the frontend
shows it colored green (settled) or amber (still pending) instead of the
confirmed-only figure.
Round outcome display: the win/lose reveal and the "pagamento al vincitore
in corso" status were fighting over the same UI slot, and the reveal broke
across a page refresh. Now:
- The round-status box (generic phase progress) and the personal win/lose
box are independent and can both be visible at once.
- The win/lose box only renders for users who actually played in that round
(new user_played field on GET /rounds/current, via a new optional-auth
dependency so the endpoint stays usable logged-out).
- The reveal delay is anchored to the round's server-provided closes_at
instead of a client-side "first seen" timestamp, so repeated reloads can't
reset it, and the revealed result is persisted in localStorage so it
survives a refresh even after the round has fully closed.
- GET /users/me/last-round-result is a durable DB-backed backstop for
players who miss the live window entirely (backgrounded tab, offline).
Also hardens the frontend polling loop: call() now times out instead of
hanging forever, and a session-epoch counter stops an in-flight request from
a previous login from resurrecting a duplicate poll loop after logout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add a request timeout (AbortController) to the frontend's call() helper, so a
hung server request no longer freezes the entire polling chain silently.
- Add GET /users/me/last-round-result: a durable, DB-backed fallback for the
round outcome, since /rounds/current drops winner_user_id the instant a
round flips from "paying_out" to "closed" — a backgrounded tab or a missed
poll could otherwise mean a player never learns whether they won.
- Refresh the balance display when a win is revealed (live or via the new
backstop), instead of leaving the pre-payout balance on screen.
- Guard refreshRound() with a session-epoch counter so an in-flight request
from a previous login can't re-arm the poll loop after logout, which
previously produced a duplicate "zombie" polling chain.