app-template/packages/trpc/AGENTS.md

3.6 KiB
Raw Permalink Blame History

AGENTS.md — @app/trpc

职责

API 层:tRPC 路由 + service 业务逻辑。service 可不依赖 tRPC 独立调用(脚本/测试);DB 读写经 @app/dao,不直接写 SQL。

域划分:

  • 账户域:user、auth
  • 媒体域:挂在 media 路由下的 mount / library / stream / danmaku / scrape / playback

新域按同样模式追加。

结构

src/
  context.ts              # initTRPC 单例 + TrpcContext
  router/
    index.ts              # appRouter 组装(权威定义:user / auth / media)
    user.router.ts        # user 路由(与 index.ts 内定义重复,改路由时两边同步或收敛到一处)
    auth.router.ts        # auth 路由
    media.router.ts       # 媒体域扁平 procedure(mount* / library* / scrape* / playback* / danmaku*)
  services/
    user.service.ts       # userService
    auth.service.ts       # authService:会话 / 密码
    password.ts           # scrypt 哈希(与 @app/db seed 一致)
    procedure.ts          # protectedProcedure 等
    secret.ts             # 媒体流密钥
    mount.service.ts      # mountService:WebDAV 挂载
    webdav-client.ts      # WebDAV 客户端(含单测)
    library.service.ts    # libraryService:扫描 / 分组 / 剧集
    stream.service.ts     # 流式输出(含单测)
    danmaku.service.ts    # danmakuService:弹幕拉取 / 导入 / 设置(含单测)
    scrape.service.ts     # scrapeService:番剧识别 / 绑定(含单测)
    playback.service.ts   # playbackService:进度上报 / 续播
  load-env.ts
  server.ts               # 独立 HTTP 服务(PORT,默认 4000)
  index.ts                # 对外:appRouter、类型、services
  router.ts               # 兼容旧入口的再导出

构建:vite build(emptyOutDir: false)→ tsc -p tsconfig.dts.json 产出 .d.ts。勿开 dts 的 incremental(vite 会先清产物,缓存会导致 tsc 跳过 emit);勿改回 vite-plugin-dts。

请求流

web /api/trpc  ──►  appRouter  ──►  service  ──►  @app/dao  ──►  @app/db

也可 yarn dev:api 跑 server.ts(独立端口);web SSR 内嵌时通常不用。

媒体域 procedure 用 protectedProcedure(需登录,取 ctx.userId);路由层只做 input 映射 + 调 service。

修改指南

  1. 改入参:先改 @app/types 的 Zod schema,再挂到 t.procedure.input(...)。
  2. 加 procedure:路由只做 input 映射 + 调 service;业务在 services/*.service.ts;SQL 在 @app/dao。
  3. 加领域:新建 services/x.service.ts + 在 media.router.ts(或新 router/x.router.ts)挂 procedure,接到 appRouter,并在 index.ts 导出。
  4. 导出给前端的类型用 RouterInputs / RouterOutputs(来自 router/index.ts)。
  5. 外部 API(弹幕/刮削)调用集中在对应 service,注意超时与错误包装;SSRF/路径穿越防护见 stream.service / webdav-client。

约束

  • exactOptionalPropertyTypes:service 的 update 入参写成 name?: string | undefined。
  • noUncheckedIndexedAccess:判空逻辑在 DAO 内处理(参考 userDao.create)。
  • 不要在 router/service 里写 SQL;不在 service 里依赖 HTTP/tRPC context(除非鉴权明确需要)。
  • router.ts 仅兼容旧 import,新代码从 index.ts / ./router/index.js 引入。
  • service 旁的 *.test.ts 用 vitest/vite 跑(vite.config.ts),改行为时同步补测。

命令

yarn workspace @app/trpc typecheck
yarn workspace @app/trpc lint
yarn workspace @app/trpc build
yarn workspace @app/trpc dev      # tsx watch src/server.ts