修复涵盖 6 大类问题: 1. api-gateway - 路径前缀剥离 /api 而非 /api/v1,保留下游 /v1/ controller 前缀 - JWKS URL 默认值修复 - publicPaths 白名单对齐 /v1/iam/* 2. iam - iam.module.ts exports 补充 PermissionCacheService 和 IamRepository - main.ts resolveProtoPath() 多路径探测 proto 文件 3. core-edu - app.module.ts AuthMiddleware 全局注册 4. BFF 层 GraphQL 端点(teacher-bff / parent-bff / student-bff) - teacher-bff: mock dataScope OWN→SELF 对齐 GraphQL enum;WHATWG Request header .get() 提取 - parent-bff: handleNodeRequestAndResponse 不存在 → 直接 yoga(req,res);WHATWG Request header .get() 提取 - student-bff: auth.resolver 移除 ActionState 信封返回扁平对象;WHATWG Request header .get() 提取 5. ai - Kafka 事务降级 + 10s 超时 - gRPC 拦截器降级 - dev mode 禁用事务模式 6. 前端 + 共享包 - teacher-portal: MF 插件条件实例化 + transpilePackages + extensionAlias - ui-components: error-boundary.tsx 添加 use client - ui-tokens: tailwind-theme.css 移除 @layer base - shared-ts: 导出从源码改为 dist 编译产物;OutboxModule global:true 7. infra - .gitignore 补充 keys/ *.pem *.key secrets/ 排除规则 - infra/init-sql/02-all-services-schema.sql 36 张表 DDL 验证结果: - TS typecheck: 19 个 workspace 项目全部通过 - Go vet + Ruff: 通过 - 15 服务全部启动成功 - 3 个 BFF GraphQL 端点 + 4 个前端页面全部 200 - Gateway → iam → core-edu 端到端链路验证通过 AI identity: trae-main(集成测试修复会话)
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { Module, type DynamicModule } from "@nestjs/common";
|
||
import pino from "pino";
|
||
import { OutboxService } from "./outbox.service.js";
|
||
import { OutboxPublisher } from "./publisher.js";
|
||
import { createOutboxTable } from "./schema.js";
|
||
import {
|
||
OUTBOX_CONFIG,
|
||
OUTBOX_DB,
|
||
OUTBOX_KAFKA_PRODUCER,
|
||
OUTBOX_LOGGER,
|
||
OUTBOX_TABLE,
|
||
type OutboxConfig,
|
||
type OutboxDbClient,
|
||
type OutboxKafkaProducer,
|
||
type OutboxLogger,
|
||
} from "./types.js";
|
||
|
||
/**
|
||
* forRoot 选项。
|
||
*
|
||
* `config` 即 OutboxConfig(表名 / topic / 轮询参数)。
|
||
* `db` / `kafkaProducer` / `logger` 为基础设施实例:NestJS DynamicModule
|
||
* 无法跨模块边界注入宿主已存在的具体单例,故统一通过 forRoot 注入。
|
||
*
|
||
* `kafkaProducer` 应由调用方以 idempotent 方式创建:
|
||
* `kafka.producer({ idempotent: true, transactionalId: '<service>-tx' })`。
|
||
*/
|
||
export interface OutboxRootOptions {
|
||
config: OutboxConfig;
|
||
db: OutboxDbClient;
|
||
kafkaProducer: OutboxKafkaProducer;
|
||
/** 可选;省略时使用默认 pino logger(name=outbox) */
|
||
logger?: OutboxLogger;
|
||
}
|
||
|
||
function resolveLogger(logger: OutboxLogger | undefined): OutboxLogger {
|
||
return logger ?? pino({ name: "outbox", level: "info" });
|
||
}
|
||
|
||
/**
|
||
* OutboxModule —— 事务性 Outbox 模式的 NestJS DynamicModule。
|
||
*
|
||
* 注册并启动:
|
||
* - OutboxService:业务代码注入后调用 `publish` 写入 outbox 记录
|
||
* - OutboxPublisher:onModuleInit 启动轮询,onModuleDestroy 停止轮询
|
||
*
|
||
* 用法:
|
||
* ```ts
|
||
* @Module({
|
||
* imports: [OutboxModule.forRoot({ config, db, kafkaProducer })],
|
||
* })
|
||
* export class AppModule {}
|
||
* ```
|
||
*/
|
||
@Module({})
|
||
export class OutboxModule {
|
||
static forRoot(options: OutboxRootOptions): DynamicModule {
|
||
const table = createOutboxTable(options.config.tableName);
|
||
const logger = resolveLogger(options.logger);
|
||
|
||
return {
|
||
module: OutboxModule,
|
||
global: true,
|
||
providers: [
|
||
{ provide: OUTBOX_CONFIG, useValue: options.config },
|
||
{ provide: OUTBOX_DB, useValue: options.db },
|
||
{ provide: OUTBOX_TABLE, useValue: table },
|
||
{ provide: OUTBOX_KAFKA_PRODUCER, useValue: options.kafkaProducer },
|
||
{ provide: OUTBOX_LOGGER, useValue: logger },
|
||
OutboxService,
|
||
OutboxPublisher,
|
||
],
|
||
exports: [OutboxService],
|
||
};
|
||
}
|
||
}
|