PRD:恭学教育学生核心学习闭环 #1

Closed
opened 2026-07-27 07:43:37 +00:00 by wangziqi · 1 comment
Owner

恭学教育学生核心学习闭环 PRD

Problem Statement

当前恭学教育系统基于 RuoYi-Vue-Pro,已经具备成熟的租户、后台用户、会员、鉴权、支付、文件、短信、邮件、站内信、权限、字典、定时任务和审计基础设施,但仓库内尚无生产级教育/题库/学习模块,完整前端源码也尚未纳入当前工作区。

另一个已经运行的 Scalar API 提供了题库、练习、资料、视频、会员和运营等大量教育接口;用户同时提供了学生学习中心、租户运营后台、平台管理后台的功能原型和效果图。若前端直接接入 Scalar,或在 RuoYi 中再次独立实现身份、会员、支付等基础能力,会形成双鉴权、双租户、双订单和双数据源,造成权限不一致、数据难迁移、跨租户风险以及长期维护成本。

用户首先需要一个能够真实上线和验证的学生学习核心闭环:学生在正确租户下使用现有账号登录,浏览题库,创建练习,稳定保存答案,提交试卷,查看报告,并继续使用错题本和收藏夹。该闭环需要以 RuoYi 为统一入口和最终数据权威,同时允许尚未迁移的只读题库内容暂时经后端适配层来自 Scalar。实现还必须为后续会员支付、私有资料、视频、租户运营后台和平台治理留出清晰边界,但不能让这些后续范围阻塞第一阶段交付。

Solution

在 RuoYi-Vue-Pro 中新增独立的 Education 业务模块,以 RuoYi 作为所有前端请求、身份、租户、个人学习数据和未来支付权益的统一边界。学生 Web/H5 和 Vue 3 管理后台只能调用 RuoYi API,不得直接访问 Scalar。

第一阶段交付以下纵向学习闭环:

  1. 根据访问域名或受控租户参数识别租户。
  2. 复用现有 Member 登录、短信登录、令牌刷新和退出能力。
  3. 通过 Education 内部目录/题目接口读取题库;尚未迁移的数据由服务器端 Scalar 防腐适配层转换。
  4. 在 RuoYi/MySQL 中创建归属于当前学生和租户的练习会话,并固定题目顺序与版本。
  5. 使用幂等键、客户端序号和服务端版本安全地自动保存答案,支持刷新、断网和请求重试恢复。
  6. 以原子状态转换提交试卷,保存稳定的评分结果和历史快照。
  7. 生成练习报告、错题记录、收藏和基础学习进度。
  8. 通过一个最高层的学生核心闭环 E2E 接缝验收整体行为,并使用较低层测试补足租户隔离、所有权、幂等、并发和 Scalar 契约等不可完全由单条 E2E 覆盖的风险。

后续阶段在同一模块边界内扩展个人中心、词汇、手册、分数线、AI 推荐、资料、视频、会员支付、权益、租户运营和平台治理,并逐项把 Scalar 内容迁移到 Java/MySQL。

