Skip to content

refactor: 重构前端为vite+react#458

Merged
consistent-k merged 2 commits intomainfrom
dev
Apr 14, 2026
Merged

refactor: 重构前端为vite+react#458
consistent-k merged 2 commits intomainfrom
dev

Conversation

@consistent-k
Copy link
Copy Markdown
Owner

@consistent-k consistent-k commented Apr 14, 2026

Summary by CodeRabbit

发布说明

  • 新特性

    • 引入 Docker Compose 配置实现开发和生产环境分离部署
    • 前端框架从 Next.js 迁移至 Vite + React Router 架构
  • 改进

    • 重构后端和前端 Docker 镜像构建流程,分离为独立 Dockerfile
    • 更新 API 地址配置为 127.0.0.1
  • Chores

    • 更新代码风格指南和项目结构文档
    • 优化 ESLint 和 Prettier 配置

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Warning

Rate limit exceeded

@consistent-k has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 11 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 22 minutes and 11 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9e3313ee-23a3-4deb-99fc-efbfab2cf928

📥 Commits

Reviewing files that changed from the base of the PR and between e42fb46 and e783be2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (32)
  • .cursor/rules/frontend/workflow.mdc
  • .devcontainer/devcontainer.json
  • .prettierignore
  • README.md
  • apps/backend/src/index.ts
  • apps/backend/src/routes/registry.ts
  • apps/frontend/conf/nginx.conf
  • apps/frontend/index.html
  • apps/frontend/src/App.tsx
  • apps/frontend/src/components/BasicLayout.tsx
  • apps/frontend/src/components/InitProvider.tsx
  • apps/frontend/src/components/SiteHeader.tsx
  • apps/frontend/src/components/ThemeProvider.tsx
  • apps/frontend/src/components/ui/Loading/Loading.tsx
  • apps/frontend/src/components/ui/ThemeSelector.tsx
  • apps/frontend/src/components/video/VodList/index.tsx
  • apps/frontend/src/components/video/VodPalyer/index.tsx
  • apps/frontend/src/components/video/VodSearch/index.tsx
  • apps/frontend/src/components/video/VodSites/index.tsx
  • apps/frontend/src/components/video/VodTypes/index.tsx
  • apps/frontend/src/lib/store/useThemeStore.ts
  • apps/frontend/src/lib/store/useVodSitesStore.ts
  • apps/frontend/src/main.tsx
  • apps/frontend/src/pages/category/index.tsx
  • apps/frontend/src/pages/detail/index.tsx
  • apps/frontend/src/pages/home/index.tsx
  • apps/frontend/src/pages/setting/index.tsx
  • apps/frontend/vite.config.ts
  • docker-compose.prod.yml
  • eslint.config.mjs
  • package.json
  • tsconfig.base.json

Walkthrough

前端应用框架从 Next.js 迁移至 Vite + React Router,包括移除 Next.js 配置、添加 Vite 构建和 React Router 路由管理。后端和基础设施层面分离了 Dockerfile,更新了 Docker Compose 配置,并调整了 ESLint 规则及项目文档。

Changes

Cohort / File(s) Summary
前端框架迁移 (Next.js → Vite + React Router)
apps/frontend/src/main.tsx, apps/frontend/src/App.tsx, apps/frontend/src/components/BasicLayout.tsx, apps/frontend/src/components/InitProvider.tsx, apps/frontend/src/components/SiteHeader.tsx, apps/frontend/src/pages/...
将前端从 Next.js App Router 重构为 Vite + React Router 应用,替换路由 hooks(useRouter/usePathname → useNavigate/useLocation),移除 'use client' 指令,创建新的 React 应用入口和路由结构。
前端配置与构建工具
apps/frontend/package.json, apps/frontend/vite.config.ts, apps/frontend/tsconfig.json, apps/frontend/index.html, apps/frontend/postcss.config.mjs
替换构建工具链:移除 Next.js/PostCSS 配置,添加 Vite 配置(含 React 插件、路径别名、API 代理),更新 tsconfig 目标版本和类型定义,创建 Vite 入口 HTML。
前端页面组件迁移
apps/frontend/src/pages/home/index.tsx, apps/frontend/src/pages/category/index.tsx, apps/frontend/src/pages/detail/index.tsx, apps/frontend/src/pages/setting/index.tsx, apps/frontend/src/components/video/...
更新页面和视频组件:替换 Next.js 导航为 React Router,移除 Suspense 边界和客户端指令,调整类型定义(如 PalyerProps → PlayerProps)。
Docker 与基础设施
apps/backend/Dockerfile, apps/frontend/Dockerfile, apps/frontend/conf/nginx.conf, .github/workflows/docker-image.yml, docker-compose.yml, docker-compose.prod.yml
分离后端和前端 Dockerfile 使用独立构建阶段,前端采用 Nginx 服务(含 API 反向代理和 SPA 路由转发),更新 GitHub 工作流和 Docker Compose 配置指向新 Dockerfile。
项目文档与规则
.cursor/rules/frontend/..., CLAUDE.md, README.md
更新 cursor 规则以反映 Vite/React Router 技术栈(替换 Next.js 引用),添加 CLAUDE.md 仓库指南,扩展 README 包含 Docker Compose 部署说明和架构亮点。
ESLint 与代码规范
eslint.config.js, eslint.config.mjs, package.json
移除旧的 ESLint 配置文件(.js),创建新的 flat config 规范(.mjs)包含 React/Hooks/Prettier 插件,更新根 package.json 脚本和 Prettier 配置范围。
配置与工具链更新
tsconfig.base.json, .lintstagedrc, .prettierignore, .prettierrc, commitlint.config.js
调整 TypeScript 编译目标至 ES2022,精简 Prettier/lint-staged 配置格式,更新忽略文件模式。
后端轻微调整
apps/backend/package.json, apps/backend/src/... (多个文件)
移除后端脚本命令(typecheck/format),更新依赖版本,整理 import 语句空行(11 个文件中的重复模式),将 registry.ts 中的动态 import 改为 require,添加启动日志。
前端类型与移除的文件
apps/frontend/lib/types/index.ts, apps/frontend/next.config.ts, apps/frontend/app/layout.tsx, apps/frontend/app/home/components/HomeCarousel/index.tsx
apps/frontend/lib/types/ 移除共享类型重导出,新增至 apps/frontend/src/lib/types/;删除 Next.js 配置、根布局组件和轮播图组件(因框架迁移)。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

frontend, dependencies, ci

Poem

🐰 从 Next.js 的花园,跳到 Vite 的轻盈之舞,
Router 改了名字,但路由的故事永恒,
Nginx 守护着前端,Docker 分装后端安宁,
一次重构,万千细节汇聚,
VodHub 焕然新生!✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题准确反映了主要变更内容——前端从Next.js重构为Vite+React框架,简洁清晰地总结了核心改动。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 14, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 4 package(s) with unknown licenses.
See the Details below.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA e783be2.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

License Issues

apps/backend/package.json

PackageVersionLicenseIssue Type
@hono/node-server^1.19.14NullUnknown License
@hono/zod-openapi^1.3.0NullUnknown License
dotenv^17.4.2NullUnknown License

apps/frontend/package.json

