新增:community feature 数据层——契约 v1.3.0 十九操作全覆盖 + ToggleSync 乐观更新状态机(T3-12)
CI / flutter-gates (push) Successful in 2m26s
CI / flutter-gates (push) Successful in 2m26s
- community_models:community/media 域 DTO 逐字段照冻结契约手写 JSON 映射 (Post/FeedCard/PostComment/AuthorSummary 降级形态/媒体两步上传凭据等), 未知枚举抛 FormatException 暴露契约漂移;CursorPage 上移 core 复用 - community_repository:13 路径 19 操作全覆盖;createPost/createComment 必带 Idempotency-Key(每次逻辑提交换新键、刷新重放同键);点赞/收藏/ 关注走 PUT/DELETE 语义幂等 - community_exceptions:v1.3.0 新增 9 码 + 40902 共码类型化异常映射 - toggle_sync:乐观翻转 + 快照回滚 + 单飞合并最终意图 + 代次守卫, 点赞/收藏共用一套参数化状态机,权威终态对账收敛 - community_controller:Feed 多页缓存 + 首屏四态 + 尾部加载三态 + 游标拼接 + 刷新代次丢弃旧尾页;详情副本与卡片互动状态同源;reset 清态 - app.dart 装配:community 服务分端口直连(:8084),共享 TokenRefresher, 登出同步 reset - 测试 286 → 347(模型映射 / 19 操作线路 / 错误映射 / 竞态序列全覆盖) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
/// cursor 分页正典信封 `{items, nextCursor, hasMore}`(pets 域体重 / 健康事件,
|
||||
/// community 域 Feed / 我的帖子 / 评论 / 收藏共用;自 pet_models.dart 上移至 core)。
|
||||
class CursorPage<T> {
|
||||
const CursorPage({
|
||||
required this.items,
|
||||
required this.nextCursor,
|
||||
required this.hasMore,
|
||||
});
|
||||
|
||||
factory CursorPage.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
T Function(Map<String, dynamic>) itemFromJson,
|
||||
) {
|
||||
return CursorPage(
|
||||
items: (json['items'] as List)
|
||||
.map((item) => itemFromJson(item as Map<String, dynamic>))
|
||||
.toList(),
|
||||
// 不透明 base64url 游标,客户端不得解析;hasMore=false 时恒为 null。
|
||||
nextCursor: json['nextCursor'] as String?,
|
||||
hasMore: json['hasMore'] as bool,
|
||||
);
|
||||
}
|
||||
|
||||
final List<T> items;
|
||||
final String? nextCursor;
|
||||
final bool hasMore;
|
||||
}
|
||||
@@ -25,6 +25,14 @@ const String patbondPetApiBaseUrl = String.fromEnvironment(
|
||||
defaultValue: 'http://127.0.0.1:8083',
|
||||
);
|
||||
|
||||
/// community 服务基地址(/api/v1/posts、/api/v1/feed、/api/v1/media 等
|
||||
/// community/media 域 13 路径):沿用分端口直连模式,
|
||||
/// `--dart-define=PATBOND_COMMUNITY_API_BASE_URL=...` 注入。
|
||||
const String patbondCommunityApiBaseUrl = String.fromEnvironment(
|
||||
'PATBOND_COMMUNITY_API_BASE_URL',
|
||||
defaultValue: 'http://127.0.0.1:8084',
|
||||
);
|
||||
|
||||
/// 构建全局共用的 Dio 实例。
|
||||
///
|
||||
/// `validateStatus` 放行所有状态码:错误信封由 [ApiClient] 统一解析成
|
||||
|
||||
@@ -48,6 +48,36 @@ abstract final class ApiCodes {
|
||||
|
||||
/// 提醒状态机 / completed-completedAt 一致性违反(HTTP 422)。
|
||||
static const careReminderRuleViolation = 42202;
|
||||
|
||||
// ------ community / media 域(契约 v1.3.0 冻结,M3 第二波定型 9 个)------
|
||||
|
||||
/// 对可见帖子/评论无相应操作权限(改删他人已发布帖、删他人可见评论)。
|
||||
static const postAccessDenied = 40301;
|
||||
|
||||
/// 帖子不存在 / 已软删 / hidden/archived(含作者)/ 他人 draft
|
||||
/// (防枚举,全部情况响应一致;互动路径上含作者本人草稿)。
|
||||
static const postNotFound = 40403;
|
||||
|
||||
/// 评论不存在、已删或所属帖子不可见(防枚举合并)。
|
||||
static const commentNotFound = 40404;
|
||||
|
||||
/// media asset 不存在、非本人所有或已删(防枚举合并)。
|
||||
static const mediaNotFound = 40405;
|
||||
|
||||
/// 目标用户不存在或已注销(合并不泄露成因)。
|
||||
static const communityUserNotFound = 40406;
|
||||
|
||||
/// 同 Idempotency-Key 不同 payload(规范化 request_hash 不符)。
|
||||
static const idempotencyKeyMismatch = 40905;
|
||||
|
||||
/// 引用了本人所有但非 ready(uploading/failed)状态的 asset(HTTP 422)。
|
||||
static const mediaNotReady = 42203;
|
||||
|
||||
/// 自关注(仅 PUT;自取关走 DELETE 的 200 幂等 no-op)。
|
||||
static const selfFollow = 42204;
|
||||
|
||||
/// 上传状态不允许确认(非 uploading 态或对象校验未通过,HTTP 422)。
|
||||
static const mediaUploadStateInvalid = 42205;
|
||||
}
|
||||
|
||||
/// API 调用的类型化异常。页面按类型映射为三层错误呈现
|
||||
|
||||
Reference in New Issue
Block a user