Turns practice sessions into a ghost hunt. /practice (or the Mini App button) logs a session and damages whichever of the 5 ghosts is currently haunting the player's room. Miss more than a couple of days and the ghost claws back some progress, so steady beats sporadic.
Roster: Sparky → The Bed Crawler → The Window Stalker → Red-Aura Wraith → Rockstar Specter (final boss, two-phase fight).
- A bot token from @BotFather
- This repo deployed on Railway (or any host that can run Python + expose HTTPS)
Your Railway service is already connected to the GitHub repo. After you push the new files:
In the Railway service → Variables, set:
| Variable | Required | Description |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Yes | Token from BotFather |
MINI_APP_URL |
Recommended | Your public Railway URL, e.g. https://your-service.up.railway.app |
GHOST_HUNTER_DB |
Optional | Path for SQLite. Default: ghost_hunter.db |
PORT |
Auto | Railway sets this |
If you leave MINI_APP_URL empty, the app will try to use RAILWAY_PUBLIC_DOMAIN automatically.
Railway should detect the Procfile. If not, set the start command to:
uvicorn webapp:app --host 0.0.0.0 --port $PORTThis single process serves:
- The Mini App (web UI + API)
- The Telegram bot (polling in a background thread)
The bot stores progress in a local SQLite file. Railway’s ephemeral filesystem wipes on redeploy unless you attach a volume.
- Railway project → your service → Settings → Volumes
- Add a volume, mount path e.g.
/data - Set variable:
GHOST_HUNTER_DB=/data/ghost_hunter.db
Push to main. Railway will rebuild and redeploy.
After deploy, open the public URL — you should see the Mini App home (roster). /api/health should return {"ok":true}.
- Open @BotFather
/setmenubutton→ select your bot- URL:
https://YOUR-RAILWAY-DOMAIN(same asMINI_APP_URL) - Button text:
Hunt Ghosts(or anything)
- URL:
- Optional but recommended:
/newapp→ create a Mini App linked to the bot with the same URL (gives you at.me/YourBot/applink) - Optional:
/setdomain→ set the Railway domain so WebApp features work cleanly
The bot also tries to set the menu button automatically on startup when MINI_APP_URL is present.
/start— intro/practice— log a session/status— current ghost, progress bar, streak/ghosts— full roster/app— open Mini App button
- Home (
/) — current ghost, progress bar, big “Log practice” button, full roster - Separate cards (
/card/sparky,/card/bed-crawler, …) — dedicated page per ghost
Practice only works on the ghost that is currently active for the player.
Progress is shared: a practice logged in the Mini App updates the same player record as /practice in chat.
pip install -r requirements.txt
export TELEGRAM_BOT_TOKEN="your-token"
export MINI_APP_URL="https://your-ngrok-or-local-tunnel" # optional for menu button
uvicorn webapp:app --host 0.0.0.0 --port 8000For Telegram to open the Mini App you need HTTPS. Use ngrok or similar:
ngrok http 8000
# then set MINI_APP_URL to the https URL and update BotFatherTo run only the bot (no web):
python bot.pybot.py # Telegram commands + menu button
game.py # Shared logic + SQLite
webapp.py # FastAPI Mini App + API + starts bot thread
templates/ # Mini App HTML (home + per-ghost cards)
Procfile # Railway start command
requirements.txt
- Python 3.10+
- Polling is used (no webhook required). One Railway service is enough.
- If the bot thread fails to start, check logs for
TELEGRAM_BOT_TOKENand network access toapi.telegram.org.