PackageVersionLicenseIssue Type
react-router^7.13.2NullUnknown License

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
npm/@hono/node-server ^1.19.14 UnknownUnknown
npm/@hono/zod-openapi ^1.3.0 UnknownUnknown
npm/@types/node ^25.6.0 UnknownUnknown
npm/dotenv ^17.4.2 UnknownUnknown
npm/@vitejs/plugin-react ^6.0.1 UnknownUnknown
npm/react-router ^7.13.2 UnknownUnknown
npm/vite ^8.0.3 UnknownUnknown
npm/eslint-config-prettier ^10.1.8 UnknownUnknown
npm/eslint-plugin-react ^7.37.5 UnknownUnknown
npm/eslint-plugin-react-hooks ^7.0.1 UnknownUnknown
npm/@emnapi/core 1.9.2 🟢 3.8
Details
CheckScoreReason
Code-Review⚠️ 0Found 0/30 approved changesets -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained🟢 1019 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/@emnapi/wasi-threads 1.2.1 🟢 3.8
Details
CheckScoreReason
Code-Review⚠️ 0Found 0/30 approved changesets -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained🟢 1019 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/@hono/node-server 1.19.14 UnknownUnknown
npm/@hono/zod-openapi 1.3.0 UnknownUnknown
npm/@napi-rs/wasm-runtime 1.1.3 🟢 5.4
Details
CheckScoreReason
Code-Review🟢 4Found 11/26 approved changesets -- score normalized to 4
Maintained🟢 1030 commit(s) and 6 issue activity found in the last 90 days -- score normalized to 10
Security-Policy🟢 10security policy file detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/@oxc-project/types 0.124.0 UnknownUnknown
npm/@rolldown/binding-android-arm64 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-darwin-arm64 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-darwin-x64 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-freebsd-x64 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-linux-arm-gnueabihf 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-linux-arm64-gnu 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-linux-arm64-musl 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-linux-ppc64-gnu 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-linux-s390x-gnu 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-linux-x64-gnu 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-linux-x64-musl 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-openharmony-arm64 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-wasm32-wasi 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-win32-arm64-msvc 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/binding-win32-x64-msvc 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/pluginutils 1.0.0-rc.15 UnknownUnknown
npm/@rolldown/pluginutils 1.0.0-rc.7 UnknownUnknown
npm/@types/node 25.6.0 🟢 6.6
Details
CheckScoreReason
Code-Review🟢 9Found 28/30 approved changesets -- score normalized to 9
Maintained🟢 1030 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Security-Policy🟢 10security policy file detected
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing⚠️ 0project is not fuzzed
npm/@vitejs/plugin-react 6.0.1 🟢 7.3
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review⚠️ 2Found 4/20 approved changesets -- score normalized to 2
Maintained🟢 1030 commit(s) and 4 issue activity found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions🟢 7detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 7dependency not pinned by hash detected -- score normalized to 7
Binary-Artifacts🟢 10no binaries found in the repo
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Security-Policy🟢 10security policy file detected
SAST🟢 9SAST tool is not run on all commits -- score normalized to 9
npm/cookie 1.1.1 🟢 6.8
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration
CI-Tests🟢 717 out of 24 merged PRs checked by a CI test -- score normalized to 7
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Code-Review🟢 7Found 20/27 approved changesets -- score normalized to 7
Contributors🟢 10project has 20 contributing companies or organizations
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Dependency-Update-Tool🟢 10update tool detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Maintained🟢 44 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 4
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies🟢 4dependency not pinned by hash detected -- score normalized to 4
SAST🟢 8SAST tool detected but not run on all commits
Security-Policy🟢 9security policy file detected
Signed-Releases⚠️ -1no releases found
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
Vulnerabilities⚠️ 022 existing vulnerabilities detected
npm/dotenv 17.4.2 🟢 4.4
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained🟢 1030 commit(s) and 9 issue activity found in the last 90 days -- score normalized to 10
Security-Policy🟢 9security policy file detected
Code-Review⚠️ 0Found 2/21 approved changesets -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/lightningcss 1.32.0 UnknownUnknown
npm/lightningcss-android-arm64 1.32.0 UnknownUnknown
npm/lightningcss-darwin-arm64 1.32.0 UnknownUnknown
npm/lightningcss-darwin-x64 1.32.0 UnknownUnknown
npm/lightningcss-freebsd-x64 1.32.0 UnknownUnknown
npm/lightningcss-linux-arm-gnueabihf 1.32.0 UnknownUnknown
npm/lightningcss-linux-arm64-gnu 1.32.0 UnknownUnknown
npm/lightningcss-linux-arm64-musl 1.32.0 UnknownUnknown
npm/lightningcss-linux-x64-gnu 1.32.0 UnknownUnknown
npm/lightningcss-linux-x64-musl 1.32.0 UnknownUnknown
npm/lightningcss-win32-arm64-msvc 1.32.0 UnknownUnknown
npm/lightningcss-win32-x64-msvc 1.32.0 UnknownUnknown
npm/prettier 3.8.2 🟢 7.2
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 6 issue activity found in the last 90 days -- score normalized to 10
Code-Review🟢 8Found 4/5 approved changesets -- score normalized to 8
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Packaging⚠️ -1packaging workflow not detected
Security-Policy🟢 10security policy file detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing⚠️ 0project is not fuzzed
SAST🟢 9SAST tool detected but not run on all commits
npm/react-router 7.14.0 🟢 5.1
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 7 issue activity found in the last 90 days -- score normalized to 10
Security-Policy🟢 10security policy file detected
Code-Review⚠️ 1Found 4/27 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
License🟢 10license file detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Fuzzing⚠️ 0project is not fuzzed
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/rolldown 1.0.0-rc.15 UnknownUnknown
npm/set-cookie-parser 2.7.2 🟢 4
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Maintained🟢 1017 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 0Found 1/11 approved changesets -- score normalized to 0
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/undici-types 7.19.2 🟢 8.3
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 1030 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10
Security-Policy🟢 9security policy file detected
Dependency-Update-Tool🟢 10update tool detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 8binaries present in source code
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 4dependency not pinned by hash detected -- score normalized to 4
Vulnerabilities🟢 100 existing vulnerabilities detected
SAST🟢 9SAST tool detected but not run on all commits
License🟢 10license file detected
Fuzzing🟢 10project is fuzzed
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Signed-Releases⚠️ -1no releases found
Packaging🟢 10packaging workflow detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
CI-Tests🟢 1030 out of 30 merged PRs checked by a CI test -- score normalized to 10
Contributors🟢 10project has 83 contributing companies or organizations
npm/vite 8.0.8 🟢 6.5
Details
CheckScoreReason
Code-Review🟢 5Found 16/28 approved changesets -- score normalized to 5
Maintained🟢 1030 commit(s) and 19 issue activity found in the last 90 days -- score normalized to 10
Security-Policy🟢 10security policy file detected
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Binary-Artifacts🟢 5binaries present in source code
Pinned-Dependencies🟢 6dependency not pinned by hash detected -- score normalized to 6
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Fuzzing⚠️ 0project is not fuzzed
SAST🟢 6SAST tool is not run on all commits -- score normalized to 6

Scanned Files

  • apps/backend/package.json
  • apps/frontend/package.json
  • package.json
  • pnpm-lock.yaml

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
apps/frontend/src/components/video/VodPalyer/index.tsx (1)

19-52: ⚠️ Potential issue | 🟠 Major

播放器实例缺少绑定与清理,存在泄漏风险

创建的 Player 实例未赋给 xgInstanceRef.current,且 useDeepCompareEffect 缺少清理函数。当 urlshowType 变化时,旧实例无法被销毁,导致内存泄漏。

修复方案
         const player = new Player({
             id: 'xgplayer',
             url,
             height: '100%',
             width: '100%',
             autoplay: true,
             playsinline: true,
             plugins: [HlsPlugin],
             hls: {
                 retryCount: 3,
                 retryDelay: 1000,
                 loadTimeout: 10000,
                 fetchOptions: {
                     mode: 'cors'
                 }
             }
         });
+        xgInstanceRef.current = player;
         player.on('error', (e: any) => {
             onError?.(e.message);
         });
