175 lines
6.6 KiB
Markdown
175 lines
6.6 KiB
Markdown
# CLAUDE.md — oa.tlyq.ai 统一门户
|
||
|
||
## 项目概述
|
||
|
||
oa-ai 是基于 Next.js 的 OA 统一门户,域名 `oa.tlyq.ai`。提供站点聚合导航、LLDAP 统一认证入口、用户管理(创建/删除/角色分配)、密码修改功能。各子站点(assets/issue)各自直连 LLDAP 认证,通过共享 JWT(`tlyq_session` cookie, domain=.tlyq.ai)实现跨站点免登录。
|
||
|
||
---
|
||
|
||
## 快速参考
|
||
|
||
| 属性 | 值 |
|
||
|------|-----|
|
||
| 站点域名 | `oa.tlyq.ai` |
|
||
| 服务器 | txjp(IP: 43.133.38.210) |
|
||
| 代码路径 | `/root/docker/oa-ai/` |
|
||
| 本地端口 | 6179 |
|
||
| 容器名 | `oa-ai` |
|
||
| 默认账号 | `admin` / `admin123`(LLDAP 统一管理) |
|
||
|
||
### 常用命令
|
||
|
||
```bash
|
||
npm run dev # 本地开发(端口 6179)
|
||
npm run build # 生产构建
|
||
```
|
||
|
||
---
|
||
|
||
## 关键文件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `src/middleware.ts` | 全局路由守卫:检查 `tlyq_session` cookie,未认证跳转 /login |
|
||
| `src/lib/jwt.ts` | 共享 JWT 签发/验证(HS256,与 assets/issue 共用密钥和格式) |
|
||
| `src/lib/ldap.ts` | LLDAP 认证(ldapAuth)+ 密码修改(ldapChangePassword)+ 用户存在性检查 |
|
||
| `src/lib/email.ts` | 邮件发送(nodemailer,163 企业邮箱,创建用户时发送凭证) |
|
||
| `src/app/page.tsx` | 门户首页:站点卡片导航(核心系统 + 其他站点) |
|
||
| `src/app/login/page.tsx` | 登录页(LLDAP 认证) |
|
||
| `src/app/profile/page.tsx` | 个人信息页(账户信息 + 修改密码) |
|
||
| `src/app/admin/create-user/page.tsx` | 用户管理页(创建/删除/角色管理,仅 admin 可见) |
|
||
| `src/app/api/auth/login/route.ts` | 登录 API(OA 仅 LLDAP 认证,无本地 DB) |
|
||
| `src/app/api/auth/logout/route.ts` | 退出 API(清除 tlyq_session) |
|
||
| `src/app/api/auth/change-password/route.ts` | 修改密码(docker exec 调 lldap_set_password) |
|
||
| `src/app/api/admin/create-user/route.ts` | 创建用户(SQLite 写 LLDAP + 自动同步站点 + 角色设置) |
|
||
| `src/app/api/admin/users/route.ts` | 用户列表/删除(GET/DELETE) |
|
||
| `src/app/api/admin/user-roles/route.ts` | 角色查询/修改(GET/PUT) |
|
||
| `src/components/ThemeToggle.tsx` | 深色/浅色主题切换按钮 |
|
||
| `src/app/profile/change-password-form.tsx` | 修改密码客户端组件 |
|
||
| `src/app/admin/create-user/role-manager.tsx` | 角色管理组件(待保存机制 + 批量提交) |
|
||
|
||
---
|
||
|
||
## 认证机制
|
||
|
||
OA 本身**不存储用户数据**(无本地 users 表),纯 LLDAP 认证:
|
||
|
||
1. 用户登录 → LDAP bind 验证 → 签发 `tlyq_session` JWT(7 天)
|
||
2. 中间件检查 `tlyq_session` → 有效则设置 `session` cookie → 放行
|
||
3. 退出清除 `tlyq_session`
|
||
|
||
跨站点共享:assets/issue 各自中间件优先检查 `tlyq_session`,有效则免登录。
|
||
|
||
---
|
||
|
||
## 环境配置
|
||
|
||
### 本地与云端差异
|
||
|
||
| 环境变量 | 本地开发 | 云服务器(txjp) |
|
||
|---------|---------|----------------|
|
||
| `LDAP_URL` | `ldap://localhost:3890` | `ldap://lldap:3890` |
|
||
| `LDAP_BASE_DN` | `dc=tlyq,dc=ai` | 同 |
|
||
| `LDAP_ADMIN_DN` | `uid=admin,ou=people,dc=tlyq,dc=ai` | 同 |
|
||
| `LDAP_ADMIN_PASS` | `admin123` | LLDAP admin 密码 |
|
||
| `JWT_SECRET` | `dev-secret-key-local` | 强随机值(与 assets/issue 相同) |
|
||
| `COOKIE_DOMAIN` | `""`(空) | `.tlyq.ai` |
|
||
| `SMTP_HOST` | `smtphz.qiye.163.com` | 163 企业邮箱 |
|
||
| `SMTP_PORT` | `465` | SSL 端口 |
|
||
| `SMTP_USER` | `gxp@qx002575.com` | 发件邮箱 |
|
||
| `SMTP_PASS` | 见 .env | 邮箱密码 |
|
||
| `SMTP_FROM` | `gxp@qx002575.com` | 发件人地址 |
|
||
|
||
### `.env` 示例
|
||
|
||
```bash
|
||
LDAP_URL=ldap://localhost:3890
|
||
LDAP_BASE_DN=dc=tlyq,dc=ai
|
||
LDAP_ADMIN_DN=uid=admin,ou=people,dc=tlyq,dc=ai
|
||
LDAP_ADMIN_PASS=admin123
|
||
JWT_SECRET=dev-secret-key-local
|
||
COOKIE_DOMAIN=
|
||
NODE_ENV=development
|
||
SMTP_HOST=smtphz.qiye.163.com
|
||
SMTP_PORT=465
|
||
SMTP_USER=gxp@qx002575.com
|
||
SMTP_PASS=
|
||
SMTP_FROM=gxp@qx002575.com
|
||
```
|
||
|
||
---
|
||
|
||
## Docker 部署
|
||
|
||
```
|
||
txjp 服务器
|
||
├── oa-ai(容器) ← Next.js standalone,监听 3000
|
||
├── nginx-ai ← 反向代理 oa.tlyq.ai → oa-ai:3000
|
||
└── webnet(external) ← 共享网络
|
||
```
|
||
|
||
生产环境需要 OA 容器能访问 Docker socket(`/var/run/docker.sock`)以执行 `docker exec lldap` 修改密码和创建用户。
|
||
|
||
---
|
||
|
||
## 主题切换
|
||
|
||
支持深色/浅色双主题:
|
||
- `layout.tsx` 注入 `<script>` 读取 localStorage/系统偏好设置 `dark` class
|
||
- CSS 变量 `var(--bg)`、`var(--text)` 等响应主题变化
|
||
- `ThemeToggle` 组件:`document.documentElement.classList.toggle('dark')` + localStorage 持久化
|
||
- 配色对齐 assets/issue(slate/blue)
|
||
|
||
---
|
||
|
||
## 站点 URL 规则
|
||
|
||
源码中站点跳转 URL 均使用 localhost,部署时 `deploy-ai.sh` 通过 `sed` 自动替换为生产域名。
|
||
|
||
---
|
||
|
||
## 开发规范
|
||
|
||
- **新增页面**:在 `src/app/` 下创建,中间件自动检查认证
|
||
- **API 路由**:`/api/auth/` 公开,`/api/admin/` 需 admin 权限
|
||
- **admin 校验**:`verifySharedJwt(token).username === 'admin'`
|
||
|
||
---
|
||
|
||
## 故障排查
|
||
|
||
### OA 502 Bad Gateway
|
||
|
||
**常见原因**:nginx DNS 缓存旧 IP。OA 容器重启后 IP 变化,nginx 仍向旧 IP 发送请求。
|
||
|
||
**解决**:
|
||
```bash
|
||
docker restart nginx-ai
|
||
```
|
||
|
||
### 用户管理/角色管理一直加载
|
||
|
||
**原因**:OA 容器未挂载 assets/issue 的 SQLite 数据库文件,或 LLDAP 容器缺少 `sqlite3`。
|
||
|
||
**检查**:
|
||
```bash
|
||
docker exec oa-ai ls /data/other-sites/assets/ # 应有 assets.db, assets.db-wal, assets.db-shm
|
||
docker exec oa-ai ls /data/other-sites/issue/ # 应有 issue.db, issue.db-wal, issue.db-shm
|
||
docker exec lldap which sqlite3 # 应有 /usr/bin/sqlite3
|
||
```
|
||
|
||
**LLDAP 容器 sqlite3 安装**(每次容器重建后需重新安装):
|
||
```bash
|
||
docker exec lldap apk add --no-cache sqlite
|
||
```
|
||
|
||
### 生产部署关键点
|
||
|
||
- **Docker socket**:OA 需 `/var/run/docker.sock` 挂载(用于 `docker exec lldap` 创建用户和改密)
|
||
- **数据库卷**:OA 需挂载 assets/issue 的 Docker volume **整个数据目录**(非单个文件),确保 SQLite WAL 文件(`.db-wal`/`.db-shm`)共享,否则权限管理页面无法实时反映子站点用户变更:
|
||
- `/var/lib/docker/volumes/assets-ai_assets-data/_data` → `/data/other-sites/assets`
|
||
- `/var/lib/docker/volumes/issue-ai_issue-data/_data` → `/data/other-sites/issue`
|
||
- **WAL 共享**:OA 容器必须挂载整个目录而非单个 `.db` 文件。挂载单个文件会导致 WAL 文件独立,sqlite3 CLI 读取过期数据。参见 `docker-compose.yml` 中的 volumes 配置
|
||
- **JWT 密钥**:三站点必须一致(`JWT_SECRET=oa-shared-jwt-secret-tlyq-2026`)
|
||
- **COOKIE_DOMAIN**:生产必须设为 `.tlyq.ai`
|