No description
  • Python 84.2%
  • JavaScript 7.8%
  • HTML 5%
  • CSS 2.6%
  • Shell 0.2%
  • Other 0.2%
Find a file
2026-11-12 18:45:51 +00:00
accounts Mask public deposit errors and retain private admin diagnostics 2026-11-09 22:07:23 +01:00
blackjack Recognize verified operator top-ups sent to house subaddresses 2026-11-12 19:43:21 +01:00
config Separate Django domains into apps and share game accounting 2026-11-03 17:28:26 +01:00
core Add provably fair blackjack with offline HTML and Python checkers 2026-11-04 22:46:47 +01:00
deploy/monero Patch Python runtime and dependency security floors 2026-11-06 12:10:06 +01:00
deposits Recognize verified operator top-ups sent to house subaddresses 2026-11-12 19:43:21 +01:00
docs Recognize verified operator top-ups sent to house subaddresses 2026-11-12 19:43:21 +01:00
operations Separate Django domains into apps and share game accounting 2026-11-03 17:28:26 +01:00
payouts Mask public deposit errors and retain private admin diagnostics 2026-11-09 22:07:23 +01:00
scripts Mask public deposit errors and retain private admin diagnostics 2026-11-09 22:07:23 +01:00
static/blackjack Mask public deposit errors and retain private admin diagnostics 2026-11-09 22:07:23 +01:00
templates Limit active deposits and shorten new payment windows 2026-11-09 21:45:41 +01:00
treasury Recognize verified operator top-ups sent to house subaddresses 2026-11-12 19:43:21 +01:00
.dockerignore big 2026-10-21 23:31:06 +02:00
.env.example Add optional production-only Umami frontend analytics 2026-11-03 16:38:55 +01:00
.gitignore big 2026-10-21 23:31:06 +02:00
AGENTS.md Recognize verified operator top-ups sent to house subaddresses 2026-11-12 19:43:21 +01:00
compose.local.yaml Separate Django domains into apps and share game accounting 2026-11-03 17:28:26 +01:00
compose.mainnet.yaml Remove Basic Auth from mainnet proxy configuration 2026-11-03 16:54:25 +01:00
compose.stagenet.yaml Add optional production-only Umami frontend analytics 2026-11-03 16:38:55 +01:00
cron.md Add persistent maintenance mode for safe deployments 2026-10-27 20:33:18 +01:00
Dockerfile Patch Python runtime and dependency security floors 2026-11-06 12:10:06 +01:00
manage.py doc 2026-10-12 21:38:21 +02:00
next.txt . 2026-10-12 23:16:39 +02:00
README.md Recognize verified operator top-ups sent to house subaddresses 2026-11-12 19:43:21 +01:00
requirements-dev.txt one shot 2026-10-12 21:22:38 +02:00
requirements.md requirements 2026-10-12 20:47:41 +02:00
requirements.txt Patch Python runtime and dependency security floors 2026-11-06 12:10:06 +01:00
sql-back.md over underpayment logic 2026-10-27 23:10:34 +01:00
vpn-firewall-rule.txt big 2026-10-21 23:31:06 +02:00

Schedule Command 0 * * * * python manage.py cleanup_unfinished_accounts */15 * * * * python manage.py record_house_balance

sudo LOCAL_BUILD_NETWORK=host ./scripts/dev.sh up --build -d

sudo ./scripts/dev.sh ps

Findout HouseWallet locally

sudo docker exec -it

python manage.py shell -c 'from core.monero import WalletRPC; print(WalletRPC().call("get_address", account_index=0)["address"])'

Then: sudo ./scripts/dev.sh exec web python manage.py check_reserves

Findout Seed deployed

On web container

python manage.py shell -c 'from core.monero import WalletRPC; print(WalletRPC().call("query_key", key_type="mnemonic")["key"])'

The Monero Table

New XMR rounds are provably fair: Fairness shows the locked shuffle fingerprint and lets players save their pre-deal inputs. Finished rounds offer verification and proof downloads in History, with HTML and Python offline checkers and a plain-English tutorial. Each round gets a fresh independent shuffle. Deploy matching code/static assets with migration 0022 under the documented maintenance/drain procedure; existing rounds and financial records are preserved.

The backend is split into game, accounts, deposits, payouts, treasury and operations apps. See Django app ownership, adding games and migration rollout.