+        return () => {
+            player.destroy();
+            if (xgInstanceRef.current === player) {
+                xgInstanceRef.current = null;
+            }
+        };
     }, [url, showType]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/components/video/VodPalyer/index.tsx` around lines 19 - 52,
The VodPalyer effect currently constructs a Player but never assigns it to
xgInstanceRef.current or cleans it up; update the useDeepCompareEffect in
VodPalyer to set xgInstanceRef.current = player after creation, attach the error
handler to that instance, and return a cleanup function that removes the 'error'
listener and calls the player's destroy method (or equivalent) to dispose the
instance when url or showType changes or the component unmounts; ensure you also
skip creation when showType === 'iframe' as before.
apps/frontend/src/pages/detail/index.tsx (1)

117-131: ⚠️ Potential issue | 🟠 Major

改为受控组件,使 Select 在播放线路数据变化时同步更新。

defaultValue 只在组件初次挂载时生效。当用户在同一路由切换 id/site 时,handleDetail() 会重新获取影片数据并调用 setActivePlayList() 更新状态,但 Select 仍会显示前一部影片的选中项,导致 UI 与状态不同步。

💡 改法
-                            defaultValue={activePlayList?.name}
+                            value={activePlayList?.name}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/pages/detail/index.tsx` around lines 117 - 131, The Select
is using defaultValue so it doesn't update when movieDetail or activePlayList
changes; change Select to be a controlled component by replacing defaultValue
with value={activePlayList?.name} (use the same unique symbols: Select,
activePlayList, setActivePlayList, movieDetail?.vod_play_list) and keep the
onChange handler to find and set the active playlist so the UI stays in sync
when handleDetail() updates state; ensure options still map from
movieDetail?.vod_play_list to provide matching value strings.
apps/frontend/src/pages/category/index.tsx (1)

52-62: ⚠️ Potential issue | 🟠 Major

修复 useEffectsite 依赖缺失导致的竞态条件。

第二个 useEffect 调用 getCategory() 时未检查 site 是否存在,且缺少 site 依赖。当 URL 中有 idsite 为空时,getCategory 会以空 site 参数发起 API 请求,然后第一个 useEffect 才执行重定向。同时,当 id 不变但 site 改变时,第二个 useEffect 不会重新执行,导致页面继续显示前一个站点的过期数据。

💡 建议改法
     useEffect(() => {
         if (typeof id === 'string' && id) {
-            getCategory(id, filters);
+            if (site) {
+                getCategory(id, filters);
+            }
         }
-    }, [filters, id]);
+    }, [filters, id, site]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/pages/category/index.tsx` around lines 52 - 62, 第二个
useEffect 在调用 getCategory(id, filters) 前应先确认 site 存在并把 site 加入依赖以避免竞态:在包含
getCategory 调用的 effect(当前以 [filters, id] 为依赖的那个)中先检查 typeof site === 'string' &&
site,然后才调用 getCategory;同时将 site 写入该 effect 的依赖数组(即 [filters, id, site]),确保当 site
变化时会重新触发并避免用空 site 发起请求;保留第一个 effect 用于基于 site 为空时的 navigate('/home') 重定向逻辑。
🧹 Nitpick comments (11)
.prettierignore (1)

6-6: 避免全局忽略 JSON,当前会让 JSON 的格式化链路失效

Line 6 的 **/*.json 会使 .lintstagedrc*.{md,json} 的 JSON 格式化基本被跳过。建议只忽略构建产物中的 JSON,而不是全局忽略。

可选修复示例
-**/*.json
+dist/**/*.json
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.prettierignore at line 6, 当前 .prettierignore 中的全局模式 `**/*.json` 导致所有 JSON
文件(包括 .lintstagedrc 中的 *.{md,json})被跳过,破坏了 JSON 的格式化链路。请在 .prettierignore 中删除或替换
`**/*.json` 为仅匹配构建产物的具体路径(例如
`dist/**/*.json`、`build/**/*.json`、或其它产物目录),确保不再全局忽略 JSON,从而恢复对项目根目录和源文件(如
.lintstagedrc 指定的 *.json)的格式化。
tsconfig.base.json (1)

1-13: 考虑为前端添加 isolatedModules 以提高 Vite 兼容性

当前前端已采用 Vite + esbuild 构建(package.json 确认),建议在 apps/frontend/tsconfig.json 中添加 isolatedModules: true 以确保类型检查与 esbuild 单文件转译模式兼容:

{
    "compilerOptions": {
        "isolatedModules": true
    }
}

虽然构建脚本显式执行了 tsc && vite build(完整类型检查在转译前进行),但 isolatedModules 仍是 Vite 项目的最佳实践。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tsconfig.base.json` around lines 1 - 13, Add "isolatedModules": true to the
compilerOptions of the frontend tsconfig to ensure compatibility with
Vite/esbuild single-file transpilation; locate the apps/frontend/tsconfig.json
(the file that defines compilerOptions for the frontend build) and add the
isolatedModules flag under compilerOptions so it reads compilerOptions { ...,
"isolatedModules": true }.
docker-compose.prod.yml (1)

34-37: 考虑添加 Redis 持久化和重启策略

Redis 服务当前没有配置数据持久化,容器重启后缓存数据会丢失。如果这是预期行为(仅用于缓存)则可以接受,否则建议添加持久化配置。同时建议为所有服务添加重启策略以提高可靠性。

♻️ 可选的增强配置
   redis:
     image: redis:alpine
     ports:
       - '127.0.0.1:6379:6379'
+    restart: unless-stopped
+    volumes:
+      - redis_data:/data
+    command: redis-server --appendonly yes
+
+volumes:
+  redis_data:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.prod.yml` around lines 34 - 37, 当前 docker-compose 中的 redis
服务定义 (redis, image: redis:alpine, ports: '127.0.0.1:6379:6379')
未配置持久化和重启策略;如果需要保留数据,请为服务添加持久化卷绑定或命名卷并配置 RDB/AOF 持久化相关设置以及合适的 restart 策略(例如
always 或 unless-stopped)以提升可靠性;定位并修改服务块 redis,加入 volumes 条目指向主机目录或命名卷并在
docker-compose 中添加 restart: 条目,同时如需持久化请在 Redis 配置(或指定命令/配置文件)中启用 RDB/AOF 参数。
apps/frontend/Dockerfile (1)

23-28: 可选:考虑使用非 root 用户运行 Nginx

Trivy 标记了容器以 root 用户运行的安全风险。对于 Nginx 容器,实现非 root 运行需要额外配置(修改监听端口或使用 nginx-unprivileged 镜像)。鉴于这是服务静态文件的简单场景,此优化可作为后续改进项。

♻️ 可选方案:使用 nginx-unprivileged 镜像
-FROM nginx:alpine AS runner
+FROM nginxinc/nginx-unprivileged:alpine AS runner
 RUN rm -f /etc/nginx/conf.d/default.conf
 COPY --from=builder /app/apps/frontend/dist /usr/share/nginx/html
 COPY --from=builder /app/apps/frontend/conf/nginx.conf /etc/nginx/conf.d/default.conf
-EXPOSE 80
+EXPOSE 8080
 CMD ["nginx", "-g", "daemon off;"]

注意:使用此方案需要同步更新 nginx.conf 中的监听端口和 docker-compose.prod.yml 中的端口映射。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/Dockerfile` around lines 23 - 28, The Dockerfile currently runs
Nginx as root; change the base/runtime image to a non-root variant (e.g., use an
nginx unprivileged image) to remove the root-user risk and then update related
configs: switch the FROM in apps/frontend/Dockerfile to the non-root nginx image
and ensure the nginx.conf referenced by COPY (apps/frontend/conf/nginx.conf)
uses a non-privileged listen port, and adjust docker-compose.prod.yml port
mappings accordingly so host→container port mapping matches the new unprivileged
port.
.cursor/rules/frontend/workflow.mdc (1)

69-69: dynamic 是 Next.js 特有的 API

dynamic 导入是 Next.js 的 next/dynamic API。在 Vite + React 架构下,应使用 React.lazy() 配合 Suspense 实现动态导入。

