oa-ai/CLAUDE.md

7.0 KiB
Raw Permalink Blame History

CLAUDE.md — oa.tlyq.ai 统一门户

项目概述

oa-ai 是基于 Next.js 的 OA 统一门户,域名 oa.tlyq.ai。提供站点聚合导航、LLDAP 统一认证入口、用户管理(创建/删除/角色分配、密码修改功能。各子站点assets/issue各自直连 LLDAP 认证,通过共享 JWTtlyq_session cookie, domain=.tlyq.ai实现跨站点免登录。


快速参考

属性
站点域名 oa.tlyq.ai
服务器 txjpIP: 43.133.38.210
代码路径 /root/docker/oa-ai/
本地端口 6179
容器名 oa-ai
默认账号 admin / admin123LLDAP 统一管理)

常用命令

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 邮件发送Resend API创建用户时发送密码设置链接不含明文密码
src/lib/setup-token.ts 一次性密码设置 token 签发/验证JWT24 小时有效)
src/app/setup-password/page.tsx 密码设置页(公开,通过邮件链接 token 访问)
src/app/api/auth/setup-password/route.ts 密码设置 API验证 token + 调用 lldap_set_password
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 登录 APIOA 仅 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 JWT7 天)
  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
运行时动态读取 LLDAP admin 密码通过 docker exec lldap printenv 获取,不存本地
JWT_SECRET dev-secret-key-local 强随机值(与 assets/issue 相同)
COOKIE_DOMAIN ""(空) .tlyq.ai
RESEND_API_KEY re_xxxxxxxxxxxx Resend API KeySending Access 权限)

.env 示例

LDAP_URL=ldap://localhost:3890
LDAP_BASE_DN=dc=tlyq,dc=ai
LDAP_ADMIN_DN=uid=admin,ou=people,dc=tlyq,dc=ai
JWT_SECRET=dev-secret-key-local
COOKIE_DOMAIN=
NODE_ENV=development
RESEND_API_KEY=re_xxxxxxxxxxxx

Docker 部署

txjp 服务器
├── oa-ai容器                 ← Next.js standalone监听 3000
├── nginx-ai                      ← 反向代理 oa.tlyq.ai → oa-ai:3000
└── webnetexternal            ← 共享网络

生产环境需要 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/issueslate/blue

站点 URL 规则

源码中站点跳转 URL 均使用 localhost部署时 deploy-ai.sh 通过 sed 自动替换为生产域名。


开发规范

  • 新增页面:在 src/app/ 下创建,中间件自动检查认证
  • API 路由/api/auth/ 公开,/api/admin/ 需 admin 权限
  • admin 校验verifySharedJwt(token).username === 'admin'

Git Tag 规范

使用日期版本号 vYYYY.MM.DD(如 v2026.05.18)。提交后打 tag 再推送:

git tag v$(date +%Y.%m.%d) && git push origin main && git push origin v$(date +%Y.%m.%d)

同一天多次提交只打一个 tag。详见根目录 CLAUDE.md


故障排查

OA 502 Bad Gateway

常见原因nginx DNS 缓存旧 IP。OA 容器重启后 IP 变化nginx 仍向旧 IP 发送请求。

解决

docker restart nginx-ai

用户管理/角色管理一直加载

原因OA 容器未挂载 assets/issue 的 SQLite 数据库文件,或 LLDAP 容器缺少 sqlite3

检查

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 安装(每次容器重建后需重新安装):

docker exec lldap apk add --no-cache sqlite

生产部署关键点

  • Docker socketOA 需 /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