A self-hosted band management application for organising sheet music and coordinating live performances.
- Sheet music library — upload versioned PDF sheets per song/instrument combination; view and download from any device on your network
- Live mode — a lead musician broadcasts the current and upcoming song to all connected band members in real time (Server-Sent Events); followers can auto-navigate to their sheet
- Suggestion menu — during a live performance, filter the song catalogue by genre, tag, or target audience without breaking the flow
- Setlists — build ordered song lists for a gig; run live mode scoped to a setlist
- Click tracks — attach an audio file to any song; control playback and tempo from the app
- Metronome — built-in BPM metronome synced to the current song
- MIDI mappings — per-song, per-instrument MIDI channel/value configuration
- Offline bundles — export the full database (or a single setlist) as a
.tar.gz; restore it on a gig laptop with a single script so the band can run fully offline over a hotspot - Role-based access —
Adminusers manage the library;Guestusers view sheets and participate in live mode
Screenshots coming soon.
| Layer | Technology |
|---|---|
| Frontend | Vue 3 · TypeScript · Vite · Pinia · PrimeVue 4 (Aura theme) · Tailwind CSS |
| Backend | NestJS · TypeScript · Prisma ORM |
| Database | PostgreSQL 16 |
| Real-time | Server-Sent Events via NestJS + RxJS BehaviorSubject |
| PDF rendering | PDF.js (pdfjs-dist 4.x) |
| Reverse proxy | nginx (dev/offline) · Caddy (production with automatic HTTPS) |
| Containers | Docker · Docker Compose |
- Docker Desktop (includes Docker Compose)
git clone https://github.com/philippilievski/tunebase.git
cd tunebase
cp .env.example .envOpen .env and set the four required values:
POSTGRES_PASSWORD=<strong-random-password>
DATABASE_URL=postgresql://postgres:<strong-random-password>@db:5432/tunebase?schema=public
JWT_SECRET=<output-of: openssl rand -hex 32>
REGISTER_OTP=<passcode-you-share-with-band-members>Tip (Windows):
opensslis included with Git Bash. Open Git Bash and runopenssl rand -hex 32to generate the JWT secret.
docker compose up| Service | URL |
|---|---|
| Frontend (Vite dev server) | http://localhost:5173 |
| Backend API | http://localhost:3000 |
| PostgreSQL | localhost:5433 |
A seed admin account is created automatically in development:
| Field | Value |
|---|---|
admin@tunebase.dev |
|
| Password | admin123 |
Change the seed password before sharing the app with anyone. The seed user is never created in production builds.
# On your server
git clone https://github.com/philippilievski/tunebase.git
cd tunebase
# Configure
cp .env.production.example .env
# Edit .env — fill in all values (see Environment variables below)
# Edit Caddyfile — replace the placeholder domain with your real domain
nano Caddyfile
# Start
docker compose -f docker-compose.prod.yml up -d --buildCaddy handles TLS certificate provisioning automatically.
Set SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD in your .env before starting. The seed runs automatically on every start and is idempotent — the user is only created once.
SEED_ADMIN_EMAIL=your@email.com
SEED_ADMIN_PASSWORD=a-strong-passwordAfter the stack starts, log in with those credentials. You can then invite other band members via the registration page (they'll need the REGISTER_OTP).
Use this when your venue has no internet and you want the band to connect to your laptop over a hotspot.
- Open Settings → Offline Bundle in the app
- Choose "Full dataset" or a specific setlist
- Click Download Bundle — saves a
.tar.gzfile
.\restore.ps1 tunebase-bundle-<timestamp>.tar.gz
# or double-click restore.bat and pick the file./restore.sh tunebase-bundle-<timestamp>.tar.gzThe script starts the stack on port 8080. Share http://<laptop-ip>:8080 with band members (they must be on your hotspot).
# Stop when done
docker compose -f docker-compose.local.yml down --volumes| Variable | Required | Description |
|---|---|---|
POSTGRES_PASSWORD |
Yes | PostgreSQL password for the postgres user |
DATABASE_URL |
Yes | Full Prisma connection string — must embed the same password |
JWT_SECRET |
Yes | Secret used to sign JWT tokens. Generate: openssl rand -hex 32 |
REGISTER_OTP |
Yes | One-time passcode required for new user registration |
SEED_ADMIN_EMAIL |
No | If set together with SEED_ADMIN_PASSWORD, seeds this user as Admin on start |
SEED_ADMIN_PASSWORD |
No | Password for the seeded admin (plaintext — hashed before storage) |
CORS_ORIGIN |
No | Allowed CORS origin(s), comma-separated. Leave unset behind nginx. |
All development variables plus:
| Variable | Required | Description |
|---|---|---|
POSTGRES_USER |
Yes | PostgreSQL username (default: postgres) |
POSTGRES_DB |
Yes | PostgreSQL database name (default: tunebase) |
SEED_ADMIN_EMAIL |
Recommended | Email for the initial admin account |
SEED_ADMIN_PASSWORD |
Recommended | Password for the initial admin account |
| Secret | Description |
|---|---|
SSH_HOST |
Server hostname or IP |
SSH_USER |
SSH username |
SSH_PRIVATE_KEY |
Private key for SSH authentication |
DEPLOY_PATH |
Absolute path on the server where the repo lives |
Requires Node.js 20+ and a running PostgreSQL instance.
# Terminal 1 — backend (Postgres must be on port 5433, or set DATABASE_URL)
cd backend
cp .env.example .env # edit DATABASE_URL to point to your local Postgres
npm install
npx prisma migrate deploy
npx prisma db seed
npm run start:dev
# Terminal 2 — frontend (Vite proxies /api to localhost:3000)
cd frontend
npm install
npm run devtunebase/
├── frontend/src/
│ ├── api/ # Service layer — one class per resource
│ ├── components/ # Feature-organised Vue components
│ ├── stores/ # Pinia stores
│ ├── views/ # Route-level views (including /admin/*)
│ └── utils/ # Toast, PDF render, date helpers
├── backend/src/
│ ├── controllers/ # One controller per resource
│ ├── services/ # Business logic + Prisma queries
│ ├── guards/ # AuthGuard + RolesGuard (APP_GUARD)
│ ├── decorators/ # @Roles(), @Public()
│ └── export/ # ExportModule — streams .tar.gz bundles
├── backend/prisma/
│ └── schema.prisma # Source of truth for the data model
├── docker-compose.yml # Development stack
├── docker-compose.prod.yml # Production (Caddy + NestJS + Postgres)
├── docker-compose.local.yml # Offline/gig mode
├── Caddyfile # Caddy reverse-proxy config (update domain before deploying)
├── .env.example # Variable reference for development
├── .env.production.example # Variable reference for production
├── restore.sh # Offline restore — Linux/Mac
├── restore.ps1 # Offline restore — Windows
└── restore.bat # Double-click restore launcher — Windows
See CONTRIBUTING.md.