Files
juwan-frontend/静态模拟数据残留审计报告.md
T
zetaloop e3a392ae0d docs(audit): add mock-data and unimplemented APIs
Add two audit reports covering static mock data residue and hidden/unimplemented interfaces and logic.
2026-02-26 05:00:20 +08:00

20 KiB
Raw Blame History

静态模拟数据残留审计报告

总体结论

项目当前没有任何真实后端 HTTP 请求。全仓库仅 1 处 fetch(lib/api/search.ts:34),请求的是本地 Next.js Route /api/search,而该 Route 本身也以 mock 数据为源。@tanstack/react-queryQueryClientProvider 已挂载(app/providers.tsx),但全仓库 0 处 useQuery/useMutation 调用。无 .env 文件,无 mock/real 环境切换开关。


一、静态实体数据源 lib/mock/*.ts

15 个文件,定义了全部业务实体的硬编码数组,是整个模拟体系的根:

文件 导出 实体类型
lib/mock/users.ts:3 mockUsers: User[] 用户
lib/mock/users.ts:119 currentUser = mockUsers[0] 当前登录用户
lib/mock/games.ts:3 mockGames: Game[] 游戏
lib/mock/services.ts:3 mockServices: PlayerService[] 陪玩服务
lib/mock/players.ts:5 mockPlayers: Player[] 打手
lib/mock/shops.ts:4 mockShops: Shop[] 店铺
lib/mock/orders.ts:4 mockOrders: Order[] 订单
lib/mock/disputes.ts:3 mockDisputes: Dispute[] 争议
lib/mock/reviews.ts:3 mockReviews: Review[] 评价
lib/mock/posts.ts:4 mockPosts: Post[] 帖子
lib/mock/comments.ts:4 mockComments: Comment[] 评论
lib/mock/chat.ts:3 mockChatSessions: ChatSession[] 聊天会话
lib/mock/chat.ts:95 mockChatMessages: ChatMessage[] 聊天消息
lib/mock/favorites.ts:3 mockFavorites: Favorite[] 收藏
lib/mock/notifications.ts:3 mockNotifications: Notification[] 通知
lib/mock/transactions.ts:3 mockTransactions: WalletTransaction[] 交易流水
lib/mock/transactions.ts:139 walletBalance = 275 钱包余额

聚合出口:lib/mock/index.ts


二、Store 层 — mock 初始化 + 前端本地状态机

12 个 Zustand store 全部以 mock 数据初始化,运行时在前端内存中增删改查并生成 ID/时间戳:

Store 文件 初始化行 mock 来源
store/shops.ts:14 shops: mockShops mockShops
store/players.ts:12 players: mockPlayers mockPlayers
store/services.ts:14 services: mockServices mockServices
store/orders.ts:315 orders: mockOrders mockOrders
store/disputes.ts:203 disputes: mockDisputes.map(asRecord) mockDisputes
store/reviews.ts:51 reviews: mockReviews mockReviews + mockUsers:24
store/posts.ts:25 posts: mockPosts mockPosts
store/comments.ts:13 comments: mockComments mockComments
store/chat.ts:23-24 sessions: mockChatSessions, messages: mockChatMessages mockChatSessions + mockChatMessages + mockUsers:15
store/favorites.ts:14 favorites: mockFavorites mockFavorites
store/notifications.ts:21 notifications: mockNotifications mockNotifications
store/wallet.ts:20-21 balance: walletBalance, transactions: mockTransactions walletBalance + mockTransactions

所有 store 还通过 generateId() 在前端本地生成实体 IDstore/orders.ts:318,350store/services.ts:21store/wallet.ts:29,45,71,102,132store/disputes.ts:231 等),切后端后 ID 应由服务端分配。


三、伪 API 层 lib/api/*.ts

15 个模块名义上是 API 层,实际全部是同步读写本地 store 或直接返回 mock:

文件 实际行为 风险
lib/api/users.ts:1,4,8,12 直接 import { currentUser, mockUsers } 并 return 高 — 直接返回 mock
lib/api/games.ts:1,4,8 直接 import { mockGames } 并 return 高 — 直接返回 mock
lib/api/orders.ts:11 useOrderStore.getState().orders 中 — 读本地 store
lib/api/services.ts:4 useServiceStore.getState().services 中 — 读本地 store
lib/api/players.ts:4 usePlayerStore.getState().players 中 — 读本地 store
lib/api/shops.ts:4 useShopStore.getState().shops 中 — 读本地 store
lib/api/posts.ts:7 usePostStore.getState().posts 中 — 读写本地 store
lib/api/comments.ts:8 useCommentStore.getState().comments 中 — 读写本地 store
lib/api/chat.ts:6 useChatStore.getState().sessions 中 — 读写本地 store
lib/api/favorites.ts:4 useFavoriteStore.getState().favorites 中 — 读本地 store
lib/api/notifications.ts:7 useNotificationStore.getState().notifications 中 — 读写本地 store
lib/api/transactions.ts:4 useWalletStore.getState().transactions 中 — 读本地 store
lib/api/reviews.ts:6 useReviewStore.getState().reviews 中 — 读写本地 store
lib/api/disputes.ts:6 useDisputeStore.getState().disputes 中 — 读写本地 store
lib/api/search.ts:34 fetch('/api/search?...') 唯一 fetch,但后端仍是 mock
lib/api/client.ts:9 requestWithAuth 仅包装执行器做未登录拦截 无网络请求

四、唯一 HTTP 链路 — 搜索

lib/api/search.ts:34        → fetch(`/api/search?${params}`)
app/api/search/route.ts:1   → import { mockPlayers, mockServices, mockShops } from "@/lib/mock"
app/api/search/route.ts:51  → players: mockPlayers, shops: mockShops, services: mockServices

搜索是项目里唯一走了 HTTP 请求的链路,但 Next.js Route Handler 的数据源仍然是 mock。


五、前端状态自动推进(Demo 定时器)

这是切后端时事故概率最高的部分 — 前端 setTimeout 自动推进业务状态,真实后端应由服务端事件驱动。

定时常量:

lib/config/demo-timers.ts:1   ORDER_ACCEPT_TIMEOUT_MS  = 30_000
lib/config/demo-timers.ts:2   ORDER_CLOSE_TIMEOUT_MS   = 30_000
lib/config/demo-timers.ts:3   ORDER_REVIEW_TIMEOUT_MS  = 30_000
lib/config/demo-timers.ts:5   DISPUTE_TO_REVIEWING_MS  = 5_000
lib/config/demo-timers.ts:6   DISPUTE_TO_RESOLVED_MS   = 10_000

订单自动流转:

位置 行为
store/orders.ts:172-206 scheduleOrderTimeout — 订单进入 pending_accept/pending_close/pending_review 后启动 setTimeout 自动超时流转
store/orders.ts:405-413 自动派单模拟 — 当店铺 dispatchMode === "auto" 时,setTimeout(3000) 自动调用 acceptOrder

争议自动推进:

位置 行为
store/disputes.ts:142-163 setTimeout(DISPUTE_TO_REVIEWING_MS) — 自动将争议从 open → reviewing
store/disputes.ts:165-197 setTimeout(DISPUTE_TO_RESOLVED_MS) — 自动将争议从 reviewing → resolved 并回写订单

六、认证/表单流程模拟

位置 行为
app/(auth)/login/page.tsx:35-36 await new Promise(r => setTimeout(r, 500)) + login(getCurrentUserForLogin(), ...)
app/(auth)/register/page.tsx:50-51 同上
components/login-dialog.tsx:44-45 同上
app/(auth)/forgot-password/page.tsx:27 await new Promise(r => setTimeout(r, 500)) + toast
app/(account)/verify/page.tsx:41-52 submitWithMockApproval — 提交认证后 setTimeout(3000) 自动调用 approveVerification

getCurrentUserForLogin() 最终来自 lib/api/users.ts:12lib/mock/users.ts:119currentUser = mockUsers[0],即无论输入什么账号密码,登录的永远是同一个硬编码用户。


七、硬编码展示值

位置 内容
app/(account)/wallet/page.tsx:154 ¥1,280.00(本月收入,写死)
app/(account)/wallet/page.tsx:158 ¥320.00(待结算,写死)
app/(account)/wallet/page.tsx:162 ¥5,400.00(已提现,写死)
app/(auth)/layout.tsx:4-8 12,000+ 认证打手 / 98.6% 好评率 / 50,000+ 完成订单(营销数字,写死)
app/(order)/dispute/[id]/page.tsx:377 UI 文案含"模拟处理结果"字样

八、页面数据源分类(34 个页面)

Store Only14 个)— 完全不经过 lib/api,直接读写 store

app/(account)/notifications/page.tsx
app/(account)/settings/page.tsx
app/(account)/verify/page.tsx              [含 setTimeout 模拟]
app/(account)/wallet/page.tsx
app/(dashboard)/dashboard/services/page.tsx
app/(dashboard)/dashboard/shop/employees/page.tsx
app/(dashboard)/dashboard/shop/orders/page.tsx
app/(dashboard)/dashboard/shop/page.tsx
app/(dashboard)/dashboard/shop/rules/page.tsx
app/(dashboard)/dashboard/shop/templates/page.tsx  [含 setTimeout]
app/(main)/post/new/page.tsx
app/(order)/chat/page.tsx
app/(order)/order/[id]/page.tsx
app/(order)/orders/page.tsx

API + Store 混合(9 个)— 经过 lib/api 但 lib/api 本身也是读 store

app/(auth)/login/page.tsx                  [含 setTimeout 模拟登录]
app/(auth)/register/page.tsx               [含 setTimeout 模拟注册]
app/(dashboard)/dashboard/page.tsx
app/(dashboard)/dashboard/services/new/page.tsx
app/(dashboard)/dashboard/shop/income/page.tsx
app/(order)/chat/[id]/page.tsx
app/(order)/dispute/[id]/page.tsx
app/(order)/order/new/page.tsx             [含 setTimeout]
app/(order)/review/[id]/page.tsx

API Only7 个)— 仅经过 lib/api,但 lib/api 底层仍是本地数据:

app/(main)/page.tsx
app/(main)/community/page.tsx
app/(main)/player/[id]/page.tsx
app/(main)/post/[id]/page.tsx
app/(main)/search/page.tsx                 [唯一真正 fetch 的页面]
app/(main)/shop/[id]/page.tsx
app/(main)/user/[id]/page.tsx

无 API/Store(4 个)— 纯静态或纯前端模拟:

app/(auth)/forgot-password/page.tsx        [setTimeout 模拟]
app/(main)/help/page.tsx                   [纯静态内容]
app/(main)/privacy/page.tsx                [纯静态内容]
app/(main)/terms/page.tsx                  [纯静态内容]

九、组件层直接读写业务 Store(绕过 lib/api

useAuthStore/useLoginDialogStore 外,以下共享组件直接操作业务 store:

组件 直接引用的 store
components/order-actions.tsx:14-16 useChatStore, useOrderStore, useShopStore
components/favorite-button.tsx:6 useFavoriteStore
components/post-like-button.tsx:5 usePostStore
components/post-comments.tsx:5 useCommentStore
components/post-comment-count.tsx:3 useCommentStore
components/header.tsx:19-20 useNotificationStore, useShopStore

十、已排除项(确认不存在)

  • .env / .env.local / .env.development 等环境配置文件
  • 无 mock/real 环境切换开关(NEXT_PUBLIC_*MOCK*USE_MOCK 等)
  • 无运行时 MSW 拦截代码(msw 仅作为 @vitest/mocker 的 peer dep 出现在 lockfile
  • axiosaxios-mock-adapterjson-servermiragejs 使用
  • 无运行时 .json 文件作为数据源导入
  • Promise.resolve 模拟异步返回
  • 无 Next.js rewrites/redirects/proxy 配置
  • useQuery/useMutation/useSWR 全仓库 0 处调用

十一、隐蔽未实现接口(更像真功能,实际仍在前端自转)

这些条目即使去掉了明显的 mock 字样,也会在切真实后端后造成严重偏差:UI 提示可用或可保存,实际没有任何可被后端接入的请求/数据契约/权限边界。

类型 现象 关键证据(单行) 切后端后常见失败模式
Client Store 与 Server Component 断层 管理页或发布页写入 Zustand 后,跳转到详情/公开页看不到改动 app/(main)/post/new/page.tsx:79createPost 写前端 store / app/(main)/post/[id]/page.tsx:17(详情页从 server 侧读 getPostById 新创建内容在列表可见,详情页 404 或展示旧数据;店铺模板预览不反映保存结果
图片/文件上传未落到接口 多处上传只生成本地 blob URL 或占位图,刷新或换设备即失效 app/(account)/settings/page.tsx:75app/(order)/chat/[id]/page.tsx:152app/(order)/dispute/[id]/page.tsx:88app/(main)/post/new/page.tsx:84app/(account)/verify/page.tsx:170 后端接入后出现上传缺字段、图片无法复现、消息图片仅本机可见
会话列表未按参与者过滤 消息列表直接渲染全部会话,只在详情页才做参与者校验 app/(order)/chat/page.tsx:12 列表出现无关会话,后端接入时需要补齐按用户查询与分页
店铺规则字段缺少业务约束 规则页可保存 allowMultiShop 等字段,员工邀请直接改归属,不存在申请/同意流 app/(dashboard)/dashboard/shop/rules/page.tsx:48 / app/(dashboard)/dashboard/shop/employees/page.tsx:75 / store/players.ts:13 规则与权限不生效,导致运营规则与实际行为脱节
智能派单与流程推进为固定定时器 自动派单固定 3 秒自动接单;待接单/结单/评价自动超时推进;争议自动进入 reviewing/resolved store/orders.ts:186store/orders.ts:408store/disputes.ts:142 与真实状态机/消息队列/人工审核不一致,产生错误状态与资金流偏差
交易明细与订单关联靠字符串解析 收入统计用正则从 transaction.description 里提取 ord id app/(dashboard)/dashboard/shop/income/page.tsx:51 后端字段结构化后该逻辑失效,统计漏算或误算
身份切换与实体模型不对齐 登录永远是固定用户 u1(consumer),UI 允许切换到 player/owner;导航用 user.id 直接拼 player/shop 路由 app/(auth)/login/page.tsx:36 / lib/mock/users.ts:119 / components/header.tsx:85 / lib/mock/players.ts:7 / lib/mock/shops.ts:7 打手/店主页面长期空态或 404;店铺后台永远提示无可管理店铺
看似走 API,实际仍为 mock /search 会发起 fetch,但 /api/search 路由以 mockPlayers/mockShops/mockServices 作为数据源 lib/api/search.ts:34 / app/api/search/route.ts:1 接真实后端时容易遗漏替换点,导致线上仍走假数据

复扫命令

后续持续监控可用以下 6 条命令覆盖主要信号:

rg -n '@/lib/mock' app lib store components
rg -n '\bfetch\(' app lib store components
rg -n 'setTimeout\(' app lib store components
rg -n 'from "@/store/' app components
rg -n 'URL\.createObjectURL' app components
rg -n 'window\.prompt' app