feat: P2-15 cron-based DingTalk/WeCom sync with logging and incremental sync
- Add @nestjs/schedule dependency
- Create SyncLog entity (platform, syncType, status, recordsCount, errorMessage, timestamps)
- Create SyncState entity for tracking lastSyncAt per platform
- SyncService with @Cron('0 2 * * *') daily scheduled sync
- Incremental sync: tracks last_sync_at per platform, passes to integration APIs
- Full/incremental mode determined by existence of prior sync
- SyncController: POST /sync/trigger (manual), GET /sync/logs (history)
- Register SyncModule in AppModule with ScheduleModule
This commit is contained in:
@@ -20,3 +20,5 @@ export { ClassTeacher, TeacherRoleType } from './class-teacher.entity';
|
||||
export { ClassSchedule, ScheduleType } from './class-schedule.entity';
|
||||
export { AttendanceRecord } from './attendance-record.entity';
|
||||
export { DingAttendanceRaw } from './ding-attendance-raw.entity';
|
||||
export { SyncLog } from './sync-log.entity';
|
||||
export { SyncState } from './sync-state.entity';
|
||||
|
||||
35
apps/server/src/entities/sync-log.entity.ts
Normal file
35
apps/server/src/entities/sync-log.entity.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';
|
||||
|
||||
export type SyncPlatform = 'dingtalk' | 'wecom';
|
||||
export type SyncType = 'full' | 'incremental';
|
||||
export type SyncStatus = 'running' | 'success' | 'failed';
|
||||
|
||||
@Entity('sync_logs')
|
||||
export class SyncLog {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ type: 'varchar', length: 20 })
|
||||
platform: SyncPlatform;
|
||||
|
||||
@Column({ name: 'sync_type', type: 'varchar', length: 20 })
|
||||
syncType: SyncType;
|
||||
|
||||
@Column({ type: 'varchar', length: 20 })
|
||||
status: SyncStatus;
|
||||
|
||||
@Column({ name: 'records_count', type: 'integer', default: 0 })
|
||||
recordsCount: number;
|
||||
|
||||
@Column({ name: 'error_message', type: 'text', nullable: true })
|
||||
errorMessage: string | null;
|
||||
|
||||
@Column({ name: 'started_at', type: 'datetime', nullable: true })
|
||||
startedAt: Date | null;
|
||||
|
||||
@Column({ name: 'finished_at', type: 'datetime', nullable: true })
|
||||
finishedAt: Date | null;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
}
|
||||
11
apps/server/src/entities/sync-state.entity.ts
Normal file
11
apps/server/src/entities/sync-state.entity.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
import type { SyncPlatform } from './sync-log.entity';
|
||||
|
||||
@Entity('sync_state')
|
||||
export class SyncState {
|
||||
@PrimaryColumn({ type: 'varchar', length: 20 })
|
||||
platform: SyncPlatform;
|
||||
|
||||
@Column({ name: 'last_sync_at', type: 'datetime', nullable: true })
|
||||
lastSyncAt: Date | null;
|
||||
}
|
||||
Reference in New Issue
Block a user