# Loot Hunt A digital alternate reality game — find and scan hidden QR codes in real life to earn points and climb the leaderboard. ## How It Works 1. **Admins** create hunts, manage all content, assign roles, and reset passwords 2. **Organizers** create and manage their own hunts with printable QR code cards 3. **Players** scan hidden QR codes to earn points — first find gets the most points 4. **Leaderboards** track top players per hunt and globally ### Point System | Scan Order | Points | |-----------|--------| | 1st scan | 500 | | 2nd scan | 250 | | 3rd scan | 100 | | 4th+ | 50 | Players earn points only once per package. Re-scanning lets you update the package hint. ### Roles | Capability | Admin | Organizer | Player | |---|---|---|---| | Create hunts | Yes | Yes | No | | Manage/edit/delete own hunts | Yes | Yes | No | | Manage other users' hunts | Yes | No | No | | Download QR code PDFs | Yes | Own hunts | No | | Password reset | Yes | No | No | | Delete any image / clear hints | Yes | No | No | | Assign organizer role | Yes | No | No | ### Features - **QR Code Cards** — Printable Avery 5371 format PDFs with double-sided backs - **First Finder Photos** — First scanner can upload/replace an image per package - **Hints** — Most recent scanner can leave a message for the next finder - **Player Profiles** — Stats, rank, hunt breakdown, and recent activity - **Dark Mode** — Toggle with system preference detection and localStorage persistence - **Relative Timestamps** — "3h ago" format with full date on hover - **Flash Messages** — Feedback on actions (create, edit, delete, upload, etc.) - **Paginated Leaderboards** — 25 per page with navigation controls - **Admin Dashboard** — Hunt stats, top finders, discovery rate, recent scans, role management ## Tech Stack - **Node.js** + Express - **SQLite** via sql.js (WASM) - **EJS** templates - **PDFKit** + qrcode for printable QR sheets - **Docker** deployment via Portainer ## Quick Start (Development) ```bash cp .env.example .env npm install node src/setup-admin.js admin yourpassword npm run dev ``` Visit `http://localhost:3000` ## Docker Deployment The project deploys via Gitea Actions → Docker build → Portainer stack update. ```bash # Build locally docker build -t loot-hunt . # Run docker run -p 3000:3000 -v loot-data:/app/data \ -e SESSION_SECRET=your-secret \ -e BASE_URL=https://loot-hunt.com \ loot-hunt # Create admin user inside container docker exec -it loot-hunt node src/setup-admin.js admin yourpassword ``` ## Environment Variables | Variable | Description | Default | |----------|-------------|---------| | `PORT` | Server port | `3000` | | `NODE_ENV` | Environment | `production` | | `BASE_URL` | Public URL (for QR codes) | `http://localhost:3000` | | `SESSION_SECRET` | Session encryption key | (required) | | `DB_PATH` | SQLite database path | `./data/loot-hunt.db` | | `UPLOADS_DIR` | Image uploads directory | `./data/uploads` | | `TRUST_PROXY` | Trust reverse proxy headers | `false` | ## Project Structure ``` src/ ├── app.js # Express application entry point ├── setup-admin.js # CLI tool to create/promote admin users ├── config/ │ └── database.js # SQLite (sql.js) initialization, schema & migrations ├── middleware/ │ └── auth.js # Auth, admin & organizer middleware ├── models/ │ └── index.js # All database operations ├── routes/ │ ├── auth.js # Login/register/logout/password reset │ ├── admin.js # Hunt management, PDF download, roles, password reset │ ├── loot.js # QR scan handling, image upload, hints │ └── hunts.js # Public hunt profiles, leaderboards, player profiles ├── utils/ │ └── pdf.js # Avery 5371 QR code PDF generation └── views/ # EJS templates public/ ├── css/ │ └── style.css # Styles with dark mode support └── js/ └── timeago.js # Relative timestamp formatting ```