Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
275f2c0
feat: add web dashboard shell with Next.js 16, Tailwind v4, Discord O…
BillChirico Feb 16, 2026
94a7642
fix: add Discord token refresh logic in JWT callback
BillChirico Feb 16, 2026
f778664
fix: add rate limiting, bot API auth, and BOT_API_URL handling
BillChirico Feb 16, 2026
7ad5a2a
fix: log errors and persist selected guild in server-selector
BillChirico Feb 16, 2026
16cda88
fix: update Dockerfile for monorepo layout with proper lockfile handling
BillChirico Feb 16, 2026
6671671
fix: use default export in proxy.ts for Next.js 16 detection
BillChirico Feb 16, 2026
ff66bab
docs: add BOT_API_SECRET to .env.example
BillChirico Feb 16, 2026
c2bfb38
test: update getMutualGuilds test for new unfiltered fallback behavior
BillChirico Feb 16, 2026
ab55240
fix(web): replace console.warn/error with logger utility
BillChirico Feb 16, 2026
53ceb00
fix(web): fix Dockerfile paths for monorepo standalone output
BillChirico Feb 16, 2026
15765c2
fix(web): graceful degradation when bot API is unreachable
BillChirico Feb 16, 2026
8f45c86
docs: add JSDoc noting getUserAvatarUrl as public utility for future …
BillChirico Feb 16, 2026
e36c483
fix: use named proxy export for Next.js 16 convention
BillChirico Feb 16, 2026
9f7ff8a
chore: update dependencies and package manager versions
BillChirico Feb 16, 2026
cca8abc
fix: security hardening — remove client token, validate secrets, add …
BillChirico Feb 16, 2026
a021b5e
fix: guild pagination, token refresh handling, health check, invite g…
BillChirico Feb 16, 2026
3508d85
refactor: error boundaries, server component DashboardShell, empty state
BillChirico Feb 16, 2026
d24e2f4
test: comprehensive tests for refresh tokens, rate limits, proxy, mocks
BillChirico Feb 16, 2026
f0aacd6
refactor: extract getBotInviteUrl into shared utility with minimal pe…
BillChirico Feb 16, 2026
56618d7
fix: read callbackUrl from searchParams in login page
BillChirico Feb 16, 2026
3685bed
refactor: split discord.ts into server-only and client-safe modules
BillChirico Feb 16, 2026
808d980
fix: add missing await to response.json() in fetchBotGuilds
BillChirico Feb 16, 2026
c30be52
fix: validate callbackUrl to prevent open redirect in login page
BillChirico Feb 16, 2026
b2a8cd8
fix: harden env file defaults — empty NEXTAUTH_SECRET, add BOT_API_SE…
BillChirico Feb 16, 2026
73131ff
fix: improve Dockerfile — consolidate RUN, add --chown on public, add…
BillChirico Feb 16, 2026
fde9e9f
fix: proxy callbackUrl uses pathname, auth validates Discord creds, c…
BillChirico Feb 16, 2026
e43faeb
fix: component improvements — ErrorCard, global-error, login flash, l…
BillChirico Feb 16, 2026
a5ee59e
fix: BigInt try-catch in getUserAvatarUrl, add signal to getMutualGuilds
BillChirico Feb 16, 2026
545784e
fix: improve test quality — vi.spyOn, env cleanup, fake timers, userE…
BillChirico Feb 16, 2026
89f2498
fix: use asChild prop to avoid invalid button-inside-anchor HTML
BillChirico Feb 16, 2026
dc64788
fix: use structured logger instead of console.error in global-error
BillChirico Feb 16, 2026
39e7832
fix: add defensive catch to fetchBotGuilds in Promise.all for gracefu…
BillChirico Feb 16, 2026
3dcd6cd
fix: add build-time verification for standalone server.js path in Doc…
BillChirico Feb 16, 2026
357ba27
fix: replace console.error with logger in error boundaries
BillChirico Feb 16, 2026
d5f23e6
fix: include root package.json in Dockerfile deps stage for pnpm lock…
BillChirico Feb 16, 2026
70bd187
fix(web): remove unused Button import and rename error boundary
BillChirico Feb 16, 2026
cb8dc68
fix(web): harden auth — catch network errors, handle token refresh fa…
BillChirico Feb 16, 2026
2aaee64
fix(web): simplify AbortController in server-selector
BillChirico Feb 16, 2026
85ad19d
fix(web): improve discord.server.ts — caching, validation, discrimina…
BillChirico Feb 16, 2026
4b236a2
fix(web): improve test assertions and mocking patterns
BillChirico Feb 16, 2026
cafaaea
test(web): update dashboard layout test for server-side auth check
BillChirico Feb 16, 2026
bd43742
fix: resolve RefreshTokenError race condition — single handler in Header
BillChirico Feb 16, 2026
cdf1161
fix: remove misplaced web/.dockerignore — root .dockerignore is used …
BillChirico Feb 16, 2026
629800a
fix: force dynamic rendering for guilds API route — no user-scoped ca…
BillChirico Feb 16, 2026
3f7052a
fix: guard against malformed retry-after header, remove unnecessary S…
BillChirico Feb 16, 2026
c90da47
fix: add explicit string cast for accessToken in guilds route
BillChirico Feb 16, 2026
fabf4a7
docs: add intentional console usage comment to web logger
BillChirico Feb 16, 2026
c033e53
fix: prevent error message leak in guilds API route
BillChirico Feb 16, 2026
694f6c3
fix: add signingOut guard to prevent duplicate sign-outs
BillChirico Feb 16, 2026
7e31e00
fix: add suppressHydrationWarning to global error boundary html tag
BillChirico Feb 16, 2026
abf5650
fix: remove unnecessary email scope from Discord OAuth
BillChirico Feb 16, 2026
50bf40e
fix: use pattern matching for secret placeholder validation
BillChirico Feb 16, 2026
71ec8c1
docs: add web dashboard section to README
BillChirico Feb 16, 2026
548b11f
fix: add RefreshTokenError guard and AbortSignal to guilds route
BillChirico Feb 16, 2026
566d50e
fix: harden dockerignore, JSON parsing, and remove unnecessary use cl…
BillChirico Feb 16, 2026
578fb32
fix: improve server-selector empty state UX with invite CTA
BillChirico Feb 16, 2026
2e927f4
test: improve header and auth test coverage
BillChirico Feb 16, 2026
87af30f
test: add RefreshTokenError redirect test to proxy middleware
BillChirico Feb 16, 2026
d8e8509
refactor: remove unused getUserAvatarUrl (YAGNI)
BillChirico Feb 16, 2026
059ce7c
fix: remove unnecessary suppressHydrationWarning from global-error
BillChirico Feb 16, 2026
4633616
fix: add AbortSignal support to fetchBotGuilds and signal-aware rate …
BillChirico Feb 16, 2026
d08fd3d
fix: prevent aborted request from resetting loading state in server-s…
BillChirico Feb 16, 2026
d85a30d
fix: clean up abort listener on normal sleep resolve in fetchWithRate…
BillChirico Feb 16, 2026
1288d98
fix: prevent infinite redirect loop on RefreshTokenError in login page
BillChirico Feb 16, 2026
6bb1fde
feat: add /api/health endpoint for container health checks
BillChirico Feb 16, 2026
c2a1439
fix: document access token exclusion and verify BOT_PERMISSIONS value
BillChirico Feb 16, 2026
0ec9d89
fix: add response validation, lang attr, and guild icon fallback
BillChirico Feb 16, 2026
bb4425a
fix: preserve query string in proxy redirect and validate refresh tok…
BillChirico Feb 16, 2026
38c51ee
fix: handle 401 in server-selector and add unauthenticated header state
BillChirico Feb 16, 2026
a2bdaab
feat: add Content-Security-Policy header and fix global-error dark mode
BillChirico Feb 16, 2026
7273ebc
refactor: clean up types, assertions, and fallbacks
BillChirico Feb 16, 2026
f06acfe
fix: update README scripts table — replace nonexistent pnpm lint with…
BillChirico Feb 16, 2026
c752959
test: simplify test imports and fix descriptions
BillChirico Feb 16, 2026
09234c4
fix: remove CSP header to prevent Next.js hydration breakage
BillChirico Feb 16, 2026
d575442
fix: add Array.isArray guard to fetchUserGuilds and defensive expires…
BillChirico Feb 16, 2026
0fe85b0
test: fix env pollution, add unauthenticated and skeleton assertions
BillChirico Feb 16, 2026
cdff4ec
fix: secure JWT accessToken handling and add refresh token guards
BillChirico Feb 16, 2026
d302bbb
fix: centralize RefreshTokenError handling in login page
BillChirico Feb 16, 2026
61beeb6
fix: scope Discord CDN paths and add Dockerfile build context comment
BillChirico Feb 16, 2026
50d1aa0
docs: document proxy.ts NextAuth v4 compat and verify health endpoint
BillChirico Feb 16, 2026
f572b00
test: add data-testid to header skeleton
BillChirico Feb 16, 2026
d9489c1
test: update login test for centralized RefreshTokenError handling
BillChirico Feb 16, 2026
326e610
fix: correct guild default icon path and rename shadowed variable
BillChirico Feb 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,9 @@ coverage/
verify-*.js
VERIFICATION_GUIDE.md