Wrong-amount deposits can be explicitly reviewed and credited by a superuser; see manual deposit credits for the guarded workflow, late-payment inspection, player resolution notes and migrations 0019–0020. No automatic mismatch credit or deposit refund is provided.

Django 6 blackjack with an animated, responsive English interface, a 1 XMR virtual bankroll, server-side rules, exact integer balances, game history, and an operations dashboard at /admin/ by default. Set DJANGO_ADMIN_PATH=staff-console/ and redeploy to move it to /staff-console/; see admin URL configuration.

Supported Monero networks are stagenet and mainnet only. Development defaults to stagenet. The local Docker setup explicitly enables stagenet XMR play; unconfigured/external deployments keep real play disabled. See player wallet setup for stagenet/mainnet wallets and the separately requested unsupported testnet wallet experiment.

Full developer documentation is in docs/README.md: architecture and models, every HTTP endpoint, a source-code reference, configuration and operations, testing/maintenance guidance, and the input-validation security review. Current product, security, and documentation requirements for contributors are in AGENTS.md.

Practice play now runs entirely in browser memory: no accounts, games, actions, ledger, history, diagnostics or demo sessions are stored in the database. It starts with 1 virtual XMR, survives Leave/rejoin in the same open page, and resets on reload/close. Real XMR play keeps all backend authorization and persistent accounting. Apply migration 0016_browser_only_practice to remove old virtual records and enforce real-only stored accounts; deploy all app/worker services together. See practice storage and rollout.

PostgreSQL deployment fix: replacement migration 0017_practice_cleanup_postgresql automatically supersedes 0016 for pending/failing upgrades, validating deferred foreign-key checks before the table alteration in the same transaction. Already-applied 0016 is preserved without repeating cleanup. If Coolify reports web unhealthy with pending trigger events, deploy this revision with the existing wallet/database volumes; normal startup migrations use the replacement. See recovery steps.

The compact table stacks its four actions above the next-deal bet picker and New deal. It displays combined and per-hand stakes, a live shoe count, and card totals that update as each card lands. Draws take 620 ms; profitable rounds get a shorter 80-coin Monero celebration. Paginated history combines results and bankroll movements; click a round to expand its shuffle, cards, decisions, and settlement. Rules include examples; reduced-motion settings disable falling coins and card delays.

Last games shows Live wins and Biggest wins from completed real-XMR games, with independently random short player aliases, grouped hand counts and net XMR winnings. See Last games implementation and migration 0013.

XMR games use each player's recorded available balance without waiting for the wallet or node. Deposits and payout sending keep strict wallet/confirmation checks. If a cash out lacks spendable house funds, it stays reserved in a funding hold: staff see the exact saved shortfall, fund the house wallet and use Review & continue cash out for that same request. A top-up alone does not release the hold, and uncertain sends are never automatically replaced or relayed again. House reserves remains private monitoring with Check funds and the original HOUSE_RESERVE_BUFFER_XMR (default 0.1 XMR) diagnostic policy. See house backing monitoring and cash-out funding/continuation. No new schema or environment setting; deploy web and payout worker together.

Operator capital accidentally sent to an unassigned house subaddress can be recognized with the preview-first record_house_topup terminal command, after treasury migration 0002. It verifies the original payment without sending XMR or crediting players; see the exact repair commands and limits.

Mainnet cash-outs independently require ten observed confirmations for deposited XMR. Any credited deposit still below ten remains held against the player's balance; confirmed funds remain eligible and All requests only that eligible amount. Stagenet cash-outs are unchanged. See the confirmation safeguard; deploy web, static assets and scanner together, with no new migration or setting.

For future deployments, use Admin → Maintenance mode → Activate maintenance, wait for Ready to deploy, redeploy web/scanner/payouts, then Deactivate maintenance. Games, deposits and cash outs pause while players see a notice; rounds and funds are preserved. Apply migration 0018 during the first coordinated installation. See maintenance deployment workflow for the initial rollout, terminal commands and blockchain/deadline limits.

Admin → Table issues records new player/game action failures with searchable player addresses, request/game links, exact historical reserve shortfalls and repair steps. Apply migration 0014_table_issue with this update; no new environment variable is needed. See debugging player table issues for lookup, retry safety and recording limits.

The 25 October security audit reviews injection, account/fund ownership and the complete cash-out process, with confirmed allocation/admin-authentication/dependency gaps, conditional RPC custody risk and reproducible disposable probes. Its findings are not a security certification or completed remediation.