📝 建议更新文档
-- Use `dynamic` imports for heavy components (e.g., video player)
+- Use `React.lazy()` with `Suspense` for heavy components (e.g., video player)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/frontend/workflow.mdc at line 69, 本条规则当前建议使用 Next.js 的
`dynamic`,但在 Vite + React 项目里应改为说明使用 React.lazy 和 Suspense 实现动态导入;请在
workflow.mdc 中把 “Use `dynamic` imports for heavy components (e.g., video
player)” 文本改为推荐使用 `React.lazy()` + `Suspense`(针对重组件如 VideoPlayer 或 video
player),并补充短说明如何在组件加载失败或加载中显示占位器(fallback),以便读者在 Vite 环境下正确实现按需加载。
apps/backend/Dockerfile (1)

15-28: 建议使用非 root 用户运行容器

静态分析工具 Trivy 标记了容器以 root 用户运行的安全风险。Node.js Alpine 镜像已内置 node 用户,建议在 runner 阶段切换到该用户以提高安全性。

🔒️ 建议添加 USER 指令
 FROM node:24-alpine AS runner
 WORKDIR /app
 RUN corepack enable

 COPY --from=builder /app/node_modules ./node_modules
 COPY --from=builder /app/apps/backend/node_modules ./apps/backend/node_modules
 COPY --from=builder /app/apps/backend/dist ./apps/backend/dist
 COPY --from=builder /app/apps/backend/package.json ./apps/backend/
 COPY --from=builder /app/apps/backend/logs ./apps/backend/logs
 COPY package.json pnpm-workspace.yaml ./

+RUN chown -R node:node /app
+USER node
+
 ENV NODE_ENV=production
 EXPOSE 8888
 CMD ["node", "apps/backend/dist/index.js"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend/Dockerfile` around lines 15 - 28, 当前 runner 阶段容器以 root 身份运行(见
FROM node:24-alpine AS runner、WORKDIR /app、CMD ["node",
"apps/backend/dist/index.js"]),需要切换到非 root 用户以消除 Trivy 报告的风险;在 runner 阶段在确保 /app
及其子目录(由 COPY 复制的文件)归属非 root 用户后切换到内置 node 用户(或创建/使用特定非特权用户),即在复制文件后执行对 /app
目录的所有权调整(chown 到 node)并添加 USER node,这样运行 CMD 时不会以 root 启动并能访问必要文件。
apps/frontend/src/App.tsx (1)

22-28: 考虑添加 404 路由处理

当前路由配置没有处理未知路径的情况。用户访问不存在的路由时会看到空白页面。

♻️ 建议添加通配符路由
                     <Routes>
                         <Route path="/" element={<Navigate to="/home" replace />} />
                         <Route path="/home" element={<HomePage />} />
                         <Route path="/category" element={<CategoryPage />} />
                         <Route path="/detail" element={<DetailPage />} />
                         <Route path="/setting" element={<SettingPage />} />
+                        <Route path="*" element={<Navigate to="/home" replace />} />
                     </Routes>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/App.tsx` around lines 22 - 28, Routes lacks a catch-all for
unknown paths which causes blank pages; add a wildcard Route (path="*") to the
existing Routes block so unknown URLs render a 404/NotFound view (or redirect) —
create or use a NotFoundPage component and add Route with element={<NotFoundPage
/>} (or element={<Navigate to="/home" replace />} if you prefer redirect)
alongside the other Route entries (Routes, Route, Navigate, HomePage,
CategoryPage, DetailPage, SettingPage).
apps/backend/package.json (1)

19-20: ESLint 配置不必要地将 React 规则应用于后端代码

根据 eslint.config.mjs,React 和 React Hooks 插件的规则应用到 **/*.{ts,tsx,js,jsx} 全局范围,而后端代码中无 React 依赖且不使用任何 React Hooks。建议在 ESLint 配置中限制 React 相关规则仅应用于前端目录(如 apps/frontend/**),避免不必要的规则污染。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend/package.json` around lines 19 - 20, The ESLint config currently
applies React and React Hooks rules globally via the file glob pattern
"**/*.{ts,tsx,js,jsx}"; update eslint.config.mjs to restrict React-related
plugins/rules so they only target the front-end (e.g., use an override or change
the files pattern to "apps/frontend/**" or "apps/frontend/**/*.{ts,tsx,js,jsx}")
and remove React/react-hooks rules from backend-targeted patterns; ensure
backend files continue to use appropriate Node/TypeScript rules and that
React/react-hooks rules remain applied only to the frontend (identify the plugin
names "plugin:react" / "react-hooks" and the global files/glob pattern in
eslint.config.mjs when making the change).
eslint.config.mjs (1)

44-54: 导入排序配置与项目约定不一致。

当前配置 'newlines-between': 'never' 不允许导入组之间有空行,但根据项目编码规范,导入顺序应在 builtins → externals → internals 组之间保留空行。

如果这是有意的配置变更,请确认更新相关文档;否则建议调整为 'always'

♻️ 如需保持空行分隔
             'import-x/order': [
                 'warn',
                 {
                     groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
-                    'newlines-between': 'never',
+                    'newlines-between': 'always',
                     alphabetize: {
                         order: 'asc',
                         caseInsensitive: true
                     }
                 }
             ]

Based on learnings: "Import order must follow: builtins → externals → internals, with blank lines between groups"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eslint.config.mjs` around lines 44 - 54, The import order rule
'import-x/order' currently sets 'newlines-between': 'never', which contradicts
the project convention requiring blank lines between builtins, externals and
internals; update the rule configuration for 'import-x/order' to use
'newlines-between': 'always' so builtins → externals → internals are separated
by blank lines (or, if the change was intentional, ensure the project docs are
updated to reflect the new convention).
apps/frontend/conf/nginx.conf (1)

1-34: Nginx 配置结构良好。

配置正确设置了:

  • Gzip 压缩
  • 静态资源长期缓存
  • API 代理到 backend:8888(与后端配置一致)
  • SPA 路由回退

可选改进:考虑添加基础安全响应头以增强安全性。

🛡️ 可选:添加安全响应头
 server {
     listen 80;
     server_name localhost;
     root /usr/share/nginx/html;
     index index.html;

+    # 安全响应头
+    add_header X-Content-Type-Options "nosniff" always;
+    add_header X-Frame-Options "SAMEORIGIN" always;
+
     # Gzip 压缩
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/conf/nginx.conf` around lines 1 - 34, Add common security
response headers in the nginx server block to harden responses: insert
add_header directives (e.g., X-Frame-Options, X-Content-Type-Options,
Referrer-Policy, Permissions-Policy, and a conservative Content-Security-Policy)
inside the main server { } (or inside location / to apply to SPA responses) and
ensure Strict-Transport-Security is added only when TLS is enabled; also make
sure add_header uses the always flag where appropriate and that headers are not
overridden by the /api proxy (add them in both server block and proxy_set_header
contexts if needed).
apps/frontend/src/pages/detail/index.tsx (1)

104-111: 给懒加载播放器补一个局部 Suspense 边界。

PlayerComponent 已经改成 React.lazy(),但本文件里已经没有对应的 Suspense 包裹了。若路由上层没有统一边界,播放器首次渲染会直接挂起;即便上层有全局边界,播放器 chunk 的加载也会把整页一起切到 fallback。

💡 建议改法
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { Suspense, useEffect, useMemo, useState } from 'react';
@@
-                    <PlayerComponent
-                        url={playerUrl}
-                        onError={(msg: string) => {
-                            message.error(msg);
-                        }}
-                        showType={playerShowType}
-                        style={{ width: '100%' }}
-                    />
+                    <Suspense fallback={<Loading />}>
+                        <PlayerComponent
+                            url={playerUrl}
+                            onError={(msg: string) => {
+                                message.error(msg);
+                            }}
+                            showType={playerShowType}
+                            style={{ width: '100%' }}
+                        />
+                    </Suspense>

Also applies to: 177-177

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/pages/detail/index.tsx` around lines 104 - 111,
PlayerComponent is now lazy-loaded (React.lazy) but this file no longer wraps it
in a local Suspense boundary, so its initial load can suspend the whole page;
wrap each usage of PlayerComponent in a React.Suspense with a small local
fallback (e.g., spinner or skeleton) to limit suspension to the player only,
ensure React.Suspense is imported where missing, and apply the same local
Suspense wrapper to the other PlayerComponent instance referenced later in the
file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/backend/src/routes/registry.ts`:
- Around line 25-29: The production branch uses require('./registry.gen') inside
an ESM module which throws "require is not defined"; change that to use dynamic
import: await import('./registry.gen') and assign mod.namespaces to namespaces
and mod.default to app. Make the enclosing function that contains the
isProduction check async (or convert its caller to await it) so you can use
await import, and keep references to the symbols namespaces and app and the
module name './registry.gen' when updating the code.

In `@apps/frontend/index.html`:
- Line 2: The page currently sets the HTML root element's language to lang="en"
which conflicts with the Chinese content; update the <html> element's lang
attribute from "en" to "zh-CN" (i.e., change lang="en" → lang="zh-CN") so screen
readers and input methods match the page language, and re-run any HTML
accessibility/lint checks to validate the change.
- Line 5: 移除 viewport 元标签中阻止缩放的属性:删除 user-scalable=no 和
maximum-scale=1.0(以及任何类似阻止缩放的属性),保留响应设置例如 width=device-width 和
initial-scale=1.0,以恢复用户缩放能力并改善可访问性;在 apps/frontend 的 index.html 中定位包含 <meta
name="viewport"> 的标签并更新其属性即可。

In `@apps/frontend/src/components/InitProvider.tsx`:
- Around line 14-18: The redirect in InitProvider's useEffect uses
navigate('/setting') which pushes a history entry and can create a back-button
redirect loop; update the navigate call inside the useEffect to perform a
replace navigation (use navigate('/setting', { replace: true })) so the settings
redirect replaces the current history entry instead of adding one; ensure you
update the call site in the InitProvider component (the useEffect containing
vod_hub_api, hasError and navigate) and keep the effect dependencies unchanged.

In `@apps/frontend/src/components/video/VodSearch/index.tsx`:
- Around line 192-193: The route build in the VodSearch component currently
encodes vod.vod_id but not the site parameter (see the navigate call that
constructs `/detail?id=${encodeURIComponent(vod.vod_id as
string)}&site=${site}`), which can break when site contains special characters;
update that navigate invocation (and the duplicate occurrence later) to encode
the site value as well (e.g., use encodeURIComponent(site)) so both id and site
are safely URL-encoded before navigating.

In `@apps/frontend/src/components/video/VodTypes/index.tsx`:
- Around line 92-99: The URL construction in handleTabClick uses raw values
(name, key, site) which can break when they contain special characters; update
handleTabClick to encode query parameters before calling navigate (e.g., use
encodeURIComponent or build the query via URLSearchParams) so the name derived
from items.find(...)? .label and other params are safely encoded when navigating
to `/category?id=...&name=...&site=...`; ensure both the 'name' and other
dynamic values (key, site) are encoded consistently.

In `@CLAUDE.MD`:
- Around line 49-50: Update the custom provider guidance to explicitly require
these individual route files—namespace.ts, home.ts, homeVod.ts, category.ts,
detail.ts, play.ts, and search.ts—and state that each file must export a route
object that implements the Route interface (i.e., export const route: Route =
...); also clarify that CMS Providers only need namespace.ts and index.ts using
the createCMSRoutes() factory; ensure the wording replaces the vague "home.ts,
category.ts, etc." with this exact list and the export requirement so generated
routes follow the expected structure.
- Around line 144-153: The markdown table starting with the header "| Item |
Convention | Example |" lacks blank lines before and after it (causing
markdownlint MD058); add one empty line immediately before that table header and
one empty line immediately before the following "### Git Workflow" heading so
the table is separated from surrounding content and the lint warning is
resolved.

