# 🦈 Shark Attack Fantasy League — Offline Recovery Manual **Author:** Sho'Nuff | **Audience:** Germaine **Last updated:** July 9, 2026 **Purpose:** Recover the full shark game system without Sho'Nuff being online. --- ## 1. What Is This? (Quick Overview) The Shark Attack Fantasy League is a game where players draft shark-attack regions and score points when real shark events hit those regions. It has three parts: | Part | What it does | Where it lives | |------|-------------|----------------| | **Backend** | Python web server + database | `/root/shark-game/backend/` — port 8083 | | **Frontend** | Web pages you see in the browser | `/var/www/shark-game/` | | **Scraper** | Fetches shark news and scores points | `/root/shark-game/scraper/` — runs via cron | **Domains:** `shark.iamgmb.com` (the main site) and `shark.itpropartner.com` (backup URL) --- ## 2. Prerequisites — What You MUST Have Installed If you're reading this on the server, check these are available: ```bash which sqlite3 # Should show /usr/bin/sqlite3 which python3 # Should show /usr/bin/python3 which aws # Should show /opt/awscli-venv/bin/aws which curl # Should show /usr/bin/curl which systemctl # Should show /usr/bin/systemctl which journalctl # Should show /usr/bin/journalctl ``` If any of those are missing, install them: ```bash # Debian/Ubuntu apt-get install -y sqlite3 curl systemd # AWS CLI (if missing) apt-get install -y python3-pip pip3 install awscli ``` --- ## 3. System Architecture — What Runs Where ``` ┌─────────────────────────────────────────────────────────┐ │ Internet │ └──────────┬──────────────────────────────┬────────────────┘ │ │ shark.iamgmb.com shark.itpropartner.com │ │ ▼ ▼ ┌──────────────────────────────────────────┐ │ Caddy (reverse proxy) │ │ /etc/caddy/Caddyfile │ │ shark.iamgmb.com → 127.0.0.1:8083 │ │ shark.itpropartner.com → static files │ └──────────────┬───────────────────────────┘ │ ┌──────────────▼───────────────────────────┐ │ FastAPI Backend (port 8083) │ │ /root/shark-game/backend/server.py │ │ Runs as: shark-game.service (systemd) │ └──────────────┬───────────────────────────┘ │ ┌──────────────▼───────────────────────────┐ │ SQLite Database │ │ /root/shark-game/backend/game.db │ └───────────────────────────────────────────┘ ``` **Frontend files** are served by Caddy from `/var/www/shark-game/`: - `index.html` — Main game page - `draft-room.html` — Draft interface - `league.html` — League dashboard - `settings.html` — User settings - `how-to-play.html` — Rules - `help.html` — Help page - `sw.js` — Service worker (push notifications) --- ## 4. Daily Operations — How to Check the Game ### 4.1 Is the game running? ```bash systemctl status shark-game ``` **What to look for:** - **Active: active (running)** ✅ — everything is fine - **Active: inactive (dead)** ❌ — the service has stopped - **Active: failed** ❌ — something crashed ### 4.2 View recent logs ```bash # Last 50 lines journalctl -u shark-game -n 50 # Follow live logs (like tail -f) journalctl -u shark-game -n 50 -f # View today's logs journalctl -u shark-game --since today # Filter for errors journalctl -u shark-game -n 200 | grep -i "error\|traceback\|exception" ``` ### 4.3 Check the database ```bash # Open interactive SQLite shell sqlite3 /root/shark-game/backend/game.db # Or run a query directly sqlite3 /root/shark-game/backend/game.db "SELECT * FROM users;" # Useful queries: sqlite3 /root/shark-game/backend/game.db "SELECT id, email, display_name, is_admin FROM users;" sqlite3 /root/shark-game/backend/game.db "SELECT id, name, status, invite_code FROM leagues;" sqlite3 /root/shark-game/backend/game.db "SELECT * FROM scores ORDER BY created_at DESC LIMIT 10;" ``` ### 4.4 Check disk space ```bash df -h /root/shark-game/ ``` ### 4.5 Restart the game ```bash systemctl restart shark-game ``` Then verify it came back up: ```bash sleep 3 && systemctl status shark-game ``` --- ## 5. Backup & Restore ### 5.1 How backups work The game database (`game.db`) is NOT backed up separately — it's included in the **Hermes live-sync** backup, which runs every 15 minutes and uploads to Wasabi S3. ### 5.2 Checking backups exist ```bash aws s3 ls s3://hermes-vps-backups/ --endpoint-url https://s3.us-east-1.wasabisys.com ``` You should see folders like `live/`, `live-sync/`, `standby/`. ### 5.3 Restoring the database from S3 **Step 1:** Stop the game (so it doesn't write to the DB while restoring) ```bash systemctl stop shark-game ``` **Step 2:** Download the latest state.db backup ```bash aws s3 cp s3://hermes-vps-backups/live-sync/state.db /root/shark-game/backend/game.db \ --endpoint-url https://s3.us-east-1.wasabisys.com ``` *(Note: The backup is named `state.db` on S3 but we save it locally as `game.db`)* **Step 3:** Restart the game ```bash systemctl start shark-game ``` ### 5.4 Restoring the frontend files The frontend files are in `/var/www/shark-game/`. If they get deleted, you can rebuild them from: 1. **If the git repo exists:** `cd /root/shark-game && git pull` 2. **If the S3 backup has them:** Download them from the `live/` prefix and copy to `/var/www/shark-game/` 3. **If neither exists:** Contact me — I'll need to regenerate the frontend files ### 5.5 Taking a manual backup (for safety) ```bash cp /root/shark-game/backend/game.db /root/shark-game/backend/game.db.backup.$(date +%Y%m%d-%H%M%S) ``` --- ## 6. Common Issues & How to Fix Them ### 6.1 "Port 8083 already in use" **Symptom:** `systemctl start shark-game` fails, or you see "Address already in use" in logs. **Fix:** ```bash fuser -k 8083/tcp systemctl restart shark-game ``` ### 6.2 "Database locked" errors **Symptom:** Users see errors when trying to join leagues, make picks, or view scores. Logs show "database is locked". **Fix:** ```bash rm -f /root/shark-game/backend/game.db.lock rm -f /root/shark-game/backend/game.db-shm rm -f /root/shark-game/backend/game.db-wal systemctl restart shark-game ``` ### 6.3 "500 Internal Server Error" when joining a league **Symptom:** Users can't join leagues. You see "500" errors in the browser. **Fix:** ```bash journalctl -u shark-game -n 50 | grep -A10 "500\|Error\|Traceback" ``` Common causes: - Missing environment variables - Database schema mismatch (after restoring wrong backup) - Invalid invite code ### 6.4 Push notifications not sending **Symptom:** Users report they're not getting push notifications. **Check 1:** Is the service worker loaded? ```bash curl -I https://shark.iamgmb.com/sw.js ``` **Check 2:** Are the VAPID keys set? ```bash systemctl show shark-game | grep -i vapid ``` **Check 3:** Test push ```bash curl -X POST https://shark.iamgmb.com/api/push/test ``` **Fix:** If VAPID keys are missing, restart the service: ```bash systemctl restart shark-game ``` ### 6.5 Website shows blank page / 502 Bad Gateway **Symptom:** `shark.iamgmb.com` shows a blank page or 502 error. **Fix:** ```bash systemctl status shark-game systemctl status caddy systemctl restart shark-game systemctl restart caddy ``` ### 6.6 SSL certificate expired **Symptom:** Browser shows "Your connection is not private" warning. **Fix:** Caddy auto-renews certificates. Restart if needed: ```bash systemctl restart caddy ``` --- ## 7. Scraper & Scoring ### 7.1 How scoring works The scraper searches for shark news articles, scores them, and writes pending scores to: `/root/shark-game/data/pending-scores.json` The backend picks up these files and awards points to players who drafted the affected regions. ### 7.2 Scheduled runs The scraper runs automatically via system cron at **8:00 AM ET** every day: ``` 0 8 * * * /root/shark-game/scraper/run.sh ``` There's also a **draft reminder** that runs every 15 minutes during draft season. ### 7.3 Manual scrape If you need to run the scraper right now: ```bash cd /root/shark-game source .venv/bin/activate python3 scraper/scrape.py >> data/scraper.log 2>&1 deactivate ``` Or use the wrapper script: ```bash cd /root/shark-game && bash scraper/run.sh ``` ### 7.4 Check scraper results ```bash tail -50 /root/shark-game/data/scraper.log ``` ```bash cat /root/shark-game/data/pending-scores.json ``` ### 7.5 View the current cron jobs ```bash crontab -l ``` You should see entries for the scraper and draft reminder. --- ## 8. Push Notifications — How They Work The game uses **Web Push API** (browser push notifications): 1. **VAPID keys** authenticate the server to send pushes 2. **Service worker** (`/var/www/shark-game/sw.js`) receives pushes in the browser 3. **Users** subscribe via the browser's permission prompt when they visit the site **VAPID keys** are stored as environment variables and embedded in the server code at `/root/shark-game/backend/server.py`. They include: - `VAPID_PRIVATE_KEY` - `VAPID_PUBLIC_KEY` - `VAPID_CLAIMS` → `mailto:g@germainebrown.com` **Push subscription data** is stored in the `push_subscriptions` table in the database. ### Push notification test ```bash curl -X POST https://shark.iamgmb.com/api/push/test ``` ### Check if users are subscribed ```bash sqlite3 /root/shark-game/backend/game.db "SELECT COUNT(*) FROM push_subscriptions;" ``` --- ## 9. Quick Command Reference ### Service Management ```bash systemctl status shark-game # Check if running systemctl restart shark-game # Restart the backend systemctl stop shark-game # Stop the backend systemctl start shark-game # Start the backend ``` ### Logs ```bash journalctl -u shark-game -n 100 # Last 100 log lines journalctl -u shark-game -n 100 -f # Live tail journalctl -u shark-game --since today # Today's logs journalctl -u shark-game -n 200 | grep -i error # Errors only ``` ### Database ```bash sqlite3 /root/shark-game/backend/game.db "SELECT * FROM users;" sqlite3 /root/shark-game/backend/game.db "SELECT * FROM leagues;" sqlite3 /root/shark-game/backend/game.db "SELECT * FROM scores ORDER BY created_at DESC LIMIT 20;" sqlite3 /root/shark-game/backend/game.db "SELECT id, display_name, email FROM users WHERE is_admin=1;" sqlite3 /root/shark-game/backend/game.db "PRAGMA integrity_check;" ``` ### Scraper ```bash cd /root/shark-game && bash scraper/run.sh # Force scrape now tail -50 /root/shark-game/data/scraper.log # View scraper log cat /root/shark-game/data/pending-scores.json # View pending scores crontab -l # List scheduled jobs ``` ### Backups ```bash cp /root/shark-game/backend/game.db /root/shark-game/backend/game.db.backup.$(date +%Y%m%d) aws s3 ls s3://hermes-vps-backups/ --endpoint-url https://s3.us-east-1.wasabisys.com systemctl stop shark-game aws s3 cp s3://hermes-vps-backups/live-sync/state.db /root/shark-game/backend/game.db \ --endpoint-url https://s3.us-east-1.wasabisys.com systemctl start shark-game ``` ### Port / Network ```bash fuser -k 8083/tcp ss -tlnp | grep 8083 curl -I https://shark.iamgmb.com curl http://127.0.0.1:8083/ ``` ### Push Notifications ```bash curl -X POST https://shark.iamgmb.com/api/push/test curl https://shark.iamgmb.com/api/push/vapid-public-key sqlite3 /root/shark-game/backend/game.db "SELECT COUNT(*) FROM push_subscriptions;" ``` --- ## 10. Complete Recovery Flow — If Everything Is Broken Follow these steps in order if the entire game is down. ### Step 1: Check server is reachable ```bash ping -c 2 shark.iamgmb.com ``` ### Step 2: Check web server (Caddy) ```bash systemctl status caddy # If not running: systemctl restart caddy ``` ### Step 3: Check backend service ```bash systemctl status shark-game # If not running: systemctl start shark-game ``` ### Step 4: Check port 8083 ```bash ss -tlnp | grep 8083 # If nothing listening: systemctl restart shark-game # If wrong process: fuser -k 8083/tcp && systemctl restart shark-game ``` ### Step 5: Check the database ```bash sqlite3 /root/shark-game/backend/game.db "PRAGMA integrity_check;" # Should return "ok" ``` ### Step 6: Check the scraper ran today ```bash tail -20 /root/shark-game/data/scraper.log # If last run was yesterday, run it manually cd /root/shark-game && bash scraper/run.sh ``` ### Step 7: Test the site ```bash curl -I https://shark.iamgmb.com # Should return HTTP/2 200 ``` ### Step 8: Restore from backup (if DB is corrupted) ```bash systemctl stop shark-game aws s3 cp s3://hermes-vps-backups/live-sync/state.db /root/shark-game/backend/game.db \ --endpoint-url https://s3.us-east-1.wasabisys.com systemctl start shark-game ``` --- ## 11. File Locations Map | What | Path | |------|------| | Backend server | `/root/shark-game/backend/server.py` | | Database | `/root/shark-game/backend/game.db` | | Python virtual environment | `/root/shark-game/backend/venv/` | | Frontend files | `/var/www/shark-game/` | | Service worker (push) | `/var/www/shark-game/sw.js` | | Scraper script | `/root/shark-game/scraper/scrape.py` | | Scraper wrapper | `/root/shark-game/scraper/run.sh` | | Scraper dependencies | `/root/shark-game/scraper/requirements.txt` | | Scraper log | `/root/shark-game/data/scraper.log` | | Pending scores | `/root/shark-game/data/pending-scores.json` | | Systemd service | `/etc/systemd/system/shark-game.service` | | Caddy config | `/etc/caddy/Caddyfile` | --- ## 12. Database Tables Reference | Table | Purpose | |-------|---------| | `users` | Players — email, display name, admin status, notification prefs | | `leagues` | Leagues — name, invite code, status (draft/active/closed), max players | | `league_members` | Which users belong to which leagues | | `league_excluded_regions` | Regions excluded from a league's draft | | `regions` | Shark attack regions (geo-areas players draft) | | `draft_picks` | Which player drafted which region in which league | | `scores` | Score events — what happened, how many points, which region | | `user_scores` | Running total scores per user | | `push_subscriptions` | Web push notification subscriptions | --- ## 13. Environment Variables | Variable | Purpose | |----------|---------| | `VAPID_PRIVATE_KEY` | Private key for Web Push notifications | | `VAPID_PUBLIC_KEY` | Public key for Web Push notifications | To check if they're loaded: ```bash systemctl show shark-game -P Environment ``` --- ## 14. Contact / Escalation If you've tried everything in this manual and the game is still broken: 1. **Save the logs:** ```bash journalctl -u shark-game -n 500 > /tmp/shark-game-logs.txt ``` 2. **Save the database:** ```bash cp /root/shark-game/backend/game.db /root/shark-game/backend/game.db.crash ``` 3. **Send me the files.** I can work from logs alone if needed. --- > **🦈 Remember:** The most common fix is simply `systemctl restart shark-game`. Try that first before doing anything complicated!