Local development with Docker

Run the same stagenet stack as deployed dev, including PostgreSQL, private house-wallet RPC, the deposit scanner and the public-node relay. Docker with current Compose and Buildx plugins is the only required host installation:

./scripts/dev.sh
./scripts/dev.sh exec web python manage.py createsuperuser

Open http://localhost:8000. Play for free keeps the 1 virtual XMR simulation. Play for XMR uses actual stagenet coins: generate and save an account number, confirm it, then enter it to log in. Generate a deposit address for an exact amount of at least 0.01 XMR and pay once within one hour; wait for sync/confirmations.

Player accounts now use 16-digit account numbers, grouped in fours, with server-enforced generation/login limits. Your Wallet can Show/Hide the secret number. Deposits have independent one-use addresses, exact amounts and one-hour payment-detection windows. Apply migration 0015 and restart/redeploy web, scanner and payout worker together. Locally: ./scripts/dev.sh exec web python manage.py migrate, then ./scripts/dev.sh up --no-build -d web deposits payouts. Preserve .env (especially DJANGO_SECRET_KEY), wallet/cache and database. The previous internal address/password approach has no login, conversion or permanent-address scanning path; retained test records are audit-only. See player accounts.

Both funding dialogs and wallet activity retain deposit requests, including expired ones, with older requests available through pagination. At most one unpaid, unexpired request may be active per account. New requests expire after one hour; existing deadlines remain unchanged. Both dialogs show the existing request and disable new allocation until payment is detected or it expires. Generation attempts, including retries, are limited to 5/account/hour, 15/trusted-IP/hour and 600 globally/hour. Deadlines show the date and Berlin time, including daylight-saving changes, while the database retains timezone-aware UTC instants. This interface/limit update needs no schema migration or new configuration; deploy web code and static assets together.

Local app source is mounted read-only into web and the deposit worker. Edit HTML, CSS or JavaScript on your computer and refresh the page; Python edits automatically restart the local web/worker processes. To apply this to an already-running stack once, run sudo ./scripts/dev.sh up --no-build -d web deposits. Local web uses Django's development server with debug enabled; hosted dev keeps Gunicorn. See live code updates.

Use .env as the only active configuration file; .env.example is its template. First startup creates it with independent secrets and stagenet XMR play enabled if absent. If upgrading from .env.local, the script moves those local settings into .env, preserving credentials and privately backing up any previous .env under .local-setup-backups/. Future starts reuse .env.

See environment variables by deployment for every variable's local stagenet, deployed stagenet and deployed mainnet value/scope. Local and bundled deployed stagenet derive MONERO_RPC_URL automatically; leave it blank in .env. The bundled mainnet stack also derives its private URL; only optional externally operated wallets need an explicit private endpoint.

Optional Umami frontend analytics uses UMAMI_SCRIPT_URL and UMAMI_WEBSITE_ID from your tracking snippet. Both default to blank and load only with DJANGO_DEBUG=False; local development always omits the tracker.

The script combines compose.stagenet.yaml with compose.local.yaml; local database/wallet volumes have their own Compose project. Set STAGENET_NODE_URLS in .env. No local blockchain/node is required; the wallet still needs to catch up before deposits credit. Both RPCs and PostgreSQL stay private; only web binds to localhost. Staff creation remains terminal-only.

./scripts/dev.sh ps
./scripts/dev.sh logs -f web
./scripts/dev.sh exec -T wallet-rpc python /opt/monero/entrypoint.py status
./scripts/dev.sh exec web python manage.py test
./scripts/dev.sh down

If image builds report DNS failures resolving PyPI/Debian on Linux, retry with LOCAL_BUILD_NETWORK=host ./scripts/dev.sh up --build -d (prefix with sudo if required for Docker access). The script supplies Bake's separate --allow=network.host grant, then starts containers with their private runtime networks. See build DNS troubleshooting.

Local networks use explicit subnets so startup does not need Docker's automatic address pool. If images already built and startup reported all predefined address pools have been fully subnetted, retry with sudo ./scripts/dev.sh up --no-build -d after this update. See network allocation troubleshooting for the .env subnet overrides and overlap checks.