User Stories

  1. As a student, I want the application to identify the correct school or tenant from my entry point, so that I enter the right branded learning environment.
  2. As a student, I want a clear error when no valid tenant can be resolved, so that I do not accidentally sign in to the wrong organization.
  3. As a student, I want to be blocked when a tenant is disabled, so that the platform does not expose inactive tenant data.
  4. As a student, I want to sign in with my existing mobile number and password, so that I do not need a separate education account.
  5. As a student, I want to sign in with an SMS verification code, so that I can recover access without remembering a password.
  6. As a student, I want supported social or WeChat login methods to keep working, so that education does not replace the platform’s existing authentication options.
  7. As a student, I want my session to refresh securely, so that a long learning session is not lost when an access token expires.
  8. As a student, I want to log out from the education application, so that another person using the device cannot access my learning data.
  9. As a student, I want to return to the page I originally requested after login, so that authentication does not interrupt my intended task.
  10. As a student, I want the application to display my existing nickname and avatar, so that my education profile is consistent with my member account.
  11. As a student, I want the application to preserve the tenant context after login, so that subsequent requests cannot drift into another tenant.
  12. As a student, I want to see a learning home page with a clear entry into the question bank, so that I can start studying quickly.
  13. As a student, I want to resume an unfinished practice session from the learning home page, so that a refresh or temporary interruption does not discard my work.
  14. As a student, I want to browse question banks by subject, category, region, major, or other supported catalog dimensions, so that I can find relevant material.
  15. As a student, I want catalog filters to preserve their selected state while I navigate, so that I can compare and refine content efficiently.
  16. As a student, I want clear loading, empty, unavailable, and permission-denied states in the catalog, so that I understand why content is not displayed.
  17. As a student, I want only published and permitted question banks to appear, so that I do not see draft or unauthorized content.
  18. As a student, I want question counts and practice configuration to be accurate, so that I understand what will be included before starting.
  19. As a student, I want to create a practice session from selected criteria, so that the server prepares a stable set of questions for me.
  20. As a student, I want the question order to remain stable throughout a practice session, so that refreshing does not reorder my work.
  21. As a student, I want historical practice to preserve the version of each question I answered, so that later question edits do not change my old result.
  22. As a student, I want question content to render correctly on desktop and mobile widths, so that I can learn on either device.
  23. As a student, I want formulas and rich question content to render correctly, so that mathematical and technical questions remain understandable.
  24. As a student, I want answer options to be easy to select using touch or mouse, so that answering is efficient and accessible.
  25. As a student, I want to move to the previous or next question, so that I can navigate the practice naturally.
  26. As a student, I want an answer-card overview, so that I can see answered, unanswered, and current questions.
  27. As a student, I want my answer to save automatically, so that I do not lose progress if I leave the page unexpectedly.
  28. As a student, I want to see whether an answer is saving, saved, retrying, or failed, so that I know whether my progress is safe.
  29. As a student, I want a failed autosave to retry safely, so that network instability does not create duplicate or corrupted answers.
  30. As a student, I want an older delayed save request to be rejected rather than overwrite my newer answer, so that request reordering cannot corrupt progress.
  31. As a student, I want refreshing the page to restore the latest server-accepted answers, so that the server remains the durable source of truth.
  32. As a student, I want duplicate clicks or requests to have one effective result, so that accidental repetition does not change my practice incorrectly.
  33. As a student, I want to be prevented from answering a submitted, expired, cancelled, or foreign session, so that session state remains trustworthy.
  34. As a student, I want correct answers and explanations hidden before submission, so that the practice cannot be cheated through API inspection.
  35. As a student, I want a confirmation before final submission when unanswered questions remain, so that I can choose whether to review them.
  36. As a student, I want submitting a practice session to be atomic, so that I never receive a partially scored report.
  37. As a student, I want repeated submission after a timeout to return the original result, so that I do not create duplicate reports.
  38. As a student, I want a clear score, correct count, incorrect count, and completion summary after submission, so that I understand my performance.
  39. As a student, I want question-level result details after submission, so that I can learn from mistakes.
  40. As a student, I want permitted explanations to appear after submission, so that I can understand the correct reasoning.
  41. As a student, I want my practice history ordered and paginated, so that I can revisit previous work.
  42. As a student, I want a report to remain stable even if an administrator later edits a question, so that historical records are auditable.
  43. As a student, I want incorrectly answered questions added to my wrong-question book, so that I can focus future review.
  44. As a student, I want repeated mistakes on the same question to increase its error count rather than create duplicate rows, so that the wrong-question book remains useful.
  45. As a student, I want to mark a wrong question as mastered without deleting its history, so that progress remains visible.
  46. As a student, I want to create a review practice from wrong questions, so that I can close knowledge gaps.
  47. As a student, I want to favorite a question, so that I can return to important material later.
  48. As a student, I want favoriting the same question repeatedly to remain idempotent, so that duplicate actions do not create duplicate records.
  49. As a student, I want to remove a favorite, so that my collection remains relevant.
  50. As a student, I want wrong questions and favorites to be paginated and filterable, so that large collections remain manageable.
  51. As a student, I want another student to be unable to read or mutate my sessions, reports, wrong questions, or favorites, so that my learning data remains private.
  52. As a student, I want another tenant to be unable to access my tenant’s private question banks or learning records, so that organizations remain isolated.
  53. As a student, I want a traceable support reference when an upstream content service fails, so that support can investigate without exposing sensitive details.
  54. As a tenant operator, I want student authentication to reuse the platform’s member system, so that I do not manage duplicate accounts.
  55. As a tenant operator, I want education data automatically scoped to my tenant, so that I cannot accidentally view another tenant’s students or content.
  56. As a tenant operator, I want permission-controlled access to future education management screens, so that roles can be assigned through the existing menu and role system.
  57. As a tenant operator, I want student learning reports to be based on immutable practice snapshots, so that supervision data remains trustworthy.
  58. As a tenant operator, I want education actions to appear in existing access, error, and operation logs, so that incidents can be investigated centrally.
  59. As a platform operator, I want public and tenant-owned content represented explicitly, so that public sharing does not require disabling tenant isolation globally.
  60. As a platform operator, I want Scalar-backed capabilities to be visible through configuration and metrics, so that migration progress and dependency risk are measurable.
  61. As a platform operator, I want to enable the new learning flow for pilot tenants first, so that production risk is contained.
  62. As a platform operator, I want independent feature switches for catalog reads, practice creation, payments, private media, and imports, so that failures can be isolated.
  63. As a platform operator, I want rollback to preserve practice history and idempotency records, so that deployment rollback does not lose student work.
  64. As a support engineer, I want requests correlated by request or trace ID across RuoYi and Scalar, so that cross-system failures are diagnosable.
  65. As a support engineer, I want logs to exclude tokens, phone numbers, correct answers, payment secrets, and signed URLs, so that observability does not create a data leak.
  66. As a developer, I want one internal education contract independent of Scalar DTOs, so that the external provider can be changed or retired safely.
  67. As a developer, I want Scalar errors translated consistently rather than converted to successful empty data, so that frontend and monitoring behavior is honest.
  68. As a developer, I want contract tests for the Scalar envelope and errors, so that upstream changes fail before deployment.
  69. As a developer, I want all personal learning writes to go directly to Java/MySQL, so that there is no dual-write reconciliation problem.
  70. As a developer, I want existing member, tenant, permission, file, notification, and later payment APIs reused, so that the education module remains focused on education behavior.
  71. As a developer, I want the education module to expose narrow module APIs, so that other modules do not import its mappers or data objects.
  72. As a developer, I want schema changes delivered as ordered, reversible or explicitly non-reversible scripts, so that database releases can be operated safely.
  73. As a QA engineer, I want one high-level E2E scenario to cover the entire student core loop, so that the released experience is tested from the user’s perspective.
  74. As a QA engineer, I want targeted integration tests for tenant isolation, ownership, idempotency, concurrency, and adapter behavior, so that security and consistency failures are exercised deterministically.
  75. As a product owner, I want the first release limited to the student core learning loop, so that value can be validated before building every prototype screen.
  76. As a product owner, I want later membership, payment, private media, tenant operations, and platform governance to fit the same architecture, so that the first release does not become a dead end.
  77. As a product owner, I want visual acceptance against the supplied concept images on desktop and H5 widths, so that functional completion also meets the intended experience.
  78. As a product owner, I want incomplete future features clearly labeled rather than represented with mock data, so that release status is transparent.