In `@docker-compose.prod.yml`:
- Line 27: The CACHE_TTL environment value is currently set to 60000 but the
config code multiplies process.env.CACHE_TTL by 1000 when computing ttl (ttl:
process.env.CACHE_TTL ? parseInt(process.env.CACHE_TTL, 10) * 1000 : 1000 * 60),
so change the env value to seconds (e.g., set CACHE_TTL=60) in the
docker-compose file to produce a 60s TTL; ensure the updated value is applied
where CACHE_TTL is read (process.env.CACHE_TTL) and adjust any related docs if
necessary.

In `@package.json`:
- Line 27: 从 package.json 中移除未使用的依赖 "eslint-plugin-compat":在 package.json 中删除
"eslint-plugin-compat": "^7.0.1" 条目,确认 eslint.config.mjs
没有引用或导入该插件(若存在引用一并移除),然后更新锁文件并重新安装依赖(运行 npm install 或 yarn install / pnpm
install)以使 package-lock.json / yarn.lock 与 package.json 同步。

In `@README.md`:
- Around line 172-184: Update the two Docker Compose commands in the README:
replace the legacy "docker-compose up -d" invocation with "docker compose up -d"
and replace "docker-compose -f docker-compose.prod.yml up -d" with "docker
compose -f docker-compose.prod.yml up -d"; edit the section that references
docker-compose.yml and docker-compose.prod.yml so the examples use the modern
"docker compose" syntax.

---

Outside diff comments:
In `@apps/frontend/src/components/video/VodPalyer/index.tsx`:
- Around line 19-52: The VodPalyer effect currently constructs a Player but
never assigns it to xgInstanceRef.current or cleans it up; update the
useDeepCompareEffect in VodPalyer to set xgInstanceRef.current = player after
creation, attach the error handler to that instance, and return a cleanup
function that removes the 'error' listener and calls the player's destroy method
(or equivalent) to dispose the instance when url or showType changes or the
component unmounts; ensure you also skip creation when showType === 'iframe' as
before.

In `@apps/frontend/src/pages/category/index.tsx`:
- Around line 52-62: 第二个 useEffect 在调用 getCategory(id, filters) 前应先确认 site 存在并把
site 加入依赖以避免竞态:在包含 getCategory 调用的 effect(当前以 [filters, id] 为依赖的那个)中先检查 typeof
site === 'string' && site,然后才调用 getCategory;同时将 site 写入该 effect 的依赖数组(即
[filters, id, site]),确保当 site 变化时会重新触发并避免用空 site 发起请求;保留第一个 effect 用于基于 site
为空时的 navigate('/home') 重定向逻辑。

In `@apps/frontend/src/pages/detail/index.tsx`:
- Around line 117-131: The Select is using defaultValue so it doesn't update
when movieDetail or activePlayList changes; change Select to be a controlled
component by replacing defaultValue with value={activePlayList?.name} (use the
same unique symbols: Select, activePlayList, setActivePlayList,
movieDetail?.vod_play_list) and keep the onChange handler to find and set the
active playlist so the UI stays in sync when handleDetail() updates state;
ensure options still map from movieDetail?.vod_play_list to provide matching
value strings.

---

Nitpick comments:
In @.cursor/rules/frontend/workflow.mdc:
- Line 69: 本条规则当前建议使用 Next.js 的 `dynamic`,但在 Vite + React 项目里应改为说明使用 React.lazy
和 Suspense 实现动态导入;请在 workflow.mdc 中把 “Use `dynamic` imports for heavy components
(e.g., video player)” 文本改为推荐使用 `React.lazy()` + `Suspense`(针对重组件如 VideoPlayer 或
video player),并补充短说明如何在组件加载失败或加载中显示占位器(fallback),以便读者在 Vite 环境下正确实现按需加载。

In @.prettierignore:
- Line 6: 当前 .prettierignore 中的全局模式 `**/*.json` 导致所有 JSON 文件(包括 .lintstagedrc 中的
*.{md,json})被跳过,破坏了 JSON 的格式化链路。请在 .prettierignore 中删除或替换 `**/*.json`
为仅匹配构建产物的具体路径(例如 `dist/**/*.json`、`build/**/*.json`、或其它产物目录),确保不再全局忽略
JSON,从而恢复对项目根目录和源文件(如 .lintstagedrc 指定的 *.json)的格式化。

