# Production/staging .env for the game-dev.onlinetestingserver.com box.
# Copy to server/.env ON THE SERVER and fill in every <generate> value there:
#
#   openssl rand -hex 24
#
# LARAVEL_APP_KEY is the one exception - Laravel generates it, not openssl:
#
#   docker compose run --rm laravel php artisan key:generate --show
#
# Never reuse LAN development keys, and never send a filled-in copy of this
# file over chat or email.

# Client-facing key. MUST match serverKey in the Unity client's
# Assets/Settings/OnlineConfig.asset - it is a public identifier, not a secret.
NAKAMA_SERVER_KEY=52eecb6ed1bb1c79f6b181069b2e97ebb467d9c6acf3d3ea

# Server-to-server key (?http_key=...). Secret. Generate on this machine.
NAKAMA_HTTP_KEY=<generate>

# Second factor on the rpc_gs_* endpoints. Secret. Generate on this machine.
GS_SHARED_SECRET=<generate>

# Nakama console login (port 7351, loopback-only - reach it via SSH tunnel).
NAKAMA_CONSOLE_USER=admin
NAKAMA_CONSOLE_PASSWORD=<generate>

# Operator ports (CockroachDB 26257/8080, Nakama 7349/7351) bind here.
# 127.0.0.1 = loopback only. CockroachDB runs --insecure, so NEVER set this
# to 0.0.0.0 on an internet-facing machine.
ADMIN_BIND=127.0.0.1

# Empty = per-mode scene pools from nakama/data/modules/config.lua (recommended
# in production). A scene name here forces every match into that scene.
MATCH_SCENE=

# Activates the gameserver service in docker-compose.yml, so ONE
# `docker compose up -d` starts CockroachDB + Nakama + the game server together.
# Requires Builds/LinuxServer/ to exist next to server/ (it does in the handover
# layout). Remove this line to go back to running the game server separately.
COMPOSE_PROFILES=gameserver

# The address CLIENTS dial for game traffic (UDP). The machine's PUBLIC IP -
# never localhost, never a container IP.
GS_PUBLIC_HOST=108.178.43.90

# UDP port for Mirror KCP. Must be open in the firewall (CSF: UDP_IN) and
# published on the container:  -p 25565:25565/udp
GS_PORT=25565

# How the game server reaches Nakama. As a compose service it shares Nakama's
# network, so the service name resolves - leave this as is.
GS_NAKAMA_URL=http://nakama:7350

# ---------------------------------------------------------------------------
# Laravel API stack (accounts, wallet, shop, leaderboards, friends, progression)
# ---------------------------------------------------------------------------
#
# These keys are REQUIRED. docker-compose.yml fail-fasts on LARAVEL_APP_KEY,
# MYSQL_PASSWORD and MYSQL_ROOT_PASSWORD, so a .env missing this block stops the
# ENTIRE stack - Nakama and the game server included - with a message naming the
# first key it could not find.

# Master switch for match entry fees and payouts.
#
# Leave 0 until the Laravel container is confirmed healthy. With it on the
# economy fails CLOSED: if Laravel is unreachable when the entry fee is charged,
# the match is cancelled rather than played for free.
ECONOMY_ENABLED=0

# How Nakama's Lua reaches Laravel. Compose service name, resolved on the shared
# network - not a public URL, and never the LARAVEL_PORT host binding.
LARAVEL_URL=http://laravel:8080

# Host port for the Laravel API.
LARAVEL_PORT=8090

# Interface for LARAVEL_PORT.
#
# /api and /s2s SHARE this one port, and this loopback bind is the only thing
# keeping /s2s off the internet. Keep it at 127.0.0.1 and reverse-proxy ONLY
# /api from the box's Apache - see DEPLOYMENT.md section 3, "Exposing the API".
#
# Do NOT confuse this with ADMIN_BIND above. They are different keys guarding
# different ports, and a blanket find-and-replace of 127.0.0.1 exposes the
# unauthenticated CockroachDB.
#LARAVEL_BIND=127.0.0.1
LARAVEL_BIND=0.0.0.0

# Second factor on every /s2s/* route (sent as X-JD-S2S). Secret, server-to-
# server only - it NEVER ships in a client build. Generate on this machine.
LARAVEL_S2S_SECRET=<generate>

# Laravel's APP_KEY. NOT openssl - Laravel generates this one itself:
#   docker compose run --rm laravel php artisan key:generate --show
LARAVEL_APP_KEY=<generate-with-artisan>