Implementation Decisions

  • RuoYi is the unified application boundary and final source of truth. Frontends will not call Scalar directly.
  • A new Education business module will own education-specific behavior and data. It will follow the repository’s controller, service, conversion, data-object, mapper, enum, job, and module-API conventions.
  • The existing Member module will own student credentials, login, token refresh, logout, mobile number, nickname, avatar, level, points, tags, and other generic member data. Education-specific profile data will reference the member ID instead of duplicating account fields.
  • The existing System module will own tenant administration, admin users, roles, menus, permissions, dictionaries, configuration, notifications, email, SMS, and audit facilities.
  • The existing Infra module will own file records and storage. Education will own the authorization decision for paid or private resources.
  • The Pay module will remain disabled during the first student-core release and will be activated in a later payment slice. Education orders and entitlements will be projections linked to Pay orders rather than an independent payment engine.
  • The first release will activate Member and Education in the Maven reactor and server. Unrelated modules will remain disabled to limit build and runtime scope.
  • The Scalar integration will be a server-side anti-corruption layer. External DTOs, enum values, pagination, errors, timestamps, identifiers, and metadata will be converted to internal education contracts before reaching services or controllers.
  • Scalar will initially provide only explicitly approved read-only content capabilities. Student practice sessions, answers, reports, wrong questions, favorites, progress, future orders, entitlements, and private-resource decisions will never be written to Scalar.
  • Each capability will have an explicit source state such as SCALAR_READ, JAVA_NATIVE, or MIGRATED. The system will not silently fall back between providers.
  • Scalar failures will be mapped to explicit domain errors. An unavailable upstream must not appear as an empty successful catalog.
  • Scalar requests will receive tenant context derived from the authenticated server context. The frontend cannot override authorization, tenant, user, or platform identity headers.
  • Scalar authentication will use an approved server credential or token-exchange mechanism. Forwarding a frontend token is not permitted unless the frozen contract explicitly requires it and it passes security review.
  • The public student API will use the repository’s existing app API conventions, standard success envelope, and page representation. A compatibility facade may preserve /api paths if the restored frontend requires them, but it will delegate to the same services rather than duplicate logic.
  • Student IDs and tenant IDs for protected resources will be derived from the security context. Request-body user or tenant IDs will not be trusted.
  • Tenant-scoped education data will use the platform’s tenant-aware base object and database interceptor by default.
  • Public content will use an explicit ownership scope or public marker. It will not be implemented by broadly disabling the tenant interceptor.
  • Any tenant bypass will be isolated to a narrow platform service, documented, permission-protected, and covered by cross-tenant tests.
  • The initial content model will include question banks, hierarchical catalog nodes, questions, options, source identifiers, publication state, content versions, and appropriate tenant-aware indexes.
  • Correct answers and explanations will be treated as protected fields. Pre-submission student DTOs will not contain them.
  • A practice session will belong to one tenant and one member. It will include a client-generated session identifier, lifecycle state, content selection, question count, score, timestamps, and a concurrency version.
  • Starting a practice will freeze the question sequence and version. The system will retain enough snapshot data to keep historical reports stable after content changes.
  • Answer autosave will require an idempotency key, a client command sequence, and the latest known server session version.
  • Replaying the same idempotency key with the same request will return the original result. Reusing it for a different payload will return a conflict.
  • Stale sequence or version updates will be rejected instead of overwriting newer accepted answers.
  • Session submission will be an atomic, one-way state transition. Retrying a successfully committed submission will return the original result.
  • Session ownership and active state will be checked in the service layer even when a controller is authenticated.
  • Wrong questions will use one record per tenant, student, and question, with accumulated error count and mastery state. Marking as mastered will not erase history.
  • Favorites will use one record per tenant, student, target type, and target ID and will support idempotent add/remove behavior.
  • Basic learning progress will be stored as reliable aggregates. Expensive trends and summaries may later be calculated asynchronously through the existing job system.
  • External resource mappings will preserve provider, external resource type, external ID, local ID, source version, synchronization state, and last synchronization time.
  • Import and synchronization operations will use durable jobs and issue records rather than executing large migrations in a web request.
  • Database changes will be delivered as ordered education SQL scripts with preconditions, verification queries, rollback SQL where safe, explicit rollback limitations, and lock-impact notes. The project will not pretend that Flyway or Liquibase exists when it does not.
  • Permission names will follow the established education:<resource>:<action> pattern and will be seeded with menus and dictionaries rather than hardcoded only in the frontend.
  • Stable business state machines will use Java enums and centralized transition validation. Dictionaries will provide configurable display values.
  • Existing notification templates, mail accounts, SMS services, and in-app notification services will be reused. Education services will provide template codes and parameters rather than implementing a second delivery engine.
  • Existing API access logs, API error logs, operation logs, login logs, and job logs will be reused. Education will add domain records only where business history must survive general log retention.
  • Private media will not rely on the generic public and tenant-ignored file download route. A future Education access endpoint will authenticate the caller, validate tenant and resource state, check entitlement or operator permission, issue a short-lived URL, and audit the decision.
  • The administration frontend will use the restored Vue 3 and Element Plus codebase and its existing request, route, store, permission, layout, form, table, pagination, upload, and theme conventions.
  • The student frontend will be a responsive Web/H5 experience using the restored production frontend baseline. The static prototype is an acceptance reference, not a replacement architecture.
  • The first release will cover tenant resolution, authentication shell, question-bank browsing, practice creation, answer autosave and recovery, submission, report, history, wrong questions, and favorites.
  • Vocabulary, handbook, scorelines, AI recommendations, resources, videos, messages, growth, membership, payments, entitlements, tenant operations, platform governance, and full Scalar retirement will be implemented as later vertical slices.
  • Feature flags will independently control Scalar catalog reads, Java content reads, practice creation, future payments, private media, imports, and frontend route exposure.
  • Initial production rollout will use a pilot tenant. The release sequence will expand schema first, deploy disabled code, verify existing modules, enable read paths, then enable learning writes.
  • Rollback will preserve practice history, reports, idempotency records, future orders, and entitlements. User-specific data will never roll back to Scalar.
  • Observability will include request/trace ID, tenant, actor, use case, provider, upstream request ID, endpoint, latency, result, practice session, future order/import job, and authorization decision. Sensitive values will be redacted.
  • The complete frontend sources, exact commits, machine-readable Scalar OpenAPI contract, production database version, Scalar availability expectations, and stable external identifier semantics are prerequisites to implementation.

Testing Decisions

  • Tests will assert externally observable behavior rather than private method calls, mapper invocation counts, or implementation-specific object construction.
  • The primary acceptance seam will be one browser-level student core-loop E2E: resolve tenant, authenticate, browse a question bank, create a practice, save answers, refresh and recover, retry one simulated failed save, submit, inspect the report, and visit wrong questions and favorites.
  • The E2E will also assert that browser network traffic contains no direct request to Scalar.
  • The E2E will run at both representative desktop and H5 viewport sizes and capture key screenshots for comparison with the supplied concepts.
  • Authentication tests will reuse the highest existing authentication seams: login endpoints, refresh, logout, and current-member behavior. Education will not unit-test the internals of Member authentication.
  • Tenant isolation tests will create at least two tenants and overlapping-looking resource identifiers. They will assert that cross-tenant catalog, session, report, wrong-question, favorite, and future media access is denied.
  • Ownership tests will create at least two students in one tenant and assert that one student cannot read, update, submit, or replay another student’s practice.
  • Scalar adapter contract tests will cover single-item and paginated envelopes, request metadata, missing optional fields, additional fields, malformed required fields, 400, 401, 403, 404, 409, 429, timeout, and 5xx behavior.
  • Scalar adapter tests will assert that failures are not converted to empty successes and that sensitive headers are not accepted from callers.
  • Practice creation tests will assert stable question order, content version retention, ownership, tenant scope, and idempotent handling of a repeated client session identifier.
  • Autosave tests will assert normal save, identical replay, payload mismatch conflict, stale sequence rejection, stale server-version rejection, delayed request ordering, refresh recovery, inactive-session rejection, and cross-user rejection.
  • Submission tests will assert atomic scoring, unanswered questions, repeated submission, a timeout after commit, content edits after session creation, and stable historical reports.
  • Wrong-question tests will assert unique upsert behavior, accumulated error count, mastery without history deletion, and review selection.
  • Favorite tests will assert idempotent add, idempotent remove, tenant and owner filtering, and pagination.
  • Response-security tests will assert that pre-submission DTOs and error logs do not contain correct answers or explanations.
  • Logging tests will focus on the observable presence of correlation fields and absence of secrets, not exact log-line formatting.
  • Database tests will follow the project’s existing Spring and database test foundations and test real constraints for unique tenant/source mappings, sessions, answers, wrong questions, favorites, and idempotency records.
  • Build verification will include the Education module with dependencies, the server package with activated Member/Education modules, and the restored frontend’s actual lint, type-check, test, and production build commands.
  • Smoke tests against the real Scalar deployment will be read-only and version-pinned. They will run before enabling an adapter-backed feature in a target environment.
  • Release verification will check existing System, Infra, and Member behavior for regressions before enabling any Education feature flag.
  • Future payment tests will cover duplicate provider callbacks, status polling, browser return URLs that disagree with server state, refund replay, entitlement projection, and refund-access semantics.
  • Future private-media tests will cover unauthenticated requests, wrong tenant, wrong student, expired entitlement, unpublished asset, short-lived URL generation, and audit records.
  • Test fixtures will not contain production tokens, real student personal data, provider secrets, or licensed content not approved for test storage.

