From e9b3ca587d8604894930fda35b39467bf52dc399 Mon Sep 17 00:00:00 2001 From: Standley Gury Date: Sun, 19 Jul 2026 16:24:03 +0800 Subject: [PATCH] refactor: Remove Claude settings and environment files; update API base URL handling --- .claude/settings.local.json | 22 ---------------------- .gitignore | 1 + CLAUDE.md | 2 +- src/UI/App/.env.development | 1 - src/UI/App/.env.production | 1 - src/UI/App/src/services/api.ts | 14 ++++++++++---- 6 files changed, 12 insertions(+), 29 deletions(-) delete mode 100644 .claude/settings.local.json delete mode 100644 src/UI/App/.env.development delete mode 100644 src/UI/App/.env.production diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index cf599e2..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "permissions": { - "allow": [ - "WebFetch(domain:github.com)", - "WebSearch", - "WebFetch(domain:support.discord.com)", - "Skill(dataviz)", - "Bash(node scripts/validate_palette.js \"#ff6b6b,#4ecdc4,#45b7d1,#f9ca24,#f0932b,#eb4d4b,#6ab04c,#9c88ff\" --mode dark)", - "PowerShell(node \"C:\\\\Users\\\\stand\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\bundled-skills\\\\2.1.206\\\\086a8e9e37ae6507cf6e474311e79744\\\\dataviz\\\\scripts\\\\validate_palette.js\" \"#ff6b6b,#4ecdc4,#45b7d1,#f9ca24,#f0932b,#eb4d4b,#6ab04c,#9c88ff\" --mode dark)", - "PowerShell(node \"C:\\\\Users\\\\stand\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\bundled-skills\\\\2.1.206\\\\086a8e9e37ae6507cf6e474311e79744\\\\dataviz\\\\scripts\\\\validate_palette.js\" \"#3987e5,#199e70,#c98500,#008300,#9085e9,#e66767,#d55181,#d95926\" --mode dark --surface \"#366472\")", - "PowerShell(node \"C:\\\\Users\\\\stand\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\G--personal-Discord-Music-Bot\\\\42ca7a0b-f5a7-4a2e-a708-2f026c81c580\\\\scratchpad\\\\mock-api.js\")", - "PowerShell(try { $conns = Get-NetTCPConnection -LocalPort 5000,5173 -State Listen -ErrorAction Stop } catch { $conns = @\\(\\) }; if \\($conns.Count -eq 0\\) { \"no listeners on 5000/5173\" } else { foreach \\($c in $conns\\) { $p = Get-Process -Id $c.OwningProcess -ErrorAction SilentlyContinue; if \\($p -and $p.ProcessName -match 'node|bun'\\) { Stop-Process -Id $p.Id -Force -Confirm:$false; \"killed $\\($p.ProcessName\\) pid $\\($p.Id\\) on port $\\($c.LocalPort\\)\" } else { \"port $\\($c.LocalPort\\): $\\($p.ProcessName\\) left alone\" } } })", - "PowerShell(bun run *)", - "PowerShell(Start-Process node -ArgumentList \"C:\\\\Users\\\\stand\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\G--personal-Discord-Music-Bot\\\\42ca7a0b-f5a7-4a2e-a708-2f026c81c580\\\\scratchpad\\\\mock-api.js\" -WindowStyle Hidden; Set-Location \"G:\\\\personal\\\\Discord_Music_Bot\\\\src\\\\UI\\\\App\"; Start-Process bun -ArgumentList \"run\",\"dev\" -WindowStyle Hidden; Start-Sleep -Seconds 5; \\(Invoke-WebRequest http://localhost:5173 -UseBasicParsing\\).StatusCode; \\(Invoke-WebRequest http://localhost:5000/api/users -UseBasicParsing\\).StatusCode)", - "PowerShell(Test-Path *)", - "PowerShell($out = \"C:\\\\Users\\\\stand\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\G--personal-Discord-Music-Bot\\\\42ca7a0b-f5a7-4a2e-a708-2f026c81c580\\\\scratchpad\"; & \"C:\\\\Program Files \\(x86\\)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe\" --headless --disable-gpu --dump-dom \"http://localhost:5000/api/users\" 2>$null | Select-Object -First 3)", - "PowerShell($html = & \"C:\\\\Program Files \\(x86\\)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe\" --headless --disable-gpu --dump-dom \"http://localhost:5173/\" 2>&1; \"len=$\\($html.Length\\)\"; $html2 = & \"C:\\\\Program Files \\(x86\\)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe\" --headless --disable-gpu --dump-dom \"http://127.0.0.1:5000/api/users\" 2>&1; \"api-len=$\\($html2.Length\\)\"; \\($html2 | Out-String\\).Substring\\(0, [Math]::Min\\(300, \\($html2 | Out-String\\).Length\\)\\))", - "PowerShell(Get-Process *)", - "PowerShell(try { $c = Get-NetTCPConnection -LocalPort 5173 -State Listen -ErrorAction Stop; $c | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -Confirm:$false }; \"killed vite\" } catch { \"no listener on 5173\" }; try { $c = Get-NetTCPConnection -LocalPort 5000 -State Listen -ErrorAction Stop; $c | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -Confirm:$false }; \"killed mock api\" } catch { \"no listener on 5000\" })" - ] - } -} diff --git a/.gitignore b/.gitignore index bc605fb..e6d2806 100644 --- a/.gitignore +++ b/.gitignore @@ -483,4 +483,5 @@ $RECYCLE.BIN/ # Vim temporary swap files *.swp +.claude/* diff --git a/CLAUDE.md b/CLAUDE.md index 29c38c2..29057c8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,7 +51,7 @@ Tests live in `src/Tests/` (xUnit + NSubstitute; integration tests use Testconta - **Tests** (`src/Tests/`) - xUnit test project: `Unit/` (queue, guild player, guild player manager, eventing) and `Integration/` (blacklist/statistics/user services against Testcontainers PostgreSQL). - **UI** (`src/UI/`) - `Api/` - ASP.NET Core minimal-API endpoints (see `ControllerExtensions.cs`) with JWT bearer auth. Anonymous stats endpoints (`/api/statistics-all`, `/api/statistics-today` for today's top songs, `/api/users`); radio-source CRUD and token validation require authorization. Login checks against `JwtSettings:InternalPassword` (no user password hashing). - - `App/` - React 19 + TypeScript SPA, responsive down to phone widths (breakpoints at 1024/768/480px in `index.css`; `hide-sm`/`hide-md` classes drop table columns on small screens). The index route is an Overview landing page (`pages/Overview.tsx` + `components/RankList.tsx`) with headline stats, top-songs-today, all-time favorites, top listeners, and a latest-activity feed derived from each user's recent songs. The song/user dashboards support search, sortable columns, pagination (`Pagination`/`SortableTh` components, 10 rows per page), an all-time/today filter (songs), relative "last played" timestamps (`utils/time.ts`), and auto-refresh every 60s via TanStack Query `refetchInterval`. Charts adapt to mobile via the `useIsMobile` hook. The API base URL is relative (`/api`) in production builds because the Worker serves the SPA and API from the same origin (works for local docker and deployment alike); only `.env.development` points at `http://localhost:5000/api` for the Vite dev server. Build output writes into `src/Worker/wwwroot/`, which is served by the Worker as static files with SPA fallback to `index.html`. + - `App/` - React 19 + TypeScript SPA, responsive down to phone widths (breakpoints at 1024/768/480px in `index.css`; `hide-sm`/`hide-md` classes drop table columns on small screens). The index route is an Overview landing page (`pages/Overview.tsx` + `components/RankList.tsx`) with headline stats, top-songs-today, all-time favorites, top listeners, and a latest-activity feed derived from each user's recent songs. The song/user dashboards support search, sortable columns, pagination (`Pagination`/`SortableTh` components, 10 rows per page), an all-time/today filter (songs), relative "last played" timestamps (`utils/time.ts`), and auto-refresh every 60s via TanStack Query `refetchInterval`. Charts adapt to mobile via the `useIsMobile` hook. The API base URL is hardcoded in `services/api.ts`: relative `/api` for builds (the Worker serves the SPA and API from the same origin, so this works for local docker and deployment alike) and `http://localhost:5000/api` only when `import.meta.env.DEV` is true (the Vite dev server). Do NOT reintroduce `VITE_API_BASE_URL` env files: bun auto-loads `.env*` into `process.env`, which outranks `.env.production` in Vite and once leaked the dev URL into a deployed production build. Note that `deployment/docker-compose.override.yml` (VS debug tooling) sets `BUILD_CONFIGURATION: Debug` and a `--wait-for-debugger` entrypoint; it is auto-applied if you run `docker compose` from `deployment/` without `-f`, so always use the explicit `-f deployment/docker-compose.yml` form for real runs. Build output writes into `src/Worker/wwwroot/`, which is served by the Worker as static files with SPA fallback to `index.html`. - **Worker** (`src/Worker/`) - Composition root. Program.cs builds a `WebApplication` that hosts the NetCord Discord gateway (registered via `AddDiscordGateway`), the ASP.NET Core web API, and the `GuildPlayerManager` hosted service in one process on port 5000. ### Key Patterns diff --git a/src/UI/App/.env.development b/src/UI/App/.env.development deleted file mode 100644 index 64c0b37..0000000 --- a/src/UI/App/.env.development +++ /dev/null @@ -1 +0,0 @@ -VITE_API_BASE_URL=http://localhost:5000/api diff --git a/src/UI/App/.env.production b/src/UI/App/.env.production deleted file mode 100644 index 14ea4ad..0000000 --- a/src/UI/App/.env.production +++ /dev/null @@ -1 +0,0 @@ -VITE_API_BASE_URL=/api diff --git a/src/UI/App/src/services/api.ts b/src/UI/App/src/services/api.ts index e2049c5..ec4d21b 100644 --- a/src/UI/App/src/services/api.ts +++ b/src/UI/App/src/services/api.ts @@ -1,4 +1,10 @@ -// The production build uses a relative path because the Worker serves the SPA -// and the API from the same origin (works for local docker and deployment). -// The dev server overrides this via .env.development to reach localhost:5000. -export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? '/api'; +// Production builds use a relative path because the Worker serves the SPA and +// the API from the same origin (works for local docker and deployment alike). +// Dev-mode builds (vite dev server on :5173, or build:dev) target the Worker +// on localhost:5000 directly. +// Deliberately not read from VITE_API_BASE_URL: bun auto-loads .env files into +// process.env, which outranks .env.production in Vite and once leaked the dev +// URL into a production build. +export const API_BASE_URL = import.meta.env.DEV + ? 'http://localhost:5000/api' + : '/api';