fix: 项目结构优化及后端同步适配 (#11)
Reviewed-on: #11
This commit was merged in pull request #11.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# 前后端通信约定
|
||||
|
||||
当前后端是相邻的 `hono-api` 仓库,默认根地址 `http://localhost:3000`。业务接口由 Hono 提供,认证由 Better Auth 提供;旧 `opencloud-backend` FastAPI 项目不参与当前调用。
|
||||
|
||||
## 职责
|
||||
|
||||
| 层 | 文件 | 负责内容 |
|
||||
| ------------ | ------------------------------------------------- | ----------------------------------------------------------- |
|
||||
| HTTP 传输 | `src/lib/api.ts` | Cookie、查询编码、JSON/FormData、HTTP 错误和 401 事件 |
|
||||
| 业务调用 | `src/features/{clouds,profile,admin}/api.ts` | 资源路径、输入/输出类型、批量分块、分页收集、响应适配 |
|
||||
| 响应适配 | `src/lib/api-adapters.ts` | 生成 DTO 到前端视图模型的明确映射,图片 URL |
|
||||
| 后端契约 | `src/types/api-contract.ts` | 从后端 schema 生成并同步,禁止手改 |
|
||||
| 前端模型 | `src/types/models.ts`、`src/types/view-models.ts` | 页面需要的 Cloud、CloudType、Profile、CloudDetail、AuthUser |
|
||||
| 认证客户端 | `src/features/auth/authClient.ts` | Better Auth SDK 与其独立错误协议 |
|
||||
| 页面与 store | `src/features/` | 交互、缓存、业务展示;调用业务 API 模块 |
|
||||
|
||||
页面不再直接调用 `apiRequest`;ESLint 会检查该规则。传输层不引用云图/用户模型,也不承担认证 SDK 的职责。后端数据库命名、HTTP 字段命名和页面显示字段各自有明确适配位置。稀有度统一使用后端数值,不再伪造 `common` 分类。
|
||||
|
||||
## 请求与响应
|
||||
|
||||
`apiRequest` 的路径相对于后端根地址,如 `/clouds`,不要加入 `/api/v1`。查询条件通过 `query` 对象传入,由传输层编码一次。JSON body 是普通对象,上传模块接受类型化参数并构建 FormData,浏览器生成 multipart Content-Type。
|
||||
|
||||
所有请求携带 Cookie。`auth: false` 表示该公开请求的 401 不触发清空登录状态,并不禁止携带 Cookie。需要登录的请求默认派发 `opencloud:auth-expired`。传输层不会重试写操作;网络错误、非法成功响应及结构化 HTTP 错误会抛给调用者。
|
||||
|
||||
业务错误为 `{message, issues?}`,保存在 `ApiError.message/status/detail`。成功 JSON 响应必须能解析;204 返回 undefined。图片 URL 直接用于媒体元素,不通过 JSON 请求函数。
|
||||
|
||||
云图分页使用 `{items, page, page_size, has_more}`。页面通过 `has_more` 控制下一页;热力图、点赞集合与当前管理统计需要完整集合时,由业务 API 使用 `collectPages` 收集。地图为上限 1000 条的时间范围数组,用户管理与云类型目录目前为非分页数组。没有实时订阅或跨页快照。
|
||||
|
||||
批量变更每次最多 100 个 UUID。已完成的删除批次立即修补缓存,后续批次失败不会回滚。上传仍逐张进行,失败前已上传的云图保留;没有恢复上传或自动整批重试。
|
||||
|
||||
## 契约同步与验证
|
||||
|
||||
后端 `src/schemas/` 是单一事实来源。后端生成的 `contracts/api.ts` 只含 HTTP 类型,不引入数据库、SDK、服务端配置或运行时包。前端保存类型快照,独立构建不依赖旁边存在后端仓库。
|
||||
|
||||
两仓库配套修改时:
|
||||
|
||||
```bash
|
||||
# 在 hono-api 中
|
||||
npm run contract:generate
|
||||
npm run check
|
||||
|
||||
# 在 opencloud 中
|
||||
npm run api:sync
|
||||
npm run api:check
|
||||
npm run check
|
||||
npm run build
|
||||
```
|
||||
|
||||
后端不在默认位置时,设置 `OPENCLOUD_API_DIR` 为实际路径。`api:check` 比较已生成的后端类型与前端快照,不会替代后端的 `contract:check`;两者都通过才能确认契约一致。前端 `npm test` 使用 Node 内置测试与 TypeScript 类型剥离,需要 Node 22.18+,不新增测试框架依赖。
|
||||
|
||||
## 部署与迁移
|
||||
|
||||
此次改动需要两端一起发布或回滚。旧路径 `/cloud`、`/profile`、`/image`、`/info/cloudtype` 改为 `/clouds`、`/profiles`、`/images`、`/cloud-types`;旧请求字段 `type_id/user_name/user_role` 改为 `cloud_type_id/username/role`。云图响应使用 `cloud_type/review_status`,日期统一 ISO UTC,批量 ID 为字符串数组。
|
||||
|
||||
认证仍在 `/auth/*`,VITE_API_URL 仍为后端根地址。完整端点与迁移表在后端 `API.md`。本次不需要数据库迁移,TypeScript 字段改名显式映射原数据库列。
|
||||
@@ -0,0 +1,159 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1800" height="1420" viewBox="0 0 1800 1420" role="img" aria-labelledby="title desc">
|
||||
<title id="title">OpenCloud 当前架构</title>
|
||||
<desc id="desc">前端 Vue 页面和 Pinia store 经业务 API 模块、HTTP 传输层访问 Hono 后端;后端路由使用校验、鉴权、Drizzle 和复用服务,集中序列化响应。Better Auth 独立处理认证,认证与业务共用 PostgreSQL,图片存于对象存储,邮件由 Resend 发送。下方展示从后端 Zod schema 生成并同步前端 TypeScript 契约的开发流程。</desc>
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="9" markerHeight="9" refX="8" refY="4.5" orient="auto-start-reverse"><path d="M0 0 9 4.5 0 9" fill="#34745d"/></marker>
|
||||
<marker id="return" markerWidth="9" markerHeight="9" refX="8" refY="4.5" orient="auto"><path d="M0 0 9 4.5 0 9" fill="#0284c7"/></marker>
|
||||
<marker id="build" markerWidth="9" markerHeight="9" refX="8" refY="4.5" orient="auto"><path d="M0 0 9 4.5 0 9" fill="#a16207"/></marker>
|
||||
<style>
|
||||
text { font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', sans-serif; fill: #243746; }
|
||||
.title { font-size: 42px; font-weight: 750; letter-spacing: -1px; }
|
||||
.section { font-size: 26px; font-weight: 700; }
|
||||
.node { font-size: 23px; font-weight: 700; }
|
||||
.body { font-size: 19px; }
|
||||
.small { font-size: 16px; }
|
||||
.muted { fill: #64748b; }
|
||||
.code { font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace; font-size: 16px; fill: #475569; }
|
||||
.flow { fill: none; stroke: #34745d; stroke-width: 2.5; marker-end: url(#arrow); stroke-linejoin: round; }
|
||||
.response { fill: none; stroke: #0284c7; stroke-width: 2.5; stroke-dasharray: 8 6; marker-end: url(#return); }
|
||||
.build { fill: none; stroke: #a16207; stroke-width: 2.5; stroke-dasharray: 5 5; marker-end: url(#build); }
|
||||
</style>
|
||||
</defs>
|
||||
<rect width="1800" height="1420" fill="#f6fafd"/>
|
||||
|
||||
<rect x="48" y="44" width="68" height="68" fill="#cbd5e1"/>
|
||||
<rect x="44" y="40" width="68" height="68" fill="#e0f2fe" stroke="#bae6fd"/>
|
||||
<path d="M59 71h8V59h21v7h11v21H59z" fill="#7dd3fc"/><path d="M82 50h13v13H82z" fill="#f5c66b"/>
|
||||
<text x="138" y="79" class="title">OpenCloud · 当前系统架构</text>
|
||||
<text x="140" y="111" class="body" style="fill:#64748b">运行时请求、认证与开发期契约同步 / 2026-09-30</text>
|
||||
<path d="M 1255 63 H 1310" class="flow"/>
|
||||
<text x="1325" y="70" class="small">调用 / 请求</text>
|
||||
<path d="M 1255 100 H 1310" class="response"/>
|
||||
<text x="1325" y="107" class="small">JSON 响应</text>
|
||||
<path d="M 1515 100 H 1570" class="build"/>
|
||||
<text x="1585" y="107" class="small">契约生成 / 同步</text>
|
||||
<rect x="40" y="172" width="510" height="832" fill="#edf7fc" stroke="#cbd5e1"/>
|
||||
<text x="64" y="213" class="section">01 浏览器 · opencloud</text>
|
||||
<text x="64" y="244" class="small" style="fill:#64748b">Vue 3 · Pinia · Vue Router · Vite</text>
|
||||
<rect x="680" y="172" width="650" height="832" fill="#f2faf6" stroke="#cbd5e1"/>
|
||||
<text x="704" y="213" class="section">02 API 服务 · hono-api</text>
|
||||
<text x="704" y="244" class="small" style="fill:#64748b">Hono · Better Auth · Zod · Drizzle</text>
|
||||
<rect x="1450" y="172" width="310" height="832" fill="#f8fafc" stroke="#cbd5e1"/>
|
||||
<text x="1474" y="213" class="section">03 数据与外部服务</text>
|
||||
<text x="1474" y="244" class="small" style="fill:#64748b">持久化、图片与邮件</text>
|
||||
<rect x="69" y="282" width="460" height="104" fill="#cbd5e1"/>
|
||||
<rect x="65" y="278" width="460" height="104" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="87" y="314" class="node">页面 / 组件 / Pinia stores</text>
|
||||
<text x="87" y="346" class="body">交互、加载状态、业务缓存</text>
|
||||
<text x="87" y="373" class="code">src/features/</text>
|
||||
<rect x="69" y="435" width="460" height="123" fill="#cbd5e1"/>
|
||||
<rect x="65" y="431" width="460" height="123" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="87" y="467" class="node">业务 API 模块</text>
|
||||
<text x="87" y="499" class="code">clouds/api.ts · profile/api.ts · admin/api.ts</text>
|
||||
<text x="87" y="526" class="body">路径、分页、批量分块、响应适配</text>
|
||||
<text x="87" y="553" class="code">api-adapters.ts → 前端视图模型</text>
|
||||
<rect x="69" y="614" width="460" height="122" fill="#cbd5e1"/>
|
||||
<rect x="65" y="610" width="460" height="122" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="87" y="646" class="node">HTTP 传输层</text>
|
||||
<text x="87" y="678" class="code">src/lib/api.ts</text>
|
||||
<text x="87" y="705" class="body">Cookie · 查询编码 · JSON / FormData</text>
|
||||
<text x="87" y="732" class="body">ApiError · 401 认证失效事件</text>
|
||||
<path d="M 295 382 V 431" class="flow"/>
|
||||
<path d="M 295 554 V 610" class="flow"/>
|
||||
<text x="66" y="775" class="small" style="fill:#64748b">浏览器媒体元素直接请求 /images/:id/:variant</text>
|
||||
<rect x="69" y="828" width="460" height="111" fill="#cbd5e1"/>
|
||||
<rect x="65" y="824" width="460" height="111" fill="#fff" stroke="#94b8aa"/>
|
||||
<text x="87" y="860" class="node">独立认证客户端</text>
|
||||
<text x="87" y="892" class="code">authClient.ts → Better Auth SDK</text>
|
||||
<text x="87" y="919" class="body">登录 / 注册 / 会话 / 邮箱验证 / 密码</text>
|
||||
<text x="66" y="976" class="small" style="fill:#64748b">AMap:浏览器按需加载地图 SDK</text>
|
||||
<rect x="709" y="282" width="600" height="104" fill="#cbd5e1"/>
|
||||
<rect x="705" y="278" width="600" height="104" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="727" y="314" class="node">统一响应序列化</text>
|
||||
<text x="727" y="346" class="code">src/serializers.ts</text>
|
||||
<text x="727" y="373" class="body">Cloud / CloudType / User → JSON · ISO UTC</text>
|
||||
<rect x="709" y="435" width="600" height="123" fill="#cbd5e1"/>
|
||||
<rect x="705" y="431" width="600" height="123" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="727" y="467" class="node">业务路由 + 按需复用服务</text>
|
||||
<text x="727" y="499" class="code">/clouds · /cloud-types · /profiles · /admin</text>
|
||||
<text x="727" y="526" class="body">Zod 请求校验 · 会话、角色与所有权校验</text>
|
||||
<text x="727" y="553" class="body">Drizzle 查询 · 分页 / 点赞 / 压缩 / 存储</text>
|
||||
<rect x="709" y="614" width="600" height="122" fill="#cbd5e1"/>
|
||||
<rect x="705" y="610" width="600" height="122" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="727" y="646" class="node">Hono HTTP 入口</text>
|
||||
<text x="727" y="678" class="code">src/index.ts</text>
|
||||
<text x="727" y="705" class="body">CORS · request ID · 计时 · 错误处理</text>
|
||||
<text x="727" y="732" class="body">资源路由分发;/images 代理图片流</text>
|
||||
<path d="M 1005 610 V 554" class="flow"/>
|
||||
<text x="1025" y="590" class="small" style="fill:#34745d">分发 / 校验</text>
|
||||
<path d="M 1005 431 V 382" class="flow"/>
|
||||
<text x="1025" y="412" class="small" style="fill:#34745d">查询结果</text>
|
||||
<path d="M 525 669 H 705" class="flow"/>
|
||||
<text x="554" y="626" class="small" style="fill:#34745d">HTTPS</text>
|
||||
<text x="553" y="649" class="small" style="fill:#34745d">携带 Cookie</text>
|
||||
<path d="M 705 323 H 612 V 704 H 525" class="response"/>
|
||||
<text x="568" y="300" class="small" style="fill:#0284c7">响应</text>
|
||||
<text x="706" y="775" class="small" style="fill:#64748b">JSON 业务协议与 Better Auth 原生协议分别处理</text>
|
||||
<rect x="709" y="828" width="600" height="111" fill="#cbd5e1"/>
|
||||
<rect x="705" y="824" width="600" height="111" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="727" y="860" class="node">Better Auth · /auth/*</text>
|
||||
<text x="727" y="892" class="code">HttpOnly session cookie · Drizzle adapter</text>
|
||||
<text x="727" y="919" class="body">认证表与业务表共用同一个 PostgreSQL</text>
|
||||
<path d="M 525 880 H 705" class="flow"/>
|
||||
<text x="554" y="861" class="code">/auth/*</text>
|
||||
<text x="706" y="976" class="small" style="fill:#64748b">事务外图片存储:串行写入,上传失败执行补偿清理</text>
|
||||
<rect x="1474" y="282" width="270" height="142" fill="#cbd5e1"/>
|
||||
<rect x="1470" y="278" width="270" height="142" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="1492" y="314" class="node">PostgreSQL</text>
|
||||
<text x="1492" y="346" class="body">用户 / 会话 / 凭据</text>
|
||||
<text x="1492" y="373" class="body">云类型 / 云图 / 点赞</text>
|
||||
<text x="1492" y="400" class="small">业务与认证共同使用</text>
|
||||
<path d="M 1305 469 H 1394 V 350 H 1470" class="flow"/>
|
||||
<text x="1360" y="326" class="small" style="fill:#34745d">Drizzle</text>
|
||||
<rect x="1474" y="492" width="270" height="142" fill="#cbd5e1"/>
|
||||
<rect x="1470" y="488" width="270" height="142" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="1492" y="524" class="node">对象存储</text>
|
||||
<text x="1492" y="556" class="body">MinIO / S3 兼容接口</text>
|
||||
<text x="1492" y="583" class="code">original + preview</text>
|
||||
<text x="1492" y="610" class="small">上传、删除、图片读取</text>
|
||||
<path d="M 1305 520 H 1415 V 556 H 1470" class="flow"/>
|
||||
<text x="1353" y="500" class="small" style="fill:#34745d">storage</text>
|
||||
<rect x="1474" y="828" width="270" height="111" fill="#cbd5e1"/>
|
||||
<rect x="1470" y="824" width="270" height="111" fill="#fff" stroke="#b6c8d2"/>
|
||||
<text x="1492" y="860" class="node">Resend</text>
|
||||
<text x="1492" y="892" class="body">验证邮箱 / 密码重置</text>
|
||||
<text x="1492" y="919" class="code">services/email.ts</text>
|
||||
<path d="M 1305 880 H 1470" class="flow"/>
|
||||
<text x="1341" y="861" class="small" style="fill:#34745d">发送邮件</text>
|
||||
<text x="1471" y="687" class="small" style="fill:#64748b">公开可见规则</text>
|
||||
<text x="1471" y="718" class="body">审核通过且未隐藏</text>
|
||||
<text x="1471" y="747" class="small" style="fill:#64748b">上传者 / 管理员另行授权</text>
|
||||
<rect x="40" y="1040" width="1720" height="266" fill="#fffbef" stroke="#e6d7b0"/>
|
||||
<text x="65" y="1082" class="section">04 开发期 · 生成契约,阻止前后端类型漂移</text>
|
||||
<text x="65" y="1113" class="body" style="fill:#64748b">只同步 TypeScript 类型;前端独立构建使用已提交快照,不加载后端运行时依赖。</text>
|
||||
<rect x="69" y="1154" width="340" height="113" fill="#cbd5e1"/>
|
||||
<rect x="65" y="1150" width="340" height="113" fill="#fff" stroke="#d6bf82"/>
|
||||
<text x="87" y="1186" class="node">后端 Zod 定义</text>
|
||||
<text x="87" y="1218" class="code">hono-api/src/schemas/</text>
|
||||
<text x="87" y="1245" class="body">请求校验 + JSON 响应</text>
|
||||
<rect x="584" y="1154" width="330" height="113" fill="#cbd5e1"/>
|
||||
<rect x="580" y="1150" width="330" height="113" fill="#fff" stroke="#d6bf82"/>
|
||||
<text x="602" y="1186" class="node">后端生成物</text>
|
||||
<text x="602" y="1218" class="code">hono-api/contracts/api.ts</text>
|
||||
<text x="602" y="1245" class="small">contract:check 检查过期</text>
|
||||
<rect x="1074" y="1154" width="405" height="113" fill="#cbd5e1"/>
|
||||
<rect x="1070" y="1150" width="405" height="113" fill="#fff" stroke="#d6bf82"/>
|
||||
<text x="1092" y="1186" class="node">前端契约快照</text>
|
||||
<text x="1092" y="1218" class="code">src/types/api-contract.ts</text>
|
||||
<text x="1092" y="1245" class="body">业务 API 模块引用这些类型</text>
|
||||
<path d="M 405 1207 H 580" class="build"/>
|
||||
<text x="421" y="1185" class="code">contract:generate</text>
|
||||
<path d="M 910 1207 H 1070" class="build"/>
|
||||
<text x="944" y="1185" class="code">api:sync</text>
|
||||
<text x="1510" y="1187" class="body">跨仓库核对</text>
|
||||
<text x="1510" y="1220" class="code">api:check</text>
|
||||
<text x="1510" y="1248" class="small" style="fill:#64748b">比对两端契约</text>
|
||||
<text x="44" y="1357" class="small" style="fill:#34745d">通信约定</text>
|
||||
<text x="155" y="1357" class="body">snake_case · ISO UTC · 分页 { items, page, page_size, has_more } · 错误 { message, issues? }</text>
|
||||
<text x="44" y="1391" class="small" style="fill:#64748b">当前实现:刷新式加载;批量每次最多 100 个 ID;写请求不自动重试。图中省略页面内部组件与单个数据库索引。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
+15
-15
@@ -1,6 +1,6 @@
|
||||
# 目录结构与依赖约定
|
||||
|
||||
按业务功能组织文件,使一次功能修改涉及的页面、组件和状态尽量集中。文件迁移只改变源码路径,接口请求、DTO、store 导出与 ID、组件 props/events、路由 URL 和页面行为保持不变。
|
||||
按业务功能组织文件,使一次功能修改涉及的页面、组件和状态尽量集中。通信层按下文分工;接口变更与后端配套验证,见[通信架构](api-architecture.md)。
|
||||
|
||||
## 目录职责
|
||||
|
||||
@@ -35,25 +35,25 @@ src/
|
||||
│ ├── types/amap.d.ts # 高德类型声明,与同名加载器分开放置
|
||||
│ └── components/ # MapPickerModal、MiniLocationMap
|
||||
├── components/layout/ # 应用外壳:AppHeader
|
||||
├── lib/ # api.ts、seo.ts、theme.ts
|
||||
├── types/ # 公共 DTO、领域类型、路由元数据
|
||||
├── lib/ # api.ts、api-adapters.ts、pagination.ts、seo.ts、theme.ts
|
||||
├── types/ # 生成的 API 契约、前端模型、路由元数据
|
||||
├── styles/ # 全局设计令牌、基线、共享样式
|
||||
└── style.css # 全局样式入口
|
||||
```
|
||||
|
||||
## 文件归属
|
||||
|
||||
| 修改内容 | 归属位置 |
|
||||
| -------------------------------------- | ---------------------------- |
|
||||
| 登录、会话、验证邮件 | `features/auth/` |
|
||||
| 多个页面复用的云图详情、编辑、点赞 | `features/clouds/` |
|
||||
| 上传表单、上传弹窗、文件处理与上传状态 | `features/upload/` |
|
||||
| 用户主页、设置、贡献热力图 | `features/profile/` |
|
||||
| 图鉴列表、云型详情及其状态 | `features/encyclopedia/` |
|
||||
| 首页地图时间轴、标记交互 | `features/map/` |
|
||||
| 通用选点、位置预览、高德加载 | `shared/map/` |
|
||||
| 应用导航和整体布局 | `components/layout/` |
|
||||
| HTTP 请求与响应适配、公共 API 类型 | `lib/api.ts`、`types/api.ts` |
|
||||
| 修改内容 | 归属位置 |
|
||||
| -------------------------------------- | ------------------------------------------------------------ |
|
||||
| 登录、会话、验证邮件 | `features/auth/` |
|
||||
| 多个页面复用的云图详情、编辑、点赞 | `features/clouds/` |
|
||||
| 上传表单、上传弹窗、文件处理与上传状态 | `features/upload/` |
|
||||
| 用户主页、设置、贡献热力图 | `features/profile/` |
|
||||
| 图鉴列表、云型详情及其状态 | `features/encyclopedia/` |
|
||||
| 首页地图时间轴、标记交互 | `features/map/` |
|
||||
| 通用选点、位置预览、高德加载 | `shared/map/` |
|
||||
| 应用导航和整体布局 | `components/layout/` |
|
||||
| HTTP 请求与响应适配、公共 API 类型 | `lib/api.ts`、`lib/api-adapters.ts`、`types/api-contract.ts` |
|
||||
|
||||
按职责归属文件:快捷上传虽然从地图打开,仍属于上传模块;云图点赞虽然在多个页面使用,仍属于云图业务;选点和小地图仅提供位置能力,放在公共地图模块。
|
||||
|
||||
@@ -63,7 +63,7 @@ src/
|
||||
- 业务组件放在所属功能模块。`components/layout/` 仅存放应用布局,`lib/` 存放公共基础设施。
|
||||
- 功能模块可以依赖公共地图能力、基础设施、公共类型和其他模块的具体组件、store 或 composable。`shared/map/`、`lib/` 和 `types/` 保持独立于业务模块;新增跨模块依赖时避免循环引用。
|
||||
- 使用 `@/features/...`、`@/shared/...` 等具体文件路径,不增加统一导出所有页面和 store 的入口。路由继续在 `router/index.ts` 中动态导入各模块页面,保持按页面懒加载。
|
||||
- API 请求继续使用 `lib/api.ts`,认证 SDK 调用集中在 `features/auth/authClient.ts` 和认证 store。DTO 与领域类型仍由 `types/` 统一提供。
|
||||
- 页面与 store 调用所属功能的 `api.ts`,由该模块通过 `lib/api.ts` 发送请求。认证 SDK 调用集中在 `features/auth/authClient.ts` 和认证 store。生成 DTO 在 `types/api-contract.ts`,前端模型在 `types/models.ts` 与 `types/view-models.ts`。
|
||||
- 现有 `clouds` 与 `encyclopedia` store 保留各自的缓存行为;后续如需合并缓存,应作为独立行为变更验证。
|
||||
- 共享视觉规则遵循[样式体系](style-system.md),组件专属样式随组件迁移。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user