Out of Scope

  • Implementing all 18 student screens in the first release.
  • Implementing all 34 tenant operations pages in the first release.
  • Implementing platform tenant lifecycle, plans, subscriptions, public-bank governance, alerts, dunning, invoices, usage, and platform permissions in the first release.
  • Activating payment, refunds, wallet checkout, membership entitlements, coupons, or activation codes in the first release.
  • Implementing private paid-resource delivery or protected video playback in the first release.
  • Implementing vocabulary study, knowledge handbook, historical scorelines, AI school recommendations, downloadable resources, messages, badges, check-in, tasks, or growth features in the first release.
  • Implementing generic course and lesson management. The supplied product is initially modeled as an exam-prep catalog, question-bank, and practice system.
  • Replacing the existing Member, System, Pay, Infra, notification, email, SMS, dictionary, role, menu, job, or audit infrastructure.
  • Direct frontend integration with Scalar or persistence of Scalar/Supabase credentials in browser storage.
  • Dual-writing personal learning data to RuoYi and Scalar.
  • Treating the static prototype’s CSS, state management, or mock data as production source code.
  • Building the production frontend before the complete frontend repository and exact revision are provided.
  • Claiming DRM, anti-download, watermarking, or advanced video protection without a separately approved media-security design.
  • Introducing a new migration framework as part of the first Education slice. Database scripts will follow an explicit ordered-script process unless a separate migration decision is approved.
  • Supporting every database vendor present in the repository in the first release. MySQL is the working assumption pending production confirmation.
  • Migrating all Scalar content or decommissioning Scalar in the first release.
  • Sending private student profile data to an AI provider.
  • Building new email administration APIs unless a later frontend requirement demonstrates that the existing template and account capabilities are insufficient.

Further Notes

  • The currently checked-out frontend directories are incomplete. Implementation must pause at the frontend boundary until the production Vue 3 admin and student Web/H5 sources, branches, and exact commits are available.
  • The Scalar share page is usable for discovery, but a machine-readable OpenAPI JSON or YAML export must be frozen before adapter implementation.
  • The Scalar contract currently models education mainly as catalog nodes, content entries, question collections, practice blueprints, and questions rather than generic courses and lessons. The domain language in implementation should follow the exam-prep product unless product requirements change.
  • Known Scalar uncertainties include management question list/detail reads, platform login, payment return and polling semantics, entitlement-resource relationships, answer autosave idempotency, and asynchronous media/import job states.
  • The existing generic file download route is public and tenant-ignored. It must not be reused as the authorization boundary for paid education content.
  • The root build currently leaves Member and Pay disabled. Member is required for the first release; Pay should be activated only when the payment slice starts.
  • The desired execution order for an implementation agent is: module activation, tenant/auth shell, Scalar catalog adapter and contract tests, question read facade, practice creation, autosave and recovery, atomic submission and report, wrong questions/favorites, then full E2E and visual acceptance.
  • Each implementation change set should contain schema, seed data, domain implementation, tests, API documentation, one complete frontend slice, and verified commands. Mock data or an uncalled endpoint must not be reported as complete.
  • The issue tracker is the project’s self-hosted Gitea instance. This spec should be labeled ready-for-agent once published.