In `@apps/backend/Dockerfile`:
- Around line 15-28: 当前 runner 阶段容器以 root 身份运行(见 FROM node:24-alpine AS
runner、WORKDIR /app、CMD ["node", "apps/backend/dist/index.js"]),需要切换到非 root
用户以消除 Trivy 报告的风险;在 runner 阶段在确保 /app 及其子目录(由 COPY 复制的文件)归属非 root 用户后切换到内置 node
用户(或创建/使用特定非特权用户),即在复制文件后执行对 /app 目录的所有权调整(chown 到 node)并添加 USER node,这样运行 CMD
时不会以 root 启动并能访问必要文件。

In `@apps/backend/package.json`:
- Around line 19-20: The ESLint config currently applies React and React Hooks
rules globally via the file glob pattern "**/*.{ts,tsx,js,jsx}"; update
eslint.config.mjs to restrict React-related plugins/rules so they only target
the front-end (e.g., use an override or change the files pattern to
"apps/frontend/**" or "apps/frontend/**/*.{ts,tsx,js,jsx}") and remove
React/react-hooks rules from backend-targeted patterns; ensure backend files
continue to use appropriate Node/TypeScript rules and that React/react-hooks
rules remain applied only to the frontend (identify the plugin names
"plugin:react" / "react-hooks" and the global files/glob pattern in
eslint.config.mjs when making the change).

In `@apps/frontend/conf/nginx.conf`:
- Around line 1-34: Add common security response headers in the nginx server
block to harden responses: insert add_header directives (e.g., X-Frame-Options,
X-Content-Type-Options, Referrer-Policy, Permissions-Policy, and a conservative
Content-Security-Policy) inside the main server { } (or inside location / to
apply to SPA responses) and ensure Strict-Transport-Security is added only when
TLS is enabled; also make sure add_header uses the always flag where appropriate
and that headers are not overridden by the /api proxy (add them in both server
block and proxy_set_header contexts if needed).

In `@apps/frontend/Dockerfile`:
- Around line 23-28: The Dockerfile currently runs Nginx as root; change the
base/runtime image to a non-root variant (e.g., use an nginx unprivileged image)
to remove the root-user risk and then update related configs: switch the FROM in
apps/frontend/Dockerfile to the non-root nginx image and ensure the nginx.conf
referenced by COPY (apps/frontend/conf/nginx.conf) uses a non-privileged listen
port, and adjust docker-compose.prod.yml port mappings accordingly so
host→container port mapping matches the new unprivileged port.

In `@apps/frontend/src/App.tsx`:
- Around line 22-28: Routes lacks a catch-all for unknown paths which causes
blank pages; add a wildcard Route (path="*") to the existing Routes block so
unknown URLs render a 404/NotFound view (or redirect) — create or use a
NotFoundPage component and add Route with element={<NotFoundPage />} (or
element={<Navigate to="/home" replace />} if you prefer redirect) alongside the
other Route entries (Routes, Route, Navigate, HomePage, CategoryPage,
DetailPage, SettingPage).

In `@apps/frontend/src/pages/detail/index.tsx`:
- Around line 104-111: PlayerComponent is now lazy-loaded (React.lazy) but this
file no longer wraps it in a local Suspense boundary, so its initial load can
suspend the whole page; wrap each usage of PlayerComponent in a React.Suspense
with a small local fallback (e.g., spinner or skeleton) to limit suspension to
the player only, ensure React.Suspense is imported where missing, and apply the
same local Suspense wrapper to the other PlayerComponent instance referenced
later in the file.

In `@docker-compose.prod.yml`:
- Around line 34-37: 当前 docker-compose 中的 redis 服务定义 (redis, image:
redis:alpine, ports: '127.0.0.1:6379:6379')
未配置持久化和重启策略;如果需要保留数据,请为服务添加持久化卷绑定或命名卷并配置 RDB/AOF 持久化相关设置以及合适的 restart 策略(例如
always 或 unless-stopped)以提升可靠性;定位并修改服务块 redis,加入 volumes 条目指向主机目录或命名卷并在
docker-compose 中添加 restart: 条目,同时如需持久化请在 Redis 配置(或指定命令/配置文件)中启用 RDB/AOF 参数。

In `@eslint.config.mjs`:
- Around line 44-54: The import order rule 'import-x/order' currently sets
'newlines-between': 'never', which contradicts the project convention requiring
blank lines between builtins, externals and internals; update the rule
configuration for 'import-x/order' to use 'newlines-between': 'always' so
builtins → externals → internals are separated by blank lines (or, if the change
was intentional, ensure the project docs are updated to reflect the new
convention).

In `@tsconfig.base.json`:
- Around line 1-13: Add "isolatedModules": true to the compilerOptions of the
frontend tsconfig to ensure compatibility with Vite/esbuild single-file
transpilation; locate the apps/frontend/tsconfig.json (the file that defines
compilerOptions for the frontend build) and add the isolatedModules flag under
compilerOptions so it reads compilerOptions { ..., "isolatedModules": true }.
🪄 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: 1449fa5d-eb6d-40a0-9c38-93c09c192df5

📥 Commits

Reviewing files that changed from the base of the PR and between 4ee8bc2 and e42fb46.

