feat(hub): add /database admin surface with Feishu login

Adds a self-contained `/database/*` HTTP surface under hub/src/database:
- /database/admin: Feishu-only login page (Tailwind, light theme)
- /database/dashboard: session-gated sidebar + content shell
- /database/dev-login: DEV ONLY session bypass, double-gated by
  NODE_ENV != production AND HUB_DEV_LOGIN_BYPASS; never active in prod

hub.ts mounts the plugin after the admin plugin so the cookie parser and
/auth/feishu/* routes are available. The dev bypass logic is fully contained
in the database module; admin auth routes are untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 21:02:04 +08:00
parent 73cb0e5b47
commit df66691d24
5 changed files with 404 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
# src/database/
`/database/*` HTTP 面。代码写在这个目录里,`hub.ts` 通过 `plugin.ts` 挂载它,
所以服务器启动时能正确识别这些路由。
页面:
- `/database/admin` —— 飞书登录页(唯一登录方式)
- `/database/dashboard` —— 左菜单 + 右内容的后台,未登录会跳回 `/database/admin`
登录走平台既有的飞书 OAuth:登录页的按钮指向 `/auth/feishu/<orgSlug>`
回调由 `src/admin/routes/authRoutes.ts` 处理并种下 session cookie。
## 文件
| 文件 | 职责 |
|------|------|
| `plugin.ts` | 模块对外入口,`hub.ts``registerDatabasePlugin()` |
| `routes/databaseRoutes.ts` | 路由 + 页面渲染,**你主要在这里加内容** |
新增一类端点时:要么直接往 `databaseRoutes.ts``app.get("/database/...")`
要么新建 `routes/xxxRoutes.ts` 并在 `databaseRoutes.ts``registerXxxRoutes(app, {...})`
注册一次。
## 约定(与 admin 面一致)
1. 路由用**绝对路径** `"/database/..."`,不用 Fastify prefix —— 每条路由 grep 得到。
2. **guard 前置、fail closed**:凡碰数据的端点第一行先跑
`requireSession` / `requireOrgRole` / `requireProjectPermission`
(都在 `../admin/auth/guards.js`)。
3. **租户隔离**ADR-0020):每个 Prisma 查询都 scope 到 `auth.organization.id`
不得跨 org。禁止无鉴权的数据路由。
4. 数据库通过传入的 `config.prisma` 访问(全进程单例,见 `../db.ts`);
不要在这里 `new PrismaClient()`
## 为什么代码在 `src/` 下
`tsconfig.json` 固定 `rootDir: "src"``include: ["src/**/*.ts"]`。只有
`src/` 下的 `.ts` 会被 `tsc` 编译、被 `tsx watch``npm run dev`)加载。放在
`src/` 之外的目录不会被构建,外部识别不到。