# 恭学教育学生核心学习闭环 PRD ## Problem Statement 当前恭学教育系统基于 RuoYi-Vue-Pro,已经具备成熟的租户、后台用户、会员、鉴权、支付、文件、短信、邮件、站内信、权限、字典、定时任务和审计基础设施,但仓库内尚无生产级教育/题库/学习模块,完整前端源码也尚未纳入当前工作区。 另一个已经运行的 Scalar API 提供了题库、练习、资料、视频、会员和运营等大量教育接口;用户同时提供了学生学习中心、租户运营后台、平台管理后台的功能原型和效果图。若前端直接接入 Scalar,或在 RuoYi 中再次独立实现身份、会员、支付等基础能力,会形成双鉴权、双租户、双订单和双数据源,造成权限不一致、数据难迁移、跨租户风险以及长期维护成本。 用户首先需要一个能够真实上线和验证的学生学习核心闭环:学生在正确租户下使用现有账号登录,浏览题库,创建练习,稳定保存答案,提交试卷,查看报告,并继续使用错题本和收藏夹。该闭环需要以 RuoYi 为统一入口和最终数据权威,同时允许尚未迁移的只读题库内容暂时经后端适配层来自 Scalar。实现还必须为后续会员支付、私有资料、视频、租户运营后台和平台治理留出清晰边界,但不能让这些后续范围阻塞第一阶段交付。 ## Solution 在 RuoYi-Vue-Pro 中新增独立的 Education 业务模块,以 RuoYi 作为所有前端请求、身份、租户、个人学习数据和未来支付权益的统一边界。学生 Web/H5 和 Vue 3 管理后台只能调用 RuoYi API,不得直接访问 Scalar。 第一阶段交付以下纵向学习闭环: 1. 根据访问域名或受控租户参数识别租户。 2. 复用现有 Member 登录、短信登录、令牌刷新和退出能力。 3. 通过 Education 内部目录/题目接口读取题库;尚未迁移的数据由服务器端 Scalar 防腐适配层转换。 4. 在 RuoYi/MySQL 中创建归属于当前学生和租户的练习会话,并固定题目顺序与版本。 5. 使用幂等键、客户端序号和服务端版本安全地自动保存答案,支持刷新、断网和请求重试恢复。 6. 以原子状态转换提交试卷,保存稳定的评分结果和历史快照。 7. 生成练习报告、错题记录、收藏和基础学习进度。 8. 通过一个最高层的学生核心闭环 E2E 接缝验收整体行为,并使用较低层测试补足租户隔离、所有权、幂等、并发和 Scalar 契约等不可完全由单条 E2E 覆盖的风险。 后续阶段在同一模块边界内扩展个人中心、词汇、手册、分数线、AI 推荐、资料、视频、会员支付、权益、租户运营和平台治理,并逐项把 Scalar 内容迁移到 Java/MySQL。 ## User Stories 1. As a student, I want the application to identify the correct school or tenant from my entry point, so that I enter the right branded learning environment. 2. As a student, I want a clear error when no valid tenant can be resolved, so that I do not accidentally sign in to the wrong organization. 3. As a student, I want to be blocked when a tenant is disabled, so that the platform does not expose inactive tenant data. 4. As a student, I want to sign in with my existing mobile number and password, so that I do not need a separate education account. 5. As a student, I want to sign in with an SMS verification code, so that I can recover access without remembering a password. 6. As a student, I want supported social or WeChat login methods to keep working, so that education does not replace the platform’s existing authentication options. 7. As a student, I want my session to refresh securely, so that a long learning session is not lost when an access token expires. 8. As a student, I want to log out from the education application, so that another person using the device cannot access my learning data. 9. As a student, I want to return to the page I originally requested after login, so that authentication does not interrupt my intended task. 10. As a student, I want the application to display my existing nickname and avatar, so that my education profile is consistent with my member account. 11. As a student, I want the application to preserve the tenant context after login, so that subsequent requests cannot drift into another tenant. 12. As a student, I want to see a learning home page with a clear entry into the question bank, so that I can start studying quickly. 13. As a student, I want to resume an unfinished practice session from the learning home page, so that a refresh or temporary interruption does not discard my work. 14. As a student, I want to browse question banks by subject, category, region, major, or other supported catalog dimensions, so that I can find relevant material. 15. As a student, I want catalog filters to preserve their selected state while I navigate, so that I can compare and refine content efficiently. 16. As a student, I want clear loading, empty, unavailable, and permission-denied states in the catalog, so that I understand why content is not displayed. 17. As a student, I want only published and permitted question banks to appear, so that I do not see draft or unauthorized content. 18. As a student, I want question counts and practice configuration to be accurate, so that I understand what will be included before starting. 19. As a student, I want to create a practice session from selected criteria, so that the server prepares a stable set of questions for me. 20. As a student, I want the question order to remain stable throughout a practice session, so that refreshing does not reorder my work. 21. As a student, I want historical practice to preserve the version of each question I answered, so that later question edits do not change my old result. 22. As a student, I want question content to render correctly on desktop and mobile widths, so that I can learn on either device. 23. As a student, I want formulas and rich question content to render correctly, so that mathematical and technical questions remain understandable. 24. As a student, I want answer options to be easy to select using touch or mouse, so that answering is efficient and accessible. 25. As a student, I want to move to the previous or next question, so that I can navigate the practice naturally. 26. As a student, I want an answer-card overview, so that I can see answered, unanswered, and current questions. 27. As a student, I want my answer to save automatically, so that I do not lose progress if I leave the page unexpectedly. 28. As a student, I want to see whether an answer is saving, saved, retrying, or failed, so that I know whether my progress is safe. 29. As a student, I want a failed autosave to retry safely, so that network instability does not create duplicate or corrupted answers. 30. As a student, I want an older delayed save request to be rejected rather than overwrite my newer answer, so that request reordering cannot corrupt progress. 31. As a student, I want refreshing the page to restore the latest server-accepted answers, so that the server remains the durable source of truth. 32. As a student, I want duplicate clicks or requests to have one effective result, so that accidental repetition does not change my practice incorrectly. 33. As a student, I want to be prevented from answering a submitted, expired, cancelled, or foreign session, so that session state remains trustworthy. 34. As a student, I want correct answers and explanations hidden before submission, so that the practice cannot be cheated through API inspection. 35. As a student, I want a confirmation before final submission when unanswered questions remain, so that I can choose whether to review them. 36. As a student, I want submitting a practice session to be atomic, so that I never receive a partially scored report. 37. As a student, I want repeated submission after a timeout to return the original result, so that I do not create duplicate reports. 38. As a student, I want a clear score, correct count, incorrect count, and completion summary after submission, so that I understand my performance. 39. As a student, I want question-level result details after submission, so that I can learn from mistakes. 40. As a student, I want permitted explanations to appear after submission, so that I can understand the correct reasoning. 41. As a student, I want my practice history ordered and paginated, so that I can revisit previous work. 42. As a student, I want a report to remain stable even if an administrator later edits a question, so that historical records are auditable. 43. As a student, I want incorrectly answered questions added to my wrong-question book, so that I can focus future review. 44. As a student, I want repeated mistakes on the same question to increase its error count rather than create duplicate rows, so that the wrong-question book remains useful. 45. As a student, I want to mark a wrong question as mastered without deleting its history, so that progress remains visible. 46. As a student, I want to create a review practice from wrong questions, so that I can close knowledge gaps. 47. As a student, I want to favorite a question, so that I can return to important material later. 48. As a student, I want favoriting the same question repeatedly to remain idempotent, so that duplicate actions do not create duplicate records. 49. As a student, I want to remove a favorite, so that my collection remains relevant. 50. As a student, I want wrong questions and favorites to be paginated and filterable, so that large collections remain manageable. 51. As a student, I want another student to be unable to read or mutate my sessions, reports, wrong questions, or favorites, so that my learning data remains private. 52. As a student, I want another tenant to be unable to access my tenant’s private question banks or learning records, so that organizations remain isolated. 53. As a student, I want a traceable support reference when an upstream content service fails, so that support can investigate without exposing sensitive details. 54. As a tenant operator, I want student authentication to reuse the platform’s member system, so that I do not manage duplicate accounts. 55. As a tenant operator, I want education data automatically scoped to my tenant, so that I cannot accidentally view another tenant’s students or content. 56. As a tenant operator, I want permission-controlled access to future education management screens, so that roles can be assigned through the existing menu and role system. 57. As a tenant operator, I want student learning reports to be based on immutable practice snapshots, so that supervision data remains trustworthy. 58. As a tenant operator, I want education actions to appear in existing access, error, and operation logs, so that incidents can be investigated centrally. 59. As a platform operator, I want public and tenant-owned content represented explicitly, so that public sharing does not require disabling tenant isolation globally. 60. As a platform operator, I want Scalar-backed capabilities to be visible through configuration and metrics, so that migration progress and dependency risk are measurable. 61. As a platform operator, I want to enable the new learning flow for pilot tenants first, so that production risk is contained. 62. As a platform operator, I want independent feature switches for catalog reads, practice creation, payments, private media, and imports, so that failures can be isolated. 63. As a platform operator, I want rollback to preserve practice history and idempotency records, so that deployment rollback does not lose student work. 64. As a support engineer, I want requests correlated by request or trace ID across RuoYi and Scalar, so that cross-system failures are diagnosable. 65. As a support engineer, I want logs to exclude tokens, phone numbers, correct answers, payment secrets, and signed URLs, so that observability does not create a data leak. 66. As a developer, I want one internal education contract independent of Scalar DTOs, so that the external provider can be changed or retired safely. 67. As a developer, I want Scalar errors translated consistently rather than converted to successful empty data, so that frontend and monitoring behavior is honest. 68. As a developer, I want contract tests for the Scalar envelope and errors, so that upstream changes fail before deployment. 69. As a developer, I want all personal learning writes to go directly to Java/MySQL, so that there is no dual-write reconciliation problem. 70. As a developer, I want existing member, tenant, permission, file, notification, and later payment APIs reused, so that the education module remains focused on education behavior. 71. As a developer, I want the education module to expose narrow module APIs, so that other modules do not import its mappers or data objects. 72. As a developer, I want schema changes delivered as ordered, reversible or explicitly non-reversible scripts, so that database releases can be operated safely. 73. As a QA engineer, I want one high-level E2E scenario to cover the entire student core loop, so that the released experience is tested from the user’s perspective. 74. As a QA engineer, I want targeted integration tests for tenant isolation, ownership, idempotency, concurrency, and adapter behavior, so that security and consistency failures are exercised deterministically. 75. As a product owner, I want the first release limited to the student core learning loop, so that value can be validated before building every prototype screen. 76. As a product owner, I want later membership, payment, private media, tenant operations, and platform governance to fit the same architecture, so that the first release does not become a dead end. 77. As a product owner, I want visual acceptance against the supplied concept images on desktop and H5 widths, so that functional completion also meets the intended experience. 78. As a product owner, I want incomplete future features clearly labeled rather than represented with mock data, so that release status is transparent. ## Implementation Decisions - RuoYi is the unified application boundary and final source of truth. Frontends will not call Scalar directly. - A new Education business module will own education-specific behavior and data. It will follow the repository’s controller, service, conversion, data-object, mapper, enum, job, and module-API conventions. - The existing Member module will own student credentials, login, token refresh, logout, mobile number, nickname, avatar, level, points, tags, and other generic member data. Education-specific profile data will reference the member ID instead of duplicating account fields. - The existing System module will own tenant administration, admin users, roles, menus, permissions, dictionaries, configuration, notifications, email, SMS, and audit facilities. - The existing Infra module will own file records and storage. Education will own the authorization decision for paid or private resources. - The Pay module will remain disabled during the first student-core release and will be activated in a later payment slice. Education orders and entitlements will be projections linked to Pay orders rather than an independent payment engine. - The first release will activate Member and Education in the Maven reactor and server. Unrelated modules will remain disabled to limit build and runtime scope. - The Scalar integration will be a server-side anti-corruption layer. External DTOs, enum values, pagination, errors, timestamps, identifiers, and metadata will be converted to internal education contracts before reaching services or controllers. - Scalar will initially provide only explicitly approved read-only content capabilities. Student practice sessions, answers, reports, wrong questions, favorites, progress, future orders, entitlements, and private-resource decisions will never be written to Scalar. - Each capability will have an explicit source state such as `SCALAR_READ`, `JAVA_NATIVE`, or `MIGRATED`. The system will not silently fall back between providers. - Scalar failures will be mapped to explicit domain errors. An unavailable upstream must not appear as an empty successful catalog. - Scalar requests will receive tenant context derived from the authenticated server context. The frontend cannot override authorization, tenant, user, or platform identity headers. - Scalar authentication will use an approved server credential or token-exchange mechanism. Forwarding a frontend token is not permitted unless the frozen contract explicitly requires it and it passes security review. - The public student API will use the repository’s existing app API conventions, standard success envelope, and page representation. A compatibility facade may preserve `/api` paths if the restored frontend requires them, but it will delegate to the same services rather than duplicate logic. - Student IDs and tenant IDs for protected resources will be derived from the security context. Request-body user or tenant IDs will not be trusted. - Tenant-scoped education data will use the platform’s tenant-aware base object and database interceptor by default. - Public content will use an explicit ownership scope or public marker. It will not be implemented by broadly disabling the tenant interceptor. - Any tenant bypass will be isolated to a narrow platform service, documented, permission-protected, and covered by cross-tenant tests. - The initial content model will include question banks, hierarchical catalog nodes, questions, options, source identifiers, publication state, content versions, and appropriate tenant-aware indexes. - Correct answers and explanations will be treated as protected fields. Pre-submission student DTOs will not contain them. - A practice session will belong to one tenant and one member. It will include a client-generated session identifier, lifecycle state, content selection, question count, score, timestamps, and a concurrency version. - Starting a practice will freeze the question sequence and version. The system will retain enough snapshot data to keep historical reports stable after content changes. - Answer autosave will require an idempotency key, a client command sequence, and the latest known server session version. - Replaying the same idempotency key with the same request will return the original result. Reusing it for a different payload will return a conflict. - Stale sequence or version updates will be rejected instead of overwriting newer accepted answers. - Session submission will be an atomic, one-way state transition. Retrying a successfully committed submission will return the original result. - Session ownership and active state will be checked in the service layer even when a controller is authenticated. - Wrong questions will use one record per tenant, student, and question, with accumulated error count and mastery state. Marking as mastered will not erase history. - Favorites will use one record per tenant, student, target type, and target ID and will support idempotent add/remove behavior. - Basic learning progress will be stored as reliable aggregates. Expensive trends and summaries may later be calculated asynchronously through the existing job system. - External resource mappings will preserve provider, external resource type, external ID, local ID, source version, synchronization state, and last synchronization time. - Import and synchronization operations will use durable jobs and issue records rather than executing large migrations in a web request. - Database changes will be delivered as ordered education SQL scripts with preconditions, verification queries, rollback SQL where safe, explicit rollback limitations, and lock-impact notes. The project will not pretend that Flyway or Liquibase exists when it does not. - Permission names will follow the established `education:<resource>:<action>` pattern and will be seeded with menus and dictionaries rather than hardcoded only in the frontend. - Stable business state machines will use Java enums and centralized transition validation. Dictionaries will provide configurable display values. - Existing notification templates, mail accounts, SMS services, and in-app notification services will be reused. Education services will provide template codes and parameters rather than implementing a second delivery engine. - Existing API access logs, API error logs, operation logs, login logs, and job logs will be reused. Education will add domain records only where business history must survive general log retention. - Private media will not rely on the generic public and tenant-ignored file download route. A future Education access endpoint will authenticate the caller, validate tenant and resource state, check entitlement or operator permission, issue a short-lived URL, and audit the decision. - The administration frontend will use the restored Vue 3 and Element Plus codebase and its existing request, route, store, permission, layout, form, table, pagination, upload, and theme conventions. - The student frontend will be a responsive Web/H5 experience using the restored production frontend baseline. The static prototype is an acceptance reference, not a replacement architecture. - The first release will cover tenant resolution, authentication shell, question-bank browsing, practice creation, answer autosave and recovery, submission, report, history, wrong questions, and favorites. - Vocabulary, handbook, scorelines, AI recommendations, resources, videos, messages, growth, membership, payments, entitlements, tenant operations, platform governance, and full Scalar retirement will be implemented as later vertical slices. - Feature flags will independently control Scalar catalog reads, Java content reads, practice creation, future payments, private media, imports, and frontend route exposure. - Initial production rollout will use a pilot tenant. The release sequence will expand schema first, deploy disabled code, verify existing modules, enable read paths, then enable learning writes. - Rollback will preserve practice history, reports, idempotency records, future orders, and entitlements. User-specific data will never roll back to Scalar. - Observability will include request/trace ID, tenant, actor, use case, provider, upstream request ID, endpoint, latency, result, practice session, future order/import job, and authorization decision. Sensitive values will be redacted. - The complete frontend sources, exact commits, machine-readable Scalar OpenAPI contract, production database version, Scalar availability expectations, and stable external identifier semantics are prerequisites to implementation. ## Testing Decisions - Tests will assert externally observable behavior rather than private method calls, mapper invocation counts, or implementation-specific object construction. - The primary acceptance seam will be one browser-level student core-loop E2E: resolve tenant, authenticate, browse a question bank, create a practice, save answers, refresh and recover, retry one simulated failed save, submit, inspect the report, and visit wrong questions and favorites. - The E2E will also assert that browser network traffic contains no direct request to Scalar. - The E2E will run at both representative desktop and H5 viewport sizes and capture key screenshots for comparison with the supplied concepts. - Authentication tests will reuse the highest existing authentication seams: login endpoints, refresh, logout, and current-member behavior. Education will not unit-test the internals of Member authentication. - Tenant isolation tests will create at least two tenants and overlapping-looking resource identifiers. They will assert that cross-tenant catalog, session, report, wrong-question, favorite, and future media access is denied. - Ownership tests will create at least two students in one tenant and assert that one student cannot read, update, submit, or replay another student’s practice. - Scalar adapter contract tests will cover single-item and paginated envelopes, request metadata, missing optional fields, additional fields, malformed required fields, 400, 401, 403, 404, 409, 429, timeout, and 5xx behavior. - Scalar adapter tests will assert that failures are not converted to empty successes and that sensitive headers are not accepted from callers. - Practice creation tests will assert stable question order, content version retention, ownership, tenant scope, and idempotent handling of a repeated client session identifier. - Autosave tests will assert normal save, identical replay, payload mismatch conflict, stale sequence rejection, stale server-version rejection, delayed request ordering, refresh recovery, inactive-session rejection, and cross-user rejection. - Submission tests will assert atomic scoring, unanswered questions, repeated submission, a timeout after commit, content edits after session creation, and stable historical reports. - Wrong-question tests will assert unique upsert behavior, accumulated error count, mastery without history deletion, and review selection. - Favorite tests will assert idempotent add, idempotent remove, tenant and owner filtering, and pagination. - Response-security tests will assert that pre-submission DTOs and error logs do not contain correct answers or explanations. - Logging tests will focus on the observable presence of correlation fields and absence of secrets, not exact log-line formatting. - Database tests will follow the project’s existing Spring and database test foundations and test real constraints for unique tenant/source mappings, sessions, answers, wrong questions, favorites, and idempotency records. - Build verification will include the Education module with dependencies, the server package with activated Member/Education modules, and the restored frontend’s actual lint, type-check, test, and production build commands. - Smoke tests against the real Scalar deployment will be read-only and version-pinned. They will run before enabling an adapter-backed feature in a target environment. - Release verification will check existing System, Infra, and Member behavior for regressions before enabling any Education feature flag. - Future payment tests will cover duplicate provider callbacks, status polling, browser return URLs that disagree with server state, refund replay, entitlement projection, and refund-access semantics. - Future private-media tests will cover unauthenticated requests, wrong tenant, wrong student, expired entitlement, unpublished asset, short-lived URL generation, and audit records. - Test fixtures will not contain production tokens, real student personal data, provider secrets, or licensed content not approved for test storage. ## Out of Scope - Implementing all 18 student screens in the first release. - Implementing all 34 tenant operations pages in the first release. - Implementing platform tenant lifecycle, plans, subscriptions, public-bank governance, alerts, dunning, invoices, usage, and platform permissions in the first release. - Activating payment, refunds, wallet checkout, membership entitlements, coupons, or activation codes in the first release. - Implementing private paid-resource delivery or protected video playback in the first release. - Implementing vocabulary study, knowledge handbook, historical scorelines, AI school recommendations, downloadable resources, messages, badges, check-in, tasks, or growth features in the first release. - Implementing generic course and lesson management. The supplied product is initially modeled as an exam-prep catalog, question-bank, and practice system. - Replacing the existing Member, System, Pay, Infra, notification, email, SMS, dictionary, role, menu, job, or audit infrastructure. - Direct frontend integration with Scalar or persistence of Scalar/Supabase credentials in browser storage. - Dual-writing personal learning data to RuoYi and Scalar. - Treating the static prototype’s CSS, state management, or mock data as production source code. - Building the production frontend before the complete frontend repository and exact revision are provided. - Claiming DRM, anti-download, watermarking, or advanced video protection without a separately approved media-security design. - Introducing a new migration framework as part of the first Education slice. Database scripts will follow an explicit ordered-script process unless a separate migration decision is approved. - Supporting every database vendor present in the repository in the first release. MySQL is the working assumption pending production confirmation. - Migrating all Scalar content or decommissioning Scalar in the first release. - Sending private student profile data to an AI provider. - Building new email administration APIs unless a later frontend requirement demonstrates that the existing template and account capabilities are insufficient. ## Further Notes - The currently checked-out frontend directories are incomplete. Implementation must pause at the frontend boundary until the production Vue 3 admin and student Web/H5 sources, branches, and exact commits are available. - The Scalar share page is usable for discovery, but a machine-readable OpenAPI JSON or YAML export must be frozen before adapter implementation. - The Scalar contract currently models education mainly as catalog nodes, content entries, question collections, practice blueprints, and questions rather than generic courses and lessons. The domain language in implementation should follow the exam-prep product unless product requirements change. - Known Scalar uncertainties include management question list/detail reads, platform login, payment return and polling semantics, entitlement-resource relationships, answer autosave idempotency, and asynchronous media/import job states. - The existing generic file download route is public and tenant-ignored. It must not be reused as the authorization boundary for paid education content. - The root build currently leaves Member and Pay disabled. Member is required for the first release; Pay should be activated only when the payment slice starts. - The desired execution order for an implementation agent is: module activation, tenant/auth shell, Scalar catalog adapter and contract tests, question read facade, practice creation, autosave and recovery, atomic submission and report, wrong questions/favorites, then full E2E and visual acceptance. - Each implementation change set should contain schema, seed data, domain implementation, tests, API documentation, one complete frontend slice, and verified commands. Mock data or an uncalled endpoint must not be reported as complete. - The issue tracker is the project’s self-hosted Gitea instance. This spec should be labeled `ready-for-agent` once published.
wangziqi added the
ready-for-agent
label 2026-07-27 07:43:37 +00:00
Author
Owner