# MySQL for Laravel. Deliberately its own database, never CockroachDB - that
# node runs --insecure, has no backups, and is not an Eloquent target.
#
# MYSQL_PORT is the HOST port only, and is 3309 rather than 3306 because this
# box already runs its own MySQL on the default port. Laravel is unaffected: it
# reaches the database as mysql:3306 over the compose network. Bound to
# ADMIN_BIND (loopback) like every other operator surface - reach it with:
#   ssh -L 3309:127.0.0.1:3309 user@host
MYSQL_PORT=3309
MYSQL_DATABASE=jd
MYSQL_USER=jd
MYSQL_PASSWORD=<generate>
MYSQL_ROOT_PASSWORD=<generate>

# Starting wallet for every new account, guest or social.
STARTER_COINS=1000
STARTER_DIAMONDS=0

# --- Economy tuning ---------------------------------------------------------
# Every key below is OPTIONAL: compose supplies these exact values as defaults,
# so omitting them changes nothing. They are listed because they were invisible
# before - the values existed in Laravel config but Compose never forwarded them,
# so editing .env had no effect at all. Now it does.
#
# Changing any of them needs the Laravel container recreated, not just restarted:
#   docker compose up -d --force-recreate laravel

# Match entry fee per mode, in coins. Charged server-side when the lobby fills.
ENTRY_FEE_1V1=100
ENTRY_FEE_2V2=100
ENTRY_FEE_5V5=100
ENTRY_FEE_FFA=100

# Coins picked up on the route. Pickups happen on the CLIENT, so the client
# reports a total and the server clamps it: MATCH_COINS_MAX is the ceiling per
# match (or per solo run) and COIN_VALUE is wallet coins per collected coin.
# The current map holds 768 coins, so 1000 leaves headroom.
MATCH_COINS_MAX=1000
COIN_VALUE=1

# Coins for completing a map's objectives (collect N coins, finish within N
# minutes...). The client reports the bonus it earned with the coins above and
# the server clamps it to this, per match or solo run. Paid once, in the same
# award. Wallet coins, not multiplied by COIN_VALUE.
OBJECTIVE_BONUS_MAX=500

# Season points a WIN awards. A loss costs the same, EXCEPT where a *_LOSS_*
# override exists: Free For All has one winner and three losers, so a symmetric
# value would drain the ladder by twice the award every match.
POINTS_1V1=250
POINTS_2V2=500
POINTS_5V5=1000
POINTS_FFA=300
POINTS_LOSS_FFA=100

# Whether shop items may be priced in coins as well as diamonds.
SHOP_COINS_ENABLED=true

# ############################################################################
# LEAVE THIS false. It enables the two endpoints that create currency from
# nothing: the currency-pack "purchase" (nothing charges real money yet, so
# buying is simply a grant) and POST /api/dev/wallet/grant, a direct faucet.
#
# They exist so the game can be demonstrated before payments are wired. On a
# host players can reach, they hand out unlimited coins and diamonds, and every
# balance, purchase and leaderboard downstream assumes currency was earned.
#
# With it false the store still LISTS packs; buying returns 402 and the grant
# endpoint 404s (it does not advertise that it exists).
# ############################################################################
DEV_GRANTS_ENABLED=false

# ---------------------------------------------------------------------------
# Outbound mail (verification + password-reset codes)
# ---------------------------------------------------------------------------

# MUST be exactly `log` or `smtp` - anything else, including a placeholder left
# unedited, makes Laravel throw "Mailer [...] is not defined" on the FIRST
# sign-up. That is a nastier failure than it sounds: this key is not one of the
# eight compose fail-fasts, so the whole stack boots perfectly and only breaks
# when a real player tries to register, as a 500 with no detail.
#
# (It shipped here as `<smtp-or-log>` and did exactly that on 2026-09-07.
# Defaulted to `log` now: a working value beats a descriptive one in a field
# where being wrong is silent until it is expensive.)
#
# `log` writes the code to storage/logs/laravel.log instead of sending it, and
# cannot fail. Verification does not gate play, so `log` is a perfectly usable
# state for a test deployment - players simply never receive the email.
#
# Set `smtp` and fill in the four values below once real mail is wanted.
MAIL_MAILER=log

# Only read when MAIL_MAILER=smtp. Left EMPTY rather than filled with
# placeholders: an empty value is obviously unset, whereas <smtp-host> looks
# configured and fails at connect time.
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=metafrolic4@gmail.com
MAIL_PASSWORD=ememlqlpsttasohr
# tls for 587 (STARTTLS), ssl for 465.
MAIL_SCHEME=tls

# The From: header. Must be an address the SMTP provider will let you send as,
# or mail is accepted and then silently dropped by the recipient's spam filter.
MAIL_FROM_ADDRESS=metafrolic4@gmail.com
MAIL_FROM_NAME=JustDifferent
