docs(education): define manual collection contract

This commit is contained in:
2026-07-31 01:25:52 +08:00
parent 2daeb43c5a
commit 62bbdd4b87
3 changed files with 73 additions and 10 deletions

View File

@@ -1,6 +1,6 @@
# EDU-010 — Tenant content publication and graph integrity
- **Status:** in progress — catalog graph-integrity, JAVA_READ tenant-question lifecycle, Question Placement, and tenant Content Node lifecycle slices are delivered; category, collection, and blueprint authoring remain
- **Status:** in progress — catalog graph-integrity, JAVA_READ tenant-question lifecycle, Question Placement, and tenant Content Node lifecycle slices are delivered; the Manual Question Collection slice is contract-ready but not implemented; category and blueprint authoring remain
- **Type:** implementation program
- **Phase:** 3
- **Blockers:** EDU-004 ✓ (done), EDU-009 ✓ (done), provider-authority decision ✓ (resolved 2026-07-30, see decisions.md), PUBLIC graph-semantics decision ✓ (resolved 2026-07-30, see decisions.md)
@@ -28,6 +28,11 @@ Authorized tenant administrators can author, classify, publish, archive, and ret
- [x] Publication is transactional and auditable.
- [x] Tenant Question Placement is permission-separated, tenant-safe, optimistic, and frozen after publication.
- [x] Database graph-integrity changes use `flyway-postgresql` and forward migrations V4070/V4090.
- [x] The next Manual Question Collection bounded contract, exclusions, pre-provisioning constraint, and readiness gates are explicit before implementation.
- [ ] A current-tenant `TENANT_OWNED` Manual Question Collection can be authored only in `JAVA_READ` on an existing ACTIVE, visible Content Node.
- [ ] Collection lifecycle is `DRAFT → ACTIVE → ARCHIVED` with one optimistic authoring version; ACTIVE content/membership is immutable and archive is terminal.
- [ ] DRAFT membership is ordered replace-all, accepts only current-tenant `TENANT_OWNED` PUBLISHED Questions, and rejects duplicates.
- [ ] Collection archive gates only collection-route discovery while direct Question visibility and historical Practice snapshots remain unchanged.
## Delivery progress — graph-integrity slice (2026-07-30)
@@ -98,6 +103,35 @@ Delivered:
- Activation/archive append an actor/version/status audit in the same transaction. V4100 makes that audit append-only and uses a deferred constraint trigger to reject lifecycle changes without the matching audit.
- Student catalog discovery and Question Placement continue to require `is_active=true`; V4100 constrains that flag to `publication_status='ACTIVE'`, so drafts/archives cannot appear or accept placement.
## Next slice — Manual Question Collection bounded contract (accepted 2026-07-31)
This section records domain and readiness decisions only. No production Java, SQL, Flyway migration, permission seed, or runtime behavior is delivered by this documentation step.
Accepted boundary:
1. Native authority only: every collection command is available only in `JAVA_READ`; unsupported modes must fail before persistence access.
2. Tenant ownership only: tenant APIs manage current-tenant `TENANT_OWNED` collections. PUBLIC Questions, PUBLIC collection curation, and platform-curator workflows are excluded.
3. Placement boundary: a collection belongs to one existing ACTIVE, visible Content Node. Content Entry creation is excluded, so that node and its structurally available Content Entry must already be provisioned before collection authoring.
4. Manual assembly only: membership is an explicit ordered list, not a dynamic filter, Category result, Question Bank query, node-descendant query, or Practice Blueprint.
5. Lifecycle and concurrency: collections move only `DRAFT → ACTIVE → ARCHIVED`. One optimistic authoring version covers accepted draft revisions, ordered membership replacement, activation, and archive. ACTIVE collection fields and membership are immutable; ARCHIVED is terminal.
6. Membership replacement: only a DRAFT collection accepts an ordered replace-all membership command. Every member must be a current-tenant `TENANT_OWNED` PUBLISHED Question. Duplicate Question IDs are a request conflict and are not deduplicated or upserted.
7. Visibility: an ACTIVE collection may be discovered only through its available Content Node. Archive closes collection listing and collection-question discovery, but does not archive member Questions, change their direct visibility, or invalidate immutable Practice Question Snapshots already captured.
8. Access metadata: `access_rules` remains descriptive reserved metadata. This slice does not interpret it as paid, private, member, SVIP, quota, or other entitlement enforcement.
9. Explicit exclusions: dynamic filters, paid/private access, Category CRUD, Practice Blueprint authoring, Content Entry creation, PUBLIC content/curation, Retire, and legacy section/score/required membership extensions.
### Readiness and implementation gates
- [x] Current target evidence identifies `education_question_collection_question` as the sole collection-membership fact, with tenant-scoped duplicate prevention and deterministic membership order.
- [x] Legacy evidence confirms manual collections, transactional replace-all membership, server-derived counts, active-parent route gating, and an independent `DRAFT/ACTIVE/ARCHIVED` lifecycle; richer dynamic/filter and per-member scoring semantics are deliberately excluded.
- [x] Provider-neutral option safety is already resolved by EDU-001 and `QuestionContentSafety`; it is not an EDU-010 blocker.
- [x] Root Education SQL is already classified as non-operational manual/design history by EDU-005; module-owned PostgreSQL Flyway remains authoritative. Shared-environment adoption inventory remains an operational rollout gate, not an unresolved schema-owner decision.
- [ ] Before implementation, allocate the next project-wide Flyway version through `flyway-postgresql` and design forward adoption from the current boolean collection availability fields.
- [ ] Make collection listing and collection-question reads validate collection lifecycle and Content Node availability at the route boundary; the current Java collection-question read loads membership without first proving the parent collection is available.
- [ ] Define separate collection author/publish/archive permissions, tenant-bound command requests, lifecycle audit, CAS conflict errors, server-derived `question_count`, and transaction boundaries.
- [ ] Add focused service, method-security, and real-PostgreSQL tests for provider fail-before-Mapper behavior, cross-tenant/PUBLIC rejection, duplicate membership, stale versions, ACTIVE immutability, terminal archive, route gating, direct Question visibility, and snapshot preservation.
No new ADR is added: this bounded slice consistently applies the existing native-authority and lifecycle decisions and does not introduce a separate hard-to-reverse architectural trade-off.
## Verification evidence (2026-07-30)
- `mvn -pl yudao-module-education clean test` with the five `EDU_TEST_POSTGRES_*` variables pointed at the local Docker PostgreSQL: **502 tests passed**, including 20 Flyway migration tests and nine lifecycle/placement PostgreSQL integration tests. V4090 was actually executed in disposable PostgreSQL schemas.