Education 学生核心闭环阶段总结

已完成并已推送

Issue #2–#10 的代码实现已完成并推送到:

  • 分支:feature/education-core-loop
  • 汇总提交:ce02f8a feat(education): complete student core loop delivery
  • 远程:Gitea origin

已交付能力

  1. Education 模块外壳、配置、错误码、SQL 和权限种子。
  2. 租户解析与 Education context。
  3. Scalar 目录防腐层和错误/分页契约。
  4. 题目浏览、可见性过滤、练习配置预览。
  5. 可恢复练习会话、稳定题目顺序和内容版本快照。
  6. 幂等答案自动保存、版本/序号冲突保护和刷新恢复。
  7. 原子交卷、稳定报告、历史查询和报告快照。
  8. 错题本、掌握状态和错题复习入口。
  9. 收藏夹、幂等收藏/取消和收藏状态查询。
  10. 本地学生核心闭环 acceptance harness。

验证结果

  • mvn -pl yudao-module-education -am test:通过,401 tests,0 failures,0 errors。
  • mvn -pl yudao-module-education -am -DskipTests compile:通过。
  • mvn -pl yudao-server -am package -DskipTests:通过。
  • tools/education-student-harness/npm test:通过,6 个 Playwright 场景通过;smoke、contract、adapter tests 通过。
  • git diff --check:通过。

