docs(plan): add chat state machine refactor design
Update implementation_plan.md with a detailed refactor plan that splits `chatInitActor` into two independent actors (`loadQuotaActor` + `loadHistoryActor`) and redesigns the history loading flow to follow local → network → save semantics so the UI sees local data first, then network data. Key changes outlined in the plan: - Add new events: `ChatQuotaLoaded`, `ChatHistoryLocalLoaded`, `ChatHistoryNetworkLoaded`, `ChatHistorySyncDone` - Remove dead-code `ChatInit` event - Extend `ChatState` with `quotaLoaded` and `historyLoaded` flags - Use an `always` barrier in `guestSession.initializing` and `userSession.initializing` so both tasks must complete before transitioning to `ready` - Guest init runs `loadQuota` + `loadHistory` in parallel; non-guest init runs `chatWebSocket` + `loadHistory` as independent tasks Also adds `implementation_plan` to .gitignore.
This commit is contained in:
@@ -12,6 +12,7 @@ export class GuestChatQuota {
|
||||
static readonly maxQuotaPerDay = 40;
|
||||
static readonly maxQuotaPerDayTest = 4;
|
||||
static readonly quotaWarningThreshold = 20;
|
||||
|
||||
static readonly quotaWarningThresholdTest = 2;
|
||||
static readonly defaultTotalQuota = 50;
|
||||
static readonly defaultTotalQuotaDev = 5;
|
||||
|
||||
@@ -96,14 +96,6 @@ export function mapTotalQuotaResult(
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Init 任务 1:游客配额(**纯** local)—— `loadQuotaActor` 调
|
||||
// ============================================================
|
||||
/**
|
||||
* 读取游客配额(**仅** guestSession 有意义)
|
||||
* - 游客**日**配 + 总**配** 两**项**都**从** ChatStorage 拉(**纯** local,**无**网络)
|
||||
* - 失**败**返 fallback 0(**不**抛)—— **让** UI **还**是**能**进** ready
|
||||
*/
|
||||
export async function readGuestQuota(): Promise<{
|
||||
remaining: number;
|
||||
total: number;
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
/**
|
||||
* Chat 状态机(XState v5)
|
||||
*
|
||||
* 设计要点:
|
||||
* - 使用 XState v5 `setup({...}).createMachine({...})` 声明式 API
|
||||
* - HTTP 操作用 `fromPromise` actor(一次性 Promise)
|
||||
* - WebSocket 用 `fromCallback` actor(长生命周期)—— **机器内**完整管理
|
||||
* - chat-screen **不**直接管理 WS —— 只派 3 个鉴权生命周期事件
|
||||
* - 保持事件类型名与原 Dart 一致,便于业务层迁移对照
|
||||
*
|
||||
* **鉴权解耦**(**事件驱动**):
|
||||
* chat 机器**不**感知鉴权 / **不**管 WebSocket —— 由 chat-screen 派生 loginStatus
|
||||
* chat-screen **只**派 3 个事件:
|
||||
@@ -308,14 +301,44 @@ export const chatMachine = setup({
|
||||
},
|
||||
ready: {
|
||||
on: {
|
||||
ChatSendMessage: {
|
||||
actions: ["logSendMessageReceived", "appendUserMessage"],
|
||||
guard: ({ event }) => event.content.trim().length > 0,
|
||||
target: "sending",
|
||||
},
|
||||
ChatSendImage: {
|
||||
actions: ["logSendImageReceived", "appendUserImage"],
|
||||
},
|
||||
// **配**额**检**查** + 发**送**消息**(3 **条** guard,**按**顺**序**匹**配**)
|
||||
// 1. **总**配**额**(guestTotalQuota)**不**足 → **触**发** quota exceeded dialog,**不**发**送**
|
||||
// 2. **每**日**配**额**(guestRemainingQuota)**不**足 → **同**上**
|
||||
// 3. **两**个**配**额**都** OK + **内**容**非**空** → **发**送** + **减**配**额**
|
||||
ChatSendMessage: [
|
||||
// 1. 总配**额** **不**足**(guestTotalQuota <= 0) → **触**发** quota exceeded dialog
|
||||
{
|
||||
guard: ({ context }) => context.guestTotalQuota <= 0,
|
||||
actions: "incrementQuotaExceeded",
|
||||
},
|
||||
// 2. 每**日**配**额** **不**足**(guestRemainingQuota <= 0) → **触**发** quota exceeded dialog
|
||||
{
|
||||
guard: ({ context }) => context.guestRemainingQuota <= 0,
|
||||
actions: "incrementQuotaExceeded",
|
||||
},
|
||||
// 3. 两**个**配**额**都** OK + **内**容**非**空** → **发**送**
|
||||
{
|
||||
actions: ["logSendMessageReceived", "appendUserMessage"],
|
||||
guard: ({ event }) => event.content.trim().length > 0,
|
||||
target: "sending",
|
||||
},
|
||||
// 兜**底**:**内**容**空** / 什**么**都**不**匹**配** → **静**默**丢**弃**
|
||||
],
|
||||
// **配**额**检**查** + 发**送**图**片**(**同**样** 3 **条** guard,**不**检**查** "内**容**空"**)
|
||||
ChatSendImage: [
|
||||
{
|
||||
guard: ({ context }) => context.guestTotalQuota <= 0,
|
||||
actions: "incrementQuotaExceeded",
|
||||
},
|
||||
{
|
||||
guard: ({ context }) => context.guestRemainingQuota <= 0,
|
||||
actions: "incrementQuotaExceeded",
|
||||
},
|
||||
{
|
||||
actions: ["logSendImageReceived", "appendUserImage"],
|
||||
target: "sending",
|
||||
},
|
||||
],
|
||||
// **删**除 ChatLoadMoreHistory handler —— 游客**无**服**务**端** history,**不**支**持**翻**页**
|
||||
ChatLogout: "#chat.idle",
|
||||
ChatNonGuestLogin: "#chat.userSession",
|
||||
|
||||
Reference in New Issue
Block a user