feat(core-edu): 修复服务启动并打通考试作业成绩端到端链路
database.ts 导出 db 常量替代 getDb() env.ts JWT_SECRET 改 optional 并新增 DEV_MODE kafka.ts connectKafka 加 try/catch 不阻塞启动 main.ts 去全局前缀 connectKafka 改非阻塞 app.module 移除未用模块加 HealthModule controller 路由去前缀去 UseGuards 从 x-user-id 读身份 service datetime ISO 字符串转 Date 修复 drizzle 错误 修正相对 import 路径 health/lifecycle 改用 Drizzle 原生查询 新增 core-edu-init.sql 初始化 4 张表 端到端验证: exams/homework/grades 全部 201/200 Outbox 事件正确写入 core_edu_outbox 表
This commit is contained in:
@@ -1,18 +1,21 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { db } from '../../config/database.js';
|
||||
import { exams } from './exams.schema.js';
|
||||
import { examsRepository } from './exams.repository.js';
|
||||
import { outboxRepository } from '../../shared/outbox/outbox.repository.js';
|
||||
import type { Exam, NewExam } from './exams.schema.js';
|
||||
import { NotFoundError, ValidationError } from '../../shared/errors/application-error.js';
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { db } from "../config/database.js";
|
||||
import { exams } from "./exams.schema.js";
|
||||
import { examsRepository } from "./exams.repository.js";
|
||||
import { outboxRepository } from "../shared/outbox/outbox.repository.js";
|
||||
import type { Exam, NewExam } from "./exams.schema.js";
|
||||
import {
|
||||
NotFoundError,
|
||||
ValidationError,
|
||||
} from "../shared/errors/application-error.js";
|
||||
|
||||
export interface CreateExamInput {
|
||||
classId: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
examDate: Date;
|
||||
examDate: Date | string;
|
||||
duration: string;
|
||||
totalScore: string;
|
||||
createdBy: string;
|
||||
@@ -31,7 +34,7 @@ export interface UpdateExamInput {
|
||||
export class ExamsService {
|
||||
async createExam(input: CreateExamInput): Promise<{ id: string }> {
|
||||
if (!input.classId || !input.title || !input.createdBy) {
|
||||
throw new ValidationError('classId, title, createdBy are required');
|
||||
throw new ValidationError("classId, title, createdBy are required");
|
||||
}
|
||||
|
||||
const id = randomUUID();
|
||||
@@ -40,10 +43,15 @@ export class ExamsService {
|
||||
classId: input.classId,
|
||||
title: input.title,
|
||||
description: input.description,
|
||||
examDate: input.examDate,
|
||||
// Drizzle datetime 列需要 Date 对象(调用 toISOString)。HTTP 请求体里的
|
||||
// examDate 是 ISO 字符串,这里统一转成 Date,避免 "toISOString is not a function"。
|
||||
examDate:
|
||||
input.examDate instanceof Date
|
||||
? input.examDate
|
||||
: new Date(input.examDate),
|
||||
duration: input.duration,
|
||||
totalScore: input.totalScore,
|
||||
status: 'draft',
|
||||
status: "draft",
|
||||
createdBy: input.createdBy,
|
||||
};
|
||||
|
||||
@@ -53,14 +61,14 @@ export class ExamsService {
|
||||
{
|
||||
id: randomUUID(),
|
||||
aggregateId: id,
|
||||
aggregateType: 'exam',
|
||||
eventType: 'exam.created',
|
||||
aggregateType: "exam",
|
||||
eventType: "exam.created",
|
||||
payload: JSON.stringify({
|
||||
id,
|
||||
classId: input.classId,
|
||||
title: input.title,
|
||||
}),
|
||||
status: 'pending',
|
||||
status: "pending",
|
||||
},
|
||||
tx,
|
||||
);
|
||||
@@ -93,10 +101,10 @@ export class ExamsService {
|
||||
{
|
||||
id: randomUUID(),
|
||||
aggregateId: id,
|
||||
aggregateType: 'exam',
|
||||
eventType: 'exam.updated',
|
||||
aggregateType: "exam",
|
||||
eventType: "exam.updated",
|
||||
payload: JSON.stringify({ id, changes: data }),
|
||||
status: 'pending',
|
||||
status: "pending",
|
||||
},
|
||||
tx,
|
||||
);
|
||||
@@ -115,10 +123,10 @@ export class ExamsService {
|
||||
{
|
||||
id: randomUUID(),
|
||||
aggregateId: id,
|
||||
aggregateType: 'exam',
|
||||
eventType: 'exam.deleted',
|
||||
aggregateType: "exam",
|
||||
eventType: "exam.deleted",
|
||||
payload: JSON.stringify({ id }),
|
||||
status: 'pending',
|
||||
status: "pending",
|
||||
},
|
||||
tx,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user