完成定义

Issue #2–#10 的“代码实现完成”已达成,对应子 issue 已关闭。

尚未完成 / 明确阻塞

以下不宣称已完成:

  • 真实 Student Web/H5 生产前端接入、lint、类型检查、生产构建。
  • 真实 Pilot 环境的 Member 登录、租户配置和浏览器 E2E。
  • 真实 Scalar endpoint smoke、固定上游版本和有效只读凭据验证。
  • 真实 MySQL 空库迁移、升级、回滚演练。
  • 生产 trace/request ID 与 Scalar request ID 关联证据。
  • 生产监控指标、日志脱敏和跨租户拒绝证据。

这些限制已记录在 docs/education/pilot-acceptance-runbook.md。因此本总控 issue 保持 open,作为真实 Pilot 验收和前端补齐的后续跟踪入口。

## Education 学生核心闭环阶段总结 ### 已完成并已推送 Issue #2–#10 的代码实现已完成并推送到: - 分支:`feature/education-core-loop` - 汇总提交:`ce02f8a feat(education): complete student core loop delivery` - 远程:Gitea `origin` ### 已交付能力 1. Education 模块外壳、配置、错误码、SQL 和权限种子。 2. 租户解析与 Education context。 3. Scalar 目录防腐层和错误/分页契约。 4. 题目浏览、可见性过滤、练习配置预览。 5. 可恢复练习会话、稳定题目顺序和内容版本快照。 6. 幂等答案自动保存、版本/序号冲突保护和刷新恢复。 7. 原子交卷、稳定报告、历史查询和报告快照。 8. 错题本、掌握状态和错题复习入口。 9. 收藏夹、幂等收藏/取消和收藏状态查询。 10. 本地学生核心闭环 acceptance harness。 ### 验证结果 - `mvn -pl yudao-module-education -am test`:通过,401 tests,0 failures,0 errors。 - `mvn -pl yudao-module-education -am -DskipTests compile`:通过。 - `mvn -pl yudao-server -am package -DskipTests`:通过。 - `tools/education-student-harness/npm test`:通过,6 个 Playwright 场景通过;smoke、contract、adapter tests 通过。 - `git diff --check`:通过。 ### 完成定义 Issue #2–#10 的“代码实现完成”已达成,对应子 issue 已关闭。 ### 尚未完成 / 明确阻塞 以下不宣称已完成: - 真实 Student Web/H5 生产前端接入、lint、类型检查、生产构建。 - 真实 Pilot 环境的 Member 登录、租户配置和浏览器 E2E。 - 真实 Scalar endpoint smoke、固定上游版本和有效只读凭据验证。 - 真实 MySQL 空库迁移、升级、回滚演练。 - 生产 trace/request ID 与 Scalar request ID 关联证据。 - 生产监控指标、日志脱敏和跨租户拒绝证据。 这些限制已记录在 `docs/education/pilot-acceptance-runbook.md`。因此本总控 issue 保持 open,作为真实 Pilot 验收和前端补齐的后续跟踪入口。
Sign in to join this conversation.
No description provided.