RPC networks also reserve separate automatic allocation ranges so a wallet/app cannot take the relay's fixed address after a restart. Existing local setups must add matching STAGENET_NODE_IP_RANGE and STAGENET_RPC_IP_RANGE values and recreate project networks while preserving volumes; follow relay address conflicts and deposit debugging.

The diagnosed local Eddie VPN rule is saved in vpn-firewall-rule.txt, with a duplicate check and removal instructions. Review its specific relay subnet, public node IP/port and VPN interface before reuse; it is applied manually, not at app startup.

down preserves accounts and wallet data; do not add -v. Source edits appear through the mounts; dependency/Dockerfile changes still need ./scripts/dev.sh up --build -d. Changes to .env or Compose require ./scripts/dev.sh up --no-build -d to recreate affected containers. See local Docker setup, funding and operations for complete instructions, node URLs, ports and sync troubleshooting. Hosted dev continues to use Coolify's stagenet setup; mainnet uses its separate fixed-network Compose file below.

Without Docker

Python 3.12 or later with current security patches is required (upstream 3.12.16 / 3.13.18 or equivalent vendor backports as of 6 November 2026). Ubuntu may need sudo apt install python3-venv before creating an environment. See the Python security update and image rebuild requirements.

python3 -m venv .venv
.venv/bin/python -m pip install --upgrade 'pip>=26.3,<27'
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python manage.py migrate
.venv/bin/python manage.py createsuperuser
.venv/bin/python manage.py runserver

This defaults to SQLite for single-process demo development. Real XMR play requires PostgreSQL. Django reads environment variables; the Compose .env file is not automatically loaded by manage.py.

Table rules

  • Six decks, securely shuffled anew for each round. Cards are dealt player, dealer, player, dealer; the dealer's second card is hidden until settlement.
  • Natural blackjack pays 6:5. A 0.01 XMR natural returns 0.022 XMR including the wager.
  • Dealer hits soft 17 and checks for blackjack before player actions. Matching naturals push.
  • Double on the first two cards totaling 10 or 11; take one card and stand.
  • Split identical ranks into two hands. No resplits or double after split. Split aces receive one card each and stand. Split 21 pays 1:1.
  • No surrender or insurance. Other wins pay 1:1; pushes return the wager.
  • Bets: 0.01, 0.025, 0.05 XMR. The ambiguous 0025 in requirements.md is interpreted as 0.025.

These choices use the house-favorable column from the brief. The dealer-peek rule means extra split/double wagers are never placed against an already-determined dealer blackjack. Every round stores its rule snapshot.

Deploy stagenet or mainnet with public nodes

Use compose.stagenet.yaml for hosted stagenet or compose.mainnet.yaml for mainnet. Both run the game, PostgreSQL, scanner, payout worker, private house wallet and keyless public-node relay on one Coolify VPS. There is no local monerod, blockchain volume or second VPS requirement. Each file fixes its own network and uses separate persistent wallet/database volumes.

Leave MONERO_RPC_URL blank in both bundled setups: Compose supplies the private wallet endpoint. Keep RPC digest credentials configured. Set STAGENET_NODE_URLS or MAINNET_NODE_URLS to the public daemon HTTPS providers; public nodes never receive house-wallet credentials. Mainnet has no guessed provider default and always requires at least ten deposit confirmations and actual unlocking.

Follow public-node deployment, the environment matrix and automatic payouts. For the full stagenet Coolify procedure and required proxy Basic Auth middleware, see Stagenet in Coolify. Hosted services expose web only on internal port 8000; no RPC/database host port is published. All secrets are runtime-only. Preserve existing stagenet resources/volumes when adding mainnet. Mainnet opens without proxy Basic Auth; Django staff login and player account-number checks still apply. Redeploy mainnet after updating Compose; see mainnet proxy setup.

Audit and integrity

  • All game decisions, hidden cards, shoe state, timestamps, and settlement records are available to authorized staff. The browser never receives the shoe or an active dealer hole card.
  • Ledger entries capture every bankroll movement with a unique reference and balance afterward. Game, ledger, and payment records are read-only in admin. They remain editable by a database administrator; this is an application audit trail, not an externally tamper-proof log.
  • PostgreSQL account row locks serialize money operations. Database constraints prevent negative balances, duplicate output credits, multiple active rounds, and duplicate request IDs. Client action receipts plus round versions prevent accidental retries and stale actions from changing a round twice.
  • CSRF protection, session cookies and network-separated password accounts protect access. Demo funds cannot cross into the XMR table or be withdrawn.
  • Strict schemas reject unexpected fields, ambiguous JSON, invalid UUIDs/types, and malformed money. Salted Argon2id credentials, session rotation/revocation, committed global/IP/account throttles and fresh cash-out passwords protect player authentication. Financial RPC quantities and states are validated before credits or payout completion.
  • Randomness uses Python's operating-system-backed secrets.SystemRandom. This version does not implement a player-verifiable shuffle protocol.

