chore: fork from IRIS track 供 LICA 部门独立运行

- 复制来源: /home/yueli/track @ 192c8ee (feature/ai-audit-update)
- 组织隔离目标: LICA
- 端口规划: 前端 8030 / 后端 8031 / 数据库 8032
- 已排除 deploy.sh、deploy_full.sh、docker-compose.prod.yml(IRIS 生产发布脚本)
- 已排除工作区未提交改动,取干净的 192c8ee 状态
This commit is contained in:
2026-09-21 15:56:52 +08:00
commit 3286a11bc7
212 changed files with 44060 additions and 0 deletions

63
AGENTS.md Normal file
View File

@ -0,0 +1,63 @@
# AGENTS.md
本仓库Track 生产流转系统)的工作笔记。仅在验证过之后才写入,避免传谣。
## 架构速览
- `backend/` FastAPI + SQLAlchemy 2.x(async) + AlembicPostgreSQL。
- `frontend/` React 19 + Vite + antd + Tailwind。路由见 `src/App.tsx`
管理端菜单见 `src/components/layout/AdminLayout.tsx``MENU` 数组)。
- 登录不走 Track 自己的用户表,而是**只读** MOM(KCGL) 的 `sys_user`
`sys_user.username``"真实姓名/登录账号"``login()`
`WHERE username LIKE '%/<账号>'` 匹配,`display_name``/` 拆解得到。
MOM 连接配置在 `app/core/mom_database.py`(同步 psycopg2 引擎)。
## 本地起环境(关键,踩过的坑都在这)
1. **本机没有 Postgres 时需要先装**(容器内 `sudo` 可用):
`sudo -n apt-get install -y --fix-missing postgresql postgresql-contrib`
然后 `sudo -n pg_ctlcluster 17 main start`
本仓库不使用 pgvector无需额外扩展。
2. **数据库端口与生产默认值不同**,必须用环境变量覆盖:
- `DATABASE_URL=postgresql+asyncpg://track:track_prod_2026@127.0.0.1:5432/track_production`
- `MOM_DB_HOST=127.0.0.1``MOM_DB_PORT=5432`
- `SECRET_KEY=<≥32 字符>``DEBUG=false` 时配置项会**拒绝**默认 SECRET_KEY
(见 `app/core/config.py` 的校验),不设会直接 import 失败。
3. 迁移:`cd backend && python3 -m alembic upgrade head`(没有全局 `alembic` 命令,
要用 `python3 -m alembic`)。校验纯 SQL 用 `alembic upgrade head --sql`
4. 前端 proxy 指向 Docker 服务名 `backend:8000`。本机跑要么把
`127.0.0.1 backend` 写进 `/etc/hosts`,要么直接给
`VITE_API_BASE_URL=http://localhost:<port>/api/v1` 绕过 proxy。
注意 dev server 由 `basicSsl` 起 HTTPS跨域需要后端
`CORS_ORIGINS` 加上 `https://localhost:1420`
## 测试的坑(重要)
- **不要用 `starlette.testclient.TestClient` 测异步 SQLAlchemy 应用。**
它每个请求新建事件循环,而引擎是模块级单例、池里挂着 asyncpg 连接,
跨循环复用会报 `got Future attached to a different loop`,表现为随机 500。
正确做法:`httpx.AsyncClient(transport=httpx.ASGITransport(app=app))`
并在单个 `asyncio.run()` 里跑完全部请求。生产 uvicorn 单循环无此问题。
- 仓库目前**没有** pytest 基建,也没有前端测试脚本。
## 已知的待修问题(截至 1.0应用 分支)
- **读接口大面积未鉴权**(已实测,非推测):无 token 直接 200 的包括
`/api/v1/users/`、全部 `/api/v1/dashboard/*`(含
`people-history/export` —— 匿名即可批量导出个人工时台账)、
`/api/v1/analytics/*``/api/v1/screen/*``/api/v1/orders/`
写操作和 `/api/v1/tasks``/api/v1/products` 是有鉴权的。
新增接口请统一用 `app/core/deps.py``require_admin` / `require_roles`
- 「管理员角色」这份规则此前散在 4 处(后端 `task_service``products.py` 内联、
前端 `constants/task.ts``AdminProductsPage` 内联),已因此出过事故。
**后端唯一事实来源是 `app/core/roles.py`,前端用 `constants/task.ts::isAdminRole`。**
新增判断不要手写 `===` 比较。
- `task_logs.task_id` 是 NOT NULL 外键,只能挂任务,不是通用审计。通用审计是
`audit_logs`(本轮新增,由 `app/core/audit_middleware.py` 自动采集)。
## 约定
- 时间统一北京时间(`app/core/time_utils.py`),库里存 timestamptz。
- 中文枚举标签尽量由服务端下发(如审计接口的 `module_label`/`action_label`
避免前端再抄一份映射开始漂移。
- 本仓库的提交信息用中文,说明「为什么」而非「改了什么」。