Pump Shinsa is a full-stack Pump It Up community platform for running tournaments and duels, sharing score progress, and organizing player communities.
It combines:
- competitive tools (round-robin tournaments, gauntlet finals, offline/online duels)
- social features (posts, follows, comments, reactions, activity feed)
- PIUGame sync (pumbility, best scores, recently played)
- notifications (in-app, SSE real-time stream, optional web push)
- PWA support (installable app + offline fallback)
- Create/manage tournaments with metadata and custom round difficulty ranges.
- Generate full round-robin matches per round.
- Match flow: draw songs -> veto phase -> submit result.
- Optional gauntlet phase after round robin:
- seeded from standings
- escalating difficulty
- winner advances to next match
- Standings with wins/losses/points and Buchholz tie-break.
- Offline duels:
- create duel cards manually
- draw random songs by level/mode
- submit scores and auto-resolve duel winner
- Online duels:
- invitation-based player matching
- turn-based draw/accept/decline flow
- live room polling for state + chat
- spectator/player “pump” reactions
- end-duel handshake where both players must request end
- User registration/login/profile editing.
- Follow/unfollow users.
- Post feed with:
- text + image uploads (compressed server-side)
- optional YouTube links
- threaded comments/replies
- post/comment reaction (“pump”) toggles
- Score activity content:
- upscore posts (improved scores)
- new clear posts (first clears)
- comments/replies/reactions per item type
- Public recent activity aggregation on dashboard.
- Create communities with custom slug, avatar/banner, badges.
- Open or invite-only membership model.
- Owner/moderator role controls.
- Join requests workflow for private communities.
- Member tags and tag assignment.
- Community-specific posts/comments/reactions.
- Mention suggestions and mention notifications.
- Store encrypted PIUGame credentials.
- Sync endpoints:
- pumbility scores
- full best scores import (background task + progress)
- recently played import
- Creates social activity entries from score improvements/new clears.
- Notification records persisted in SQLite.
- SSE stream endpoint for near real-time notification delivery.
- Optional Web Push (VAPID-based) for browser push notifications.
- Invitation and interaction notifications integrated across features.
- Web app manifest + icons.
- Service worker caching strategy:
- precache app shell assets
- runtime cache for pages/assets
- offline fallback page (
/offline.html)
- React 18
- React Router 6
- Vite 6
- Tailwind CSS
- Recharts (analytics charts)
- Node.js + Express
- better-sqlite3 (SQLite)
- JWT auth (
jsonwebtoken) - Password hashing (
bcryptjs) - File uploads (
multer) + image processing (sharp)
- PIUGame scraping:
axios,cheerio,tough-cookie - Browser push:
web-push - Optional OCR parser pipeline: Python + OpenCV + RapidOCR
- PM2 config included (
ecosystem.config.js)
.
├── client/ # React + Vite frontend
│ ├── src/
│ └── public/
├── server/ # Express API + DB schema/routes/libs
│ ├── db/
│ ├── routes/
│ ├── lib/
│ └── piu_score_parser.py
├── pump-phoenix.json # Song/chart data source for bootstrap/seed
├── ecosystem.config.js # PM2 process config
└── package.json # Root scripts (server + client orchestration)
- Node.js
18+(20 LTS recommended) - npm
9+ - Python
3.10+(optional, only needed for OCR endpoint) - pip (optional, for OCR dependencies)
- Install root dependencies:
npm install- Install frontend dependencies:
cd client
npm install
cd ..- (Optional) Install OCR Python dependencies (only if you will use
/api/parser/score):
python3 -m pip install -r server/requirements.txt- Start full dev stack (API + Vite dev server):
npm run dev- Open:
- frontend:
http://localhost:5173 - API:
http://localhost:3001
In development, Vite proxies /api and /uploads to port 3001.
This project does not currently load .env automatically with dotenv; set env vars in your shell, PM2 config, or process manager.
| Variable | Default | Required in Prod | Purpose |
|---|---|---|---|
PORT |
3001 |
No | Express server port |
DB_PATH |
server/db/shinsa.db |
Yes (recommended) | SQLite file path |
NODE_ENV |
unset | Yes | Runtime mode |
JWT_SECRET |
hardcoded fallback | Yes | JWT signing secret |
PIU_ENCRYPT_KEY |
hardcoded fallback | Yes | Encrypt/decrypt PIUGame credentials |
APP_URL |
http://localhost:5173 |
Yes | Public app origin used for OAuth callback redirects |
YOUTUBE_CLIENT_ID |
empty | If YouTube sync used | Google OAuth client ID for YouTube linking |
YOUTUBE_CLIENT_SECRET |
empty | If YouTube sync used | Google OAuth client secret for YouTube linking |
YOUTUBE_REDIRECT_URI |
${APP_URL}/api/youtube/oauth/callback |
If YouTube sync used | Must match the Google OAuth redirect URI exactly |
YOUTUBE_OAUTH_SCOPES |
https://www.googleapis.com/auth/youtube.force-ssl |
No | Space/comma separated scopes to request from Google |
YOUTUBE_OAUTH_STATE_SECRET |
JWT_SECRET fallback |
Yes (recommended) | Signs the temporary OAuth state payload |
YOUTUBE_ENCRYPT_KEY |
PIU_ENCRYPT_KEY fallback |
Yes (recommended) | Encrypts stored YouTube access/refresh tokens |
VAPID_SUBJECT |
mailto:support@pumpshinsa.com |
If push used | Web push VAPID subject |
VAPID_PUBLIC_KEY |
empty | If push used | Web push public key |
VAPID_PRIVATE_KEY |
empty | If push used | Web push private key |
Generate VAPID keys (if enabling push):
npx web-push generate-vapid-keys- DB schema and migrations run automatically at server startup (
initializeDb). - If
songstable is empty, charts are auto-bootstrapped frompump-phoenix.json. - You can force a clean reseed with:
npm run seedNote: npm run seed deletes and recreates the DB file.
npm run dev- run API + frontend togethernpm run server- run API onlynpm run client- run Vite dev server onlynpm run build- build frontend intoclient/distnpm run start- start API server (serves built frontend)npm run seed- reset DB and seed songs
npm run devnpm run buildnpm run preview
npm install
cd client && npm install && cd ..NODE_OPTIONS=--max-old-space-size=4096 npm run buildExample:
sudo mkdir -p /var/data/shinsa
sudo chown -R "$USER" /var/data/shinsaexport NODE_OPTIONS=--max-old-space-size=4096
export NODE_ENV=production
export PORT=3001
export DB_PATH=/var/data/shinsa/shinsa.db
export APP_URL='https://pumpshinsa.com'
export JWT_SECRET='replace-with-strong-secret'
export PIU_ENCRYPT_KEY='replace-with-strong-secret'
export YOUTUBE_CLIENT_ID='replace-with-google-client-id'
export YOUTUBE_CLIENT_SECRET='replace-with-google-client-secret'
# Optional overrides:
# export YOUTUBE_REDIRECT_URI='https://pumpshinsa.com/api/youtube/oauth/callback'
# export YOUTUBE_OAUTH_SCOPES='https://www.googleapis.com/auth/youtube.force-ssl'
# export YOUTUBE_OAUTH_STATE_SECRET='replace-with-strong-secret'
# export YOUTUBE_ENCRYPT_KEY='replace-with-strong-secret'
# Optional push:
# export VAPID_SUBJECT='mailto:you@example.com'
# export VAPID_PUBLIC_KEY='...'
# export VAPID_PRIVATE_KEY='...'npm run startThe Express server serves both API and built frontend (client/dist).
ecosystem.config.js already defines an app named shinsa.
pm2 start ecosystem.config.js
pm2 save
pm2 status- Put the app behind a reverse proxy (Nginx/Caddy) for TLS.
- Example Nginx config with gzip+brotli:
deploy/nginx/shinsa.conf.example. - Web Push requires HTTPS in real browsers (except localhost).
- Google OAuth for YouTube linking also requires HTTPS in production, a verified domain, and a redirect URI that exactly matches
APP_URL+/api/youtube/oauth/callbackunlessYOUTUBE_REDIRECT_URIis overridden. - Ensure outbound network access for PIUGame scraping endpoints.
- Persist and back up your SQLite database file.
Main API groups:
/api/tournaments,/api/players,/api/matches/api/duels,/api/online-duels/api/auth,/api/social,/api/communities/api/piugame/api/notices,/api/songs,/api/dashboard/api/parser/score(OCR score parsing endpoint)
Run npm run build first. Server expects client/dist.
Install Python deps:
python3 -m pip install -r server/requirements.txt- Ensure VAPID keys are set.
- Ensure site is served over HTTPS.
- Ensure browser permission is granted.
Set DB_PATH to a writable directory and ensure parent directory exists.
Confirm song data exists (pump-phoenix.json) and run npm run seed if needed.
- Replace fallback
JWT_SECRET. - Replace fallback
PIU_ENCRYPT_KEY. - Store secrets in your process manager/secret store, not in source.
- Use HTTPS and secure reverse proxy settings.
- Back up SQLite regularly.
No license file is currently included in this repository.