Validation

.venv/bin/python manage.py test
.venv/bin/python manage.py check
.venv/bin/python manage.py makemigrations --check --dry-run
node --check static/blackjack/app.js

The suite includes SQLite-compatible tests and 16 PostgreSQL-only concurrency regressions, plus relay transport/failover and stagenet deposit-readiness tests. It covers deterministic blackjack outcomes, exact payouts, invalid moves, splits, session isolation, public shoe counts, owned/redacted round steps and ledger balances, replay protection, forged/ambiguous inputs, password authentication/address-first reservations, migration, throttling and session revocation, deposit deduplication, malformed RPC data, withdrawal reservations/refunds, supported-network startup, private RPC/login enforcement, and proxy bypass. Run against PostgreSQL by setting DATABASE_URL to a disposable test-capable database before invoking manage.py test; SQLite skips PostgreSQL-only race tests. These checks do not verify a live wallet or certify hot-wallet safety.

For the isolated password-account flow (mock wallet, temporary database, synthetic funds), run .venv/bin/python scripts/player_account_smoke.py. See player migration and recovery before upgrading funded accounts; rebuild with the new dependencies and preserve wallet/database volumes.

For an optional desktop/mobile browser smoke check, start the demo server and run:

.venv/bin/python -m pip install -r requirements-dev.txt
.venv/bin/python -m playwright install chromium --only-shell
.venv/bin/python scripts/browser_smoke.py --screenshots /tmp/blackjack-preview

Deposit rows now distinguish the app confirmation target from wallet unlocking and playable ledger credit. Apply migration 0009_deposit_unlock_state; use fixed two-confirmation credit with STAGENET_ALLOW_LOCKED_DEPOSITS=False for local/hosted stagenet. Mainnet uses fixed payment bands (below 0.1/0.5/1/5 XMR → 2/4/6/8 confirmations; 5+ → 10); cash-outs keep ten-confirmation maturity. MONERO_MIN_CONFIRMATIONS is removed. See deposit timing and rollout.

The 2026-10-23 payout change report records these UI/deployment changes, their implementation locations and verification limits.

Contact beside Rules opens the admin-help modal. Its SimpleX invitation is currently an explicit placeholder. Failed table actions remain visible with a Contact shortcut; reserve-pause feedback directs players to the admin without exposing private house totals.

How to get Monero on the left of the landing and table footers opens a wallet/buying/swap guide. See researched options and official sources for USD/EUR purchases, BTC atomic swaps, wallet choices and node privacy, and the per-request follow-up report for changes. The landing footer also has Contact on the right, sharing the table's help modal. Opening either guide or contact keeps the visitor on the landing page.

Coolify cron checklist lists all recurring maintenance tasks and their exact settings. Scheduled maintenance explains the optional historical signup cleanup, dry run, safe address archival and migration 0010. The wallet/activity change report records requests a–e and their separate verification.

Admin → House wallets shows private total/spendable XMR, observation time and a daily graph. House-wallet monitoring covers migration 0011 and the record_house_balance Coolify task. Deploy migrations 0010/0011 before scheduling the new jobs; preserve existing volumes and keys.

Fee-blocked cash outs now have a superuser Review blocked transaction fee confirmation in Withdrawals. Apply migration 0012 and redeploy all app processes; approval lets the worker send the saved original payment with its exact reviewed fee. See the review/recovery procedure and timestamped change report.

Admin → Withdrawals → Cash-out progress → Stopped / waiting collects pending and stalled payments. See the stopped cash-out report. Every unfinished row also has Review & approve payout, with a signed superuser confirmation for the worker's checkpoint-specific recovery. See how each stopped payment continues.

Withdrawals also show the Last reported issue, its recorded time and a safe next step, including worker/readiness failures before transaction processing. Use the existing review flow to continue the same reservation/original payment; uncertain sends never authorize a replacement or automatic refund. See failure diagnosis.