CaseOrion
CS-style case opening site with virtual credits, inventory, multiplayer item betting, shop, leaderboard, and an admin panel for cases / drops / rates.
Stack
- Server: Node.js, Express, Prisma, SQLite, express-session, Socket.IO
- Client: React (Vite), React Router, Socket.IO client
Setup
npm run install:all
npm run db:push
npm run db:seed
npm run dev
- App: http://localhost:5173
- API: http://localhost:3001
- LAN: http://<your-lan-ip>:5173 (Vite binds to
0.0.0.0)
Create server/.env if missing:
DATABASE_URL="file:./dev.db"
PORT=3001
CLIENT_ORIGIN=http://localhost:5173
SESSION_SECRET=dev-secret
STARTING_BALANCE=10000
STARTING_OSU=100
JACKPOT_ROUND_SECONDS=30
JACKPOT_MAX_ITEMS=3
Demo accounts
| Role | Username | Password |
|---|---|---|
| Admin | admin |
admin123 |
| Player | player |
player123 |
Local seed defaults; override admin via ADMIN_USERNAME / ADMIN_PASSWORD. In Docker, those env vars in .env.prod are required and applied on every start.
New registrations receive 100.00 starting credits and 100 osu (STARTING_BALANCE / STARTING_OSU in server/.env; credits stored in cents).
Features
- Login / register (username + password)
- Inventory: sort by recent or value, multi-select sell at instance value (float/wear), bulk Sell below threshold, favorites (★ — cannot be sold or auto-sold; can still be bet in battles), Vault staking (up to 3 slots by default; +1 per Vault Capacity skill) — staked items earn dividends every 10 min (10% value online / 1% offline, scaled by float² wear and rarity)
- Auto-sell: optional threshold (shared with bulk sell); on case opens, credits are applied after the reel finishes; on battle wins, items taken from other players below the threshold are sold immediately
- Wear (float): each case drop gets a random float
0–1and paint seed; grades FN / MW / FT / WW / BS (CS ranges). CatalogmarketValueis the Field-Tested reference; instancevalueCentsscales by float within the wear band (FN up to +50%, MW +15–30%, FT mid ≈ catalog, WW down to −40%, BS lower) - Feed Drop: toggle in nav — live left column of latest case unboxes + MultiPlayers Battle winners
- Cases page: browse and open crates (CS-style reel, result rolled server-side)
- Case keys (per crate): 1 key → x10; each 100 opens of that case earns +1 key up to x20 (keys 1→11, +1 open per key: x11…x20); from x20 onward each next key costs 200, 300, 400… opens (100 × tier) and adds +1 max open (x21, x22…) — no cap
- Battle hub (
/battle):- MultiPlayers Case — live shared pot preview on the hub (top items, pot total, players), up to 3 items, win chance by value, Socket.IO sync
- 1vX Case — custom rooms (player/item limits, min value), spectate in-progress
- Coinflip — stub (coming soon)
- Shop (nav balance pill →
/shop): spend osu on credit packs; watch an ad every 1 min for 100.00–200.00 cr - Profile (username in nav): avatar, bio, password, stats, logout
- Presence: online status (Socket.IO), total play time, last connection — shown on own and public profiles
- Achievements (
/achievements, also from profile): 10 starter badges unlocked by play (cases, battles, catalog, prestige, shop, playtime); earned badges appear on the profile - Prestige: pay 1 000 000 000 000.00 cr to reset; earn Pr (1000 base + ~1000 per 100 000 000 000.00 cr excess); spend Pr on a skill tree (Fortune, Yield, Polish, Bulk, Discount, Quality, noTime, Refund, Respin, Vault Capacity, Offline/Online Yield)
- Leaderboard: richest players (balance + inventory value); click a row to open a public player profile (
/player/:username) with stats and inventory - Admin: overview dashboard, players (credit adjust), cases / items / drops (split pages, search filters)
Docker (production)
# Build & push to Docker Hub (foufure/casegambling)
docker login
./scripts/docker-build-push.sh
# optional version tag:
./scripts/docker-build-push.sh v1.0.0
# Run
cp .env.prod.example .env.prod # edit secrets / CLIENT_ORIGIN / ADMIN_*
docker compose --env-file .env.prod up -d
Set ADMIN_USERNAME and ADMIN_PASSWORD in .env.prod (required). On each container start the admin account is created or updated from these values.
App listens on HOST_PORT (default 3009 → container 3001). Data: volume casegambling_data (SQLite), uploads: casegambling_uploads.
Backup / restore
On the Docker prod server (export DB to bring home):
# Copy these two scripts onto the server next to docker-compose.yml, then:
./scripts/docker-db-export.sh
# → backups/casegambling-… (+ .tar.gz)
# Optional: restore a backup into Docker
./scripts/docker-db-import.sh ./backups/casegambling-YYYYMMDD-HHMMSS.tar.gz
On your laptop (local server/prisma/dev.db):
# Import the archive you copied from prod (stop `npm run dev` first)
./scripts/local-db-import.sh ./backups/casegambling-YYYYMMDD-HHMMSS.tar.gz
npm run db:push # sync schema if needed
npm run dev
# Export local DB (e.g. to push back to Docker)
./scripts/local-db-export.sh
./scripts/docker-db-import.sh ./backups/casegambling-….tar.gz
Typical prod → local flow: docker-db-export.sh on the server → scp the .tar.gz → local-db-import.sh on the laptop.
Notes
- Balances and prices are integers in cents; osu is a separate demo currency for the shop
- Catalog item price = Field-Tested reference; each inventory row stores
floatValue,wear,paintSeed,valueCents,favorite, optional vaultstaked/stakedAt/lastYieldAt - Per-user auto-sell settings:
autoSellEnabled,autoSellThresholdCents(default threshold 10.00 cr) - Case key progress stored in
CaseKeyProgress(per user + case); backfill:npm run db:backfill-case-keys --prefix server - Inventory items locked while deposited in a bet; unlocked or transferred on resolve; staked vault items cannot be sold, auto-sold, or bet
- Avatars / uploads under
server/uploads/(volume in Docker) - Real-time via Socket.IO; Docker Hub image name is lowercase:
foufure/casegambling - Max 10 simultaneous browser windows/tabs per account (Socket.IO); override with
MAX_SOCKETS_PER_USER - Swap
DATABASE_URLto PostgreSQL later without changing app logic