fix(education): align capability and catalog boundaries

This commit is contained in:
2026-07-31 16:26:39 +08:00
parent 4573c41c0e
commit 184452404d
3 changed files with 24 additions and 6 deletions

View File

@@ -41,7 +41,8 @@ public class EducationCapabilityController {
"answer-save", "session-submit", "practice-report", "vocabulary-review",
"exam-reminder", "learning-award", "student-feedback", "learning-summary",
"tenant-leaderboard", "content-import-assets", "content-import-jobs",
"content-export-policy"))
"content-export-policy", "class-management", "class-invitations",
"education-entitlements", "resource-product-bindings"))
.themes(describeThemes())
.catalogReadEnabled(educationProperties.isCatalogReadEnabled())
.practiceWriteEnabled(educationProperties.isPracticeWriteEnabled())
@@ -58,14 +59,16 @@ public class EducationCapabilityController {
List.of("education", "infra"),
List.of("production-scanner-adapter", "production-import-parser", "export-artifact-generation"),
List.of(), "FEATURE_FLAG", "POSTGRESQL_INTEGRATION_TESTED"),
theme("EDU-012", "classes-relationships", "BLOCKED",
theme("EDU-012", "classes-relationships", "BOUNDED_IMPLEMENTED",
List.of("education", "member", "system"),
List.of("relationship-role-model", "class-data-scope", "invitation-contract"),
List.of(), "FEATURE_FLAG", "CONTRACT_ONLY"),
List.of("teacher-role-expansion", "platform-admin-cross-tenant-operations"),
List.of(), "FEATURE_FLAG", "POSTGRESQL_INTEGRATION_TESTED",
List.of("/admin-api/education/classes", "/app-api/education/class-invitations")),
theme("EDU-013", "commercialization", "BOUNDED_IMPLEMENTED",
List.of("education", "mall", "pay"),
List.of("education", "mall", "pay", "member", "crm"),
List.of("mall-order-item-public-event", "pay-refund-public-event", "crm-referral-contract"),
List.of(), "ACCESS_FAIL_CLOSED", "POSTGRESQL_INTEGRATION_TESTED"),
List.of(), "ACCESS_FAIL_CLOSED", "POSTGRESQL_INTEGRATION_TESTED",
List.of("/admin-api/education/commercialization", "EducationEntitlementApi")),
theme("EDU-014", "extended-learning", "PARTIAL",
List.of("education", "member", "system"),
List.of("video-entitlement-contract", "ai-recommendation-contract", "legacy-data-import"),

View File

@@ -57,6 +57,9 @@ public class QuestionCatalogServiceImpl implements QuestionCatalogService {
int pageNo = reqVO.getPageNo() != null ? reqVO.getPageNo() : 1;
int pageSize = reqVO.getPageSize() != null ? reqVO.getPageSize() : 20;
if (reqVO.getCollectionId() != null && !reqVO.getCollectionId().isBlank()) {
assertCollectionAccess(reqVO.getCollectionId());
}
CatalogQuestionPageResult pageResult = provider.listQuestions(
reqVO.getCollectionId(), reqVO.getNodeId(),
reqVO.getType(), reqVO.getDifficulty(),
@@ -127,6 +130,9 @@ public class QuestionCatalogServiceImpl implements QuestionCatalogService {
}
int requestedCount = reqVO.getQuestionCount() != null ? reqVO.getQuestionCount() : 10;
if (reqVO.getCollectionId() != null && !reqVO.getCollectionId().isBlank()) {
assertCollectionAccess(reqVO.getCollectionId());
}
CatalogPracticeBlueprintDTO blueprint = provider.getPracticeBlueprint(
reqVO.getCollectionId(), reqVO.getNodeId(),
reqVO.getType(), reqVO.getDifficulty());

View File

@@ -52,12 +52,21 @@ public class EducationCapabilityControllerTest {
assertEquals("1.0.0-test", data.getVersion(), "版本应匹配");
assertNotNull(data.getCapabilities(), "能力列表不应为空");
assertTrue(data.getCapabilities().contains("shell"), "应包含 shell 能力");
assertTrue(data.getCapabilities().containsAll(List.of("class-management", "class-invitations",
"education-entitlements", "resource-product-bindings")), "能力清单应包含已交付的 EDU-012/013 接口");
assertNotNull(data.getThemes(), "迁移主题不应为空");
assertEquals(5, data.getThemes().size(), "应完整列出 EDU-011 至 EDU-015");
assertEquals(5, data.getThemes().stream().map(EducationThemeRespVO::getKey).distinct().count(),
"迁移主题不应重复");
assertTrue(data.getThemes().stream().noneMatch(theme -> "AVAILABLE".equals(theme.getStatus())),
"未交付主题不得声明为可用");
EducationThemeRespVO classes = data.getThemes().stream()
.filter(theme -> "EDU-012".equals(theme.getKey())).findFirst().orElseThrow();
assertEquals("BOUNDED_IMPLEMENTED", classes.getStatus(), "EDU-012 已交付的有界能力不得继续标为阻塞");
assertTrue(classes.getExecutableInterfaces().contains("/admin-api/education/classes"));
EducationThemeRespVO commercialization = data.getThemes().stream()
.filter(theme -> "EDU-013".equals(theme.getKey())).findFirst().orElseThrow();
assertTrue(commercialization.getExecutableInterfaces().contains("EducationEntitlementApi"));
EducationThemeRespVO operations = data.getThemes().stream()
.filter(theme -> "EDU-015".equals(theme.getKey())).findFirst().orElseThrow();
assertEquals("LEGACY_DEPENDENT", operations.getStatus(), "默认 Scalar 模式必须披露遗留依赖");