Added OAuth-Based Discord Account Integration#19
Conversation
There was a problem hiding this comment.
I will consider managing the Invite Bot/Server source code separately as a subtree, since the same source code is also used in the SMCTF project.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Adds end-to-end Discord account linking via OAuth2, persisting link state in the backend and delegating guild/role actions to a separate invite-bot service, with frontend UI to connect/sync/unlink.
Changes:
- Backend: Discord OAuth flow + persistence (
discord_connections) + new/api/discord/*endpoints. - New standalone
invite-botNode/TypeScript service exposing an internal HTTP API to join/kick/grant role. - Frontend: profile “Discord” card + i18n strings + API bindings; plus docs and compose wiring.
Reviewed changes
Copilot reviewed 51 out of 53 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| migrations/2026-06-23/001_add_discord_connections.sql | Adds discord_connections table + unique indexes. |
| migrations/2026-06-23/999_rollback.sql | Rollback drops discord_connections. |
| invite-bot/tsconfig.json | TypeScript build configuration for invite-bot service. |
| invite-bot/src/logger.ts | Minimal JSON logger for invite-bot. |
| invite-bot/src/index.ts | Invite-bot entrypoint: start Discord client + HTTP server + shutdown handling. |
| invite-bot/src/http/server.ts | Internal HTTP API (auth + join/kick/grant/status endpoints). |
| invite-bot/src/discord/errors.ts | Maps Discord API errors to internal bot error codes/status. |
| invite-bot/src/discord/client.ts | Discord.js client wrapper implementing join/kick/grant/status. |
| invite-bot/src/config.ts | Reads env config for invite-bot. |
| invite-bot/README.md | Documents internal API routes and local commands. |
| invite-bot/package.json | Invite-bot dependencies/scripts/engine constraints. |
| invite-bot/package-lock.json | Locked dependency tree for invite-bot. |
| invite-bot/Dockerfile | Multi-stage Docker build for invite-bot runtime. |
| invite-bot/.prettierrc | Prettier formatting configuration for invite-bot. |
| invite-bot/.prettierignore | Files excluded from formatting. |
| invite-bot/.gitignore | Git ignores for invite-bot artifacts. |
| invite-bot/.env.example | Example env file for invite-bot configuration. |
| internal/service/errors.go | Adds Discord-related service error constants. |
| internal/service/discord_service.go | Implements OAuth state, callback handling, provisioning, unlink/sync/status. |
| internal/service/discord_service_test.go | Unit tests for DiscordService linking/sync/unlink/state validation. |
| internal/repo/testenv_test.go | Ensures repo tests truncate discord_connections. |
| internal/repo/discord_repo.go | Repo CRUD for discord_connections. |
| internal/repo/discord_repo_test.go | Repo tests for CRUD + unique constraint behavior. |
| internal/models/discord_connection.go | Bun model + status constants for Discord connection row. |
| internal/http/router.go | Wires new Discord routes and injects DiscordService into handlers. |
| internal/http/integration/testenv_test.go | Updates router creation in integration tests for new param. |
| internal/http/handlers/testenv_test.go | Updates handler construction for new DiscordService param. |
| internal/http/handlers/handler.go | Adds DiscordService field to Handler and updates constructor. |
| internal/http/handlers/handler_test.go | Updates handler construction for new DiscordService param. |
| internal/http/handlers/errors.go | Maps Discord service errors to HTTP statuses. |
| internal/http/handlers/discord.go | Adds connect/callback/status/sync-role/unlink handlers + redirect result mapping. |
| internal/http/handlers/discord_test.go | Handler tests for redirects, status, sync-role, unlink, disabled behavior. |
| internal/discord/oauth.go | OAuth client for Discord authorize URL, token exchange, and /users/@me. |
| internal/discord/oauth_test.go | OAuth client tests (params, form encoding, bearer header, error status). |
| internal/discord/client.go | Backend HTTP client to invite-bot internal API + error mapping. |
| internal/discord/client_test.go | Bot client tests for request paths, auth, payloads, and error mapping. |
| internal/db/db.go | Adds DiscordConnection to auto-migrate + index creation. |
| internal/config/config.go | Adds Discord config fields, env parsing, validation, and redaction. |
| frontend/src/routes/UserProfile.tsx | Adds DiscordLinkCard to profile page. |
| frontend/src/routes/ChallengeDetail.tsx | Formatting-only JSX changes. |
| frontend/src/routes/admin/Popups.tsx | Formatting-only JSX changes. |
| frontend/src/locales/ko.json | Adds Discord profile strings (Korean) + trailing comma fix. |
| frontend/src/locales/ja.json | Adds Discord profile strings (Japanese) + trailing comma fix. |
| frontend/src/locales/en.json | Adds Discord profile strings (English) + trailing comma fix. |
| frontend/src/lib/types.ts | Adds DiscordStatus + DiscordRoleStatus types. |
| frontend/src/lib/api.ts | Adds Discord API helpers (connect URL, status, sync-role, unlink). |
| frontend/src/components/UserProfile/DiscordLinkCard.tsx | UI for connect/sync/unlink + banner messaging and avatar rendering. |
| docs/docs/discord.md | Detailed backend flow/API documentation and env configuration docs. |
| docker-compose.yaml | Adds invite-bot service and points backend to it. |
| codecov.yaml | Excludes invite-bot from Go coverage reporting. |
| cmd/server/main.go | Instantiates Discord service clients and injects DiscordService into router. |
| .env.example | Documents new Discord-related backend env vars. |
Files not reviewed (1)
- invite-bot/package-lock.json: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Okay. I think we can merge now. |
This PR introduces Discord account integration using OAuth. Once a user links their Discord account, they are automatically joined to a designated Discord server and assigned a role.
All Discord interactions are handled by a separate service independent of the main backend. The backend is responsible only for managing OAuth clients and storing account-linking information. The overall flow is shown below.
The following backend environment variables have been added:
DISCORD_CLIENT_IDandDISCORD_CLIENT_SECRETcan be obtained from the Discord Developer Portal. You must also configure the corresponding Redirect URI.In addition,
DISCORD_BOT_SECRETmust match the value used by the Invite Bot/Server. The following environment variables have been added for the Invite Bot/Server:Likewise, the bot token, guild ID, and role ID should be obtained from the Discord Developer Portal and configured appropriately for your environment.
Warning
The backend server and the Invite Bot/Server are intentionally separated due to bot sharding concerns. The current implementation was not designed with a general distributed environment in mind, so the bot server should be deployed as a separate single instance. This architecture may be improved in the future.
For more details, please refer to the updated source code and documentation.