syntax = "v1" // ================================================================= // Type: 通知事件 (Notification Event) // ================================================================= type ( // CreateEventReq 創建通知事件請求 CreateEventReq { Authorization EventType string `json:"event_type" validate:"required"` // POST_PUBLISHED, COMMENT_ADDED, MENTIONED 等 ActorUID string `json:"actor_uid" validate:"required"` // 觸發者 UID ObjectType string `json:"object_type" validate:"required"` // POST, COMMENT, USER 等 ObjectID string `json:"object_id" validate:"required"` // 對應物件 ID Title string `json:"title" validate:"required"` // 顯示用標題 Body string `json:"body" validate:"required"` // 顯示用內容/摘要 Payload string `json:"payload,optional"` // JSON string(額外欄位) Priority string `json:"priority,optional" validate:"omitempty,oneof=critical high normal low"` // 優先級,預設 normal } // EventResp 通知事件回應 EventResp { EventID string `json:"event_id"` EventType string `json:"event_type"` ActorUID string `json:"actor_uid"` ObjectType string `json:"object_type"` ObjectID string `json:"object_id"` Title string `json:"title"` Body string `json:"body"` Payload string `json:"payload"` Priority string `json:"priority"` CreatedAt string `json:"created_at"` } // ListEventsReq 查詢事件列表請求 ListEventsReq { Authorization ObjectID string `json:"object_id,optional"` // 物件 ID 篩選 ObjectType string `json:"object_type,optional"` // 物件類型篩選 Limit int `json:"limit,optional" validate:"omitempty,min=1,max=100"` // 限制數量,預設 20 } // ListEventsResp 事件列表回應 ListEventsResp { Events []EventResp `json:"events"` Total int64 `json:"total,optional"` } ) // ================================================================= // Type: 用戶通知 (User Notification) // ================================================================= type ( // CreateUserNotificationReq 創建用戶通知請求 CreateUserNotificationReq { Authorization UserID string `json:"user_id" validate:"required"` // 收通知的人 EventID string `json:"event_id" validate:"required"` // 對應 notification_event.event_id TTL int `json:"ttl,optional"` // 過期時間(秒),預設 30 天 } // BulkCreateNotificationsReq 批量創建通知請求 BulkCreateNotificationsReq { Authorization UserIDs []string `json:"user_ids" validate:"required,min=1,max=100"` // 用戶 UID 列表 EventID string `json:"event_id" validate:"required"` // 對應 notification_event.event_id TTL int `json:"ttl,optional"` // 過期時間(秒),預設 30 天 } // ListNotificationsReq 查詢通知列表請求 ListNotificationsReq { Authorization Buckets []string `json:"buckets,optional"` // 分桶列表,例如 ["2025-11", "2025-10"],不提供則使用最近 3 個月 Limit int `json:"limit,optional" validate:"omitempty,min=1,max=100"` // 限制數量,預設 20 } // NotificationResp 用戶通知回應 NotificationResp { UserID string `json:"user_id"` Bucket string `json:"bucket"` // 分桶,例如 '2025-11' 或 '2025-11-17' TS string `json:"ts"` // 通知時間,排序用(UTC0) EventID string `json:"event_id"` // 對應 notification_event.event_id Status string `json:"status"` // UNREAD / READ / ARCHIVED ReadAt *string `json:"read_at,omitempty"` // 已讀時間(非必填) Event EventResp `json:"event,omitempty"` // 關聯的事件資訊(可選) } // ListNotificationsResp 通知列表回應 ListNotificationsResp { Notifications []NotificationResp `json:"notifications"` Total int64 `json:"total,optional"` UnreadCount int64 `json:"unread_count"` // 未讀數量 } // MarkAsReadReq 標記已讀請求 MarkAsReadReq { Authorization Bucket string `json:"bucket" validate:"required"` // 分桶,例如 '2025-11-17' TS string `json:"ts" validate:"required"` // 通知時間戳 } // MarkAllAsReadReq 標記全部已讀請求 MarkAllAsReadReq { Authorization Buckets []string `json:"buckets,optional"` // 分桶列表,不提供則標記所有 } // CountUnreadResp 未讀數量回應 CountUnreadResp { Count int64 `json:"count"` } ) // ================================================================= // Type: 通知游標 (Notification Cursor) // ================================================================= type ( // UpdateCursorReq 更新游標請求 UpdateCursorReq { Authorization LastSeenTS string `json:"last_seen_ts" validate:"required"` // 最後看到的時間戳 } // CursorResp 游標回應 CursorResp { UID string `json:"uid"` LastSeenTS string `json:"last_seen_ts"` UpdatedAt string `json:"updated_at"` } ) // ================================================================= // Service: 通知 API - 需要登入 (Notification Service) // ================================================================= @server( group: notification prefix: /api/v1/notifications schemes: https timeout: 30s middleware: AuthMiddleware ) service gateway { // ==================== 通知事件 ==================== @doc( summary: "創建通知事件" description: "創建一個新的通知事件,通常由系統內部調用" ) @handler createEvent post /events (CreateEventReq) returns (EventResp) @doc( summary: "取得通知事件" description: "根據 event_id 取得通知事件的詳細資訊" ) @handler getEvent get /events/:event_id (Authorization) returns (EventResp) @doc( summary: "查詢通知事件列表" description: "查詢通知事件列表,支援按物件篩選" ) @handler listEvents get /events (ListEventsReq) returns (ListEventsResp) // ==================== 用戶通知 ==================== @doc( summary: "創建用戶通知" description: "為單個用戶創建通知" ) @handler createUserNotification post /users/:user_id/notifications (CreateUserNotificationReq) returns (NotificationResp) @doc( summary: "批量創建用戶通知" description: "為多個用戶批量創建通知" ) @handler bulkCreateNotifications post /notifications/bulk (BulkCreateNotificationsReq) returns (RespOK) @doc( summary: "查詢用戶通知列表" description: "查詢當前用戶的通知列表,支援按分桶篩選和分頁" ) @handler listNotifications get /me/notifications (ListNotificationsReq) returns (ListNotificationsResp) @doc( summary: "標記通知為已讀" description: "標記單個通知為已讀狀態" ) @handler markAsRead put /me/notifications/:bucket/:ts/read (MarkAsReadReq) returns (RespOK) @doc( summary: "標記所有通知為已讀" description: "標記指定分桶或所有通知為已讀狀態" ) @handler markAllAsRead put /me/notifications/read (MarkAllAsReadReq) returns (RespOK) @doc( summary: "查詢未讀通知數量" description: "查詢當前用戶的未讀通知數量" ) @handler countUnread get /me/notifications/unread/count (Authorization) returns (CountUnreadResp) // ==================== 通知游標 ==================== @doc( summary: "取得通知游標" description: "取得當前用戶的通知游標資訊" ) @handler getCursor get /me/notifications/cursor (Authorization) returns (CursorResp) @doc( summary: "更新通知游標" description: "更新當前用戶的通知游標,用於追蹤最後查看的通知位置" ) @handler updateCursor put /me/notifications/cursor (UpdateCursorReq) returns (CursorResp) }