主要产出:
- DTO 层:app/dto/meeting_dto.go 完整定义 13 个 DTO(请求/响应/基础共用)
- Service 层:MeetingService 12 业务方法 + 11 个 sentinel 错误 + 4 辅助
- CreateRoom/JoinRoom/LeaveRoom/EndRoom 核心生命周期
- KickMember/TransferHost/GetRoom/ListMyMeetings 会议管理
- InviteUsers(+ NotifyPusher)/ RedeemInviteToken 邀请链路
- SendChat/ListChats 会议内聊天
- Controller 层:12 handler + handleError 领域错误 → HTTP 映射
- 工具层:pkg/utils/meeting_code.go(XXX-XXX-XXX + invite token)
- Stub 接口:MediaOrchestrator(Task 7 替换)+ NoopMediaOrchestrator
- 路径修正:/rooms → /rooms/mine、/invites → /invite-tokens 对齐设计
- DAO 契约修复:GetByID/GetByCode/GetByRoomAndUser/FindActiveByUser
将 gorm.ErrRecordNotFound 转为 (nil, nil),service 统一 nil 判定
- 安全强化:密码 bcrypt + 5 次错误锁 10 分钟;邀请 token 仅通过
NotifyPusher.Extra 定向下发,响应不回传
- host 自动转让:host 离会时将最早加入者提升为 host
- 单点参会:用户同一时间仅能在一个活跃会议
- API 文档:docs/api/frontend/meeting.md 重写为 12 接口完整规范
- Wire 依赖注入:MediaOrchestrator + NoopMediaOrchestrator provider
验证:
- go build / go vet / wire 零告警
- 端到端 3 用户场景:12 happy path + 5 错误路径 PASS=19 / FAIL=0
覆盖密码错/房间不存在/单点冲突/越权/邀请失效
文档同步:
- docs/progress/CURRENT_STATUS.md 增补 Task 5 章节
- .cursor/rules/project-context.mdc 更新阶段状态
- docs/plans/2026-04-21-phase2e-2-implementation.plan.md 标记 T5 ✅
下一步:Task 6(WS 信令协议 + BroadcastToMeeting 替换 PublishToUser 循环)
Made-with: Cursor
34 lines
1.2 KiB
Go
34 lines
1.2 KiB
Go
// Package meeting 会议模块(Phase 2e-2)
|
||
package meeting
|
||
|
||
import (
|
||
"github.com/echochat/backend/app/meeting/controller"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// RegisterRoutes 注册 meeting 模块的全部前台路由
|
||
// 所有接口统一挂载在 /api/v1/meeting/* 前缀下,均需 JWT 认证
|
||
// 设计文档 §6.2 的 12 个接口 Task 4 骨架阶段仅搭路由层,业务实现留待 Task 5/6/7
|
||
func RegisterRoutes(r *gin.Engine, ctrl *controller.MeetingController, jwtAuth gin.HandlerFunc) {
|
||
authed := r.Group("/api/v1/meeting")
|
||
authed.Use(jwtAuth)
|
||
{
|
||
// 会议房间生命周期
|
||
authed.POST("/rooms", ctrl.CreateRoom)
|
||
authed.GET("/rooms/mine", ctrl.ListMyMeetings)
|
||
authed.GET("/rooms/:code", ctrl.GetRoom)
|
||
authed.POST("/rooms/:code/join", ctrl.JoinRoom)
|
||
authed.POST("/rooms/:code/leave", ctrl.LeaveRoom)
|
||
authed.POST("/rooms/:code/end", ctrl.EndRoom)
|
||
|
||
authed.POST("/rooms/:code/transfer-host", ctrl.TransferHost)
|
||
authed.POST("/rooms/:code/kick", ctrl.KickMember)
|
||
|
||
authed.POST("/rooms/:code/invite", ctrl.InviteUsers)
|
||
authed.POST("/invite-tokens/:token/redeem", ctrl.RedeemInvite)
|
||
|
||
authed.POST("/rooms/:code/chats", ctrl.SendChat)
|
||
authed.GET("/rooms/:code/chats", ctrl.ListChats)
|
||
}
|
||
}
|