Files
Edu/apps/teacher-portal/next.config.js
SpecialX 61d824924a fix: 修复集成测试中发现的全部 bug — 15 服务端到端验证通过
修复涵盖 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(集成测试修复会话)
2026-07-11 01:41:46 +08:00

140 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* teacher-portal Next.js 配置
*
* 角色MF Shell 宿主ARB-002 §2.3
* - exposes: AppShell + GraphQLProvider + 共享 hooks + 共享 UI 组件
* - shared: react/react-dom/urql/graphql/@edu/* 设为 singleton
* - remotes: P2 为空NEXT_PUBLIC_MF_ENABLED=falseP3+ 逐步接入
*
* 维护者ai13teacher-portal
* 关联ARB-002 §2.2 暴露清单、03-long-term-architecture.md §1.3 绞杀者模式
*/
/** @type {import('next').NextConfig} */
// NextFederationPlugin 动态 require避免构建时硬依赖MF 2.0 在 Next 14 App Router 下按需加载)
let NextFederationPlugin;
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
NextFederationPlugin = require("@module-federation/nextjs-mf").NextFederationPlugin;
} catch {
// 依赖未安装时跳过 MF 配置(如纯 typecheck 环境)
NextFederationPlugin = null;
}
/**
* 构建 Remote 列表P2 为空P3+ 按 NEXT_PUBLIC_MF_ENABLED 启用)
*
* ARB-002 §2.3P2 Remote 数量 = 0NEXT_PUBLIC_MF_ENABLED=false 默认关
* P3 首个 Remotestudent-portal总裁 §1.3 step 4
*/
function buildRemotes(isServer) {
if (process.env.NEXT_PUBLIC_MF_ENABLED !== "true") return {};
const chunkPath = isServer ? "ssr" : "chunks";
return {
student: `student_app@http://localhost:4001/_next/static/${chunkPath}/remoteEntry.js`,
parent: `parent_app@http://localhost:4002/_next/static/${chunkPath}/remoteEntry.js`,
admin: `admin_app@http://localhost:4003/_next/static/${chunkPath}/remoteEntry.js`,
};
}
/**
* ARB-002 §2.2 MF Shell 暴露清单
*/
function buildExposes() {
return {
// 1. AppShell布局 + 导航 + 认证守卫)
"./AppShell": "./src/components/AppShell.tsx",
// 2. GraphQLProviderurql client 单例,总裁 §2.17 方案 A
"./GraphQLProvider": "./src/app/providers.tsx",
// 3. 共享 hooks
"./useAuth": "./packages/hooks/src/use-auth.ts",
"./usePermission": "./packages/hooks/src/use-permission.ts",
"./useGraphQLClient": "./packages/hooks/src/use-graphql-client.ts",
// 4. 共享 UI 组件
"./ErrorBoundary": "./packages/ui-components/src/error-boundary.tsx",
"./Loading": "./packages/ui-components/src/loading.tsx",
"./Empty": "./packages/ui-components/src/empty.tsx",
"./RequirePermission": "./packages/ui-components/src/require-permission.tsx",
};
}
/**
* ARB-002 §2.2 MF shared singleton 配置
* 避免 Remote 多实例 + 缓存不一致
*/
function buildShared() {
return {
react: { singleton: true, requiredVersion: "^18.3.0" },
"react-dom": { singleton: true, requiredVersion: "^18.3.0" },
urql: { singleton: true, requiredVersion: "^2.2.0" },
graphql: { singleton: true, requiredVersion: "^16.8.0" },
"@edu/ui-tokens": { singleton: true },
"@edu/ui-components": { singleton: true },
"@edu/hooks": { singleton: true },
};
}
const nextConfig = {
reactStrictMode: true,
// ESM 模式transpilePackages 对齐 NestJS ESM 规范
// @edu/hooks 等包使用 .js 后缀导入源码,需 transpile + extensionAlias
transpilePackages: [
"@edu/ui-components",
"@edu/ui-tokens",
"@edu/hooks",
"@edu/contracts",
"@edu/shared-ts",
],
// ARB-002MF Shell 配置exposes + sharedP2 无 remotes
// 仅当 NEXT_PUBLIC_MF_ENABLED=true 时实例化 NextFederationPlugin
// nextjs-mf 不支持 App DirectoryP2 阶段 MF 未启用时跳过避免报错)
webpack(config, { isServer }) {
// ESM 包使用 .js 后缀导入源码TS 文件),需映射 .js → .ts
config.resolve = config.resolve || {};
config.resolve.extensionAlias = {
...config.resolve.extensionAlias,
".js": [".ts", ".tsx", ".js"],
};
if (
NextFederationPlugin &&
process.env.NEXT_PUBLIC_MF_ENABLED === "true"
) {
config.plugins.push(
new NextFederationPlugin({
name: "teacher_app",
filename: "static/chunks/remoteEntry.js",
remotes: buildRemotes(isServer),
exposes: buildExposes(),
shared: buildShared(),
extraOptions: {
exposePages: false,
},
}),
);
}
return config;
},
// 反向代理:/api/v1/* → api-gateway :8080
async rewrites() {
const gateway = process.env.API_GATEWAY_URL || "http://localhost:8080";
return [
{
source: "/api/v1/:path*",
destination: `${gateway}/api/v1/:path*`,
},
{
// 登录端点(非 GraphQL认证前提F12: JWT 存 localStorage
source: "/api/auth/:path*",
destination: `${gateway}/api/auth/:path*`,
},
];
},
};
module.exports = nextConfig;