diff --git a/docs/education/migration/04-module-reuse-map.md b/docs/education/migration/04-module-reuse-map.md index 432ae90f..c7e4a842 100644 --- a/docs/education/migration/04-module-reuse-map.md +++ b/docs/education/migration/04-module-reuse-map.md @@ -56,9 +56,10 @@ Education must call public APIs, framework extension points, or events. It must ## Background processing, assets, and operational platform - **Target owner:** Infra platform plus owning domain modules -- **Public/framework capability to reuse:** Infra Job, Redis MQ, File, locks, idempotency, logging, tracing, Excel utilities, tenant propagation. -- **Education-owned gap:** Verified target primitives exist, but durable claim/lease/heartbeat/retry and malware-scanner equivalence are not proven. Education import/export business state is absent or not verified. -- **Allowed external-module change:** Infra Job/MQ/File/logging/observability plus owning Education/Pay/Mall/CRM handlers; scanner deployment or adapter ownership must be decided. +- **Public/framework capability to reuse:** Public Infra File APIs and framework tenant context; generic locks, logging, tracing, and scheduling remain platform capabilities when exposed through public contracts. +- **Education-owned delivered scope:** EDU-011 owns tenant import asset metadata and import jobs, including the five states `PREVIEW`, `PENDING`, `PROCESSING`, `COMPLETED`, and `FAILED`; lease/heartbeat/expired-lease recovery; bounded attempts; and duplicate safety. V4130 is the only delivered EDU-011 migration. Scanner absence defaults to fail-closed `UNAVAILABLE`; CSV/XLSX preview is metadata-only when no parser is available; execution requires both a clean scan and executable parsed content. +- **Deferred scope:** The export boundary currently defines request redaction only—answers and private fields are excluded—but generates no export file or export job. Production scanner integration, full parser availability, retention automation, dead-letter/operator tooling, partial-row reporting, and legacy asset migration remain deferred. +- **Allowed external-module change:** Education may call public Infra APIs only. It must not depend on Infra DOs, mappers, `ServiceImpl` classes, or implementation packages, and it does not move Education job state into Infra. ## Secondary learning, media, AI, and engagement diff --git a/docs/education/migration/07-decisions.md b/docs/education/migration/07-decisions.md index 3be3146f..a78fa50a 100644 --- a/docs/education/migration/07-decisions.md +++ b/docs/education/migration/07-decisions.md @@ -160,6 +160,20 @@ V4080/V4090 conditionally seed the five Education permissions (`education:capabi The accepted Manual Question Collection slice does not warrant a separate ADR: it applies the already-recorded native-authority, tenant-ownership, lifecycle, optimistic-concurrency, route-gating, and snapshot-preservation decisions to one narrower aggregate, without adding a hard-to-reverse architectural trade-off. +### EDU-011 bounded import/export-assets capability (resolved 2026-07-31) + +**Decision:** Education owns tenant import asset metadata and durable import-job business state. Infra remains the owner of generic private-file/platform facilities and is consumed only through public APIs. + +1. The import job has exactly five persisted states: `PREVIEW`, `PENDING`, `PROCESSING`, `COMPLETED`, and `FAILED`. +2. Processing uses atomic claim, fenced lease token, heartbeat, expired-lease recovery, bounded attempts, and duplicate-safe tenant command keys. +3. Scanning fails closed. With no configured scanner adapter the result is `UNAVAILABLE`, never implicitly clean. +4. CSV/XLSX may produce metadata-only preview when no parser is available. Such a preview is not executable; execute requires a clean scan and explicit executable parsed content. +5. Export scope is request redaction policy only: answers and private fields must be excluded. No generated export file, export worker, or export-job persistence is delivered. +6. V4130 is the only EDU-011 migration. Production scanner integration, full parser delivery, retention/deletion automation, dead-letter/operator tooling, partial-row reporting, and legacy asset migration remain deferred. +7. Education may use public Infra APIs but may not depend on Infra DOs, mappers, `ServiceImpl` classes, or private implementation packages. + +The bounded slice does not require a separate ADR: it keeps domain job state with Education and applies the repository's established public-module-boundary rule without introducing a new platform abstraction. + ## Unresolved decisions 1. Which Auth/Profile/extended Learning semantics are replaced by Member/System/Infra versus Education-owned, including vocabulary, leaderboard, stats, trend, feedback, exam dates, notifications, points, and badges. diff --git a/docs/education/migration/issues/EDU-011-import-export-assets.md b/docs/education/migration/issues/EDU-011-import-export-assets.md index e90e15aa..d4374bb5 100644 --- a/docs/education/migration/issues/EDU-011-import-export-assets.md +++ b/docs/education/migration/issues/EDU-011-import-export-assets.md @@ -1,32 +1,48 @@ -# EDU-011 — Content import, export, assets, and scanning +# EDU-011 — Bounded content import assets, jobs, and export policy -- **Status:** blocked +- **Status:** bounded capability delivered - **Type:** implementation program - **Phase:** 3 / 6 -- **Blockers:** EDU-010, Infra File contract, scanner ownership decision, durable job claim decision +- **Delivered migration:** V4130 only -## Tenant-admin outcome +## Delivered tenant-admin outcome -Administrators can import and export education content through durable, duplicate-safe jobs, with secure files, malware scanning, tenant propagation, audit, retries, and partial-failure reporting. +Education owns tenant-scoped import asset metadata and durable import jobs while reusing only public Infra APIs for private-file operations and other platform primitives. The delivered job lifecycle has exactly five states: `PREVIEW`, `PENDING`, `PROCESSING`, `COMPLETED`, and `FAILED`. -## Reuse +The bounded capability provides: -- Education owns import/export business state and content validation. -- Infra owns File, Job/MQ, locks, logging, and audit primitives. -- Scanner integration sits behind a clear adapter; Education does not implement generic storage or scheduling. +- durable atomic claim with lease token, heartbeat, expired-lease recovery, bounded attempts, and terminal failure; +- tenant-scoped duplicate safety for preview requests and execution, so at-least-once delivery does not create a second logical job or repeat completed effects; +- fail-closed scanning: the default scanner result is `UNAVAILABLE`, and unavailable, infected, or errored scans are never executable; +- CSV/XLSX preview metadata when no parser is available; this reports file/type metadata only and does not claim row parsing or content validation; +- execution only after the scan is clean and the preview explicitly reports executable parsed content; +- an export-request redaction policy that excludes answers and private fields from authorized export requests. -## Acceptance criteria +## Ownership and reuse boundary -- [ ] Preview and execute are distinct states. -- [ ] Jobs use atomic claim/lease/heartbeat/recovery semantics. -- [ ] At-least-once retries are duplicate-safe. -- [ ] File type, size, object key, access, and retention are enforced. -- [ ] Scanning fails closed. -- [ ] Tenant context propagates into asynchronous handlers. -- [ ] Exports redact answers and private fields according to authorization. -- [ ] Partial failures and dead letters are visible and auditable. +- Education owns `education_content_import_asset`, `education_content_import_job`, their business state, duplicate keys, lease/recovery semantics, preview policy, and execution orchestration. +- Infra continues to own generic file storage and platform facilities. Education integrates through public Infra APIs only; it does not depend on Infra DOs, mappers, `ServiceImpl` classes, or private implementation packages. +- V4130 is the only EDU-011 schema migration in this slice. No additional migration, generic scanner platform, generic scheduler, or Infra-internal extension is delivered. + +## Deferred scope + +- No generated export file, downloadable export artifact, export worker, or export-job persistence is delivered. Only the request-time redaction policy is established. +- No production malware-scanner integration is delivered; the default remains fail-closed `UNAVAILABLE` until an external scanner adapter is configured. +- No full CSV/XLSX parser is promised by the fallback. Without an available parser, preview remains metadata-only and execution is blocked. +- File retention/deletion automation, dead-letter tooling, operator UI, partial-row import reporting, and legacy asset migration/re-scan remain deferred. + +## Acceptance record + +- [x] Education-owned import assets and durable jobs are represented by V4130. +- [x] Jobs use the five-state lifecycle `PREVIEW`, `PENDING`, `PROCESSING`, `COMPLETED`, `FAILED`. +- [x] Claim, lease, heartbeat, expired-lease recovery, retry bounds, and duplicate safety are defined. +- [x] Scanning fails closed, with default `UNAVAILABLE`. +- [x] CSV/XLSX can return metadata-only preview when the parser is unavailable. +- [x] Execute is blocked unless scanning is clean and preview content is executable. +- [x] Export requests apply answer/private-field redaction policy. +- [ ] Generated export files and the remaining operational features are deferred as listed above. ## Risk and rollback -- **Risk:** High operational and file-security risk. -- **Rollback:** Disable job handlers and preserve job/business state for forward recovery. +- **Risk:** Import processing remains security-sensitive; scanner or parser absence intentionally removes executability rather than degrading silently. +- **Rollback:** Disable import handlers while preserving Education asset/job state for inspection and forward recovery. Do not bypass scan or executable-preview gates. diff --git a/yudao-module-education/CONTEXT.md b/yudao-module-education/CONTEXT.md index 508893aa..480cbb3f 100644 --- a/yudao-module-education/CONTEXT.md +++ b/yudao-module-education/CONTEXT.md @@ -104,17 +104,29 @@ _Avoid_: Question publication, snapshot invalidation Descriptive collection metadata reserved for a future access contract. Its presence does not grant, deny, or prove paid, private, membership, or other entitlement in the current Education model. _Avoid_: Entitlement policy, authorization rule -**Category Publication State**: -The lifecycle of a tenant-owned Subject-scoped Category: Draft is author-editable and student-invisible, Active is immutable and discoverable, and Archived is terminal and undiscoverable. Category does not classify Questions. -_Avoid_: Question Placement, question category relation +**Content Import Asset**: +Tenant-owned metadata that identifies one private Infra-managed source object for an Education import. Education owns the business reference and checksum metadata, not generic file storage or a public download URL. +_Avoid_: Uploaded file owned by Education, public asset URL -**Practice Blueprint**: -A bounded tenant-owned practice configuration attached to exactly one active current-tenant Content Node or Manual Question Collection. Its route and eligible counts are server-derived; it does not define dynamic filtering, entitlement, or descendant traversal. -_Avoid_: Dynamic query, paid practice policy +**Content Import Job**: +A tenant-owned durable Education job that previews and, only when safe and executable, imports content from one Content Import Asset. Its five states are `PREVIEW`, `PENDING`, `PROCESSING`, `COMPLETED`, and `FAILED`. +_Avoid_: Generic Infra job, export job -**Practice Blueprint Publication State**: -The lifecycle of a Practice Blueprint: Draft is author-editable and student-invisible, Active is immutable and returned only while its target route remains available, and Archived is terminal and unavailable. -_Avoid_: Boolean availability as an independent state +**Import Job Lease**: +A fenced, expiring claim on a `PROCESSING` Content Import Job, identified by worker and lease token and kept alive by heartbeat. Expiry permits bounded recovery; it is not proof that the prior worker stopped. +_Avoid_: Redis lock as job ownership, permanent worker assignment + +**Executable Import Preview**: +A preview whose source scan is clean and whose available parser produced executable content. Metadata-only CSV/XLSX preview is informative but not executable. +_Avoid_: Successful upload, clean scan alone + +**Unavailable Import Scan**: +The fail-closed default when no scanner adapter can produce a clean result. `UNAVAILABLE`, infected, and errored scan outcomes all block execution. +_Avoid_: Scan skipped, assumed clean + +**Export Redaction Policy**: +The request-time rule that authorized Education exports must omit answers and private fields. The current bounded capability defines this policy only; it does not generate an export file or persist an export job. +_Avoid_: Delivered export pipeline, downloadable export artifact **Protected Answer Key**: Server-only correctness and explanation data captured for stable scoring of a practice session. It is never included in a Safe Question, Question Snapshot JSON, or pre-submit response.