Files
Edu/docs/architecture/coord-final-decisions.md

296 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Coord 最终方案强制裁决
> 版本1.0(历史文档)
> 日期2026-07-09
> 决策者coord经用户确认
> 适用范围Edu 项目全部 15 份 AI 设计文档ai01-ai06, ai08-ai16
>
> **⚠️ 历史声明**:本文件为**批次模式时期**2026-07-09的 coord 强制裁决记录。项目已于 2026-07-10 切换为**全并行开发模式**。
>
> - 本文件正文保留原始裁决内容(含 ai07 引用),作为历史追溯凭证
> - **当前权威文档**[ai-allocation.md](./ai-allocation.md) v2.0 + [issues/README.md](./issues/README.md) + [issues/coord.md](./issues/coord.md)(新流程仲裁)
> - ai07 已移除classes 合并到 core-eduai08 负责)
> - 新仲裁记录见 [issues/coord.md](./issues/coord.md)
>
> 关联文档:[004 架构影响地图 §16](./004_architecture_impact_map.md)、[ai-allocation.md](./ai-allocation.md)、[project_rules.md](../../.trae/rules/project_rules.md)
---
## 0. 裁决原则
用户反馈:**"前面简略实现后面要重写,完全没必要,直接使用最好的方式工作"**。
各 AI 设计文档中存在大量"P2 简化 → P3 重构 → P4 再重构"的渐进式过渡方案导致前期代码后期必废弃。coord 裁决如下:
### 0.1 强制覆盖声明
- **本文档 > 各 AI 设计文档**:凡本文档列出的裁决项,各 AI 设计文档中与之冲突的"中间过渡方案"一律作废,**直接采用最终方案**
- **不分阶段**:最终方案在服务首次落地时即采用,不得以"阶段未到"为由先实现简化版
- **回写义务**:各 AI 收到本文档后,必须在 3 个工作日内回写自己的 02-architecture-design.md删除所有"中间过渡方案"描述,对齐最终方案
### 0.2 裁决依据
- 用户明确指示"直接使用最好的方式"
- project_rules.md §3.1 已规定企业级规范(如 Dockerfile 多阶段、Zod 验证、GlobalErrorFilter无理由分阶段
- 黄金模板 services/classes/ 已实现全部最终方案,其他服务对齐即可
---
## 1. 通用裁决(适用全部服务)
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 | 影响服务 |
| --- | --------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| G1 | **Dockerfile** | "P3 重构"、"P5 重构"、"待落地" | **首次实现即多阶段构建**builder + runtime | 全部 |
| G2 | **/readyz 探针** | "P2 仅返回 ok"、"P3+ 补下游探针" | **首次实现即检查全部下游依赖**DB SELECT 1 / Redis PING / Kafka 连接 / gRPC 下游可达) | 全部 |
| G3 | **/healthz** | "P2 改造" | **首次实现即 liveness 探针** | 全部 |
| G4 | **Logger** | "待引入 slog"、"console.log → P3 修复" | **首次实现即结构化日志**TS pino / Go slog / Python structlog禁止 console.log | 全部 |
| G5 | **Metrics** | "自定义业务指标待实现" | **首次实现即 /metrics 端点 + 基础业务指标** | 全部 |
| G6 | **Tracer** | "资源属性待补"、"span 待补" | **首次实现即 OTel SDK + OTLP exporter + 完整资源属性 + 全链路 span** | 全部 |
| G7 | **Zod 验证** | "P2 补全"、"P3 实施中"、"部分 → P4 全 parse" | **Controller 层首次实现即全量 schema.parse(body/query/params)** | 全部 TS |
| G8 | **GlobalErrorFilter** | "待落地"、"P4+ 对齐 ActionState" | **首次实现即注册 GlobalErrorFilter + 响应信封严格对齐 ActionState 结构** | 全部 |
| G9 | **优雅关闭** | "P2 补全" | **首次实现即 SIGTERM → app.close() → shutdownTracer(),按序关闭 HTTP→DB→Redis→Kafka** | 全部 |
| G10 | **DB 连接模式** | "const db vs getDb()" | **统一 getDb() 函数**(对齐 classes 黄金模板) | 全部 TS 持 DB 服务 |
| G11 | **ID 策略** | "cuid2 vs randomUUID" | **统一 cuid2**(对齐 classes 黄金模板) | 全部 TS 持 DB 服务 |
| G12 | **ESM import** | 缺 .js 后缀 | **所有相对 import 带 .js 后缀**NestJS ESM 模式) | 全部 TS |
| G13 | **import type** | 混用 | **仅用于类型的导入必须 import type** | 全部 TS |
| G14 | **错误码前缀** | api-gateway 无前缀 | **每个服务错误码必须用服务名大写前缀**GW_/IAM_/CORE_EDU_/CONTENT_/MSG_/DATA_ANA_/AI_/PUSH_/BFF_TEACHER_/BFF_STUDENT_/BFF_PARENT_/CLASSES_ | 全部 |
| G15 | **错误码子前缀** | 保留 EXAMS_/HOMEWORK_/GRADES_ | **统一用聚合域前缀 CORE_EDU_***,禁止子前缀 | 前端 + core-edu |
| G16 | **Kafka topic 命名** | edu.notification.events 抽象名 | **edu.\<domain>.\<aggregate>.\<action>** 具体动作(如 edu.notification.sent | 全部 |
| G17 | **proto 包名** | 不一致 | **next_edu_cloud.\<domain>.v1** | 全部 |
---
## 2. BFF 层专项裁决teacher-bff / student-bff / parent-bff
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| B1 | **API 风格** | "P2 REST → P4 GraphQL"、"P3 REST → P4+ GraphQL" | **P2 起直接 GraphQL**GraphQL Yoga + DataLoader |
| B2 | **对下游通信** | "P2 HTTP fetch → P3+ gRPC"、"P3 HTTP → P3+ gRPC" | **首次实现即 gRPC 调用下游**iam/core-edu/content/data-ana/msg/ai 全部 gRPC |
| B3 | **权限装饰器** | "BFF 加 @RequirePermission"、"待仲裁" | **BFF 豁免 @RequirePermission**(权限由 Gateway JWT + 下游服务负责BFF 仅校验 x-user-id 存在 |
| B4 | **越权防御** | "仅 teacher-bff 透传"、"student-bff 待仲裁" | **全部 BFF 强制自我越权防御**student-bff 比对 userId、parent-bff 校验 childId 绑定列表、teacher-bff 校验 teacherId 与班级关系 |
| B5 | **错误码前缀** | "STUDENT_BFF_ vs BFF_STUDENT_" | **BFF_TEACHER\_ / BFF_STUDENT\_ / BFF_PARENT_**(统一 BFF_ 前缀) |
| B6 | **缓存策略** | "不缓存 vs Redis 短缓存" | **Redis 5-30s 短缓存**(对齐 004 §6.2 BFF 混合读策略) |
| B7 | **Kafka 订阅** | "P3 评估"、"P5 评估" | **P2-P4 不订阅 Kafka**仅同步聚合P5 push-gateway 落地后再订阅 |
| B8 | **DownstreamClient 抽象** | "是否回写 teacher-bff" | **回写 teacher-bff**,作为 BFF 模式 v2 标准抽象3 个 BFF 统一使用 |
---
## 3. 业务服务专项裁决
### 3.1 iamai06
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| I1 | **gRPC server** | "P2 仅 REST → P3 启用 gRPC" | **P2 即启用 gRPC server 50052**,同时暴露 REST + gRPC |
| I2 | **Outbox** | "iam 自建 → core-edu 落地后回写 shared-ts" | **直接建 shared-ts Outbox 工具包**iam 首次实现即用 |
| I3 | **PermissionGuard** | "本地 ROLE_PERMISSIONS map → DB 驱动" | **首次实现即 DB 驱动 + Redis 缓存**,废弃本地 map |
| I4 | **AuthMiddleware** | "P2 不注册 → Controller 直读 header" | **首次实现即注册 AuthMiddleware**Controller 通过 @Req() 获取用户上下文 |
| I5 | **JWT 密钥** | "P2 本地文件 → P6 Vault" | **P2 本地文件**IAM_PRIVATE_KEY_PATH / IAM_PUBLIC_KEY_PATHP6 迁 Vault 单列后续 |
| I6 | **家长-学生关联** | "接口缺失 → P3 补" | **P2 即补全**iam_student_guardians 表 + GetChildrenByParent RPC + GET /iam/children RESTP0 阻塞 parent-bff |
| I7 | **API 版本化** | "待 coord 审查" | _*采用 /iam/v1/* 前缀_*Gateway 同步调整 |
| I8 | **iam 端点路径** | /iam/permissions/effective vs /iam/effective-permissions | **统一 GET /iam/permissions/effective**RESTful 资源路径风格) |
### 3.2 core-eduai08
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ----------------------------------------- | -------------------------------------- | -------------------------------------------------------------------- |
| C1 | **classes 合并** | "P3 初期 vs P3 末期" | **P3 开始前直接合并**classes 代码迁移到 core-educlasses 服务下线 |
| C2 | **gRPC server** | "P3 启用" | **P3 首次实现即启用 gRPC server 50053** |
| C3 | **Kafka console.log** | "P3 修复" | **首次实现即用 logger.info**,禁止 console.log |
| C4 | **AttendanceService** | "待 coord 补 proto" | **P3 首次实现即补全 proto + 实现** |
| C5 | **GetClassesByTeacher / BatchGetClasses** | "待新增" | **P3 首次实现即补全** |
| C6 | **排课 room_id** | "P3 实现 vs 预留 vs P6+" | **P3 预留字段**(不实现逻辑,但 schema 含字段) |
| C7 | **成绩计算公式** | "scope 优先级待定" | **class > subject > school**(越细粒度优先) |
| C8 | **作业 grace_period** | "0 秒 vs 300 秒" | **默认 300 秒**5 分钟宽限) |
| C9 | **schema 强制校验** | "P3 JSON Schema vs 文档约束" | **P3 仅文档约束**P6+ 引入 schema registry |
| C10 | **exam.submitted 事件** | "包含完整 answers vs 仅 submission_id" | **仅含 submission_id**(避免事件过大) |
| C11 | **archived 考试** | "物理迁移 vs 软删除 vs P6+" | **仅软删除**is_archived 字段) |
### 3.3 contentai09
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------- | -------------------- | ------------------------------------------------ |
| N1 | **gRPC server** | "gRPC 待实现" | **P4 首次实现即启用 gRPC server 50054** |
| N2 | **/readyz** | "仅 DB → P4 多依赖" | **首次实现即检查 DB/Neo4j/Kafka** |
| N3 | **QuestionService** | "P5 阻塞待补 proto" | **P4 即补全 QuestionService proto**(不等到 P5 |
| N4 | **ErrorFilter** | "错误响应结构待对齐" | **首次实现即对齐 ActionState** |
| N5 | **ChapterService** | "缺 GetChapter" | **P4 首次实现即补全** |
### 3.4 msgai10
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | --------------------- | --------------------------- | ----------------------------------------------------- |
| M1 | **gRPC server** | "gRPC 待实现" | **P5 首次实现即启用 gRPC server 50056** |
| M2 | **/readyz** | "仅 DB → P5 多依赖" | **首次实现即检查 DB/ES/Redis/Kafka/PushGateway** |
| M3 | **ZodError** | "未处理 → P5 处理" | **首次实现即处理 ZodError 分支** |
| M4 | **调用 push-gateway** | "gRPC PushService.Push" | **HTTP POST /internal/push**coord 仲裁豁免 gRPC |
| M5 | **事件 topic** | "edu.teaching.assignment.*" | **edu.teaching.homework.***(与 core-edu 发布方一致) |
### 3.5 data-anaai11
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | --------------------------- | --------------------- | ------------------------------------------------------------------------------------------------- |
| D1 | **ErrorFilter** | "v2 对齐 ActionState" | **首次实现即对齐 ActionState** |
| D2 | **Dockerfile** | "v2 设计多阶段" | **首次实现即多阶段** |
| D3 | **ClickHouse DDL** | "待 coord 建目录" | **直接建 infra/clickhouse/ddl/** |
| D4 | **analytics.proto 扩展** | "待 coord 审议" | **P4 即补全**4 端 Dashboard + Warning + MasteryDistribution + SubscribeMasteryUpdate Stream RPC |
| D5 | **warning.triggered topic** | "待 coord 登记" | **已登记**004 §7.2 + events.proto MasteryEvent |
### 3.6 aiai12
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ---------------------- | ------------------------- | ------------------------------------------------------------------------------ |
| A1 | **ErrorFilter** | "待对齐" | **首次实现即对齐 ActionState** |
| A2 | **Dockerfile** | "实现阶段需新增" | **首次实现即多阶段** |
| A3 | **gRPC 端口** | "待 coord 补登" | **已补登 50058**(见 infra/port-allocation.md |
| A4 | **ai.proto 补全** | "待 coord" | **P5 首次实现即补全** GenerateLessonPlan / StreamGenerateQuestion |
| A5 | **AIUsageEvent proto** | "待 coord" | **已补全** events.proto |
| A6 | **Prompt 模板存储** | "P5 YAML / P6+ DB" | **P5 直接用 DB 存储**(避免后期迁移) |
| A7 | **备课工作流** | "P5 Redis / P6+ Temporal" | **P5 用 FastAPI BackgroundTasks + Redis**Temporal 引入成本高P6+ 单独评估) |
| A8 | **多模态** | "P5 文本 / P6+ 多模态" | **P5 仅文本**proto v2 预留字段 |
### 3.7 push-gatewayai02
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------ | ---------------------------- | ----------------------------------------------------------------- |
| P1 | **gRPC** | "备选 gRPC PushService" | **彻底删除 gRPC 设计**,纯 HTTP + WebSocketcoord 仲裁豁免) |
| P2 | **X-Internal-Key** | "→ X-Internal-Token P5 立即" | **首次实现即 X-Internal-Token**(环境变量 INTERNAL_API_TOKEN |
| P3 | **Dockerfile** | "P5 重构" | **首次实现即多阶段** |
| P4 | **slog** | "待引入" | **首次实现即用 slog** |
| P5 | **SSE 降级** | "P7+ 考虑" | **本期仅 HTTP 长轮询预留**SSE 不实现 |
| P6 | **断线重连** | "本期仅协议预留" | **本期仅协议预留**session_id + last_seq 字段P6 实现补推逻辑 |
### 3.8 api-gatewayai01
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | -------------------- | ------------------------------------------- | ----------------------------------------------------- |
| W1 | **错误码前缀** | "无前缀" | **GW_***GW_UNAUTHORIZED 等) |
| W2 | **错误信封** | "recovery/ratelimit/circuit-breaker 待整改" | **首次实现即对齐 ActionState** |
| W3 | **slog** | "待引入" | **首次实现即用 slog** |
| W4 | **/readyz** | "待重构" | **首次实现即真实健康检查**(轮询下游 /healthz |
| W5 | **业务 metrics** | "待实现" | **首次实现即基础业务指标**(请求量/延迟/错误率/熔断) |
| W6 | **tracer 资源属性** | "待补" | **首次实现即完整**version/env/host |
| W7 | **DevMode 防护** | "P1 待办" | **首次实现即生产防护**DEV_MODE 仅非生产环境生效) |
| W8 | **per-服务实例熔断** | "P6 待办" | **保持共享 downstream 熔断**per-实例 P6 单独评估 |
---
## 4. 前端 4 portal 专项裁决
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| F1 | **admin-portal 端口** | 3003 / 3000 / 4003 三处矛盾 | **统一 4003** |
| F2 | **admin-portal MF 配置** | teacher_app@localhost:3000 | **teacher_app@localhost:4000** |
| F3 | **Web Vitals** | FID vs INP 混用 | **统一 INP**CWV 2024 标准) |
| F4 | **i18n key 命名** | bff.error / bffTeacher.error / bffStudent.error 混用 | **统一 error.\<service>.\<code_snake>**(如 error.iam.invalid_credentials、error.bffTeacher.validation_error |
| F5 | **错误码子前缀** | parent-portal 保留 GRADES_/HOMEWORK_ | **统一删除子前缀**,用 CORE_EDU_* |
| F6 | **iam 权限端点** | /iam/permissions/effective vs /iam/effective-permissions | **统一 /iam/permissions/effective** |
| F7 | **权限点命名风格** | TEACHER_DASHBOARD_VIEW / STUDENT_DASHBOARD_READ / GRADES_READ_CHILD 混用 | **统一 \<RESOURCE>\_\<ACTION>**(如 DASHBOARD_VIEW、EXAM_READ、GRADE_READ数据范围用后缀 _OWN/_CHILD如 GRADE_READ_CHILD |
| F8 | **packages 归属** | "ai07/ai13 维护 vs coord 维护" | **ai13 维护 ui-tokens/ui-components/hookscoord 仅维护 shared-ts/contracts** |
| F9 | **GraphQL vs REST** | "P2-P6 REST未来切 GraphQL" | **P2 起 BFF 用 GraphQL前端用 urql/apollo** |
| F10 | **MF 暴露粒度** | "AppShell 整体 vs 细粒度" | **暴露 AppShell 整体**,各 Remote 自行决定内部布局 |
| F11 | **teacher-portal 归属** | "004 §15.1 写 ai07ai-allocation §3.2 写 ai13" | **ai13 负责 teacher-portal**ai07 负责 classes 黄金模板) |
| F12 | **localStorage token** | "P6 评估迁移 httpOnly Cookie" | **P2 用 localStorage**httpOnly Cookie + CSRF Token P6 单独评估) |
---
## 5. 跨服务契约裁决(一次性补全,不分阶段)
### 5.1 proto 契约补全coord 负责P2 启动前全部就位)
| proto 文件 | 待补内容 | 阻塞阶段 | 完成期限 |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
| events.proto | ✅ 已补全UserEvent/RoleEvent/NotificationEvent/MasteryEvent/AIUsageEvent/KnowledgePointEvent/QuestionEvent | — | 已完成 |
| iam.proto | GetViewports / GetEffectivePermissions / GetEffectiveAccess / Logout / GetPublicKey / BatchGetUsers / GetEffectiveDataScope / GetChildrenByParent | P2 | P2 启动前 |
| core_edu.proto | AttendanceService.* / GetClassesByTeacher / BatchGetClasses | P3 | P3 启动前 |
| content.proto | ChapterService.GetChapter / QuestionService.* / TextbookService.ListTextbooks 补全 | P4 | P4 启动前 |
| analytics.proto | GetTeacherDashboard / GetStudentDashboard / GetParentDashboard / GetAdminDashboard / GetWarnings / GetMasteryDistribution / SubscribeMasteryUpdate (stream) | P4 | P4 启动前 |
| ai.proto | GenerateLessonPlan / StreamGenerateQuestion / 字段扩展 | P5 | P5 启动前 |
| msg.proto | BatchSendNotification / GetUnreadCount / BatchMarkAsRead / MarkAllAsRead / RecallNotification + NotificationPreferenceService + NotificationTemplateService + 3 个 message | P5 | P5 启动前 |
### 5.2 接口命名统一
| 调用方 | 被调方 | 统一命名 | 说明 |
| ----------------- | ------------ | ------------------------------------------------------------ | ---------------------------- |
| core-edu | content | **KnowledgeGraphService.GetPrerequisites / GetLearningPath** | 禁用 ContentService 命名 |
| teacher-bff | data-ana | **GetTeacherDashboard**(无 Stats 后缀) | 统一命名 |
| msg / student-bff | push-gateway | **HTTP POST /internal/push**body 含 user_id | 豁免 gRPC |
| ai | core-edu | **ExamService.GetExam** | 方向ai 调 core-edu非反向 |
### 5.3 gRPC server 启用时机
| 服务 | gRPC 端口 | 启用时机 | 说明 |
| ------------ | --------- | --------------- | ---------------------------------- |
| iam | 50052 | **P2** | 首次实现即启用(覆盖"P2 仅 REST" |
| core-edu | 50053 | **P3** | 首次实现即启用 |
| content | 50054 | **P4** | 首次实现即启用 |
| data-ana | 50055 | **P4** | 首次实现即启用 |
| msg | 50056 | **P5** | 首次实现即启用 |
| ai | 50058 | **P5** | 首次实现即启用 |
| push-gateway | — | **不启用** | 豁免 gRPC |
| BFF3 个) | — | **不暴露 gRPC** | 仅对下游走 gRPC |
---
## 6. 待 P6+ 单独评估事项(不阻塞当前阶段)
以下事项不属于"中间过渡方案",属于"未来扩展",保持原状:
| # | 事项 | 评估时机 |
| --- | ------------------------------------------------------------------- | --------- |
| X1 | ai 发布 edu.insight.ai.generated / feedback / workflow 3 个新 topic | P6+ |
| X2 | admin-portal 8 个新 Kafka topic + events.proto message | P6 实施时 |
| X3 | admin-portal 审计日志/安全事件归属iam vs audit-service | P6 |
| X4 | ai 备课工作流迁移 Temporal | P6+ |
| X5 | ai Prompt 模板 DB 存储迁移(已在 A6 裁决 P5 直接用 DB | — |
| X6 | admin-portal Grafana/Jaeger iframe 嵌入 | P6 |
| X7 | teacher-portal localStorage → httpOnly Cookie 迁移 | P6 |
| X8 | iam JWT 密钥迁移 Vault | P6 |
| X9 | api-gateway per-服务实例熔断 | P6 |
| X10 | schema registry 引入events.proto 强制校验) | P6+ |
---
## 7. 各 AI 回写义务
各 AI 收到本文档后,必须执行以下回写:
### 7.1 回写内容
1. 删除自己 02-architecture-design.md 中所有"中间过渡方案"描述
2. 对齐本文档的最终方案
3. 更新 §8 风险与假设(移除已裁决项)
### 7.2 回写期限
| AI | 服务 | 回写期限 | 阻塞阶段 |
| ---- | -------------- | ---------------------- | -------- |
| ai01 | api-gateway | P2 启动前 | — |
| ai02 | push-gateway | P5 启动前 | — |
| ai03 | teacher-bff | **P2 启动前** | P2 |
| ai04 | student-bff | P3 启动前 | — |
| ai05 | parent-bff | P4 启动前 | — |
| ai06 | iam | **P2 启动前** | P2 |
| ai07 | classes | 已是黄金模板,无需回写 | — |
| ai08 | core-edu | P3 启动前 | — |
| ai09 | content | P4 启动前 | — |
| ai10 | msg | P5 启动前 | — |
| ai11 | data-ana | P4 启动前 | — |
| ai12 | ai | P5 启动前 | — |
| ai13 | teacher-portal | **P2 启动前** | P2 |
| ai14 | student-portal | P3 启动前 | — |
| ai15 | parent-portal | P4 启动前 | — |
| ai16 | admin-portal | P6 启动前 | — |
### 7.3 coord 验收
各 AI 回写完成后coord 将重新运行 §8 交叉审查,确认无"中间过渡方案"残留。
---
## 8. 变更记录
| 日期 | 变更 | 决策者 |
| ---------- | --------------------------------------------------------------------------------------------------------------------- | ----------------- |
| 2026-07-09 | 初始创建,覆盖 G1-G17 / B1-B8 / I1-I8 / C1-C11 / N1-N5 / M1-M5 / D1-D5 / A1-A8 / P1-P6 / W1-W8 / F1-F12 共 80+ 项裁决 | coord用户确认 |