# Web dashboard
web/.next/
web/.env.local
web/.env.*.local
web/tsconfig.tsbuildinfo

51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ AI-powered Discord bot for the [Volvox](https://volvox.dev) developer community.
- **⚙️ Config Management** — All settings stored in PostgreSQL with live `/config` slash command for runtime changes.
- **📊 Health Monitoring** — Built-in health checks and `/status` command for uptime, memory, and latency stats.
- **🎤 Voice Activity Tracking** — Tracks voice channel activity for community insights.
- **🌐 Web Dashboard** — Next.js-based admin dashboard with Discord OAuth2 login, server selector, and guild management UI.

## 🏗️ Architecture

Expand Down Expand Up @@ -108,6 +109,18 @@ pnpm dev

Legacy OpenClaw aliases are also supported for backwards compatibility: `OPENCLAW_URL`, `OPENCLAW_TOKEN`.

### Web Dashboard

| Variable | Required | Description |
|----------|----------|-------------|
| `NEXTAUTH_URL` | ✅ | Canonical URL of the dashboard (e.g. `http://localhost:3000`) |
| `NEXTAUTH_SECRET` | ✅ | Random secret for NextAuth.js JWT encryption (min 32 chars). Generate with `openssl rand -base64 48` |
| `DISCORD_CLIENT_ID` | ✅ | Discord OAuth2 application client ID |
| `DISCORD_CLIENT_SECRET` | ✅ | Discord OAuth2 application client secret |
| `NEXT_PUBLIC_DISCORD_CLIENT_ID` | ❌ | Public client ID for bot invite links in the UI |
| `BOT_API_URL` | ❌ | URL of the bot's REST API for mutual guild filtering |
| `BOT_API_SECRET` | ❌ | Shared secret for authenticating requests to the bot API |

## ⚙️ Configuration

All configuration lives in `config.json` and can be updated at runtime via the `/config` slash command. When `DATABASE_URL` is set, config is persisted to PostgreSQL.
Expand Down Expand Up @@ -230,6 +243,44 @@ All moderation commands require the admin role (configured via `permissions.admi
| `/modlog view` | View current log routing config |
| `/modlog disable` | Disable all mod logging |

## 🌐 Web Dashboard

The `web/` directory contains a Next.js admin dashboard for managing Bill Bot through a browser.

### Features

- **Discord OAuth2 Login** — Sign in with your Discord account via NextAuth.js
- **Server Selector** — Choose from mutual guilds (servers where both you and the bot are present)
- **Token Refresh** — Automatic Discord token refresh with graceful error handling
- **Responsive UI** — Mobile-friendly layout with sidebar navigation and dark mode support

### Setup

```bash
cd web
cp .env.example .env.local # Fill in Discord OAuth2 credentials
pnpm install --legacy-peer-deps
pnpm dev # Starts on http://localhost:3000
```

> **Note:** `--legacy-peer-deps` is required due to NextAuth v4 + Next.js 16 peer dependency constraints.

### Discord OAuth2 Configuration

1. Go to your [Discord application](https://discord.com/developers/applications) → **OAuth2**
2. Add a redirect URL: `http://localhost:3000/api/auth/callback/discord` (adjust for production)
3. Copy the **Client ID** and **Client Secret** into your `.env.local`

### Scripts

| Command | Description |
|---------|-------------|
| `pnpm dev` | Start development server with hot reload |
| `pnpm build` | Production build |
| `pnpm start` | Start production server |
| `pnpm test` | Run tests with Vitest |
| `pnpm typecheck` | Type-check with TypeScript compiler |

## 🛠️ Development

### Scripts
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bill-bot",
"packageManager": "pnpm@10.28.2",
"packageManager": "pnpm@10.29.3",
"version": "1.0.0",
"description": "Volvox Discord bot - AI chat, welcome messages, and moderation",
"main": "src/index.js",
Expand All @@ -18,7 +18,7 @@
},
"dependencies": {
"discord.js": "^14.25.1",
"dotenv": "^17.2.4",
"dotenv": "^17.3.1",
"mem0ai": "^2.2.2",
"pg": "^8.18.0",
"winston": "^3.19.0",
Expand All @@ -33,7 +33,7 @@
"node": ">=18.0.0"
},
"devDependencies": {
"@biomejs/biome": "^2.3.14",
"@biomejs/biome": "^2.4.0",
"@vitest/coverage-v8": "^4.0.18",
"vitest": "^4.0.18"
}
Expand Down
Loading
Loading