feat(core-edu): 完整实现 core-edu 教学核心服务

包含 classes/exams/homework/grades/attendance/scheduling 域、outbox、iam-consumer、redis 配置等完整实现
This commit is contained in:
SpecialX
2026-07-10 19:08:56 +08:00
parent 06a646ea4e
commit 58c0ba1bd9
55 changed files with 4204 additions and 305 deletions

View File

@@ -1,16 +1,44 @@
import { mysqlTable, varchar, text, timestamp, char, bigint } from 'drizzle-orm/mysql-core';
import {
mysqlTable,
varchar,
text,
timestamp,
char,
bigint,
datetime,
index,
uniqueIndex,
} from "drizzle-orm/mysql-core";
export const outbox = mysqlTable('core_edu_outbox', {
id: char('id', { length: 36 }).notNull().primaryKey(),
aggregateId: char('aggregate_id', { length: 36 }).notNull(),
aggregateType: varchar('aggregate_type', { length: 50 }).notNull(),
eventType: varchar('event_type', { length: 100 }).notNull(),
payload: text('payload').notNull(),
status: varchar('status', { length: 20 }).notNull().default('pending'),
retryCount: bigint('retry_count', { mode: 'number' }).notNull().default(0),
createdAt: timestamp('created_at').notNull().defaultNow(),
processedAt: timestamp('processed_at'),
});
// 事务性发件箱Outbox 模式)
export const outbox = mysqlTable(
"core_edu_outbox",
{
id: char("id", { length: 36 }).notNull().primaryKey(),
eventId: char("event_id", { length: 36 }).notNull(),
aggregateId: char("aggregate_id", { length: 36 }).notNull(),
aggregateType: varchar("aggregate_type", { length: 50 }).notNull(),
eventType: varchar("event_type", { length: 100 }).notNull(),
occurredAt: datetime("occurred_at").notNull(),
payload: text("payload").notNull(),
status: varchar("status", { length: 20 }).notNull().default("pending"),
retryCount: bigint("retry_count", { mode: "number" }).notNull().default(0),
nextRetryAt: datetime("next_retry_at"),
createdAt: timestamp("created_at").notNull().defaultNow(),
processedAt: timestamp("processed_at"),
},
(table) => ({
uniqEventId: uniqueIndex("uniq_event_id").on(table.eventId),
idxOutboxStatusRetry: index("idx_outbox_status_retry").on(
table.status,
table.nextRetryAt,
),
idxOutboxAggregate: index("idx_outbox_aggregate").on(
table.aggregateType,
table.aggregateId,
),
}),
);
export type OutboxMessage = typeof outbox.$inferSelect;
export type NewOutboxMessage = typeof outbox.$inferInsert;