Skip to content

1tsRajOwO/stackup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

59 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StackUp — Swipe for your stack

STACKUP

Swipe for your stack. LFG across games.

Dating-app energy for Looking For Group — filter by game, swipe the pool,
party-code rooms, Discord connect, hide Discord + in-app chat.

Live app Marketing Release MIT Free forever Stars Next.js 16 Desktop

Open live app · Marketing · Downloads · Quick Start · Features


MIT · free forever core · calver 26.07.18

Surface URL
Live app stackup-lfg.is-a.dev · fallback stackup-three.vercel.app
Marketing GitHub Pages (/docs)
Desktop Releases — Windows .exe + Mac arm64 .dmg

Not affiliated with Riot Games.

Features

Swipe discovery Pass / Interested card stack — not a boring table
LFG rooms Party codes (in-game or StackUp) · join by code · room chat
Discord OAuth connect · optional hide Discord · Rich Presence on desktop
In-app chat DMs after Interested + room threads
Filters Game · server · language · rank · role · vibe · Verified
Desktop Electron Win + Mac · Windows in-app updates
Skins Radiant / Noir Brass / Harbor / Signal
Ops Admin console · optional Discord.js boards + feedback triage

Stack

Next.js 16 · Auth.js · Supabase · Discord.js · Electron · Tailwind 4 · GitHub Pages marketing

Quick Start

git clone https://github.com/1tsRajOwO/stackup.git
cd stackup
npm install
cp .env.example .env.local   # Discord/Google OAuth + Supabase
npm run dev                  # http://localhost:3000

Sign in → swipe Looking cards → Start LFG → join a room → Chat → Profile → Hide Discord.

Demo credentials (STACKUP_ALLOW_DEMO=1) are for local/tests only — not packaged desktop.

Production credentials (5 minutes)

1. Discord Developer Portal

  1. Create an app at Discord Developer Portal
  2. General Information → App Icon — upload StackUp’s logo (electron/resources/icon.png, 512×512+). Without this, Discord’s authorize page shows a blank icon when users click Continue with Discord. Re-upload anytime with npm run discord:upload-icon, or full branding (icon + cover + bot banner + description) with npm run discord:brand.
  3. OAuth2 → Redirects (must match exactly):
    • Web / npm run dev: http://localhost:3000/api/auth/callback/discord
    • Desktop app: http://localhost:17832/api/auth/callback/discord
    • Optional twin: http://127.0.0.1:17832/api/auth/callback/discord
    • Production web URL later (e.g. https://YOUR_DOMAIN/api/auth/callback/discord)
  4. Copy Client IDAUTH_DISCORD_ID (and optionally DISCORD_BOT_CLIENT_ID)
  5. Copy Client SecretAUTH_DISCORD_SECRET
  6. (Optional) Bot token → DISCORD_BOT_TOKEN
  7. General Information → Terms of Service URL and Privacy Policy URL (required for many public / discoverable Discord apps):
    • Prefer the deployed Next.js app (NEXT_PUBLIC_APP_URL):
      • Terms: https://YOUR_DOMAIN/terms
      • Privacy: https://YOUR_DOMAIN/privacy
    • Until the app is public, you can use the GitHub Pages mirrors:
      • Terms: https://1tsrajowo.github.io/stackup/terms.html
      • Privacy: https://1tsrajowo.github.io/stackup/privacy.html
    • Community Guidelines (optional support / description link): /guidelines or https://1tsrajowo.github.io/stackup/guidelines.html
  8. (Optional, desktop) Rich Presence → Art Assets — upload keys stackup, looking, in_match, idle from docs/assets/discord-rp-*.png (generated by branding prep) so Discord shows images with Looking / In Match / LFG status. Portal only — not uploadable via Bot API.

Local StackUp already uses Discord app 1527795268878205092 in .env.local — confirm both redirect URIs above are listed in the Developer Portal.

2. Google Cloud Console (Desktop / Electron)

  1. Create OAuth client at Google Cloud Console
  2. Application type: Desktop app (Installed)
  3. Copy Client ID → AUTH_GOOGLE_ID, Client Secret → AUTH_GOOGLE_SECRET
  4. Keep AUTH_GOOGLE_MODE=desktop (default)

StackUp’s Electron shell runs Google OAuth via loopback + PKCE (system browser → http://127.0.0.1:<port>), then finishes the Auth.js session. Use npm run desktop:dev (or the packaged app) for Google sign-in.

For browser-only Google (Web application client), set AUTH_GOOGLE_MODE=web and add redirect http://localhost:3000/api/auth/callback/google.

You can enable Discord, Google, or both. At least one is required for production auth.

3. Auth secret

openssl rand -base64 32

Set as AUTH_SECRET.

Optional anti-bot: AUTH_MIN_DISCORD_AGE_DAYS=7 (default) rejects brand-new Discord accounts.

4. Supabase

  1. Create a project at supabase.com
  2. Copy URL → SUPABASE_URL, service role key → SUPABASE_SERVICE_ROLE_KEY
  3. SQL Editor: run supabase/schema.sql (or apply migrations under supabase/migrations/)

5. Admin

Set ADMIN_DISCORD_IDS to your Discord user ID(s), comma-separated (Developer Mode → Copy User ID).
Optional: ADMIN_DISCORD_USERNAMES=1tsraj (case-insensitive) for feedback triage by username.

5b. Product feedback → Discord (optional)

In-app Report bug / Review posts to a Discord channel when configured. Staff triage from Discord buttons (or /feedback set) — status syncs with the ops Feedback tab.

Free path (recommended — no Railway): button clicks are handled by Vercel at /api/discord/interactions.

  1. Create a private channel (e.g. #stackup-feedback) on your ops guild
  2. Set on Vercel: DISCORD_FEEDBACK_CHANNEL_ID (falls back to reports → logs), DISCORD_BOT_TOKEN, DISCORD_PUBLIC_KEY, ADMIN_DISCORD_IDS / ADMIN_DISCORD_USERNAMES, Supabase keys
  3. Discord Developer Portal → your app → Interactions Endpoint URL (must be live HTTPS): https://stackup-three.vercel.app/api/discord/interactions
    When stackup-lfg.is-a.dev DNS is live, switch to
    https://stackup-lfg.is-a.dev/api/discord/interactions.
    Discord will PING the endpoint — it must return PONG (requires a deploy with this route).
  4. Ensure the bot token can Send Messages, Embed Links, and message components in that channel
  5. Optional: DISCORD_STAFF_ROLE_ID for mods; always includes ADMIN_DISCORD_IDS / ADMIN_DISCORD_USERNAMES

Apply migration supabase/migrations/20260718150000_product_feedback_discord.sql (or re-run schema.sql) so feedback rows can store Discord message IDs for sync.

Room joins require add_room_member_if_capacity and leaves require remove_room_member_and_reopen (migrations 20260718143000_* / 20260718160000_*). Apply those before deploying join-by-code / leave changes or joins will 500.

6. Public app URL

NEXT_PUBLIC_APP_URL=https://stackup-lfg.is-a.dev
AUTH_URL=https://stackup-lfg.is-a.dev

Used for metadata, PWA, wiring GitHub Pages CTAs (?app= or <meta name="stackup-app"> in /docs), and as the base for Discord Developer Portal Terms / Privacy URLs (/terms, /privacy).

Surface Terms Privacy Guidelines
Next.js app (prefer for Discord Portal) https://stackup-lfg.is-a.dev/terms https://stackup-lfg.is-a.dev/privacy https://stackup-lfg.is-a.dev/guidelines
GitHub Pages marketing terms.html privacy.html guidelines.html

Deploy

Surface Where Notes
Web app Vercel + free is-a.dev Canonical: stackup-lfg.is-a.dev
Marketing GitHub Pages Served from main /docs1tsrajowo.github.io/stackup
Desktop GitHub Releases Windows Setup .exe + Mac arm64 .dmg / .zip
Database Supabase free tier Postgres via SUPABASE_*
Discord boards / feedback posts Vercel → Discord REST DISCORD_BOT_TOKEN + channel IDs
Feedback triage buttons Vercel /api/discord/interactions Free 24/7 — works even if bot looks offline
Discord Online presence + /lfg Mac LaunchAgent (free) or Fly.io Gateway WebSocket — see below

Free domain (stackup-lfg.is-a.dev)

Registered via GitHub (no DigitalPlat / no browser signup):

  1. PR opened: is-a-dev/register#44024
  2. Domain already added on the Vercel stackup project (pending DNS verify)
  3. After maintainers merge the PR, DNS publishes in a few minutes → Vercel auto-verifies
  4. Set production env NEXT_PUBLIC_APP_URL + AUTH_URL to https://stackup-lfg.is-a.dev
  5. Discord OAuth redirect: https://stackup-lfg.is-a.dev/api/auth/callback/discord

Until then, the app stays live at https://stackup-three.vercel.app

Vercel (CLI)

npx vercel login
npx vercel          # preview
npx vercel --prod   # production

Then in the Vercel project → Settings → Environment Variables, paste values from .env.example. Set Discord OAuth redirect to https://stackup-lfg.is-a.dev/api/auth/callback/discord.

Production env checklist (Vercel web)

Keep / set on Vercel:

Variable Purpose
DISCORD_BOT_TOKEN Channel posts via Discord REST from Next.js
DISCORD_LOOKING_CHANNEL_ID / DISCORD_IN_MATCH_CHANNEL_ID / DISCORD_IDLE_CHANNEL_ID Live boards
DISCORD_LOGS_CHANNEL_ID Patch / ops details (never use generic webhook for private patch details)
DISCORD_LOGS_WEBHOOK_URL Optional logs-only webhook for patches
DISCORD_REPORTS_CHANNEL_ID Reports + appeals (optional; falls back to logs)
DISCORD_FEEDBACK_CHANNEL_ID Product bug / review embeds
DISCORD_WEBHOOK_URL Optional alternate post path (public boards — not for patch details)
DESKTOP_ATTEST_SECRET Same value on Vercel + GitHub Actions DESKTOP_ATTEST_SECRET secret — desktop join gate
DISCORD_PUBLIC_KEY Interactions signature verify (Developer Portal → Public Key)
ADMIN_DISCORD_IDS Ops console + feedback triage (Discord user snowflakes)
ADMIN_DISCORD_USERNAMES Optional triage by username (e.g. 1tsraj)
Channel map from npm run discord:provision (DISCORD_CH_*) Optional lean data channels

Unset / remove on Vercel (unless you intentionally use bot ingest):

Variable Why
DISCORD_BOT_INGEST_URL Points at optional Railway/local bot HTTP ingest — not required for REST posts
DISCORD_BOT_INGEST_SECRET Only for optional gateway bot

Without ingest vars on Vercel, Discord notifications still work via REST/webhooks. Feedback button clicks work via /api/discord/interactions (no always-on bot).

Feedback triage without Railway (free)

  1. Deploy the app so POST /api/discord/interactions is live.
  2. Discord Developer Portal → Application → Interactions Endpoint URL =
    https://stackup-three.vercel.app/api/discord/interactions
    (switch to https://stackup-lfg.is-a.dev/api/discord/interactions once that domain resolves to Vercel).
  3. Save — Discord sends a PING; the route must respond with type 1 (PONG).
  4. Set ADMIN_DISCORD_IDS / ADMIN_DISCORD_USERNAMES on Vercel so your account can press Reviewing / Resolved / Dismissed.
  5. You can run without a paid always-on host — buttons hit Vercel.

Online gateway (Discord member list)

Discord only shows StackUp Online when a gateway process holds a WebSocket (same idea as Lumen running on your Mac). Feedback buttons do not need this.

Free on your Mac (like Lumen):

# Foreground
npm run bot
# or
bash scripts/run-bot-local.sh

# Optional: start at login (KeepAlive)
cp scripts/com.stackup.discord-bot.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.stackup.discord-bot.plist

Unload with launchctl bootout gui/$(id -u)/com.stackup.discord-bot. Do not run this and Fly at the same time (one token = one session).

Fly.io (remote 24/7): fly.toml + Dockerfile.bot + scripts/deploy-bot-fly.sh. Fly’s free allowance still requires a card on file (no charge for small bots in many regions). After billing is enabled:

fly auth login
bash scripts/deploy-bot-fly.sh
# Health: https://stackup-discord-bot.fly.dev/health

Then stop the local LaunchAgent / npm run bot so sessions don’t fight.

Wire Pages → App

Ops / desktop CTAs already target the free domain:

<meta name="stackup-app" content="https://stackup-lfg.is-a.dev" />

Override anytime with ?app=https://….

Install as an app (PWA)

  • Desktop (Chrome/Edge): address bar → install icon, or menu → “Install StackUp”
  • iOS Safari: Share → Add to Home Screen
  • Android Chrome: menu → Install app / Add to Home screen

Starts at /looking in standalone mode.

Desktop app

StackUp ships as a lightweight Electron shell around the Next.js standalone server on a fixed loopback port (http://localhost:17832) so Discord OAuth redirects stay stable.

Public distribution is Windows + Mac (Apple Silicon). Users get the NSIS installer / Mac DMG from GitHub Releases. Windows also gets in-app updates (latest.yml + StackUp-Setup-*.exe).

Platform Asset Role
Windows StackUp-Setup-26.7.18.exe Public desktop + auto-update feed
Mac (arm64) StackUp-26.7.18-mac-arm64.dmg Public desktop (ad-hoc signed; use Fix Gatekeeper if needed)

Also: all releases · tag v26.07.18 (calver). Artifact filenames use electron-builder’s 26.7.18.

Desktop shell features

  • Context isolation, sandbox, no remote, DevTools stripped in production
  • Ships Next standalone + static only (not the full monorepo node_modules)
  • System tray — close hides to tray; menu: Show · Check for updates · Quit
  • Discord Rich Presence — Looking / In Match / LFG room on Discord (Profile → Desktop → toggle)
  • In-app updateselectron-updater (silent check on launch + Update button in header / Profile)
  • Subtle window fade-in + polished update button motion

Dev (Electron + Next)

npm run desktop:dev

Starts next dev and opens Electron at http://127.0.0.1:3000.

Build Windows (.exe) — public

Prefer GitHub Actions (tag push attaches Windows + Mac installers to the Release):

  1. Push a version tag (v26.07.18) or run Actions → Desktop builds → Run workflow
  2. Users install from Releases (Windows can also update in-app via Check for updates)

Patch notes (app · website · GitHub · Discord)

Edit patches.json (newest first). Each entry has a public summary and organized details.

Surface What users see
App (What's new + desktop settings) Summary only
Website /updates Summary only
GitHub Release body Summary only (CI writes release-notes.md)
Discord #stackup-logs Full organized details (channel is private)
# Dry-run / post full details to Discord logs
npm run patch:announce
npm run patch:announce -- 26.07.18

# Write release-notes.md for GitHub (summary)
npm run patch:github-notes

Re-apply private log channels after Discord layout changes:

npm run discord:provision

Locally (on Windows):

npm run desktop:build:win

Build Mac (Apple Silicon)

Mac is published on public Releases (DMG + zip + latest-mac.yml). CI also keeps the stackup-mac-arm64 artifact.

npm run desktop:build:mac

Builds use ad-hoc codesign (identity: "-") — no paid Apple Developer / CA cert required. The DMG includes Fix Gatekeeper.command (manual only — never auto-runs on app launch). Install once: quit StackUp, drag to Applications (or accept the in-app Install prompt), eject the DMG, and keep only /Applications/StackUp.app.

If Mac says “StackUp is damaged and can’t be opened”

That is Gatekeeper quarantine on an unsigned/ad-hoc build — not a broken file. After dragging StackUp.app into Applications:

  1. Double-click Fix Gatekeeper.command on the DMG, or
  2. Run: xattr -cr /Applications/StackUp.app
  3. Or right-click StackUp → Open once (if macOS offers that path)
  4. Then launch StackUp from Applications (not from the Terminal helper)

If Mac shows two StackUp apps / Dock icons

Usually an old copy is still installed alongside a new one. Before installing a new DMG:

  1. Quit StackUp fully (tray menu → Quit, or Activity Monitor → quit all StackUp)
  2. Remove older copies: /Applications/StackUp.app, any StackUp.app in Downloads, and eject/unmount old DMGs
  3. Drag the new StackUp.app into Applications (replace when asked)
  4. Launch only from Applications — do not keep running from the mounted DMG

The app enforces a single instance (com.stackup.app).

Pack (unpacked dir only)

npm run desktop:pack
Script Description
npm run desktop:dev Electron + Next dev
npm run desktop:build:win Windows NSIS .exe (public Release)
npm run desktop:build:mac Mac arm64 DMG/zip (public Release)
npm run desktop:pack Unpacked app dir

Security: Release installers load the hosted web origin (STACKUP_WEB_ORIGIN, default https://stackup-lfg.is-a.dev). They do not ship SUPABASE_SERVICE_ROLE_KEY, OAuth client secrets, or Discord bot tokens. Local embedded Next (STACKUP_EMBEDDED_SERVER=1) reads secrets only from userData .env.

App id: com.stackup.app · product name: StackUp · version: 26.07.18.

Desktop Discord OAuth redirect for embedded / desktop:dev (register in Discord Developer Portal):

http://localhost:17832/api/auth/callback/discord

Windows SmartScreen + code signing

Unsigned Windows builds may show “Windows protected your PC” (SmartScreen) — this is not a BSOD. StackUp’s builder config already sets:

  • win.signtoolOptions.publisherName, signingHashAlgorithms: [sha256]
  • signAndEditExecutable: true (version / resource metadata)
  • requestedExecutionLevel: asInvoker

For full SmartScreen trust, add a real Authenticode certificate (do not invent or commit fake certs). Store as GitHub Actions secrets only:

Secret Purpose
CSC_LINK Base64 of the .pfx (or path/URL — see electron-builder)
CSC_KEY_PASSWORD Certificate password

The Windows CI job wires these automatically and enables signing when CSC_LINK is set. Signing is not active until secrets are added. Exact steps: docs/CODE_SIGNING.md. Until then, users may need More info → Run anyway.

Auto-updates

Packaged Windows apps check GitHub Releases via electron-updater (publish.provider: github, repo 1tsRajOwO/stackup). Users tap Check for updates in the header or Profile → Desktop. Already latest shows green You’re up to date; real errors (network / download) show red Update failed. After download, Restart to update installs and relaunches.

Mac installs from the public DMG on Releases. In-app auto-update stays off (avoids Gatekeeper / relaunch churn on ad-hoc builds) — grab the next DMG when a new version ships.

Security

  • Never commit .env / .env.local (gitignored)
  • Use Discord OAuth secrets and Supabase service role only on the hosted server (never in public desktop installers)
  • Admin routes gated by ADMIN_DISCORD_IDS
  • Repo enables Dependabot, vulnerability alerts, and secret scanning where available — see SECURITY.md

Scripts

Script Description
npm run dev Next.js dev server
npm run build Production build (includes standalone for desktop)
npm run start Start production server
npm run bot Local gateway (Online + /lfg). Or LaunchAgent / Fly — see Online gateway. Buttons use Vercel interactions.
npm run lint ESLint
npm run desktop:dev Electron + Next dev
npm run desktop:build:mac Build Mac desktop app (maintainer / CI artifact only)
npm run desktop:build:win Build Windows .exe (public Release / or use CI)
npm run desktop:pack Pack unpacked desktop app

Soft-launch checklist

  • Schema applied in Supabase (incl. rooms + chat + hide_discord)
  • Discord OAuth end-to-end
  • Card stack Pass / Interested works
  • Start LFG shows team code; join by code works
  • Hide Discord forces in-app chat
  • Room + DM chat poll updates
  • Filters (server, language, rank, role) work
  • In Match hides from Looking pool
  • Admin can close rooms
  • NEXT_PUBLIC_APP_URL set; Pages CTAs point at the app
  • Discord Portal Terms (/terms) + Privacy (/privacy) URLs set
  • Privacy / Terms / Guidelines reviewed for your deployment
  • Invite 1–2 friend Discords / Valo servers

Versioning

Releases use calendar versioning YY.MM.DD (e.g. 26.07.18), tagged v26.07.18.
Desktop artifact filenames may drop zero-padding (26.7.18) — that’s electron-builder, not a different release.

License

MIT — free and open source forever. See LICENSE.

Core LFG (Discover, rooms, chat) stays free. Optional Stripe premium — if enabled on a deployment — is an add-on only; you never need it for basic stacking.

Free hosting

Surface Free host
Web app Vercel (Hobby)
Marketing site GitHub Pages from /docs
Discord feedback buttons Vercel /api/discord/interactions (no always-on bot)

About

Swipe for your stack. Discord-connected multi-game LFG — MIT, free forever. Calver v26.07.18.

Topics

Resources

License

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors