API-INFO-009 P0 | 实现批量上报阅读事件接口 【status:todo】 #109

Closed
opened 2026-06-07 11:03:38 +08:00 by wangdl · 2 comments
Owner

目标

POST /learning/reading-events/batch

规则

  • 单批最多 100 条
  • 批次整体不使用大事务,每条独立处理
  • 单条事件内:入库+聚合在同一 transaction
  • 上报接口不返回 latestProgress
  • materialId 不存在时 failed

详见设计文档 API-INFO-000。

## 目标 ```http POST /learning/reading-events/batch ``` ### 规则 - 单批最多 100 条 - 批次整体不使用大事务,每条独立处理 - 单条事件内:入库+聚合在同一 transaction - 上报接口不返回 latestProgress - materialId 不存在时 failed 详见设计文档 API-INFO-000。
wangdl added this to the M8:学习信息收集与基础分析闭环 milestone 2026-06-07 11:03:38 +08:00
wangdl changed title from API-INFO-004 P0 | 实现批量上报阅读事件接口 to API-INFO-009 P0 | 实现批量上报阅读事件接口 2026-06-07 11:22:15 +08:00
wangdl changed title from API-INFO-009 P0 | 实现批量上报阅读事件接口 to API-INFO-009 P0 | 实现批量上报阅读事件接口 【status:todo】 2026-06-07 19:04:12 +08:00
Author
Owner

审查结论:当前 API 项目学习信息收集体系基本为全新建设。可复用:JWT Guard、LearningSession 基础表/CRUD、DailyLearningActivity 基础表、ActivityController 部分接口、LearningRecord schema。其余 ReadingEvent/TemporaryMaterial/Progress/批量上报/Processor/聚合/查询接口/错误码/去重/权限/测试/文档均不存在或仅部分存在。

本 Issue: 接口不存在。依赖 schema。blocked-by:schema

标签: audit:reviewed audit:api-info status:todo work:api,work:new-module

## 审查结论:当前 API 项目学习信息收集体系基本为全新建设。可复用:JWT Guard、LearningSession 基础表/CRUD、DailyLearningActivity 基础表、ActivityController 部分接口、LearningRecord schema。其余 ReadingEvent/TemporaryMaterial/Progress/批量上报/Processor/聚合/查询接口/错误码/去重/权限/测试/文档均不存在或仅部分存在。 **本 Issue**: 接口不存在。依赖 schema。blocked-by:schema **标签**: audit:reviewed audit:api-info status:todo work:api,work:new-module
Author
Owner

完成报告

交付

1. Controllerreading-event.controller.ts:

POST /learning/reading-events/batch
@UseGuards(JwtAuthGuard)

async uploadBatch(req, body: BatchUploadReadingEventsDto) {
  // JWT → userId
  // 批次上限 100 条
  // 委托给 service.processBatch(userId, events)
  // 返回 { processed, duplicate, failed, warnings }
}

2. DTOreading-event.dto.ts:

class ReadingEventUploadItemDto {
  eventId: string;              // @IsString
  clientSessionId: string;      // @IsString
  materialId: string;           // @IsString
  readingTargetType: string;    // @IsString
  eventType: string;            // @IsString
  position?: any;               // @IsOptional
  activeSecondsDelta: number;   // @IsInt @Min(0) @Max(300)
  clientTimestampMs: number;    // @IsInt
  sequence: number;             // @IsInt
  platform: string;             // @IsString
  appVersion?: string;          // @IsOptional
  clientTimezoneOffsetMinutes?: number; // @IsOptional @IsInt
}
class BatchUploadReadingEventsDto {
  events: ReadingEventUploadItemDto[];  // @ValidateNested
}

3. Servicereading-event.service.ts 新增 processBatch():

  • 基础校验:eventId/clientSessionId 必填、activeSecondsDelta >= 0
  • delta > 300 自动截断
  • upsert 去重(userId+eventId unique)
  • 逐条独立处理(无大事务)
  • 错误不中断批次
  • 返回 { processed, duplicate, failed, warnings[] }

代码证据

// POST /learning/reading-events/batch
// Request: { events: ReadingEventUploadItemDto[] }
// Response: { processed: number, duplicate: number, failed: number, warnings: Array<{ eventId?, code, message }> }
// Batch limit: 100
// Delta cap: 300 (truncated, not rejected)
## 完成报告 ### 交付 **1. Controller** — `reading-event.controller.ts`: ```typescript POST /learning/reading-events/batch @UseGuards(JwtAuthGuard) async uploadBatch(req, body: BatchUploadReadingEventsDto) { // JWT → userId // 批次上限 100 条 // 委托给 service.processBatch(userId, events) // 返回 { processed, duplicate, failed, warnings } } ``` **2. DTO** — `reading-event.dto.ts`: ```typescript class ReadingEventUploadItemDto { eventId: string; // @IsString clientSessionId: string; // @IsString materialId: string; // @IsString readingTargetType: string; // @IsString eventType: string; // @IsString position?: any; // @IsOptional activeSecondsDelta: number; // @IsInt @Min(0) @Max(300) clientTimestampMs: number; // @IsInt sequence: number; // @IsInt platform: string; // @IsString appVersion?: string; // @IsOptional clientTimezoneOffsetMinutes?: number; // @IsOptional @IsInt } class BatchUploadReadingEventsDto { events: ReadingEventUploadItemDto[]; // @ValidateNested } ``` **3. Service** — `reading-event.service.ts` 新增 `processBatch()`: - 基础校验:eventId/clientSessionId 必填、activeSecondsDelta >= 0 - delta > 300 自动截断 - upsert 去重(userId+eventId unique) - 逐条独立处理(无大事务) - 错误不中断批次 - 返回 { processed, duplicate, failed, warnings[] } ### 代码证据 ```typescript // POST /learning/reading-events/batch // Request: { events: ReadingEventUploadItemDto[] } // Response: { processed: number, duplicate: number, failed: number, warnings: Array<{ eventId?, code, message }> } // Batch limit: 100 // Delta cap: 300 (truncated, not rejected) ```
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/api-server#109
No description provided.