16 KiB
16 KiB
Sport Era 项目说明
思考语言
思考过程请使用中文。
项目信息
- 基于 likeadmin 的体育资讯 AI 分析 App / 流量平台
- 后端:PHP 8.x + ThinkPHP / likeadmin
- 管理后台:Vue 3 + Vite + Element Plus + TypeScript
- 手机端:uni-app + Vue 3
- PC 前台:Nuxt 3 + Vue 3
- 数据库:MySQL(
sbnews,表前缀la_) - 缓存:Redis(ThinkPHP Cache facade)
子项目开发规范
修改到哪个子项目,则需要遵循对应子项目的 Agent 说明:
| 模块 | Agent 文件 | 职责 |
|---|---|---|
| 后端 | server/AGENTS.md |
API 接口、数据库建模、业务逻辑、定时任务 |
| 管理后台 | admin/AGENTS.md |
消费 adminapi 接口,构建管理页面 |
| 手机端 | uniapp/AGENTS.md |
消费 api 接口,构建 H5/App/小程序页面 |
| PC 前台 | pc/AGENTS.md |
消费 api 接口,构建 Nuxt PC 页面 |
| 测试 | qa/AGENTS.md |
后端 API 验证与前端页面验证 |
编程准则
- 做新功能之前必须先检查现有代码是否已有相关功能,避免重复开发。
- 创建新数据表时,用到的字典、枚举值、状态码等必须配置在现有的数据表或配置表内统一管理,不能硬编码。
- 相同或相似的功能必须封装为可复用的方法,避免重复代码。
- 查询字段、路由、菜单、配置前,优先以当前项目代码和
sbnews.sql/docs/sql/中结构为准;如需线上核对,再按用户要求使用可用 MCP 或指定连接方式。 - 不通过 WSL sshpass/scp 上传代码到服务器;项目代码更新由用户自行通过 SFTP 等方式处理。
- 新增项目级文档(如协作规范、业务进度、设计稿映射、产品方案、实现流程、爬虫说明等)统一存放在
docs/;根目录仅保留README.md、AGENTS.md、文档索引.md等入口文件。仅子项目专属的 README / AGENTS 等说明可放在对应子目录。
常用命令速查
| 模块 | 开发命令 | 构建命令 |
|---|---|---|
| server | php think run |
— |
| admin | npm run dev |
npm run build |
| uniapp | npm run dev:h5 |
npm run build:h5 |
| pc | npm run dev |
npm run generate / npm run build |
自动化执行边界
- 除非用户在当前任务中明确要求,否则不要自动执行构建或测试。
- **持续授权:每次修改真实源码或运行配置后都必须创建 Git commit,无须再次询问。**说明文档及
server/public/admin、server/public/mobile等生成产物不属于该触发范围。 - **
server/例外:**本次修改server/下的真实运行源码或运行配置时,除提交外还必须同步测试服;无需用户重复要求。 admin/、uniapp/、pc/、docker/、python/、qa/、scripts/等非server/源码改动只提交 commit,不自动同步测试站点;用户明确要求时除外。- 用户明确要求“构建”“测试”“部署”“上线”“发布”等操作时,才执行对应命令;但
server/源码变更适用上述持续授权同步例外。 - 对已经由用户给出的命令,可按用户原命令执行;不要额外扩展到未要求的构建、测试、提交或部署步骤。
数据库结构基准
- 数据库表前缀:
la_。 - 配置存储在
la_config表,通过ConfigService::get/set读写。 - 菜单存储在
la_system_menu表,type: M=目录、C=页面、A=按钮权限。 - 定时任务注册在
la_dev_crontab,通过php think crontab统一调度。 - MySQL 保留字如
system、order、group、key等写原生 SQL 时必须用反引号包裹。
数据库连接方式
测试数据库连接信息位于 server/.env(不入库)。连接参数:
| 配置项 | 值 |
|---|---|
| Host | 95.40.220.223 |
| Port | 3300 |
| Database | sbnews |
| User | sbnews |
| Password | 见 server/.env 中 PASSWORD 字段 |
⚠️ 安全提醒:密码禁止硬编码到代码或文档中,统一从
.env读取。命令行查询时避免-p"密码"方式(会暴露在进程列表),改用交互式输入:mysql -h 95.40.220.223 -P 3300 -u sbnews -p sbnews -e "SELECT ..." # 回车后输入密码
代码修改后验证与评审
仅在用户明确要求验证、测试或构建时,代码修改完成后按改动类型选择验证方式;未明确要求时只列出建议命令,不自动执行:
后端接口修改
- PHP 语法检查:
php -l <modified_file.php>。 - 涉及接口时确认控制器、逻辑层、验证器、列表类、模型字段一致。
- 涉及数据库字段时确认表结构、索引、字典或配置存在。
- 检查前端调用方是否需要同步更新。
前端页面修改
- 检查接口请求模块、页面路由、组件引用是否一致。
- 新增 uniapp 页面必须检查
pages.json。 - 涉及条件编译时确认 H5/App/小程序差异。
- 检查控制台、网络请求和页面渲染问题。
通用代码评审清单
| 序号 | 检查项 | 说明 |
|---|---|---|
| 1 | 改动范围 | 确认改动文件列表,是否有遗漏或多余文件 |
| 2 | 跨文件依赖 | 修改 model/controller/API 后,检查引用方是否同步 |
| 3 | 硬编码检查 | 业务枚举、分类、状态优先走字典或配置 |
| 4 | 未使用引入 | 检查多余 import/use |
| 5 | 命名一致性 | 字段、方法、路由命名与现有风格一致 |
| 6 | 安全性 | SQL 拼接、用户输入、权限校验是否安全 |
| 7 | 幂等性 | SQL 初始化必须可重复执行 |
| 8 | 文档同步 | 功能完成后更新 docs/业务进度管理.md |
服务器源码变更后必须同步
- 每次修改
server/下的真实运行源码或运行配置后,完成必要的静态检查后必须先创建 Git commit,再将代码同步到测试服;这是一项持续授权,不需要用户重复要求。 - 使用项目部署脚本并保留
-Sudo参数,目标目录固定为/www/wwwroot/test-server.sbnews.net,避免 Docker 创建的 root 权限文件中断更新。 - 默认使用以下命令将最新代码更新到测试服运行环境:
Set-Location D:\www\gs-sport-era; powershell -ExecutionPolicy Bypass -File .\scripts\deploy-server.ps1 -Sudo -AutoIncremental -AutoIncrementalCommits 3 -RemoteDir /www/wwwroot/test-server.sbnews.net
admin/、uniapp/、pc/、docker/、python/、qa/、scripts/等非server/源码改动必须提交 commit,但不要因此自动同步服务器。docs/等说明文档不触发自动提交或服务器同步。
测试环境命令与 Docker 运行清单
Git 同步
在服务器以 ubuntu 用户执行日常 Git 操作;只有 Docker 命令使用 sudo:
cd /www/wwwroot/test-server.sbnews.net
git remote -v
git fetch origin dev.1.0.0
git pull --ff-only
如果 .git/objects 权限异常,只修复 Git 元数据,不要递归修改整个项目:
sudo chown -R ubuntu:ubuntu .git
sudo chmod -R u+rwX .git
如果 .playwright-mcp/* 等未跟踪生成文件阻塞拉取,先移动到临时目录,再执行 git pull --ff-only:
backup="/tmp/sport-era-playwright-$(date +%Y%m%d%H%M%S)"
mv .playwright-mcp "$backup"
git pull --ff-only
工作区存在历史改动时,可只同步指定运行文件,避免覆盖其它现场文件:
git fetch origin dev.1.0.0
git checkout -f origin/dev.1.0.0 -- docker/docker-compose.dev.yml docker/docker-compose.crawler.yml docker/crawler
Compose 操作
cd /www/wwwroot/test-server.sbnews.net/docker
# 检查配置,不启动服务
sudo docker compose -f docker-compose.dev.yml config -q
sudo docker compose -f docker-compose.crawler.yml config -q
# PHP/前端/开发 crawler 环境
sudo docker compose -f docker-compose.dev.yml ps
sudo docker compose -f docker-compose.dev.yml build crawler
sudo docker compose -f docker-compose.dev.yml up -d --no-build --force-recreate --no-deps crawler
# 知识库 worker:依赖、Dockerfile 或 kb_worker.py 变化后必须重建
sudo docker compose -f docker-compose.crawler.yml build kb-worker
sudo docker compose -f docker-compose.crawler.yml up -d --no-build --force-recreate --no-deps kb-worker
sudo docker compose -f docker-compose.crawler.yml ps kb-worker
sudo docker logs --tail 100 sport-era-kb-worker
当前容器职责
| 容器/服务 | 作用 | 网络与端口 |
|---|---|---|
sport-era-dev-server-1 |
PHP ThinkPHP API | host network,Docker Nginx 对外 8000 |
sport-era-dev-scheduler-1 |
每分钟执行 php think crontab |
host network |
sport-era-crawler |
Python 爬虫与容器 cron | host network,共用 crawler logs/data |
sport-era-kb-worker |
消费 Redis Stream,生成 Embedding,写入 AI 知识库 | host network,Redis Stream ai:kb:sync:stream |
sport-era-dev-nginx-1 |
Docker 内 Nginx/PHP-FPM 反代 | host network,监听 8000 |
sport-era-dev-admin-1 |
Admin Vite 开发服务器 | 5176 |
sport-era-dev-uniapp-h5-1 |
uni-app H5 Vite 开发服务器 | 5177 |
当前 Compose 不启动 MySQL/Redis 容器,使用测试服外部 MySQL 3300 和 Redis 6377;私有连接参数只放在 docker/.env.server、docker/.env.docker。
宿主机 Nginx 与访问验证
修改三个测试域名反代后执行:
sudo nginx -t
sudo systemctl reload nginx
curl -kI https://test-admin.sbnews.net/
curl -kI https://testh5.sbnews.net/
curl -kI https://test-server.sbnews.net/api/index/config
域名映射为:Admin → 5176,H5 → 5177,Server/API → 8000。Admin/H5 当前是 Vite 开发模式,首屏慢时优先检查 Vite 模块转换;需要稳定快速访问时改用生产构建并由 Nginx 托管静态资源。
设计稿映射
设计稿与页面/组件映射统一维护在:
开发或还原视觉前,先确认设计稿名称、页面路径、实现状态与备注。
业务进度管理
当前业务进度、待办事项、避坑记录统一维护在:
开发或接手任务前,先查看该文档确认已完成事项、进行中事项、待办事项与避坑记录。
近期交接总结
- 当前真实开发目录以
D:\www\gs-sport-era为准;Codex worktree(如C:\Users\Administrator\.codex\worktrees\...\gs-sport-era)中的改动不会自动进入真实仓库、git log或服务器运行目录。涉及可部署代码时,先确认改动已经同步到真实目录并形成清晰提交。 - 正确的服务器运行目录是
/www/wwwroot/test-server.sbnews.net;/www/wwwroot/api.sbnews.net不是当前项目的有效同步目录,不要再部署到该路径。排查“代码已更新但服务器没生效”时,本地真实仓库看git log,服务器侧看文件内容、修改时间、容器内/app文件与定时任务日志。 - Docker crawler 任务真实执行入口是
sport-era-crawler容器。更新docker/crawler源码或config/crawler_tasks.yaml后,必须在服务器docker目录执行sudo docker compose -f docker-compose.crawler.yml build crawler和sudo docker compose -f docker-compose.crawler.yml up -d --no-deps crawler;仅重启旧容器不能保证镜像内代码更新,必要时使用--no-cache重建。 - 重启 crawler 后必须核验容器内代码和 cron,而不是只看宿主机源码:例如检查
/app/match_live_stream.py、/app/config/crawler_tasks.yaml,以及cat /etc/cron.d/* | grep match_live_stream。 - 雨燕直播间任务
match_live_stream当前应直接同步all_live_rooms.json,写入主播anchor_id、anchor_name、anchor_avatar、anchor_level以及直播间观看/关注/公告/简介字段;对应 SQL 为docs/sql/alter_match_live_anchor_fields.sql和docs/sql/insert_crontab_match_live_stream.sql。上线后用la_match_live主播字段统计和la_crawler_task_log最近任务状态共同确认是否生效。 - 测试服当前使用 Git 分支
dev.1.0.0,真实目录为/www/wwwroot/test-server.sbnews.net。同步前先确认远端origin、分支和工作区状态;不要在服务器上用 root 执行日常git pull,否则可能让.git/objects出现 root/www/ubuntu 混合权限。 - 测试环境域名反代关系:
test-admin.sbnews.net→ 宿主机5176(Admin Vite)、testh5.sbnews.net→5177(uni-app H5 Vite)、test-server.sbnews.net→8000(Docker Nginx/PHP API)。宿主机 Nginx 配置位于/www/server/panel/vhost/nginx/和对应rewrite/目录,修改后必须执行sudo nginx -t && sudo systemctl reload nginx。 docker/docker-compose.dev.yml当前包含crawler服务;PHP、scheduler、crawler、Docker Nginx 使用 host network 访问测试服 MySQL/Redis。测试服私有docker/.env.server、docker/.env.docker不入库,数据库/Redis 密码不得写入 Git。sport-era-kb-worker使用docker/docker-compose.crawler.yml,通过 Redis Streamai:kb:sync:stream消费知识库任务并生成 Embedding,写入la_ai_kb_document/la_ai_kb_chunk。测试账号仅授权127.0.0.1时,worker 必须使用 host network;crawler 镜像需要cryptography才能连接 MySQLcaching_sha2_password认证。
近期踩坑
Validate::only()只限制校验字段范围,不会自动过滤请求参数;新增字段落库前,要同时检查 validate、logic、model、保存白名单和数据库列是否同步。adminapi/match.match/edit写入失败时,先查测试库或线上库表结构,确认la_match已补齐对应字段,不要只盯业务代码。- 世界杯专题页、比赛详情页这类前后端联动改动,要统一入口显示规则和跳转目标,避免只改一处导致入口不一致。
- 构建产生的
server/public/admin、server/public/mobile等产物不要混进提交,提交前先清理临时截图和生成文件。 - uni-app iOS 端 scroll-view+JS 计算高度 间隙问题:在 iOS(APP-PLUS/MP)端,通过
uni.createSelectorQuery()计算windowHeight - topBar - inputBar然后设置scroll-view的 inlineheight会因安全区域、设备像素比等因素产生几像素偏差,导致scroll-view底部与固定输入栏之间出现间隙。正确做法:页面使用height: 100vh; display: flex; flex-direction: column,topbar 和 input-bar 设flex-shrink: 0,scroll-view 设flex: 1; min-height: 0自然填满剩余空间,不再用 JS 计算高度。 - Vue3
<script setup>中defineEmits和defineProps返回值必须赋值:defineEmits(...)的返回值才是可调用的 emit 函数,直接写defineEmits([...])不赋值会导致 "Can't find variable: emit";defineProps的返回值才能通过props.xxx访问属性,模板中自动解包但脚本中必须用props.xxx。 - 服务器 Git 权限:如果
git pull报insufficient permission for adding an object to repository database .git/objects,通常是之前用sudo git造成.git混合所有者。只修复 Git 元数据:sudo chown -R ubuntu:ubuntu .git && sudo chmod -R u+rwX .git,不要对整个项目目录递归改所有者。 - 服务器 Git 拉取被未跟踪文件阻塞:如果提示
.playwright-mcp/* would be overwritten by merge,这些是浏览器检查生成物。先把明确目录移到/tmp备份或删除,再执行git pull --ff-only;不要使用无范围的git clean -fd。 - 测试域名首屏慢的根因:Admin/H5 当前是 Vite 开发服务器,首轮按需转换大量模块,浏览器首屏可能需要 20–40 秒;宿主机 Nginx 反代本身约几百毫秒。需要快速访问时应构建生产静态资源并由 Nginx 直接托管,但这会改变频繁改代码的即时生效方式。
- uni-app H5 API 地址:H5 浏览器不能请求
http://127.0.0.1:8000,这会被浏览器当作用户本机回环地址并触发 CORS/Private Network 拦截。测试域名应使用https://test-server.sbnews.net/或同域反代路径;修改后需重启/刷新 H5 Vite 服务。