⛔ Files ignored due to path filters (2)
  • apps/frontend/app/favicon.ico is excluded by !**/*.ico
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (115)
  • .cursor/rules/frontend/code-style.mdc
  • .cursor/rules/frontend/project.mdc
  • .cursor/rules/frontend/structure.mdc
  • .cursor/rules/frontend/workflow.mdc
  • .github/workflows/docker-image.yml
  • .lintstagedrc
  • .prettierignore
  • .prettierrc
  • AGENTS.md
  • AGENTS.md
  • CLAUDE.MD
  • Dockerfile
  • README.md
  • apps/backend/Dockerfile
  • apps/backend/package.json
  • apps/backend/src/api/index.ts
  • apps/backend/src/api/namespace/index.ts
  • apps/backend/src/app.tsx
  • apps/backend/src/index.ts
  • apps/backend/src/middleware/cache.ts
  • apps/backend/src/routes/360kan/category.ts
  • apps/backend/src/routes/360kan/detail.ts
  • apps/backend/src/routes/360kan/home.ts
  • apps/backend/src/routes/360kan/homeVod.ts
  • apps/backend/src/routes/360kan/play.ts
  • apps/backend/src/routes/360kan/request.ts
  • apps/backend/src/routes/360kan/search.ts
  • apps/backend/src/routes/360zy/index.ts
  • apps/backend/src/routes/bdzy/index.ts
  • apps/backend/src/routes/bfzy/index.ts
  • apps/backend/src/routes/feifan/index.ts
  • apps/backend/src/routes/guangsuzy/index.ts
  • apps/backend/src/routes/hongniuzy/index.ts
  • apps/backend/src/routes/huyazy/index.ts
  • apps/backend/src/routes/ikunzy/index.ts
  • apps/backend/src/routes/lzzy/index.ts
  • apps/backend/src/routes/mdzy/index.ts
  • apps/backend/src/routes/proxy.ts
  • apps/backend/src/routes/registry.ts
  • apps/backend/src/routes/sdzy/index.ts
  • apps/backend/src/routes/subozy/index.ts
  • apps/backend/src/utils/cache/index.ts
  • apps/backend/src/utils/cms/category/index.ts
  • apps/backend/src/utils/cms/detail/index.ts
  • apps/backend/src/utils/cms/factory.ts
  • apps/backend/src/utils/cms/home/index.ts
  • apps/backend/src/utils/cms/homeVod/index.ts
  • apps/backend/src/utils/cms/play/index.ts
  • apps/backend/src/utils/cms/search/index.ts
  • apps/backend/src/utils/logger/index.ts
  • apps/frontend/Dockerfile
  • apps/frontend/app/home/components/HomeCarousel/index.tsx
  • apps/frontend/app/layout.tsx
  • apps/frontend/conf/nginx.conf
  • apps/frontend/index.html
  • apps/frontend/lib/types/index.ts
  • apps/frontend/next.config.ts
  • apps/frontend/package.json
  • apps/frontend/postcss.config.mjs
  • apps/frontend/src/App.tsx
  • apps/frontend/src/components/BasicLayout.module.scss
  • apps/frontend/src/components/BasicLayout.tsx
  • apps/frontend/src/components/Disclaimer.tsx
  • apps/frontend/src/components/InitProvider.tsx
  • apps/frontend/src/components/SiteHeader.tsx
  • apps/frontend/src/components/ThemeProvider.tsx
  • apps/frontend/src/components/icons/AtomIcon.tsx
  • apps/frontend/src/components/icons/SearchIcon.tsx
  • apps/frontend/src/components/index.module.scss
  • apps/frontend/src/components/ui/Loading/Loading.tsx
  • apps/frontend/src/components/ui/Loading/index.module.scss
  • apps/frontend/src/components/ui/Loading/index.ts
  • apps/frontend/src/components/ui/ThemeSelector.module.scss
  • apps/frontend/src/components/ui/ThemeSelector.tsx
  • apps/frontend/src/components/video/VodList/index.module.scss
  • apps/frontend/src/components/video/VodList/index.tsx
  • apps/frontend/src/components/video/VodPalyer/index.module.scss
  • apps/frontend/src/components/video/VodPalyer/index.tsx
  • apps/frontend/src/components/video/VodSearch/index.tsx
  • apps/frontend/src/components/video/VodSites/index.module.scss
  • apps/frontend/src/components/video/VodSites/index.tsx
  • apps/frontend/src/components/video/VodTypes/index.module.scss
  • apps/frontend/src/components/video/VodTypes/index.tsx
  • apps/frontend/src/globals.scss
  • apps/frontend/src/lib/constant/llm.ts
  • apps/frontend/src/lib/constant/prompt.ts
  • apps/frontend/src/lib/constant/site.ts
  • apps/frontend/src/lib/hooks/useIsMobile/index.ts
  • apps/frontend/src/lib/store/useSettingStore.ts
  • apps/frontend/src/lib/store/useThemeStore.ts
  • apps/frontend/src/lib/store/useVodSitesStore.ts
  • apps/frontend/src/lib/themes/index.ts
  • apps/frontend/src/lib/types/index.ts
  • apps/frontend/src/lib/utils/index.ts
  • apps/frontend/src/lib/utils/request/index.ts
  • apps/frontend/src/main.tsx
  • apps/frontend/src/pages/category/index.module.scss
  • apps/frontend/src/pages/category/index.tsx
  • apps/frontend/src/pages/detail/index.module.scss
  • apps/frontend/src/pages/detail/index.tsx
  • apps/frontend/src/pages/home/index.module.scss
  • apps/frontend/src/pages/home/index.tsx
  • apps/frontend/src/pages/setting/index.module.scss
  • apps/frontend/src/pages/setting/index.tsx
  • apps/frontend/src/services/index.ts
  • apps/frontend/src/services/vodhub/index.ts
  • apps/frontend/tsconfig.json
  • apps/frontend/vite.config.ts
  • commitlint.config.js
  • docker-compose.prod.yml
  • docker-compose.yml
  • eslint.config.js
  • eslint.config.mjs
  • package.json
  • tsconfig.base.json
💤 Files with no reviewable changes (48)
  • apps/backend/src/api/index.ts
  • apps/backend/src/app.tsx
  • apps/backend/src/middleware/cache.ts
  • apps/backend/src/routes/360zy/index.ts
  • apps/backend/src/routes/bfzy/index.ts
  • apps/backend/src/routes/hongniuzy/index.ts
  • apps/backend/src/routes/proxy.ts
  • apps/backend/src/routes/bdzy/index.ts
  • apps/backend/src/routes/360kan/category.ts
  • apps/backend/src/routes/360kan/detail.ts
  • apps/backend/src/routes/360kan/home.ts
  • apps/backend/src/routes/360kan/request.ts
  • apps/backend/src/routes/feifan/index.ts
  • apps/backend/src/routes/huyazy/index.ts
  • apps/backend/src/routes/ikunzy/index.ts
  • apps/backend/src/routes/mdzy/index.ts
  • apps/backend/src/routes/sdzy/index.ts
  • apps/backend/src/routes/guangsuzy/index.ts
  • apps/backend/src/routes/360kan/play.ts
  • apps/backend/src/api/namespace/index.ts
  • apps/backend/src/utils/cms/detail/index.ts
  • apps/backend/src/routes/subozy/index.ts
  • apps/backend/src/utils/cache/index.ts
  • apps/backend/src/routes/lzzy/index.ts
  • apps/backend/src/routes/360kan/homeVod.ts
  • apps/backend/src/routes/360kan/search.ts
  • apps/backend/src/utils/cms/category/index.ts
  • apps/backend/src/utils/cms/homeVod/index.ts
  • apps/backend/src/utils/cms/home/index.ts
  • apps/frontend/src/components/ui/Loading/Loading.tsx
  • apps/frontend/src/lib/store/useThemeStore.ts
  • apps/backend/src/utils/cms/play/index.ts
  • apps/backend/src/utils/cms/factory.ts
  • apps/frontend/src/lib/constant/llm.ts
  • apps/frontend/src/lib/store/useVodSitesStore.ts
  • apps/backend/src/utils/logger/index.ts
  • apps/backend/src/utils/cms/search/index.ts
  • apps/frontend/src/components/ThemeProvider.tsx
  • apps/frontend/src/components/ui/ThemeSelector.tsx
  • Dockerfile
  • apps/frontend/src/components/video/VodSites/index.tsx
  • apps/frontend/src/components/video/VodList/index.tsx
  • apps/frontend/lib/types/index.ts
  • apps/frontend/next.config.ts
  • apps/frontend/postcss.config.mjs
  • apps/frontend/app/layout.tsx
  • apps/frontend/app/home/components/HomeCarousel/index.tsx
  • eslint.config.js

Comment on lines 25 to 29
if (isProduction) {
const mod = (await import('./registry.gen')) as { namespaces: typeof namespaces; default: Hono };
// eslint-disable-next-line
const mod = require('./registry.gen') as { namespaces: typeof namespaces; default: Hono };
namespaces = mod.namespaces;
app = mod.default;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Verify module system settings =="
fd -HI '^package\.json$' apps/backend | while read -r f; do
  echo "--- $f"
  jq -r '.name, (.type // "<no type field>")' "$f"
done

echo
echo "== Verify TS module target =="
fd -HI 'tsconfig.*\.json' apps/backend | while read -r f; do
  echo "--- $f"
  jq -r '.compilerOptions.module // "<unset>", .compilerOptions.moduleResolution // "<unset>"' "$f"
done

echo
echo "== Check current require() usage in registry.ts =="
rg -n -C2 '\brequire\s*\(' apps/backend/src/routes/registry.ts

echo
echo "== Locate generated registry artifact (if present) =="
fd -HI 'registry\.gen\.(js|mjs|cjs|ts)$' apps/backend/src/routes || true

Repository: consistent-k/VodHub

Length of output: 1790


生产分支在 ESM 环境下使用 require() 会导致启动失败

第 27 行在 ESM 文件中直接使用 require('./registry.gen')。根据项目配置(type: module 在 package.json),此代码会抛出 require is not defined 错误,导致生产环境启动失败。建议改用 await import('./registry.gen')

修复建议
 if (isProduction) {
-    // eslint-disable-next-line
-    const mod = require('./registry.gen') as { namespaces: typeof namespaces; default: Hono };
+    const mod = (await import('./registry.gen')) as {
+        namespaces: typeof namespaces;
+        default: Hono;
+    };
     namespaces = mod.namespaces;
     app = mod.default;
 }

需要将包含此代码的函数改为 async

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend/src/routes/registry.ts` around lines 25 - 29, The production
branch uses require('./registry.gen') inside an ESM module which throws "require
is not defined"; change that to use dynamic import: await
import('./registry.gen') and assign mod.namespaces to namespaces and mod.default
to app. Make the enclosing function that contains the isProduction check async
(or convert its caller to await it) so you can use await import, and keep
references to the symbols namespaces and app and the module name
'./registry.gen' when updating the code.

Comment thread apps/frontend/index.html Outdated
Comment thread apps/frontend/index.html
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

请移除禁止缩放配置,这会造成可访问性阻断

Line 5 使用 user-scalable=nomaximum-scale=1.0 会阻止用户缩放页面,低视力用户无法完成基本阅读操作。

修复示例
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/index.html` at line 5, 移除 viewport 元标签中阻止缩放的属性:删除
user-scalable=no 和 maximum-scale=1.0(以及任何类似阻止缩放的属性),保留响应设置例如 width=device-width
和 initial-scale=1.0,以恢复用户缩放能力并改善可访问性;在 apps/frontend 的 index.html 中定位包含 <meta
name="viewport"> 的标签并更新其属性即可。

Comment thread apps/frontend/src/components/InitProvider.tsx
Comment on lines +192 to 193
navigate(`/detail?id=${encodeURIComponent(vod.vod_id as string)}&site=${site}`);
}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

请同时编码 site 查询参数,避免特殊字符导致路由参数损坏

目前只编码了 vod_id。当 site 含中文或 & 时,详情页参数可能被截断或解析错误。

修复示例
- navigate(`/detail?id=${encodeURIComponent(vod.vod_id as string)}&site=${site}`);
+ navigate(`/detail?id=${encodeURIComponent(String(vod.vod_id ?? ''))}&site=${encodeURIComponent(site)}`);

Also applies to: 226-227

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/components/video/VodSearch/index.tsx` around lines 192 -
193, The route build in the VodSearch component currently encodes vod.vod_id but
not the site parameter (see the navigate call that constructs
`/detail?id=${encodeURIComponent(vod.vod_id as string)}&site=${site}`), which
can break when site contains special characters; update that navigate invocation
(and the duplicate occurrence later) to encode the site value as well (e.g., use
encodeURIComponent(site)) so both id and site are safely URL-encoded before
navigating.

Comment thread CLAUDE.MD
Comment on lines +49 to +50
1. **CMS Providers** (Recommended): Only need `namespace.ts` and `index.ts` using `createCMSRoutes()` factory
2. **Custom Providers**: Individual route files (`home.ts`, `category.ts`, etc.) with custom logic
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

自定义 Provider 约束描述不完整,可能导致生成错误路由结构。

这里用“home.ts, category.ts, etc.”过于宽泛,缺少 namespace.tshomeVod.tsdetail.tsplay.tssearch.ts,也未强调“每个文件都要导出符合 Route 接口的 route 对象”。建议写成明确清单,避免后续实现偏差。

建议修订(示例)
-2. **Custom Providers**: Individual route files (`home.ts`, `category.ts`, etc.) with custom logic
+2. **Custom Providers**: Must define individual route files:
+   `namespace.ts`, `home.ts`, `homeVod.ts`, `category.ts`, `detail.ts`, `play.ts`, `search.ts`.
+   Each file must export a `route` object that conforms to the `Route` interface.

Based on learnings: Applies to apps/backend/src/routes/**/*.{ts,tsx} : Custom backend providers must create individual route files (namespace.ts, home.ts, homeVod.ts, category.ts, detail.ts, play.ts, search.ts), each exporting a route object conforming to the Route interface.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
1. **CMS Providers** (Recommended): Only need `namespace.ts` and `index.ts` using `createCMSRoutes()` factory
2. **Custom Providers**: Individual route files (`home.ts`, `category.ts`, etc.) with custom logic
1. **CMS Providers** (Recommended): Only need `namespace.ts` and `index.ts` using `createCMSRoutes()` factory
2. **Custom Providers**: Must define individual route files:
`namespace.ts`, `home.ts`, `homeVod.ts`, `category.ts`, `detail.ts`, `play.ts`, `search.ts`.
Each file must export a `route` object that conforms to the `Route` interface.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.MD` around lines 49 - 50, Update the custom provider guidance to
explicitly require these individual route files—namespace.ts, home.ts,
homeVod.ts, category.ts, detail.ts, play.ts, and search.ts—and state that each
file must export a route object that implements the Route interface (i.e.,
export const route: Route = ...); also clarify that CMS Providers only need
namespace.ts and index.ts using the createCMSRoutes() factory; ensure the
wording replaces the vague "home.ts, category.ts, etc." with this exact list and
the export requirement so generated routes follow the expected structure.

Comment thread CLAUDE.MD
Comment on lines +144 to +153
| Item | Convention | Example |
|---|---|---|
| Variables/functions | `camelCase` | `getLocalhostAddress` |
| Types/interfaces | `PascalCase` | `HomeData`, `RouteItem` |
| Constants | `UPPER_SNAKE_CASE` | `SUCCESS_CODE` |
| Frontend components | `PascalCase` | `VodList` |
| Frontend hooks | `use` prefix | `useIsMobile` |
| Frontend stores | `use` + `Store` suffix | `useSettingStore` |

### Git Workflow
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

表格前后缺少空行,会触发 markdownlint MD058。

建议在表格前(Line 144 前)和表格后(Line 153 前)各补一个空行,消除当前 lint warning。

建议修订(示例)
 ### Naming Conventions
+
 | Item | Convention | Example |
 |---|---|---|
 | Variables/functions | `camelCase` | `getLocalhostAddress` |
 | Types/interfaces | `PascalCase` | `HomeData`, `RouteItem` |
 | Constants | `UPPER_SNAKE_CASE` | `SUCCESS_CODE` |
 | Frontend components | `PascalCase` | `VodList` |
 | Frontend hooks | `use` prefix | `useIsMobile` |
 | Frontend stores | `use` + `Store` suffix | `useSettingStore` |
+
 ### Git Workflow
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| Item | Convention | Example |
|---|---|---|
| Variables/functions | `camelCase` | `getLocalhostAddress` |
| Types/interfaces | `PascalCase` | `HomeData`, `RouteItem` |
| Constants | `UPPER_SNAKE_CASE` | `SUCCESS_CODE` |
| Frontend components | `PascalCase` | `VodList` |
| Frontend hooks | `use` prefix | `useIsMobile` |
| Frontend stores | `use` + `Store` suffix | `useSettingStore` |
### Git Workflow
### Naming Conventions
| Item | Convention | Example |
|---|---|---|
| Variables/functions | `camelCase` | `getLocalhostAddress` |
| Types/interfaces | `PascalCase` | `HomeData`, `RouteItem` |
| Constants | `UPPER_SNAKE_CASE` | `SUCCESS_CODE` |
| Frontend components | `PascalCase` | `VodList` |
| Frontend hooks | `use` prefix | `useIsMobile` |
| Frontend stores | `use` + `Store` suffix | `useSettingStore` |
### Git Workflow
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 144-144: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.MD` around lines 144 - 153, The markdown table starting with the
header "| Item | Convention | Example |" lacks blank lines before and after it
(causing markdownlint MD058); add one empty line immediately before that table
header and one empty line immediately before the following "### Git Workflow"
heading so the table is separated from surrounding content and the lint warning
is resolved.

Comment thread docker-compose.prod.yml Outdated
Comment thread package.json Outdated
Comment thread README.md
@consistent-k consistent-k merged commit 2d66ed0 into main Apr 14, 2026
5 checks passed
@consistent-k consistent-k deleted the dev branch April 14, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant