// Package service 定义 room-service 领域服务及其持久化边界。 package service import ( "context" "time" "hyapp/services/room-service/internal/room/outbox" ) // RoomMeta 对应 rooms 表中房间的持久元数据。 type RoomMeta struct { // RoomID 是房间主键,也是恢复和 lease 路由的分区键。 RoomID string // OwnerUserID 是房间所有者,恢复无快照房间时用于重建管理员集合。 OwnerUserID int64 // HostUserID 是主持人,恢复无快照房间时用于重建管理员集合。 HostUserID int64 // SeatCount 是初始麦位数量,只有无快照恢复时需要它重建麦位。 SeatCount int32 // Mode 是房间模式,当前作为元数据持久化。 Mode string // Status 是房间基础状态,快照缺失时用于恢复 RoomState.Status。 Status string } // CommandRecord 对应 room_command_log 中一条成功命令。 type CommandRecord struct { // RoomID 是命令所属房间。 RoomID string // RoomVersion 是命令成功应用后的房间版本,恢复时按它排序回放。 RoomVersion int64 // CommandID 是幂等键,repository 必须保证同房间唯一。 CommandID string // CommandType 是反序列化命令 payload 的分发键。 CommandType string // Payload 是命令 JSON 序列化结果。 Payload []byte // Replayable 标记该命令是否参与恢复回放。 Replayable bool // CreatedAt 是命令成功落盘时间。 CreatedAt time.Time } // SnapshotRecord 对应 room_snapshots 中的一条最新快照。 type SnapshotRecord struct { // RoomID 是快照所属房间。 RoomID string // RoomVersion 是快照覆盖到的房间版本。 RoomVersion int64 // Payload 是 roomv1.RoomSnapshot 的 protobuf 序列化结果。 Payload []byte // CreatedAt 是快照生成时间。 CreatedAt time.Time } // Repository 聚合 room-service 在首版需要的全部持久化读写。 type Repository interface { // SaveRoomMeta 保存房间基础元数据,创建房间时必须先建立它。 SaveRoomMeta(ctx context.Context, meta RoomMeta) error // GetRoomMeta 读取房间基础元数据,恢复无内存 Cell 的房间依赖它。 GetRoomMeta(ctx context.Context, roomID string) (RoomMeta, bool, error) // HasCommand 判断命令是否已经成功提交,用于所有写命令幂等。 HasCommand(ctx context.Context, roomID string, commandID string) (bool, error) // SaveCommand 追加成功命令日志,关键命令恢复必须依赖它。 SaveCommand(ctx context.Context, record CommandRecord) error // ListCommandsAfter 读取快照版本之后的命令,恢复时按版本顺序回放。 ListCommandsAfter(ctx context.Context, roomID string, roomVersion int64) ([]CommandRecord, error) // SaveSnapshot 保存最新房间快照,允许覆盖旧版本但不能倒退。 SaveSnapshot(ctx context.Context, snapshot SnapshotRecord) error // GetLatestSnapshot 读取当前最新快照,恢复时优先使用它减少回放成本。 GetLatestSnapshot(ctx context.Context, roomID string) (SnapshotRecord, bool, error) // SaveOutbox 写入房间外事件,必须和成功命令保持同一提交语义。 SaveOutbox(ctx context.Context, records []outbox.Record) error // ListPendingOutbox 扫描待补偿投递事件。 ListPendingOutbox(ctx context.Context, limit int) ([]outbox.Record, error) // MarkOutboxPublished 标记事件已经投递成功。 MarkOutboxPublished(ctx context.Context, eventID string) error // MarkOutboxFailed 记录一次投递失败并保留 pending 状态等待重试。 MarkOutboxFailed(ctx context.Context, eventID string, lastErr string) error }