refactor(data): split models into separate dto and schema modules

Reorganize the data layer by separating DTOs (Data Transfer Objects) from
Zod validation schemas into distinct directory structures. Previously,
all model types were imported from a single `@/data/models` barrel
file, mixing request/response classes with validation schemas.

Changes:
- Update API files (auth, chat, metrics, user) to import DTOs from
  specific paths under `@/data/dto/*` instead of the models barrel
- Move user schema to `@/data/schemas/user/user` for type-only imports
- Create dedicated Zod schema files under `@/data/schemas/*` for
  auth and chat domain models (e.g., AppleLoginRequestSchema,
  SendMessageRequestSchema, SyncMessageSchema, SttDataSchema)
- Improve discoverability and tree-shaking by co-locating schemas
  with their respective domain areas

This is a non-functional refactor that lays the groundwork for
clearer separation between transport-layer types and runtime
validation.
This commit is contained in:
2026-06-08 19:14:40 +08:00
parent 67a72783fe
commit 75e685d418
89 changed files with 1119 additions and 853 deletions
@@ -0,0 +1,13 @@
/**
* Apple 登录请求
* 原始 Dart: AppleLoginRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const AppleLoginRequestSchema = z.object({
identityToken: z.string(),
platform: z.string(),
});
export type AppleLoginRequestInput = z.input<typeof AppleLoginRequestSchema>;
export type AppleLoginRequestData = z.output<typeof AppleLoginRequestSchema>;
@@ -0,0 +1,14 @@
/**
* Facebook 登录请求
* 原始 Dart: FacebookLoginRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const FacebookLoginRequestSchema = z.object({
accessToken: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type FacebookLoginRequestInput = z.input<typeof FacebookLoginRequestSchema>;
export type FacebookLoginRequestData = z.output<typeof FacebookLoginRequestSchema>;
@@ -0,0 +1,13 @@
/**
* Facebook ID 登录请求
* 原始 Dart: FbIdLoginRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const FbIdLoginRequestSchema = z.object({
fbId: z.string(),
avatarUrl: z.string().default(""),
});
export type FbIdLoginRequestInput = z.input<typeof FbIdLoginRequestSchema>;
export type FbIdLoginRequestData = z.output<typeof FbIdLoginRequestSchema>;
@@ -0,0 +1,14 @@
/**
* Google 登录请求
* 原始 Dart: GoogleLoginRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const GoogleLoginRequestSchema = z.object({
idToken: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type GoogleLoginRequestInput = z.input<typeof GoogleLoginRequestSchema>;
export type GoogleLoginRequestData = z.output<typeof GoogleLoginRequestSchema>;
@@ -0,0 +1,12 @@
/**
* 游客登录请求
* 原始 Dart: GuestLoginRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const GuestLoginRequestSchema = z.object({
deviceId: z.string(),
});
export type GuestLoginRequestInput = z.input<typeof GuestLoginRequestSchema>;
export type GuestLoginRequestData = z.output<typeof GuestLoginRequestSchema>;
@@ -0,0 +1,18 @@
/**
* 游客登录响应
* 原始 Dart: GuestLoginResponse (lib/data/models/auth/auth_response.dart)
*/
import { z } from "zod";
import { UserSchema } from "../user/user";
export const GuestLoginResponseSchema = z.object({
token: z.string(),
deviceId: z.string(),
userId: z.string(),
isDeviceUser: z.boolean().default(true),
expiresIn: z.number().default(2592000),
user: UserSchema.optional(),
});
export type GuestLoginResponseInput = z.input<typeof GuestLoginResponseSchema>;
export type GuestLoginResponseData = z.output<typeof GuestLoginResponseSchema>;
+16
View File
@@ -0,0 +1,16 @@
/**
* 登录请求
* 原始 Dart: LoginRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const LoginRequestSchema = z.object({
email: z.string().default(""),
username: z.string().default(""),
password: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type LoginRequestInput = z.input<typeof LoginRequestSchema>;
export type LoginRequestData = z.output<typeof LoginRequestSchema>;
+15
View File
@@ -0,0 +1,15 @@
/**
* 登录响应
* 原始 Dart: LoginResponse (lib/data/models/auth/auth_response.dart)
*/
import { z } from "zod";
import { UserSchema } from "../user/user";
export const LoginResponseSchema = z.object({
user: UserSchema,
token: z.string(),
refreshToken: z.string().default(""),
});
export type LoginResponseInput = z.input<typeof LoginResponseSchema>;
export type LoginResponseData = z.output<typeof LoginResponseSchema>;
+12
View File
@@ -0,0 +1,12 @@
/**
* 退出登录响应
* 原始 Dart: LogoutResponse (lib/data/models/auth/auth_response.dart)
*/
import { z } from "zod";
export const LogoutResponseSchema = z.object({
success: z.boolean().default(true),
});
export type LogoutResponseInput = z.input<typeof LogoutResponseSchema>;
export type LogoutResponseData = z.output<typeof LogoutResponseSchema>;
@@ -0,0 +1,12 @@
/**
* 刷新 Token 请求
* 原始 Dart: RefreshTokenRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const RefreshTokenRequestSchema = z.object({
refreshToken: z.string(),
});
export type RefreshTokenRequestInput = z.input<typeof RefreshTokenRequestSchema>;
export type RefreshTokenRequestData = z.output<typeof RefreshTokenRequestSchema>;
@@ -0,0 +1,14 @@
/**
* 刷新 Token 响应
* 原始 Dart: RefreshTokenResponse (lib/data/models/auth/auth_response.dart)
*/
import { z } from "zod";
export const RefreshTokenResponseSchema = z.object({
token: z.string(),
refreshToken: z.string(),
userId: z.string(),
});
export type RefreshTokenResponseInput = z.input<typeof RefreshTokenResponseSchema>;
export type RefreshTokenResponseData = z.output<typeof RefreshTokenResponseSchema>;
+16
View File
@@ -0,0 +1,16 @@
/**
* 注册请求
* 原始 Dart: RegisterRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const RegisterRequestSchema = z.object({
username: z.string(),
email: z.string(),
password: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type RegisterRequestInput = z.input<typeof RegisterRequestSchema>;
export type RegisterRequestData = z.output<typeof RegisterRequestSchema>;
@@ -0,0 +1,12 @@
/**
* 发送验证码请求
* 原始 Dart: SendCodeRequest (lib/data/models/auth/auth_request.dart)
*/
import { z } from "zod";
export const SendCodeRequestSchema = z.object({
email: z.string(),
});
export type SendCodeRequestInput = z.input<typeof SendCodeRequestSchema>;
export type SendCodeRequestData = z.output<typeof SendCodeRequestSchema>;
@@ -0,0 +1,16 @@
/**
* 聊天历史响应
* 原始 Dart: ChatHistoryResponse (lib/data/models/chat/chat_response.dart)
*/
import { z } from "zod";
import { ChatMessageSchema } from "./chat_message";
export const ChatHistoryResponseSchema = z.object({
messages: z.array(ChatMessageSchema),
total: z.number().default(0),
limit: z.number(),
offset: z.number(),
});
export type ChatHistoryResponseInput = z.input<typeof ChatHistoryResponseSchema>;
export type ChatHistoryResponseData = z.output<typeof ChatHistoryResponseSchema>;
+15
View File
@@ -0,0 +1,15 @@
/**
* 聊天历史中的单条消息
* 原始 Dart: ChatMessage (lib/data/models/chat/chat_response.dart)
*/
import { z } from "zod";
export const ChatMessageSchema = z.object({
role: z.string(),
content: z.string(),
id: z.string().default(""),
createdAt: z.string().default(""),
});
export type ChatMessageInput = z.input<typeof ChatMessageSchema>;
export type ChatMessageData = z.output<typeof ChatMessageSchema>;
@@ -0,0 +1,22 @@
/**
* 发送消息响应
* 原始 Dart: ChatSendResponse (lib/data/models/chat/chat_response.dart)
*/
import { z } from "zod";
export const ChatSendResponseSchema = z.object({
mode: z.string().default(""),
reply: z.string(),
voiceUrl: z.string().default(""),
audioUrl: z.string().default(""),
intimacyChange: z.number().default(0),
newIntimacy: z.number().default(0),
relationshipStage: z.string(),
currentMood: z.string().default(""),
messageId: z.string(),
isGuest: z.boolean().default(false),
timestamp: z.number().default(0),
});
export type ChatSendResponseInput = z.input<typeof ChatSendResponseSchema>;
export type ChatSendResponseData = z.output<typeof ChatSendResponseSchema>;
+13
View File
@@ -0,0 +1,13 @@
/**
* 消息同步响应
* 原始 Dart: ChatSyncData (lib/data/models/chat/chat_sync.dart)
*/
import { z } from "zod";
export const ChatSyncDataSchema = z.object({
syncedCount: z.number(),
totalHistory: z.number(),
});
export type ChatSyncDataInput = z.input<typeof ChatSyncDataSchema>;
export type ChatSyncDataData = z.output<typeof ChatSyncDataSchema>;
@@ -0,0 +1,13 @@
/**
* 消息同步请求
* 原始 Dart: ChatSyncRequest (lib/data/models/chat/chat_sync.dart)
*/
import { z } from "zod";
import { SyncMessageSchema } from "./sync_message";
export const ChatSyncRequestSchema = z.object({
messages: z.array(SyncMessageSchema),
});
export type ChatSyncRequestInput = z.input<typeof ChatSyncRequestSchema>;
export type ChatSyncRequestData = z.output<typeof ChatSyncRequestSchema>;
+13
View File
@@ -0,0 +1,13 @@
/**
* 游客每日聊天配额数据
* 原始 Dart: GuestChatQuota (lib/data/models/chat/guest_chat_quota.dart)
*/
import { z } from "zod";
export const GuestChatQuotaSchema = z.object({
remaining: z.number(),
date: z.string(),
});
export type GuestChatQuotaInput = z.input<typeof GuestChatQuotaSchema>;
export type GuestChatQuotaData = z.output<typeof GuestChatQuotaSchema>;
@@ -0,0 +1,19 @@
/**
* 图片上传响应
* 原始 Dart: ImageUploadResponse (lib/data/models/chat/image_upload_response.dart)
*/
import { z } from "zod";
export const ImageUploadResponseSchema = z.object({
success: z.boolean().default(true),
imageId: z.string(),
thumbUrl: z.string(),
mediumUrl: z.string(),
originalUrl: z.string(),
width: z.number(),
height: z.number(),
bytes: z.number(),
});
export type ImageUploadResponseInput = z.input<typeof ImageUploadResponseSchema>;
export type ImageUploadResponseData = z.output<typeof ImageUploadResponseSchema>;
@@ -0,0 +1,20 @@
/**
* 发送消息请求
* 原始 Dart: SendMessageRequest (lib/data/models/chat/send_message_request.dart)
*/
import { z } from "zod";
export const SendMessageRequestSchema = z.object({
message: z.string().default(""),
image: z.string().default(""),
imageId: z.string().default(""),
imageThumbUrl: z.string().default(""),
imageMediumUrl: z.string().default(""),
imageOriginalUrl: z.string().default(""),
imageWidth: z.number().default(0),
imageHeight: z.number().default(0),
useWebSocket: z.boolean().default(false),
});
export type SendMessageRequestInput = z.input<typeof SendMessageRequestSchema>;
export type SendMessageRequestData = z.output<typeof SendMessageRequestSchema>;
+12
View File
@@ -0,0 +1,12 @@
/**
* STT(语音转文字)响应
* 原始 Dart: SttData (lib/data/models/chat/stt_response.dart)
*/
import { z } from "zod";
export const SttDataSchema = z.object({
text: z.string(),
});
export type SttDataInput = z.input<typeof SttDataSchema>;
export type SttDataData = z.output<typeof SttDataSchema>;
+14
View File
@@ -0,0 +1,14 @@
/**
* 待同步的单条消息
* 原始 Dart: SyncMessage (lib/data/models/chat/chat_sync.dart)
*/
import { z } from "zod";
export const SyncMessageSchema = z.object({
role: z.string(),
content: z.string(),
timestamp: z.string(),
});
export type SyncMessageInput = z.input<typeof SyncMessageSchema>;
export type SyncMessageData = z.output<typeof SyncMessageSchema>;
+42
View File
@@ -0,0 +1,42 @@
/**
* Schemas - 集中导出
*
* Zod schema + 类型(Source of Truth
* 原始 Dart: lib/data/models/
*/
export * from "./auth/apple_login_request";
export * from "./auth/facebook_login_request";
export * from "./auth/fb_id_login_request";
export * from "./auth/google_login_request";
export * from "./auth/guest_login_request";
export * from "./auth/guest_login_response";
export * from "./auth/login_request";
export * from "./auth/login_response";
export * from "./auth/logout_response";
export * from "./auth/refresh_token_request";
export * from "./auth/refresh_token_response";
export * from "./auth/register_request";
export * from "./auth/send_code_request";
export * from "./chat/chat_history_response";
export * from "./chat/chat_message";
export * from "./chat/chat_send_response";
export * from "./chat/chat_sync_data";
export * from "./chat/chat_sync_request";
export * from "./chat/guest_chat_quota";
export * from "./chat/image_upload_response";
export * from "./chat/send_message_request";
export * from "./chat/stt_data";
export * from "./chat/sync_message";
export * from "./metrics/app_event";
export * from "./metrics/pwa_event";
export * from "./user/avatar_data";
export * from "./user/credits_data";
export * from "./user/credits_history_data";
export * from "./user/personality_traits";
export * from "./user/recent_memory";
export * from "./user/update_profile_request";
export * from "./user/user";
export * from "./user/user_stats_response";
+14
View File
@@ -0,0 +1,14 @@
/**
* 应用事件上报请求
* 原始 Dart: AppEvent (lib/data/models/metrics/app_event.dart)
*/
import { z } from "zod";
export const AppEventSchema = z.object({
userId: z.string(),
browser: z.string(),
userAgent: z.string(),
});
export type AppEventInput = z.input<typeof AppEventSchema>;
export type AppEventData = z.output<typeof AppEventSchema>;
+16
View File
@@ -0,0 +1,16 @@
/**
* PWA 事件上报请求
* 原始 Dart: PwaEvent (lib/data/models/metrics/pwa_event.dart)
*/
import { z } from "zod";
export const PwaEventSchema = z.object({
deviceId: z.string(),
deviceType: z.string(),
timestamp: z.number(),
pwaInstalled: z.boolean().default(false),
pwaSupported: z.boolean().default(false),
});
export type PwaEventInput = z.input<typeof PwaEventSchema>;
export type PwaEventData = z.output<typeof PwaEventSchema>;
+13
View File
@@ -0,0 +1,13 @@
/**
* 头像数据模型
* 原始 Dart: AvatarData (lib/data/models/user/user.dart)
*/
import { z } from "zod";
export const AvatarDataSchema = z.object({
avatarUrl: z.string().default(""),
userId: z.string(),
});
export type AvatarDataInput = z.input<typeof AvatarDataSchema>;
export type AvatarDataData = z.output<typeof AvatarDataSchema>;
+13
View File
@@ -0,0 +1,13 @@
/**
* 积分数据模型
* 原始 Dart: CreditsData (lib/data/models/user/user.dart)
*/
import { z } from "zod";
export const CreditsDataSchema = z.object({
userId: z.string(),
dolBalance: z.number(),
});
export type CreditsDataInput = z.input<typeof CreditsDataSchema>;
export type CreditsDataData = z.output<typeof CreditsDataSchema>;
@@ -0,0 +1,15 @@
/**
* 积分历史记录模型
* 原始 Dart: CreditsHistoryData (lib/data/models/user/user.dart)
*/
import { z } from "zod";
export const CreditsHistoryDataSchema = z.object({
records: z.array(z.record(z.string(), z.unknown())),
total: z.number(),
limit: z.number(),
offset: z.number(),
});
export type CreditsHistoryDataInput = z.input<typeof CreditsHistoryDataSchema>;
export type CreditsHistoryDataData = z.output<typeof CreditsHistoryDataSchema>;
@@ -0,0 +1,24 @@
/**
* 个性特征模型
* 原始 Dart: PersonalityTraits (lib/data/models/user/user.dart)
*/
import { z } from "zod";
export const PERSONALITY_TRAITS_DEFAULTS = {
cheerful: 0.5,
caring: 0.5,
playful: 0.5,
serious: 0.5,
romantic: 0.5,
} as const;
export const PersonalityTraitsSchema = z.object({
cheerful: z.number().default(0.5),
caring: z.number().default(0.5),
playful: z.number().default(0.5),
serious: z.number().default(0.5),
romantic: z.number().default(0.5),
});
export type PersonalityTraitsInput = z.input<typeof PersonalityTraitsSchema>;
export type PersonalityTraitsData = z.output<typeof PersonalityTraitsSchema>;
+15
View File
@@ -0,0 +1,15 @@
/**
* 最近记忆模型
* 原始 Dart: RecentMemory (lib/data/models/user/recent_memory.dart)
*/
import { z } from "zod";
export const RecentMemorySchema = z.object({
type: z.string(),
content: z.string(),
importance: z.number(),
createdAt: z.string().default(""),
});
export type RecentMemoryInput = z.input<typeof RecentMemorySchema>;
export type RecentMemoryData = z.output<typeof RecentMemorySchema>;
@@ -0,0 +1,15 @@
/**
* 更新个人资料请求
* 原始 Dart: UpdateProfileRequest (lib/data/models/user/user.dart)
*/
import { z } from "zod";
export const UpdateProfileRequestSchema = z.object({
username: z.string().default(""),
nickname: z.string().default(""),
preferredLanguage: z.string().default(""),
currentMood: z.string().default(""),
});
export type UpdateProfileRequestInput = z.input<typeof UpdateProfileRequestSchema>;
export type UpdateProfileRequestData = z.output<typeof UpdateProfileRequestSchema>;
+27
View File
@@ -0,0 +1,27 @@
/**
* 用户模型
* 原始 Dart: User (lib/data/models/user/user.dart)
*/
import { z } from "zod";
import { PersonalityTraitsSchema, PERSONALITY_TRAITS_DEFAULTS } from "./personality_traits";
export const UserSchema = z.object({
id: z.string(),
username: z.string(),
email: z.string().default(""),
platform: z.string().default("web"),
intimacy: z.number().default(0),
dolBalance: z.number().default(0),
relationshipStage: z.string().default("密友"),
currentMood: z.string().default("happy"),
personalityTraits: PersonalityTraitsSchema.default(PERSONALITY_TRAITS_DEFAULTS),
preferredLanguage: z.string().default(""),
createdAt: z.string().default(""),
lastMessageAt: z.string().default(""),
avatarUrl: z.string().default(""),
loginProvider: z.string().default("email"),
isGuest: z.boolean().default(false),
});
export type UserInput = z.input<typeof UserSchema>;
export type UserData = z.output<typeof UserSchema>;
@@ -0,0 +1,29 @@
/**
* 用户统计响应
* 原始 Dart: UserStatsResponse (lib/data/models/user/user_stats_response.dart)
*/
import { z } from "zod";
import { PersonalityTraitsSchema, PERSONALITY_TRAITS_DEFAULTS } from "./personality_traits";
import { RecentMemorySchema } from "./recent_memory";
export const UserStatsResponseSchema = z.object({
userId: z.string(),
username: z.string(),
platform: z.string(),
intimacy: z.number(),
relationshipStage: z.string(),
dolBalance: z.number(),
totalMessages: z.number(),
lastMessageAt: z.string().default(""),
accountCreatedAt: z.string().default(""),
currentMood: z.string().default(""),
personalityTraits: PersonalityTraitsSchema.default(PERSONALITY_TRAITS_DEFAULTS),
recentMemories: z.array(RecentMemorySchema).default([]),
promptTokensTotal: z.number().default(0),
completionTokensTotal: z.number().default(0),
cacheHitTokensTotal: z.number().default(0),
tokensTotal: z.number().default(0),
});
export type UserStatsResponseInput = z.input<typeof UserStatsResponseSchema>;
export type UserStatsResponseData = z.output<typeof UserStatsResponseSchema>;