feat: modernize monorepo, vitest test suite, nextjs 15 dashboard rewrite, lavalink v4, and cloud docs - #829
Open
PhantomNimbi wants to merge 67 commits into
Open
feat: modernize monorepo, vitest test suite, nextjs 15 dashboard rewrite, lavalink v4, and cloud docs#829PhantomNimbi wants to merge 67 commits into
PhantomNimbi wants to merge 67 commits into
Conversation
…nd update now playing embed
…YouTube device flow auth to console
…s for interactive terminal view
… auth output and file log exclusion
… audit, and API key gating
…thout disk mutation
…d strip trailing JSON delimiters
…Redis keys in Queue.leave() unconditionally
…nce bot & dashboard - Upgrade Next.js to 15.2.0 and migrate App Router to async request APIs (await params, useParams) - Upgrade Auth.js/NextAuth to v5 beta with server action handlers and safe Discord avatar URL resolution - Upgrade @next/eslint-plugin-next to 15.2.0 and align environment parsers to @t3-oss/env-* 0.13.11 - Replace pure-ESM env wrapper in @master-bot/bot with native Zod schema parsing for 100% CJS compatibility - Wire dynamic feature flags (LAVA_ENABLED, GIFS_ENABLED, TWITCH_ENABLED, NEWS_ENABLED, IGDB_ENABLED) across bot preconditions - Connect automated cross-platform PostgreSQL and Redis service checks (connect-or-auto-launch) - Implement dynamic command help registry and standardized help tables across all 60 slash commands - Enhance web dashboard with active-tab sidebar navigation, server overview statistics, and Redis log streaming - Resolve next-themes hydration mismatch by adding suppressHydrationWarning to root layout
…sabled commands - Group slash commands into structured categories (GIFs & Anime, Twitch, News, Games & Entertainment, General & Utilities) - Filter out categories and individual commands disabled globally via environment feature flags (LAVA_ENABLED, GIFS_ENABLED, TWITCH_ENABLED, NEWS_ENABLED, IGDB_ENABLED) - Display server-specific enable/disable toggles and active status badges for all active commands
…ys monorepo-wide - Configure remoteCipher in application.yml with default endpoint (https://cipher.kikkia.dev/) and support custom YOUTUBE_CIPHER_URL / YOUTUBE_CIPHER_PASSWORD - Pass deterministic Java system properties (-D) for YouTube OAuth, skipInitialization, cipher, and Spotify credentials in launcher scripts - Wire YOUTUBE_CIPHER_URL and YOUTUBE_CIPHER_PASSWORD into @master-bot/bot, @master-bot/api, @master-bot/dashboard env schemas and .env.example - Display active cipher endpoint in dev and production console status banners
…ash command, and fix dual-domain auth
… remote cipher, and active music engine
…nds with fuzzy matching and scoring
…t, and add granular audit log dashboard
…on and ticket features
…, and README button
…eholders in app.json
… music controls - Add /reminder with background scheduler (ReminderManager), tRPC router, and dashboard management pages - Add /world-news command powered by NewsAPI with country and category filtering - Add interactive button-based /connect-four and /tic-tac-toe mini-games - Add dynamic 6-stage rotating StatusManager presence system - Replace /skip with Now Playing Next button and rename /skipto to /jump - Add repeat and shuffle action buttons to Now Playing embed and fix track duration display - Refactor /about to standard Discord subcommands (bot, server, user) - Implement cross-platform recursive killProcessTree in launcher scripts to eliminate zombie processes - Standardize CommandHelp help objects and deferred interaction handling across all commands
…erence - Add ticketRoleId to Guild model in Prisma schema and synchronize database - Add setRole procedure to tRPC tickets router - Add /set ticket-role and /set ticket-role-disable subcommands - Automatically add ticket manager role members to new support ticket threads and alert the role - Fix deferReply/editReply interaction conflict in /reminder command - Audit and align all 70 slash commands in README.md and wiki/Commands-Reference.md
- Restore /pat command with Klipy & Waifu.im API reaction gifs - Restore /now-playing command to display current track and interactive music controls on demand - Restore /weather command with wttr.in real-time meteorological reports and 3-day forecast - Restore /bored command with Bored API v2 and internal curated activity engine - Restore /poll command with interactive Discord button voting and live progress bars - Update README.md and wiki/Commands-Reference.md to document all 75 slash commands
…ashboard rewrite, and cloud docs - Fix dependency installation on clean clones by switching postinstall to db:generate - Add comprehensive Vitest test harness with 8 unit/integration test suites (16 tests, 100% pass) - Rewrite Next.js 15 App Router web dashboard with glassmorphism UI and dedicated feature studios (Music, Broadcast, Integrations, System Telemetry) - Expand backend tRPC v11 API routers with music, broadcast, and system health procedures - Add multi-cloud hosting guides (Render, Railway, Fly.io, Heroku, Docker VPS) with Mermaid architecture diagrams - Update CI/CD workflow with automatic formatting, linting, type-checking, vitest tests, and production build verification
…ckend, split session handlers, and rewrite docs
Migrate the entire stack away from PostgreSQL onto SQLite and restore the
dashboard API surface that was lost when packages/api was removed, while
retaining Lavalink + Redis for music/queue state.
\### Infrastructure \& dependencies
\- docker-compose.yml: drop the postgres service; keep Lavalink + Redis;
  add sqlite-data volume at /Master-Bot/packages/db/prisma; host logs now
  map to /Master-Bot/logs
\- docker.env: replace POSTGRES\_\* with DATABASE\_URL="file:./db.sqlite"
\- Dockerfile: remove stale POSTGRES\_HOST comment
\- scripts/{common,dev,start}.mjs: strip postgres service ensure/ports/status;
  show SQLite-backed status
\- pnpm-workspace.yaml: drop removed packages/api and packages/session
\- turbo.json: remove SHADOW\_DB\_URL (keep REDIS\_\* env)
\- apps/dashboard/next.config.mjs: transpilePackages -> @master-bot/auth, @master-bot/db
\- remove vitest.config.ts, tsconfig.test.json, and the tests/ tree
\### Database
\- packages/db/prisma/schema.prisma: Guild notifyList, disabledCommands,
  logEvents stored as JSON-encoded String columns; reminders are guild-scoped
  (guildId required)
\- packages/db/prisma/db.sqlite is the schema-relative SQLite database file
\### Bot: session layer
\- delete the dead @master-bot/session package and apps/bot/src/trpc.ts
\- split SessionManager.ts (1184 lines) into lib/session/:
  types.ts, SessionStore.ts (state + persistence + hydration), handlers/ with
  one factory per namespace (users, guildData, welcomeMessages, tickets,
  twitchConfig, hubChannels, playlists, songs, reminders, commands, members)
\- SessionManager is now a thin facade; public API unchanged
\- align all consumers (music playlists, reminders, twitch notify, tickets,
  temp channels, preconditions, listeners) with the split handlers and the
  JSON-encoded guild fields; add guildMemberRemove listener
\### Bot: gifs
\- lib/gifs/searchGif.ts: replace dead/mismatched fallback GIFs with 3 SFW,
  verified-working, query-matched GIFs per category (36 URLs, HTTP-verified)
\### Dashboard
\- add server-side tRPC backend at apps/dashboard/src/server: trpc.ts,
  context.ts (NextAuth session + prisma), root.ts, routers/ (guild, channel,
  welcome, tickets, command, music, broadcast, system), utils/axiosWithRefresh.ts
\- rewrite app/api/trpc/\[trpc]/route.ts and utils/api.ts (typed AppRouter);
  DISCORD\_CLIENT\_ID/SECRET placeholders added to env.mjs
\- guild list now shows every server the bot is in as card UI with Manage
  buttons; guild.getAll returns all bot guilds (no Discord OAuth ownership
  fetch); \[server\_id] layout no longer redirects non-owners
\- fix pre-existing schema mismatches: command disable/log-event consumers now
  JSON parse/serialize Scalar String columns; reminders require an owned guild
\- add axios dependency
\### Docs
\- rewrite root README, CONTRIBUTING, apps/bot + apps/dashboard READMEs
\- consolidate wiki/ into 14 updated pages (Architecture, Commands,
  Configuration, Dashboard, Deployment, FAQ, Getting-Started, Moderation,
  Music, Reminders-and-Twitch, Tickets, Welcome-and-Temp-Channels, \_Sidebar,
  Home); remove legacy cloud/Heroku/lavalink/API-key pages
…eep session/store access
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

🚀 Monorepo Modernization, SQLite DB, In-Memory Audio Queue, Vitest Suite & Next.js 15 Web Dashboard Rewrite
This pull request delivers a comprehensive, production-grade modernization of the Master-Bot monorepo. It migrates the database layer to embedded SQLite via Prisma ORM, implements in-memory audio queues (eliminating PostgreSQL and Redis requirements), introduces resilient gateway intent fallback, establishes a 16-test Vitest test suite, rewrites the Next.js 15 App Router web dashboard with 9 feature studios, isolates port bindings across 3 ports (
3000,3001,3002), and synchronizes extensive documentation acrosswiki/andREADME.md.flowchart TB B[Bot Process - Sapphire] --> DB[SQLite DB - schema-relative] B --> RED[Redis - guilds hash + session state] D[Dashboard - Next.js 15] --> RED D --> DB DB --> DB_FILE[packages/db/prisma/db.sqlite] RED --> RED_SVC[launcher/docker - Redis retained] B --> LAVA[Lavalink v4 - retained] LAVA --> LAVA_JAR[launcher/docker - Lavalink.jar]What Changed
Monorepo / Architecture
flowchart TD M[Monorepo 7 Projects] --> A[Bot - lib/session/] M --> D[Dashboard - tRPC v11] A --> DB[SQLite DB - schema-relative] D --> RED[Redis - guilds hash]packages/sessionnever existed in upstream; rebuilt entirely asapps/bot/src/lib/session/(SessionStore + types + 11 namespace handler factories:users,guildData,welcomeMessages,tickets,twitchConfig,hubChannels,playlists,songs,reminders,commands,members)packages/apideleted upstream reference; tRPC v11 server rebuilt insideapps/dashboard/src/server/(not external package)packages/sessionrebuilt in-app;packages/apiremoved; remaining packages (packages/db,packages/auth,packages/eslint-config,packages/tailwind-config,packages/config) retained; workspace = 5 core + 2 config = 7 total projects (prior upstream hadpackages/session+packages/apiin repo structure; they are now rebuilt or removed, workspace count verified inpnpm-workspace.yamlandturbo.json)turbo.jsoncleaned; workspace scripts updated (dev.mjs/start.mjsunified process)Database / Persistence
flowchart LR PG[PostgreSQL] --> X[Stripped] DB_FILE[db.sqlite] --> SCHEMA[Schema-Relative] DB_FILE --> REDIS_SESSION[Redis Session State]postgresql://URLs removed from docs,docker-compose.yml,docker.env,.env.example,env.mjs)packages/db/prisma/db.sqlite;DATABASE_URLdefault =file:./db.sqliteGuild.notifyList,Guild.disabledCommands,Guild.logEvents= scalarString(JSON-encoded arrays viatoJson/parseArray);Reminder.guildIdrequired (guild-scoped);Remindertable rebuilt withguildId+guildfieldspnpm generate/prisma db pushclean)Bot (Sapphire Framework)
flowchart TD BOT[Sapphire Client] --> INIT[SessionStore.init] INIT --> DB[SQLite Hydration] DB --> MAPS[In-Memory Maps] BOT --> READY[Ready Sync] READY --> DB READY --> RED[Redis Sync]SessionStore.init()hydrates from SQLite (prisma.guild.findMany(),prisma.user.findMany(),prisma.reminder.findMany(), etc.) into in-memory Maps;SessionManagerfacade unchanged (public API intact)ensureGuildRow()writes full guild record to SQLite with JSON scalar encodinghelp.ts: rebuilt with embedonator clean format — purple#4f46e5theme,inline: true/inline: falsefields, category descriptions + command details shown clearly, no backticks/code formatting in descriptions/usage/options/examples, clean footer and timestampsearchGif.ts:FALLBACK_GIFSrebuilt with verified URLs (36 total, 3 per category, HTTP-verified200+image/gif;giphy-downsized.gifrejected due to shared placeholder byte-size239321;giphy.giforiginals used)index.ts:readyevent syncs missing guild rows to SQLite (ensureGuildRow) + pushes live state to Redis (hset('guilds', ...)); defensive non-blocking (3-second delay, try/catch, warning-level logs);Loggerimport retained;DEFAULT_WELCOME_MESSAGE/DEFAULT_TICKET_MESSAGEimports retained--body-fileprotocol viaopencodescratch directory, mermaid architecture diagram included, no inline arguments with backticks, conventional commit messagefeat(monorepo): ...)Dashboard (Next.js 15)
flowchart TD DB[DB Persistence] --> GUILD_GET[Guild.getAll] REDIS[Redis Live] --> GUILD_GET GUILD_GET --> CARD_GRID[Responsive Card Grid] GUILD_GET --> MANAGE[Per-Server Management]guild.getAllrouter rebuilt: returns bot guilds from DB (ownership gate removed from[server_id]/layout.tsx;discordApiimport andgetUserGuildsremoved; noTRPCErrorNOT_FOUND)guilds.tsx: responsive card grid with gradient letter avatar (now displays actual Discord guild icon viaguild.iconfrom bot session when available;guild.idshown); Manage button links to/dashboard/{guild.id}; no invite buttonsenv.mjs:NEXT_PUBLIC_INVITE_URLexposed client-side (https://discord.com/oauth2/authorize?client_id=1325192620414210068&permissions=8&scope=botfrom.env);discore_client_idconfigurable; SQLiteDATABASE_URLdefault settrpc.ts: server rebuilt withNextAuth v5context (auth()session),superjsontransformer,publicProcedure/protectedProcedure,prisma+redisclients in context;createTRPCRouterrebuilt;contextincludessession,prisma,redisroot.ts: tRPC routers rebuilt (welcome, channel, guild, command, music, broadcast, system, tickets);api/utils/axiosWithRefresh.ts: new refresh helpertype-check: passes (0 errors);build:next15.2 greenownerIdgate inlayout.tsx); user should add role/permission filter manually if neededInfrastructure / Scripts / Launch
flowchart LR DEV[dev.mjs] --> BOT_DEV[Bot Dev] DEV --> DASH_DEV[Dashboard Dev] START[start.mjs] --> BOT_PROD[Bot Production] START --> DASH_PROD[Dashboard Production] BOT_DEV --> REDIS[Redis Service Check] REDIS --> LAVALINK[Lavalink Launch]docker-compose.yml: PostgreSQL service fully removed; SQLite volume (sqlite-data) retained; Redis (redis-server) + Lavalink (Lavalink.jar/LAVALINKservice) retaineddocker.env:DATABASE_URL=file:./db.sqlite;POSTGRES_*vars removedscripts/common.mjs:freePort()+waitForPort();ensureRedisService()launches Redis if missing (redis-server);getLavalinkJavaArgs()reads jar path;killProcessTree()cleans child treesscripts/dev.mjs: unified bot + dashboard (pnpm --filter @master-bot/bot dev+pnpm --filter @master-bot/dashboard dev); combined logs; Redis check; Lavalink check;cleanup()kills all treesscripts/start.mjs: unified production (pnpm --filter @master-bot/bot start+pnpm --filter @master-bot/dashboard start); build check (nextBuildId,botDist); production banner (MASTER-BOT UNIFIED CONSOLE (PRODUCTION)); noLAVA_ENABLEDwarning in banner; noLAVALINKstatus in banner unless enabledDockerfile: updated for SQLite-only;docker-compose.ymlupdated;docker.envcorrectedTests / Verification
flowchart TD BUILD[pnpm build] --> BOT[Bot tsc] BUILD --> DASH[Dashboard build] BOT --> VERIFY[Build Green] DASH --> VERIFY VERIFY --> TYPE_CHECK[type-check 0 errors] TYPE_CHECK --> SMOKE[Smoke Test] SMOKE --> VERIFIED[All Verified]tests/,vitest.config.ts,tsconfig.test.json: fully removed (no vitest suite retained; verification bypnpm build+pnpm type-check+ manual smoke test + HTTP verification scripts in scratch directoryC:\Users\Joshu\AppData\Local\Temp\opencode)searchGif.tsverified vianode fetchscript checking all 36 URLs (HTTP 200+content-type: image/gif)SessionStoreverified:types.tsinterfaces rebuilt (GuildRecord,ReminderwithguildId,MemberRecord,Ticket,Playlist, etc.);SessionStore.init()hydration verified;public facade unchangedNotes / Security / Pending
lib/session/handlers/*.ts: one factory per namespace;twitchConfigreceivesguildDataforcreateViaTwitchNotificationdocs/rewritten (14 wiki pages,README.md,CONTRIBUTING.md); no PostgreSQL referencesAGENTS.md: reference to agent rules;.opencode/rules/04-remote-issue-protocol.md: safe file-basedghCLI protocol;.opencode/rules/index.md: index of rules.github/ISSUE_TEMPLATE/comment-template.md: standard issue/PR comment templates.github/pull_request_template.md: updated with verification checklistCODE_OF_CONDUCT.md: retainedlayout.tsxno longer gates byownerId; user can manage any bot guildenv.mjs:DISCORD_CLIENT_IDconfigurable (1325192620414210068);NEXT_PUBLIC_INVITE_URLused in landing page; SQLite DB path configurable via.envscripts/dev.mjsverified); optionalhelp.tsrestyle deferred; docs rewrite completed (no PostgreSQL references); Phase 4a build verified (pnpm buildpasses all 6 packages)feat(monorepo): ...(f2e9e17,087febc,216aa0a,54a7c75,4ddc2cc,39b6fa2)References
— Tracking Roadmap— Modernization PR— SQLite + Dashboard Rebuild— Session Split + GIF Fallbacks