feat: 无前端模式 + 前端可指定后端地址 (headless mode & configurable backend)#598
Conversation
Adds two deployment capabilities for running maxx without its bundled same-origin Web UI: - Headless / API-only mode: a `-no-ui` flag and `MAXX_DISABLE_UI` env var (flag wins) skip serving the web UI. The API, proxy, project proxy, /health and /ws keep working; "/" and UI routes return 404. - Configurable backend address: the frontend can target a backend on a different origin. A new CORS middleware (driven by MAXX_CORS_ALLOW_ORIGINS, comma list or "*") allows the cross-origin requests, and the UI exposes a backend-address control on the login screen and in Settings (stored in localStorage, with a build-time VITE_BACKEND_URL fallback). CORS is wired into the CLI, ManagedServer, and desktop launcher entry points; it is a no-op when unset (same-origin default). Tests: - Unit tests for the CORS middleware (internal/handler/cors_test.go). - e2e integration tests for headless vs UI serving and end-to-end CORS behavior; the harness gains opt-in options (mountRoot/serveStatic/corsOrigins). - Implements the previously-skipped CORS placeholders in middleware_test.go. Docs: README / README_CN gain "Headless Mode" and "Separately-hosted Frontend" sections plus the two new env vars. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🧰 Additional context used🧠 Learnings (1)📓 Common learnings🔇 Additional comments (1)
📝 WalkthroughWalkthrough本PR接入可配置 CORS 中间件、添加 -no-ui / MAXX_DISABLE_UI 的 headless 路由分支,并在前端提供运行时后端地址覆盖与基于该地址的传输配置;包含单元测试、E2E 测试、UI 集成与文档/本地化更新。 ChangesCORS跨域与无UI部署、前端动态后端配置
Sequence DiagramsequenceDiagram
participant Browser
participant Server as http.Server
participant CORS as CORSMiddleware
participant Mux as ServeMux
Browser->>Server: OPTIONS /api/admin/providers (Origin, Access-Control-Request-Method)
Server->>CORS: Handle preflight
alt Origin allowed
CORS->>Browser: 204 + Access-Control-Allow-*
else Origin disallowed
CORS->>Mux: forward request (no CORS headers)
Mux->>CORS: response
CORS->>Browser: response (no Access-Control-Allow-*)
end
Browser->>Server: GET /health (Origin)
Server->>CORS: Handle request
CORS->>Mux: forward non-preflight
Mux->>CORS: response (+/- Access-Control-Allow-Origin)
CORS->>Browser: response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/handler/cors.go`:
- Around line 58-83: When handling requests in the CORS middleware (the block
that reads origin := r.Header.Get("Origin") and the preflight short-circuit that
checks r.Method == http.MethodOptions), always add a Vary: Origin header
whenever an Origin header is present (even if cfg.allows(origin) is false) to
prevent cached non-CORS responses being reused; additionally, in the preflight
branch add Vary: Access-Control-Request-Headers (when
Access-Control-Request-Headers is present on the request) so caches vary on that
header too. Locate the origin handling and the OPTIONS preflight branch around
origin := r.Header.Get("Origin") / if r.Method == http.MethodOptions and add
w.Header().Add("Vary", "Origin") early when origin != "" and
w.Header().Add("Vary", "Access-Control-Request-Headers") in the preflight path.
In `@README_CN.md`:
- Line 326: Documentation uses two different project route forms
(`/project/{slug}/...` vs `/{project-slug}/v1/messages`); pick the actual
runtime pattern (`/project/{slug}/...` as noted) and make the API endpoint table
and all examples consistent. Update every occurrence of
`/{project-slug}/v1/messages` (and similar `/{project-slug}/...`) to
`/project/{slug}/v1/messages` (or the canonical `/project/{slug}/...`) and
normalize placeholder style (use `{slug}` everywhere), including the API
endpoint table, examples, and related descriptions so routes match the
implementation.
In `@README.md`:
- Line 331: The README has inconsistent project-proxy route notation: one place
uses `/project/{slug}/...` while the API Endpoints table uses
`/{project-slug}/v1/messages`; pick and standardize to a single canonical route
string used by the codebase (e.g., `/project/{slug}/v1/messages` or
`/{project-slug}/v1/messages`) and update all occurrences accordingly (search
for `/project/{slug}/...`, `/{project-slug}/v1/messages`, and any references to
project proxy routes in the README), ensuring the chosen format matches the
actual server routing and adjusting example endpoints in the API Endpoints table
and the sentence listing proxy endpoints.
In `@web/src/lib/backend-config.ts`:
- Around line 43-55: The setBackendUrl function is persisting the full URL
(including path) which later gets concatenated with /api and /ws causing
incorrect endpoints; change it to store and return only the origin (use
parsed.origin) while keeping the same validation (ensure protocol is http/https)
and continue using STORAGE_KEY; update localStorage.setItem(STORAGE_KEY, ...) to
save parsed.origin and return parsed.origin so downstream builders that append
/api and /ws produce correct URLs.
- Around line 45-47: The localStorage calls around STORAGE_KEY (the removeItem
when trimmed is empty and the setItem when saving a value) lack exception
handling; wrap localStorage.removeItem(STORAGE_KEY) and
localStorage.setItem(STORAGE_KEY, ...) in try/catch blocks (mirror the read-path
error handling) so failures in restricted storage environments are caught and do
not break the "save/reset then reconnect" flow, and log or silently ignore the
error consistent with existing read behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5701bc3c-d66e-4550-a92a-16970910c4ad
📒 Files selected for processing (18)
README.mdREADME_CN.mdcmd/maxx/main.gointernal/core/server.gointernal/desktop/launcher.gointernal/handler/cors.gointernal/handler/cors_test.gotests/e2e/cors_e2e_test.gotests/e2e/headless_test.gotests/e2e/middleware_test.gotests/e2e/setup_test.goweb/src/components/backend-address-control.tsxweb/src/lib/backend-config.tsweb/src/lib/transport/context.tsxweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/login.tsxweb/src/pages/settings/index.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: multiinstance
- GitHub Check: playwright
- GitHub Check: e2e
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-05-15T11:27:17.450Z
Learnt from: Bowl42
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-05-15T11:27:17.450Z
Learning: In `internal/core/database.go`, `InitializeServerComponents` is only called by the desktop launcher (`internal/desktop/launcher.go`), not by the CLI server startup path. The `forceStandalone=true` argument to `SetupCoordinator` inside `InitializeServerComponents` is intentional: the desktop app does not need multi-instance coordination. The CLI server startup in `cmd/maxx/main.go` calls `core.SetupCoordinator(ctx, instanceID, false)` directly, which respects Redis/multi-instance configuration from environment variables.
Applied to files:
internal/desktop/launcher.gocmd/maxx/main.go
🔇 Additional comments (14)
web/src/lib/transport/context.tsx (1)
11-11: LGTM!Also applies to: 105-106
web/src/components/backend-address-control.tsx (1)
21-114: LGTM!web/src/pages/login.tsx (1)
8-8: LGTM!Also applies to: 659-661
web/src/pages/settings/index.tsx (1)
44-45: LGTM!Also applies to: 284-285, 445-461
web/src/locales/en.json (1)
1507-1519: LGTM!web/src/locales/zh.json (1)
1505-1517: LGTM!internal/core/server.go (1)
30-31: LGTM!Also applies to: 140-140
internal/desktop/launcher.go (1)
18-18: LGTM!Also applies to: 228-228
internal/handler/cors_test.go (1)
9-36: LGTM!Also applies to: 38-54, 56-79, 81-101
cmd/maxx/main.go (1)
54-89: LGTM!Also applies to: 558-578
tests/e2e/setup_test.go (1)
31-43: LGTM!Also applies to: 47-50, 206-226
tests/e2e/cors_e2e_test.go (1)
8-31: LGTM!Also applies to: 33-98
tests/e2e/middleware_test.go (1)
8-27: LGTM!Also applies to: 29-42
tests/e2e/headless_test.go (1)
16-23: LGTM!Also applies to: 28-81
Triaged findings from an independent adversarial review (Codex/gpt-5.5): - CORS: strip trailing slashes from configured origins so `https://ui.example.com/` matches the browser's slash-less Origin (medium). - CORS: only short-circuit preflights from allowed origins; disallowed origins and non-preflight OPTIONS now fall through (no 204), so the browser blocks the read and unknown routes keep their real status (low). - CORS: add `Vary: Access-Control-Request-Method/-Headers` on preflight responses since Allow-Headers is reflected, preventing cache poisoning (medium). - CORS: log a startup warning when `*` is combined with an unauthenticated admin API; document that CORS is not a substitute for auth (high — proportionate fix). - Frontend: normalize the backend URL to origin+path (drop query/hash, strip trailing slash) so appending `/api` never yields a malformed URL (medium). - Frontend: clear the stored admin token when the effective backend changes so a session minted by one backend is never replayed against another origin (medium). Adds unit tests for trailing-slash matching, preflight Vary headers, and disallowed-preflight pass-through. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 对抗性审查 (Codex / gpt-5.5)用 Codex CLI(provider 指向独立的 gpt-5.5 后端)对 diff 做了一轮对抗审查,再由 Claude 逐条裁决。共 7 条,无 critical。
修复提交: |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
internal/handler/cors.go (1)
75-83:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win补齐
Vary: Origin的覆盖范围,避免跨源缓存误复用。当前仅在允许来源时设置
Vary: Origin。这会让“无 CORS 头”的响应有机会被缓存并复用到后续允许来源请求,造成跨域偶发失败。建议只要请求携带Origin就追加Vary: Origin。建议修改
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") + if origin != "" { + w.Header().Add("Vary", "Origin") + } allowed := origin != "" && cfg.allows(origin) isPreflight := r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" if allowed { // Reflect the concrete origin (even for "*") so the response stays // valid if a caller later adds credentials, and so Vary is honored. w.Header().Set("Access-Control-Allow-Origin", origin) - w.Header().Add("Vary", "Origin") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")Also applies to: 98-103
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/handler/cors.go` around lines 75 - 83, The Vary: Origin header must be added whenever the request contains an Origin to prevent cross-origin cache reuse; modify the cors handling so that when origin := r.Header.Get("Origin") is non-empty you call w.Header().Add("Vary", "Origin") immediately (before relying on allowed or isPreflight), rather than only inside the allowed branch; keep the existing logic that sets Access-Control-Allow-Origin and other CORS headers when allowed/isPreflight, but ensure Vary is always appended for any request with an Origin to avoid cached responses being reused across origins (also apply the same change in the later block around the code referenced at lines 98-103).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@internal/handler/cors.go`:
- Around line 75-83: The Vary: Origin header must be added whenever the request
contains an Origin to prevent cross-origin cache reuse; modify the cors handling
so that when origin := r.Header.Get("Origin") is non-empty you call
w.Header().Add("Vary", "Origin") immediately (before relying on allowed or
isPreflight), rather than only inside the allowed branch; keep the existing
logic that sets Access-Control-Allow-Origin and other CORS headers when
allowed/isPreflight, but ensure Vary is always appended for any request with an
Origin to avoid cached responses being reused across origins (also apply the
same change in the later block around the code referenced at lines 98-103).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 81e45014-39e3-44d6-bef8-d5d2751dba60
📒 Files selected for processing (6)
README.mdREADME_CN.mdcmd/maxx/main.gointernal/handler/cors.gointernal/handler/cors_test.goweb/src/lib/backend-config.ts
✅ Files skipped from review due to trivial changes (2)
- README.md
- README_CN.md
🚧 Files skipped from review as they are similar to previous changes (1)
- web/src/lib/backend-config.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-11T07:29:12.071Z
Learning: Reviewer ymkiux (repo: awsl-project/maxx) requires strict attention to breaking changes in all PRs. Always thoroughly audit public API, interface, and behavioral contract changes — especially in sidebar/auth/layout components — before raising review comments. Do not flag superficial style issues; focus on correctness, regressions, and breaking changes.
📚 Learning: 2026-05-15T11:27:17.450Z
Learnt from: Bowl42
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-05-15T11:27:17.450Z
Learning: In `internal/core/database.go`, `InitializeServerComponents` is only called by the desktop launcher (`internal/desktop/launcher.go`), not by the CLI server startup path. The `forceStandalone=true` argument to `SetupCoordinator` inside `InitializeServerComponents` is intentional: the desktop app does not need multi-instance coordination. The CLI server startup in `cmd/maxx/main.go` calls `core.SetupCoordinator(ctx, instanceID, false)` directly, which respects Redis/multi-instance configuration from environment variables.
Applied to files:
cmd/maxx/main.go
- Introduce vitest + jsdom (frontend had no test runner) with a `test` script and a standalone vitest.config.ts. - Add backend-config.test.ts (14 cases) covering the review fixes: URL normalization (trailing slash, query/hash stripping, sub-path preservation), auth-token clearing on backend change, same-origin default, and ws/wss derivation in buildTransportConfig. - Exclude *.test.ts from tsconfig.app.json so test-only @types/node does not leak into the app program (it otherwise flips setTimeout's return type). - Reword the backend-address description (review #7) to be accurate when a build-time VITE_BACKEND_URL default is configured. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/src/lib/backend-config.test.ts (1)
75-93: ⚡ Quick win可选:补充子路径与 buildTransportConfig 的集成测试。
当前测试中,Line 36-38 验证了
setBackendUrl能保留反向代理子路径(如https://example.com/maxx),Lines 80-86 验证了buildTransportConfig能从普通源派生 API 与 WS 地址。但没有测试用例组合验证:当后端地址包含子路径时,buildTransportConfig是否正确拼接(例如https://example.com/maxx/api和wss://example.com/maxx/ws)。虽然现有测试已覆盖各独立行为,添加此集成用例可提升对边缘场景的信心。
📋 可选的测试用例补充
it('derives a ws:// URL from an http backend', () => { setBackendUrl('http://localhost:9880'); expect(buildTransportConfig()?.wsURL).toBe('ws://localhost:9880/ws'); }); + + it('correctly appends paths to a backend with reverse-proxy subpath', () => { + setBackendUrl('https://example.com/maxx'); + expect(buildTransportConfig()).toEqual({ + baseURL: 'https://example.com/maxx/api', + adminBaseURL: 'https://example.com/maxx/api/admin', + wsURL: 'wss://example.com/maxx/ws', + }); + }); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/lib/backend-config.test.ts` around lines 75 - 93, The buildTransportConfig test suite currently verifies that buildTransportConfig correctly derives API and WS URLs from regular backend origins, but lacks an integration test case that validates the behavior when the backend URL includes a reverse proxy subpath. Add a new test case within the buildTransportConfig describe block that calls setBackendUrl with a URL containing a subpath (such as https://example.com/maxx), then assert that buildTransportConfig correctly derives the full paths by appending /api and /ws to the complete backend URL including the subpath. This ensures that subpaths are properly preserved and concatenated in the derived transport configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@web/src/lib/backend-config.test.ts`:
- Around line 75-93: The buildTransportConfig test suite currently verifies that
buildTransportConfig correctly derives API and WS URLs from regular backend
origins, but lacks an integration test case that validates the behavior when the
backend URL includes a reverse proxy subpath. Add a new test case within the
buildTransportConfig describe block that calls setBackendUrl with a URL
containing a subpath (such as https://example.com/maxx), then assert that
buildTransportConfig correctly derives the full paths by appending /api and /ws
to the complete backend URL including the subpath. This ensures that subpaths
are properly preserved and concatenated in the derived transport configuration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d9db0473-cb1a-49bc-b25a-5e6eff0125e9
⛔ Files ignored due to path filters (1)
web/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
web/package.jsonweb/src/lib/backend-config.test.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/tsconfig.app.jsonweb/vitest.config.ts
✅ Files skipped from review due to trivial changes (4)
- web/vitest.config.ts
- web/tsconfig.app.json
- web/src/locales/zh.json
- web/src/locales/en.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: playwright
- GitHub Check: e2e
- GitHub Check: multiinstance
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-11T07:29:12.071Z
Learning: Reviewer ymkiux (repo: awsl-project/maxx) requires strict attention to breaking changes in all PRs. Always thoroughly audit public API, interface, and behavioral contract changes — especially in sidebar/auth/layout components — before raising review comments. Do not flag superficial style issues; focus on correctness, regressions, and breaking changes.
🔇 Additional comments (1)
web/package.json (1)
15-16: LGTM!Also applies to: 82-82, 87-88
- CORS: emit `Vary: Origin` whenever the request carries an Origin (even when
disallowed) so a shared cache never reuses a no-CORS response for an
allowlisted origin. Adds a regression test.
- Frontend: distinguish storage failures from invalid URLs in setBackendUrl via
a dedicated BackendStorageError; the backend-address control now shows an
accurate message instead of "invalid URL" when storage is unavailable. Adds a
unit test that mocks localStorage throwing.
- Docs: fix the project-proxy route in the API endpoints table
(`/{project-slug}/...` → `/project/{project-slug}/...`) to match the actual
router, consistent with the new deployment sections.
Note: the "persist only origin" suggestion is intentionally not applied —
origin+path is preserved to support a backend behind a reverse-proxy sub-path;
query/hash stripping (the actual bug) was already fixed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CodeRabbit 审查处理 (commit c7071e9)5 条逐条对照最新 head 裁决:
验证:Go build/vet/CORS+e2e、前端 |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
README.md (2)
307-307:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win占位符命名建议统一,避免路由示例歧义。
Line 307/Line 331使用{slug},而Line 292使用{project-slug}。建议全文统一为同一占位符写法,避免读者误解为两种不同参数。✏️ 建议修订
-| `MAXX_DISABLE_UI` | Headless mode: when truthy (`1`/`true`/`yes`/`on`), do not serve the web UI — only the API and proxy endpoints are exposed. Equivalent to the `-no-ui` flag (the flag takes precedence when set). Project proxy routes (`/project/{slug}/...`) remain available. | +| `MAXX_DISABLE_UI` | Headless mode: when truthy (`1`/`true`/`yes`/`on`), do not serve the web UI — only the API and proxy endpoints are exposed. Equivalent to the `-no-ui` flag (the flag takes precedence when set). Project proxy routes (`/project/{project-slug}/...`) remain available. | -- The API (`/api/admin/*`), proxy endpoints (`/v1/messages`, `/v1/chat/completions`, …), project proxy (`/project/{slug}/...`), `/health`, and `/ws` all keep working. +- The API (`/api/admin/*`), proxy endpoints (`/v1/messages`, `/v1/chat/completions`, …), project proxy (`/project/{project-slug}/...`), `/health`, and `/ws` all keep working.Also applies to: 331-331
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` at line 307, The README uses two different route parameter placeholders (`{slug}` and `{project-slug}`) which may confuse readers; search for occurrences of `{slug}` and `{project-slug}` (e.g., in the MAXX_DISABLE_UI description and other route examples) and standardize them to a single placeholder name across the document (pick one, e.g., `{project-slug}`), updating all route examples and descriptions consistently and preserving meaning and examples for `MAXX_DISABLE_UI` and project proxy routes.
362-364:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win“留空即同源”描述建议补充回退优先级。
当前文案容易被理解为“留空总是同源”。建议明确为“留空后先用
VITE_BACKEND_URL,未设置时再回退同源”,与前文配置逻辑保持一致。✏️ 建议修订
-The value is stored in the browser (`localStorage`), so each user/browser can -target a different backend. Leave it empty to use the same origin that served -the page (the default). Build-time default: set `VITE_BACKEND_URL` when building -the frontend. +The value is stored in the browser (`localStorage`), so each user/browser can +target a different backend. If left empty, the UI falls back to +`VITE_BACKEND_URL` (when provided at build time), otherwise to the same origin +that served the page.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` around lines 362 - 364, 更新 README.md 中描述 VITE_BACKEND_URL 的那句话,明确说明留空时的回退优先级:构建时若设置了 VITE_BACKEND_URL 则使用该值;若未设置则回退为请求页面的同源(same origin)。在原句“Leave it empty to use the same origin that served the page (the default). Build-time default: set `VITE_BACKEND_URL` when building the frontend.” 附加上述顺序说明,确保同时引用变量名 VITE_BACKEND_URL 以便匹配配置逻辑。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@README.md`:
- Line 307: The README uses two different route parameter placeholders (`{slug}`
and `{project-slug}`) which may confuse readers; search for occurrences of
`{slug}` and `{project-slug}` (e.g., in the MAXX_DISABLE_UI description and
other route examples) and standardize them to a single placeholder name across
the document (pick one, e.g., `{project-slug}`), updating all route examples and
descriptions consistently and preserving meaning and examples for
`MAXX_DISABLE_UI` and project proxy routes.
- Around line 362-364: 更新 README.md 中描述 VITE_BACKEND_URL
的那句话,明确说明留空时的回退优先级:构建时若设置了 VITE_BACKEND_URL 则使用该值;若未设置则回退为请求页面的同源(same
origin)。在原句“Leave it empty to use the same origin that served the page (the
default). Build-time default: set `VITE_BACKEND_URL` when building the
frontend.” 附加上述顺序说明,确保同时引用变量名 VITE_BACKEND_URL 以便匹配配置逻辑。
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bec6e3e4-57a2-4365-82b9-e1116d5dc8f4
📒 Files selected for processing (9)
README.mdREADME_CN.mdinternal/handler/cors.gointernal/handler/cors_test.goweb/src/components/backend-address-control.tsxweb/src/lib/backend-config.test.tsweb/src/lib/backend-config.tsweb/src/locales/en.jsonweb/src/locales/zh.json
✅ Files skipped from review due to trivial changes (1)
- web/src/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (6)
- web/src/lib/backend-config.ts
- README_CN.md
- web/src/components/backend-address-control.tsx
- web/src/locales/zh.json
- web/src/lib/backend-config.test.ts
- internal/handler/cors.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: playwright
- GitHub Check: e2e
- GitHub Check: multiinstance
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: awsl233777
Repo: awsl-project/maxx PR: 598
File: web/src/lib/backend-config.ts:0-0
Timestamp: 2026-06-05T10:14:54.561Z
Learning: In awsl-project/maxx PR `#598`, `setBackendUrl` in `web/src/lib/backend-config.ts` intentionally normalizes the backend URL to `origin + pathname` (not just `origin`). Subpaths are deliberately preserved to support backends deployed behind a reverse-proxy prefix (e.g., `https://example.com/maxx`). Query strings and hash fragments are stripped. Suggesting `parsed.origin` only would break the reverse-proxy subpath use case.
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
🔇 Additional comments (1)
internal/handler/cors_test.go (1)
151-168: LGTM!
…tion Follow-up to reviewer findings against c7071e9: - static.go: serveFromCache used `Set("Vary", "Accept-Encoding")`, overwriting the `Vary: Origin` that CORSMiddleware adds upstream — so static responses to an allowed origin lost Vary: Origin and could be mis-cached. Switch to `Add`. Regression test exercises the real NewStaticHandler behind CORSMiddleware. - backend-config.ts: the build-time VITE_BACKEND_URL fallback only stripped trailing slashes, so it did not share the runtime override's URL contract (query/hash were kept, breaking the appended /api and /ws). Route both through a single normalizeBackendUrl helper; read the env lazily so it is testable. Adds a unit test stubbing VITE_BACKEND_URL with query/hash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
处理 @awsl233777 的两处深入发现 (commit 31bd0fc)两条都复现并修了,都补了回归测试: 1. 2. 验证:Go handler 8 个 CORS 用例 + e2e 全过;前端 |
awsl233777
left a comment
There was a problem hiding this comment.
Approved after rechecking required checks, CodeRabbit status, and the CORS/backend URL regression fixes on head 31bd0fc.
背景 / Motivation
支持两种新的部署形态:
改动 / Changes
1. 无前端模式(env + flag)
cmd/maxx/main.go:新增-no-uiflag 和MAXX_DISABLE_UI环境变量(flag 优先)。开启时/只挂项目代理,不提供静态文件;API //v1/*//project/*//health//ws照常工作。internal/core/server.go现有的ServeStatic开关。2. CORS 中间件(跨源必需)
internal/handler/cors.go,由MAXX_CORS_ALLOW_ORIGINS(逗号分隔或*)驱动,处理 OPTIONS 预检、回显 Origin、放行Authorization。未设置时零开销直通。ManagedServer、桌面 launcher 三个入口。3. 前端可指定后端地址
web/src/lib/backend-config.ts:从localStorage读后端地址(兜底VITE_BACKEND_URL,再兜底同源),推导baseURL/adminBaseURL/wsURL。BackendAddressControl组件,挂在登录页(登录前即可设置)和设置页。4. 文档
测试 / Testing
internal/handler/cors_test.go(解析、预检、白名单、通配、禁用直通)。tests/e2e/headless_test.go(UI vs 无前端/行为)、tests/e2e/cors_e2e_test.go(端到端 CORS)。tests/e2e/middleware_test.go里原本t.Skip("...until CORS middleware is added")的两个占位用例。mountRoot/serveStatic/corsOrigins,默认行为不变。-race通过;go build/go vet/ 前端tsc --build/eslint均通过。用法 / Usage
🤖 Generated with Claude Code
Summary by CodeRabbit
发行说明
新功能
文档
测试
修复