Domain & Database Design
Mô hình miền, kiến trúc dữ liệu và thiết kế cơ sở dữ liệu Cloudflare D1, R2 và Vectorize
1. Document Purpose
Click to view detailed specifications & content
Tài liệu này mô tả thiết kế dữ liệu của EduOne Adaptive Learning Engine, bao gồm:
- Domain Model.
- Bounded Contexts.
- Aggregate boundaries.
- Data ownership.
- Logical Data Model.
- Cloudflare D1 database design.
- Cloudflare R2 object storage design.
- Cloudflare Vectorize index design.
- Cache design.
- Event and workflow data.
- Audit data.
- Versioning.
- Data consistency.
- Data lifecycle.
- Backup và recovery.
- Data privacy.
- Prototype schema.
- Pilot expansion plan.
Tài liệu này chưa mô tả chi tiết:
- REST API endpoints.
- Request và response schema.
- Workflow implementation code.
- AI prompt design.
- Recommendation algorithms.
Các nội dung đó sẽ nằm trong các phần tiếp theo của SDD.
2. Data Architecture Objectives
Click to view detailed specifications & content

Kiến trúc dữ liệu phải đáp ứng các mục tiêu sau.
DAO-01 — User (Traceability
Mọi recommendation phải có thể truy ngược về:
- Learner state.
- Evidence.
- Content candidates.
- Business rules.
- Model hoặc rule version.
- Người thực hiện override.
DAO-02 — Content safety
Hệ thống phải phân biệt rõ:
- Draft content.
- Content đang review.
- Approved content.
- Published content.
- Unpublished content.
Recommendation Engine không được lựa chọn content chưa được phê duyệt.
DAO-03 — Versionability
Các thực thể quan trọng phải có version:
- Skill.
- Indicator.
- Content item.
- Prompt.
- Recommendation policy.
- Learner state calculation method.
- Quality model.
DAO-04 — Reconstructability
Learner state phải có thể được tính lại từ evidence lịch sử nếu thuật toán thay đổi.
DAO-05 — Explainability
Dữ liệu phục vụ explanation không được chỉ tồn tại dưới dạng một đoạn văn do LLM tạo ra.
Explanation phải được xây dựng từ dữ liệu có cấu trúc:
- Reason codes.
- Evidence references.
- State snapshot.
- Candidate evaluation.
- Decision output.
DAO-06 — Cost efficiency
Dữ liệu quan hệ và giao dịch được lưu trong D1.
File, tài liệu lớn và artifact được lưu trong R2.
Embedding và semantic retrieval được lưu trong Vectorize.
Không lưu cùng một dữ liệu lớn ở nhiều hệ thống nếu không cần thiết.
DAO-07 — Dirty data tolerance
Hệ thống phải chấp nhận dữ liệu:
- Thiếu.
- Trùng.
- Đến trễ.
- Không có mapping.
- Không hoàn thành.
- Mâu thuẫn.
Dữ liệu không hợp lệ phải được đánh dấu và cô lập thay vì làm hỏng toàn bộ pipeline.
3. Cloudflare Data Services
Click to view detailed specifications & content
3.1. Cloudflare D1
D1 là relational database chính của hệ thống.
D1 được sử dụng cho:
- User và role.
- Course và class.
- Skill và indicator.
- Quiz và question.
- Submission và evidence.
- Learner state.
- Recommendation.
- Content metadata.
- Review workflow state.
- Audit events.
- AI usage records.
- Workflow references.
D1 hỗ trợ foreign key constraints giữa các bảng, vì vậy hệ thống có thể dùng foreign keys để bảo vệ tính toàn vẹn của các quan hệ cốt lõi.
Các Workers truy cập D1 thông qua environment bindings; database không được expose trực tiếp ra client.
3.2. Cloudflare R2
R2 được sử dụng cho unstructured hoặc large objects:
- Lesson documents.
- Generated content artifacts.
- Images.
- Attachments.
- Export packages.
- Dataset snapshots.
- Audit exports.
- Large AI input/output.
- Backup artifacts.
R2 là object storage phù hợp cho dữ liệu phi cấu trúc và có thể được truy cập từ Workers thông qua R2 bindings hoặc qua giao diện tương thích S3.
R2 cung cấp strong global consistency cho các thao tác được mô tả trong consistency model của dịch vụ.
3.3. Cloudflare Vectorize
Vectorize được sử dụng cho:
- Semantic content search.
- Similar-content detection.
- Retrieval-Augmented Generation.
- Content reuse.
- Duplicate lesson detection.
- Reference content retrieval.
- Semantic recommendation support.
Vectorize là vector database phân tán tích hợp với Workers và hỗ trợ metadata filtering khi truy vấn.
Metadata nên được dùng để giới hạn semantic search theo:
- Tenant.
- Course.
- Grade.
- Language.
- Content status.
- Skill.
- Indicator.
- Content type.
Vectorize hỗ trợ lưu metadata cùng vector và tạo metadata indexes để phục vụ filtering; số trường metadata được index cần được lựa chọn cẩn thận thay vì index mọi thuộc tính.
3.4. Cloudflare Cache API
Cache API được sử dụng cho:
- Public hoặc semi-public course metadata.
- Published content.
- Skill map ít thay đổi.
- Recommendation candidate catalogs.
- Non-sensitive aggregate reports.
- Configuration được đọc thường xuyên.
Cache không phải source of truth.
3.5. Cloudflare Workflows state
Cloudflare Workflows được dùng cho các tiến trình nhiều bước cần durable execution, retry, pause hoặc chờ human approval.
Workflow state không thay thế database nghiệp vụ.
D1 vẫn là source of truth cho:
- Trạng thái content.
- Approval.
- Evidence.
- Recommendation.
- Audit.
Workflow chịu trách nhiệm orchestration.
4. Data Storage Decision Matrix
Click to view detailed specifications & content
| Loại dữ liệu | Primary Store | Secondary Store | Lý do |
|---|---|---|---|
| User, role, permission | D1 | Không | Dữ liệu quan hệ |
| Course, lesson metadata | D1 | Cache | Query thường xuyên |
| Skill, indicator | D1 | Cache | Cấu trúc quan hệ |
| Quiz, question metadata | D1 | R2 nếu body lớn | Query giao dịch |
| Submission | D1 | R2 archive tùy quy mô | Cần audit |
| Evidence | D1 | Không | Source of truth |
| Learner state | D1 | Cache tùy trường hợp | Trạng thái hiện tại |
| Learner state history | D1 | R2 archive | Phân tích lịch sử |
| Recommendation | D1 | Không | Explainability |
| Candidate evaluation | D1 hoặc R2 | R2 khi payload lớn | Audit |
| Content metadata | D1 | Vectorize metadata | Filtering |
| Content body | R2 | D1 excerpt | Object lớn |
| Content embeddings | Vectorize | D1 reference | Semantic search |
| Review status | D1 | Không | Transactional |
| Review attachments | R2 | D1 reference | Object lớn |
| Prompt template | D1 | R2 nếu dài | Versioning |
| AI request/response | D1 summary | R2 full payload | Cost và audit |
| Analytics aggregates | D1 | R2 export | Dashboard |
| Audit events | D1 | R2 archive | Traceability |
| Workflow instance data | D1 reference | Workflow runtime | Orchestration |
5. Domain-Driven Design Overview
Click to view detailed specifications & content
Hệ thống được chia thành các bounded contexts.
EduOne Platform
│
├── Identity & Access Context
├── Curriculum Context
├── Learning Delivery Context
├── Learner Intelligence Context
├── Recommendation Context
├── Content Production Context
├── Content Governance Context
├── Analytics Context
└── Platform Operations ContextMỗi bounded context sở hữu dữ liệu nghiệp vụ của mình.
Không component nào được phép thay đổi trực tiếp dữ liệu thuộc context khác mà không đi qua application service hoặc domain operation được định nghĩa.
6. Bounded Contexts
Click to view detailed specifications & content
6.1. Identity & Access Context
Trách nhiệm
- User identity.
- Role.
- Permission.
- Class membership.
- Organization membership.
- Account status.
Aggregate Roots
- User.
- Role.
- Membership.
Các thực thể chính
User
├── UserRole
├── UserProfile
└── MembershipData owner
Administration Engine.
6.2. Curriculum Context
Trách nhiệm
- Course structure.
- Module.
- Lesson.
- Learning objective.
- Skill.
- Indicator.
- Prerequisite.
- Proficiency levels.
- Curriculum version.
Aggregate Roots
- Course.
- Competency Framework.
- Skill.
- Curriculum Version.
Data owner
Knowledge Engine.
6.3. Learning Delivery Context
Trách nhiệm
- Class.
- Enrollment.
- Learning assignment.
- Activity session.
- Quiz.
- Submission.
- Completion.
Aggregate Roots
- Class.
- Learning Activity.
- Quiz.
- Submission.
Data owner
Learning Delivery component.
6.4. Learner Intelligence Context
Trách nhiệm
- Evidence.
- Learner state.
- Mastery estimate.
- Confidence.
- Learning pace.
- State history.
- Evidence quality.
Aggregate Roots
- Learner Model.
- Evidence Record.
Data owner
Learner Engine.
6.5. Recommendation Context
Trách nhiệm
- Candidate generation.
- Candidate filtering.
- Ranking.
- Recommendation.
- Reason codes.
- Recommendation log.
- Override.
Aggregate Roots
- Recommendation Decision.
- Teacher Override.
Data owner
Recommendation Engine.
6.6. Content Production Context
Trách nhiệm
- Content request.
- AI draft.
- Content sections.
- Prompt version.
- Generation jobs.
- Quality findings.
Aggregate Roots
- Content Request.
- Content Draft.
- AI Generation Job.
Data owner
Content Engine.
6.7. Content Governance Context
Trách nhiệm
- Human review.
- Approval.
- Publication.
- Revision.
- Rejection.
- Content version.
- Review checklist.
Aggregate Roots
- Content Item.
- Content Review.
- Publication.
Data owner
Review Engine và Knowledge Engine.
6.8. Analytics Context
Trách nhiệm
- Product metrics.
- Learning metrics.
- Content metrics.
- Cost metrics.
- Aggregated reporting.
Aggregate Roots
- Metric Snapshot.
- Report.
Data owner
Analytics Engine.
6.9. Platform Operations Context
Trách nhiệm
- Audit events.
- AI usage.
- Workflow tracking.
- Error records.
- Data import/export.
- System configuration.
Aggregate Roots
- Audit Event.
- Workflow Record.
- AI Usage Record.
- System Configuration.
Data owner
Administration Engine và Analytics Engine.
7. Aggregate Design
Click to view detailed specifications & content
7.1. Course Aggregate
Course
├── CourseVersion
├── Module
├── Lesson
├── LearningObjective
└── CourseSkillMappingInvariants
- Course phải có ít nhất một version.
- Published course version không được sửa trực tiếp.
- Lesson phải thuộc một course version.
- Learning objective phải có mã định danh ổn định.
- Archived course không nhận enrollment mới.
7.2. Skill Aggregate
Skill
├── SkillVersion
├── Indicator
├── IndicatorVersion
├── ProficiencyLevel
└── PrerequisiteRelationshipInvariants
- Indicator phải thuộc một skill.
- Một indicator version đã được sử dụng trong evidence không được xóa vật lý.
- Quan hệ prerequisite không được tạo vòng lặp nếu business rule cấm cyclic prerequisites.
- Version mới không được làm thay đổi ý nghĩa evidence cũ.
7.3. Quiz Aggregate
Quiz
├── QuizVersion
├── Question
├── QuestionOption
├── AnswerKey
└── IndicatorMappingInvariants
- Published quiz phải có answer key nếu loại câu hỏi yêu cầu.
- Question dùng để cập nhật learner state phải có indicator mapping hợp lệ.
- Quiz version đã có submission không được sửa trực tiếp.
- Mọi sửa đổi tạo version mới.
7.4. Submission Aggregate
Submission
├── SubmissionAnswer
├── ValidationResult
├── ScoringResult
└── EvidenceReferenceInvariants
- Một submission có idempotency key.
- Một idempotency key chỉ được xử lý một lần.
- Submission có thể incomplete.
- Invalid submission vẫn có thể được lưu để audit nhưng không nhất thiết tạo evidence.
- Submission đã finalized không được thay đổi; correction tạo record mới.
7.5. Learner Model Aggregate
LearnerModel
├── LearnerIndicatorState
├── LearnerSkillState
├── PaceState
└── ModelSnapshotInvariants
- Mỗi learner chỉ có một current state cho một indicator version trong một course context.
- Current state phải tham chiếu model version.
- Confidence phải nằm trong miền giá trị hợp lệ.
- State update phải tham chiếu ít nhất một evidence hoặc reason code đặc biệt.
- Evidence lịch sử không bị ghi đè khi learner state thay đổi.
7.6. Recommendation Aggregate
RecommendationDecision
├── InputSnapshot
├── CandidateEvaluation
├── SelectedCandidate
├── Reason
├── Alternative
└── OutcomeInvariants
- Selected content phải ở trạng thái published tại thời điểm quyết định.
- Recommendation phải ghi content version cụ thể.
- Recommendation phải lưu learner state snapshot.
- Recommendation phải có policy version.
- Override không xóa recommendation gốc.
- Nếu không có candidate, recommendation result phải là fallback hoặc no-match.
7.7. Content Item Aggregate
ContentItem
├── ContentVersion
├── ContentSection
├── ContentMetadata
├── QualityFinding
├── Review
└── PublicationInvariants
- Content version chỉ có một trạng thái hiện tại.
- Published version phải có approval.
- Approval phải tham chiếu reviewer.
- Blocking quality issue phải được resolved hoặc explicitly overridden bởi người có quyền.
- Draft version không được Recommendation Engine sử dụng.
- Mỗi publication tham chiếu chính xác content version.
8. Canonical Identifiers
Click to view detailed specifications & content
Tất cả entity phải dùng identifier không mang ý nghĩa nghiệp vụ quá sâu.
Khuyến nghị sử dụng:
usr_xxx)
org_xxx (Organization)
cls_xxx (Class)
crs_xxx (Course)
mod_xxx (Module)
lsn_xxx (Lesson)
skl_xxx (Skill)
ind_xxx (Indicator)
qiz_xxx (Quiz)
qst_xxx (Question)
sub_xxx (Submission)
evd_xxx (Evidence)
lms_xxx (Learner Model)
rec_xxx (Recommendation)
cnt_xxx (Content Item)
ver_xxx (Version/Revision)
rev_xxx (Review)
pub_xxx (Publication)
wfl_xxx (Workflow)
aud_xxx (Audit Event)ID có thể được tạo bằng:
- UUID (v7).
- ULID.
- CUID2.
Ưu tiên ID có khả năng sắp xếp gần theo thời gian như UUIDv7 hoặc ULID, nhưng không được dùng thời gian trong ID như nguồn thời gian chính thức.
Mọi bảng vẫn phải có:
created_at.updated_at.created_bykhi phù hợp.versionhoặcrevision_nokhi phù hợp.
9. Multi-Tenancy Model
Click to view detailed specifications & content
Prototype có thể chỉ có một organization, nhưng schema nên hỗ trợ multi-tenancy ngay từ đầu.
Tenant root
Organization
└── Courses
└── Classes
└── Users
└── Content
└── Learner DataCác bảng nghiệp vụ chính nên có trường organization_id.
Quy tắc
- Mọi query nghiệp vụ phải được scope theo
organization_id. - Vectorize metadata phải chứa tenant hoặc organization identifier.
- R2 object key phải được phân vùng theo organization.
- Audit event phải ghi organization.
- Không dùng client-provided organization ID mà không kiểm tra membership.
Bối cảnh Prototype
organization_id = org_eduone10. Logical Data Model
Click to view detailed specifications & content
Organization
├── User
│ └── UserRole
├── Course
│ ├── CourseVersion
│ ├── Module
│ ├── Lesson
│ └── LearningObjective
├── Skill
│ ├── SkillVersion
│ ├── Indicator
│ └── IndicatorVersion
├── Class
│ ├── Enrollment
│ └── Assignment
├── Quiz
│ ├── QuizVersion
│ ├── Question
│ └── QuestionIndicatorMap
├── Submission
│ ├── SubmissionAnswer
│ └── Evidence
├── LearnerModel
│ ├── LearnerIndicatorState
│ └── LearnerStateHistory
├── ContentItem
│ ├── ContentVersion
│ ├── ContentMetadata
│ ├── QualityFinding
│ └── ContentReview
├── Recommendation
│ ├── CandidateEvaluation
│ ├── RecommendationReason
│ └── TeacherOverride
├── WorkflowRecord
├── AIUsageRecord
└── AuditEvent11. D1 Database Strategy
Click to view detailed specifications & content
11.1. Database organization
Đối với prototype, sử dụng một D1 database duy nhất: eduone-prototype-db
Các bounded contexts được tách bằng:
- Table naming prefix.
- Repository layer.
- Application services.
- Access boundaries trong code.
Không cần tách nhiều D1 databases trong hackathon vì sẽ tăng độ phức tạp không đáng có.
11.2. Pilot strategy
Trong pilot vẫn có thể giữ một database nếu quy mô nhỏ. Chỉ cân nhắc tách database khi xuất hiện nhu cầu rõ ràng (quy mô dữ liệu learner quá lớn, tách riêng analytics workloads, dữ liệu cô lập địa lý,...).
11.3. Naming convention
SQLite/D1 không sử dụng schema namespace giống một số RDBMS khác, do đó dùng prefix để tách:
iam_(Identity & Access)cur_(Curriculum)lrn_(Learning Delivery)evd_(Evidence & Learner Model)rec_(Recommendation)cnt_(Content Items & Versions)rev_(Quality & Review)ana_(Analytics)ops_(Platform Operations)
12. D1 Core Tables
Click to view detailed specifications & content
12.1. Identity Tables
iam_organizations
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
name | TEXT | NOT NULL |
slug | TEXT | UNIQUE, NOT NULL |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
updated_at | TEXT | NOT NULL |
iam_users
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK references iam_organizations(id) |
external_identity_id | TEXT | UNIQUE |
email | TEXT | NULLABLE |
display_name | TEXT | NOT NULL |
user_type | TEXT | NOT NULL |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
updated_at | TEXT | NOT NULL |
iam_roles
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK references iam_organizations(id) |
code | TEXT | NOT NULL |
name | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
iam_user_roles
| Column | Type | Constraints |
|---|---|---|
user_id | TEXT | FK references iam_users(id) |
role_id | TEXT | FK references iam_roles(id) |
scope_type | TEXT | NOT NULL |
scope_id | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
Composite primary key: (user_id, role_id, scope_type, scope_id)
12.2. Curriculum Tables
cur_courses
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK references iam_organizations(id) |
code | TEXT | NOT NULL |
title | TEXT | NOT NULL |
description | TEXT | NULLABLE |
status | TEXT | NOT NULL |
current_version_id | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
updated_at | TEXT | NOT NULL |
cur_course_versions
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
course_id | TEXT | FK references cur_courses(id) |
version_no | INTEGER | NOT NULL |
version_label | TEXT | NOT NULL |
status | TEXT | NOT NULL |
effective_from | TEXT | NULLABLE |
created_by | TEXT | FK references iam_users(id) |
created_at | TEXT | NOT NULL |
Unique constraint: (course_id, version_no)
cur_modules
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
course_version_id | TEXT | FK references cur_course_versions(id) |
title | TEXT | NOT NULL |
sequence_no | INTEGER | NOT NULL |
status | TEXT | NOT NULL |
cur_lessons
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
module_id | TEXT | FK references cur_modules(id) |
stable_key | TEXT | NOT NULL |
title | TEXT | NOT NULL |
sequence_no | INTEGER | NOT NULL |
estimated_duration_minutes | INTEGER | NOT NULL |
status | TEXT | NOT NULL |
stable_key cho phép nhận diện lesson xuyên qua các curriculum version.
cur_learning_objectives
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
lesson_id | TEXT | FK references cur_lessons(id) |
code | TEXT | NOT NULL |
statement | TEXT | NOT NULL |
sequence_no | INTEGER | NOT NULL |
status | TEXT | NOT NULL |
12.3. Skill and Indicator Tables
cur_skills
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
stable_key | TEXT | NOT NULL |
domain_code | TEXT | NOT NULL |
status | TEXT | NOT NULL |
current_version_id | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
cur_skill_versions
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
skill_id | TEXT | FK references cur_skills(id) |
version_no | INTEGER | NOT NULL |
name | TEXT | NOT NULL |
description | TEXT | NULLABLE |
proficiency_model_id | TEXT | NOT NULL |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
cur_indicators
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
skill_id | TEXT | FK references cur_skills(id) |
stable_key | TEXT | NOT NULL |
status | TEXT | NOT NULL |
current_version_id | TEXT | NULLABLE |
cur_indicator_versions
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
indicator_id | TEXT | FK references cur_indicators(id) |
version_no | INTEGER | NOT NULL |
name | TEXT | NOT NULL |
description | TEXT | NULLABLE |
observable_behavior | TEXT | NULLABLE |
mastery_threshold | REAL | NOT NULL |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
cur_prerequisites
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
source_type | TEXT | NOT NULL (e.g., 'INDICATOR', 'SKILL') |
source_id | TEXT | NOT NULL |
target_type | TEXT | NOT NULL |
target_id | TEXT | NOT NULL |
relationship_type | TEXT | NOT NULL (e.g., 'REQUIRES') |
minimum_level | REAL | NOT NULL |
created_at | TEXT | NOT NULL |
Ví dụ: source = indicator_B, target = indicator_A, relationship_type = 'REQUIRES'. Nghĩa là B yêu cầu A.
cur_objective_indicator_maps
| Column | Type | Constraints |
|---|---|---|
learning_objective_id | TEXT | FK references cur_learning_objectives(id) |
indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
weight | REAL | NOT NULL |
mapping_type | TEXT | NOT NULL |
12.4. Class and Enrollment Tables
lrn_classes
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
course_id | TEXT | FK references cur_courses(id) |
title | TEXT | NOT NULL |
teacher_id | TEXT | FK references iam_users(id) |
start_at | TEXT | NOT NULL |
end_at | TEXT | NULLABLE |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
lrn_enrollments
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
class_id | TEXT | FK references lrn_classes(id) |
student_id | TEXT | FK references iam_users(id) |
enrolled_at | TEXT | NOT NULL |
status | TEXT | NOT NULL |
learning_goal | TEXT | NULLABLE |
current_lesson_id | TEXT | NULLABLE references cur_lessons(id) |
Unique constraint: (class_id, student_id)
lrn_assignments
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
class_id | TEXT | FK references lrn_classes(id) |
content_version_id | TEXT | FK references cnt_content_versions(id) |
assigned_by | TEXT | FK references iam_users(id) |
assignment_type | TEXT | NOT NULL |
assigned_at | TEXT | NOT NULL |
due_at | TEXT | NULLABLE |
status | TEXT | NOT NULL |
12.5. Quiz Tables
lrn_quizzes
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
stable_key | TEXT | NOT NULL |
title | TEXT | NOT NULL |
status | TEXT | NOT NULL |
current_version_id | TEXT | NULLABLE |
lrn_quiz_versions
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
quiz_id | TEXT | FK references lrn_quizzes(id) |
version_no | INTEGER | NOT NULL |
content_version_id | TEXT | FK references cnt_content_versions(id) |
scoring_method | TEXT | NOT NULL |
max_score | REAL | NOT NULL |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
lrn_questions
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
quiz_version_id | TEXT | FK references lrn_quiz_versions(id) |
question_type | TEXT | NOT NULL (e.g., 'MCQ', 'CODE') |
body_text | TEXT | NOT NULL |
body_r2_key | TEXT | NULLABLE |
sequence_no | INTEGER | NOT NULL |
max_score | REAL | NOT NULL |
difficulty | TEXT | NOT NULL |
status | TEXT | NOT NULL |
lrn_question_options
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
question_id | TEXT | FK references lrn_questions(id) |
option_key | TEXT | NOT NULL |
option_text | TEXT | NOT NULL |
is_correct | INTEGER | NOT NULL (0 or 1) |
sequence_no | INTEGER | NOT NULL |
lrn_question_indicator_maps
| Column | Type | Constraints |
|---|---|---|
question_id | TEXT | FK references lrn_questions(id) |
indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
weight | REAL | NOT NULL |
evidence_type | TEXT | NOT NULL |
12.6. Submission Tables
lrn_submissions
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
class_id | TEXT | FK references lrn_classes(id) |
student_id | TEXT | FK references iam_users(id) |
quiz_version_id | TEXT | FK references lrn_quiz_versions(id) |
idempotency_key | TEXT | NOT NULL |
attempt_no | INTEGER | NOT NULL |
status | TEXT | NOT NULL |
started_at | TEXT | NOT NULL |
submitted_at | TEXT | NULLABLE |
total_score | REAL | NULLABLE |
max_score | REAL | NOT NULL |
duration_seconds | INTEGER | NULLABLE |
validation_status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
Unique constraint: (organization_id, idempotency_key)
lrn_submission_answers
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
submission_id | TEXT | FK references lrn_submissions(id) |
question_id | TEXT | FK references lrn_questions(id) |
answer_text | TEXT | NULLABLE |
selected_option_id | TEXT | NULLABLE references lrn_question_options(id) |
score | REAL | NULLABLE |
is_correct | INTEGER | NULLABLE (0 or 1) |
answered_at | TEXT | NOT NULL |
validation_status | TEXT | NOT NULL |
lrn_submission_issues
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
submission_id | TEXT | FK references lrn_submissions(id) |
issue_code | TEXT | NOT NULL |
severity | TEXT | NOT NULL (e.g., 'WARNING', 'BLOCKER') |
details_json | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
Ví dụ Issue codes: DUPLICATE_SUBMISSION, INCOMPLETE_SUBMISSION, MISSING_INDICATOR_MAPPING, UNUSUAL_DURATION, LATE_EVENT, INVALID_ANSWER.
12.7. Evidence Tables
evd_evidence
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
student_id | TEXT | FK references iam_users(id) |
class_id | TEXT | FK references lrn_classes(id) |
indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
source_type | TEXT | NOT NULL (e.g., 'QUIZ_ANSWER', 'QUIZ_RESULT') |
source_id | TEXT | NOT NULL |
observed_value | REAL | NOT NULL |
normalized_value | REAL | NOT NULL |
weight | REAL | NOT NULL |
evidence_quality | REAL | NOT NULL |
evidence_status | TEXT | NOT NULL |
occurred_at | TEXT | NOT NULL |
received_at | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
evd_evidence_issues
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
evidence_id | TEXT | FK references evd_evidence(id) |
issue_code | TEXT | NOT NULL |
severity | TEXT | NOT NULL |
details_json | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
evd_processing_records
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
source_type | TEXT | NOT NULL |
source_id | TEXT | NOT NULL |
processor_version | TEXT | NOT NULL |
workflow_instance_id | TEXT | NULLABLE |
status | TEXT | NOT NULL |
started_at | TEXT | NOT NULL |
completed_at | TEXT | NULLABLE |
error_code | TEXT | NULLABLE |
12.8. Learner Model Tables
evd_learner_models
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
student_id | TEXT | FK references iam_users(id) |
class_id | TEXT | FK references lrn_classes(id) |
model_type | TEXT | NOT NULL |
model_version | TEXT | NOT NULL |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
updated_at | TEXT | NOT NULL |
Unique constraint: (student_id, class_id, model_type)
evd_learner_indicator_states
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
learner_model_id | TEXT | FK references evd_learner_models(id) |
indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
mastery | REAL | NOT NULL |
confidence | REAL | NOT NULL |
evidence_count | INTEGER | NOT NULL |
recent_evidence_count | INTEGER | NOT NULL |
trend | TEXT | NULLABLE |
pace | TEXT | NULLABLE |
state_label | TEXT | NOT NULL |
last_evidence_at | TEXT | NULLABLE |
calculation_version | TEXT | NOT NULL |
updated_at | TEXT | NOT NULL |
Unique constraint: (learner_model_id, indicator_version_id)
evd_learner_state_history
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
learner_model_id | TEXT | FK references evd_learner_models(id) |
indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
previous_mastery | REAL | NOT NULL |
new_mastery | REAL | NOT NULL |
previous_confidence | REAL | NOT NULL |
new_confidence | REAL | NOT NULL |
trigger_type | TEXT | NOT NULL |
trigger_id | TEXT | NOT NULL |
evidence_ids_json | TEXT | NULLABLE |
calculation_version | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
evd_learner_model_snapshots
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
learner_model_id | TEXT | FK references evd_learner_models(id) |
snapshot_type | TEXT | NOT NULL |
snapshot_json | TEXT | NULLABLE |
snapshot_r2_key | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
12.9. Content Production Tables
cnt_content_requests
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
requested_by | TEXT | FK references iam_users(id) |
course_id | TEXT | FK references cur_courses(id) |
lesson_id | TEXT | FK references cur_lessons(id) |
learning_objective_id | TEXT | FK references cur_learning_objectives(id) |
indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
grade_level | TEXT | NOT NULL |
difficulty | TEXT | NOT NULL |
content_type | TEXT | NOT NULL |
duration_minutes | INTEGER | NOT NULL |
language | TEXT | NOT NULL |
requirements_json | TEXT | NULLABLE |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
updated_at | TEXT | NOT NULL |
cnt_generation_jobs
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
content_request_id | TEXT | FK references cnt_content_requests(id) |
workflow_instance_id | TEXT | NULLABLE |
prompt_version_id | TEXT | NULLABLE |
provider | TEXT | NOT NULL |
model | TEXT | NOT NULL |
status | TEXT | NOT NULL |
input_r2_key | TEXT | NULLABLE |
output_r2_key | TEXT | NULLABLE |
started_at | TEXT | NOT NULL |
completed_at | TEXT | NULLABLE |
error_code | TEXT | NULLABLE |
cnt_content_items
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
stable_key | TEXT | NOT NULL |
content_type | TEXT | NOT NULL |
status | TEXT | NOT NULL |
current_version_id | TEXT | NULLABLE |
created_by | TEXT | FK references iam_users(id) |
created_at | TEXT | NOT NULL |
updated_at | TEXT | NOT NULL |
cnt_content_versions
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
content_item_id | TEXT | FK references cnt_content_items(id) |
version_no | INTEGER | NOT NULL |
title | TEXT | NOT NULL |
summary | TEXT | NULLABLE |
body_r2_key | TEXT | NOT NULL |
body_format | TEXT | NOT NULL |
source_type | TEXT | NOT NULL (e.g. 'AI_GENERATED', 'HUMAN') |
source_generation_job_id | TEXT | NULLABLE references cnt_generation_jobs(id) |
status | TEXT | NOT NULL |
created_by | TEXT | FK references iam_users(id) |
created_at | TEXT | NOT NULL |
Unique constraint: (content_item_id, version_no)
cnt_content_metadata
| Column | Type | Constraints |
|---|---|---|
content_version_id | TEXT | PK, FK references cnt_content_versions(id) |
course_id | TEXT | FK references cur_courses(id) |
lesson_id | TEXT | FK references cur_lessons(id) |
skill_id | TEXT | FK references cur_skills(id) |
indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
grade_min | INTEGER | NOT NULL |
grade_max | INTEGER | NOT NULL |
difficulty | TEXT | NOT NULL |
estimated_duration_minutes | INTEGER | NOT NULL |
language | TEXT | NOT NULL |
activity_type | TEXT | NOT NULL |
prerequisite_json | TEXT | NULLABLE |
tags_json | TEXT | NULLABLE |
cnt_content_sections
(Tùy chọn: Dùng khi cần chỉnh sửa từng phân đoạn độc lập)
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
content_version_id | TEXT | FK references cnt_content_versions(id) |
section_type | TEXT | NOT NULL |
title | TEXT | NOT NULL |
body_r2_key | TEXT | NULLABLE |
body_text | TEXT | NULLABLE |
sequence_no | INTEGER | NOT NULL |
source_type | TEXT | NOT NULL |
12.10. Quality and Review Tables
rev_quality_checks
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
content_version_id | TEXT | FK references cnt_content_versions(id) |
check_type | TEXT | NOT NULL (e.g., 'AUTOMATED_LINT', 'SAFETY_CHECK') |
checker_type | TEXT | NOT NULL |
checker_version | TEXT | NOT NULL |
status | TEXT | NOT NULL |
score | REAL | NOT NULL |
started_at | TEXT | NOT NULL |
completed_at | TEXT | NULLABLE |
rev_quality_findings
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
quality_check_id | TEXT | FK references rev_quality_checks(id) |
criterion_code | TEXT | NOT NULL |
severity | TEXT | NOT NULL (e.g., 'INFO', 'WARNING', 'BLOCKER') |
section_reference | TEXT | NULLABLE |
message | TEXT | NOT NULL |
suggestion | TEXT | NULLABLE |
status | TEXT | NOT NULL |
resolved_by | TEXT | NULLABLE references iam_users(id) |
resolved_at | TEXT | NULLABLE |
rev_content_reviews
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
content_version_id | TEXT | FK references cnt_content_versions(id) |
reviewer_id | TEXT | FK references iam_users(id) |
review_status | TEXT | NOT NULL |
checklist_version | TEXT | NOT NULL |
comment | TEXT | NULLABLE |
started_at | TEXT | NOT NULL |
completed_at | TEXT | NULLABLE |
rev_review_checklist_items
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
review_id | TEXT | FK references rev_content_reviews(id) |
criterion_code | TEXT | NOT NULL |
result | TEXT | NOT NULL (e.g., 'PASS', 'FAIL') |
comment | TEXT | NULLABLE |
completed_at | TEXT | NOT NULL |
rev_publications
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
content_version_id | TEXT | FK references cnt_content_versions(id) |
publication_status | TEXT | NOT NULL |
approved_review_id | TEXT | NULLABLE references rev_content_reviews(id) |
published_by | TEXT | FK references iam_users(id) |
published_at | TEXT | NOT NULL |
unpublished_by | TEXT | NULLABLE references iam_users(id) |
unpublished_at | TEXT | NULLABLE |
unpublish_reason | TEXT | NULLABLE |
12.11. Recommendation Tables
rec_recommendations
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
class_id | TEXT | FK references lrn_classes(id) |
student_id | TEXT | FK references iam_users(id) |
learner_model_id | TEXT | FK references evd_learner_models(id) |
target_indicator_version_id | TEXT | FK references cur_indicator_versions(id) |
selected_content_version_id | TEXT | FK references cnt_content_versions(id) |
decision_type | TEXT | NOT NULL |
decision_status | TEXT | NOT NULL |
confidence | REAL | NOT NULL |
reason_summary | TEXT | NULLABLE |
policy_version | TEXT | NOT NULL |
learner_snapshot_id | TEXT | FK references evd_learner_model_snapshots(id) |
generated_at | TEXT | NOT NULL |
expires_at | TEXT | NULLABLE |
processing_time_ms | INTEGER | NOT NULL |
Ví dụ Decision types: PERSONALIZED, DIAGNOSTIC, FOUNDATION_FALLBACK, DEFAULT_PATH, TEACHER_ASSIGNED, NO_MATCH.
rec_candidate_evaluations
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
recommendation_id | TEXT | FK references rec_recommendations(id) |
content_version_id | TEXT | FK references cnt_content_versions(id) |
eligibility_status | TEXT | NOT NULL |
rank_score | REAL | NOT NULL |
rank_position | INTEGER | NOT NULL |
rejection_code | TEXT | NULLABLE |
evaluation_json | TEXT | NULLABLE |
rec_reasons
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
recommendation_id | TEXT | FK references rec_recommendations(id) |
reason_code | TEXT | NOT NULL |
reason_type | TEXT | NOT NULL |
evidence_id | TEXT | NULLABLE references evd_evidence(id) |
indicator_version_id | TEXT | NULLABLE references cur_indicator_versions(id) |
value_json | TEXT | NULLABLE |
sequence_no | INTEGER | NOT NULL |
Ví dụ Reason codes: LOW_MASTERY, LOW_CONFIDENCE, PREREQUISITE_NOT_MET, DIFFICULTY_MATCH, RECENT_INCORRECT_ANSWERS, CONTENT_ALREADY_COMPLETED, CONTENT_NOT_PUBLISHED, FOUNDATION_REQUIRED.
rec_teacher_overrides
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
original_recommendation_id | TEXT | FK references rec_recommendations(id) |
replacement_content_version_id | TEXT | FK references cnt_content_versions(id) |
teacher_id | TEXT | FK references iam_users(id) |
reason_code | TEXT | NOT NULL |
comment | TEXT | NULLABLE |
effective_from | TEXT | NOT NULL |
effective_until | TEXT | NULLABLE |
status | TEXT | NOT NULL |
created_at | TEXT | NOT NULL |
rec_outcomes
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
recommendation_id | TEXT | FK references rec_recommendations(id) |
outcome_type | TEXT | NOT NULL |
activity_session_id | TEXT | NULLABLE |
completion_status | TEXT | NOT NULL |
score | REAL | NULLABLE |
started_at | TEXT | NULLABLE |
completed_at | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
12.12. Workflow Tables
ops_workflow_records
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
workflow_type | TEXT | NOT NULL (e.g. 'CONTENT_CREATION', 'EVALUATION') |
workflow_instance_id | TEXT | UNIQUE, NOT NULL |
related_entity_type | TEXT | NOT NULL |
related_entity_id | TEXT | NOT NULL |
status | TEXT | NOT NULL |
current_step | TEXT | NULLABLE |
started_at | TEXT | NOT NULL |
completed_at | TEXT | NULLABLE |
failed_at | TEXT | NULLABLE |
error_code | TEXT | NULLABLE |
ops_workflow_events
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
workflow_record_id | TEXT | FK references ops_workflow_records(id) |
event_type | TEXT | NOT NULL |
step_name | TEXT | NOT NULL |
event_payload_json | TEXT | NULLABLE |
occurred_at | TEXT | NOT NULL |
12.13. AI Usage Tables
ops_ai_usage_records
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
task_type | TEXT | NOT NULL (e.g., 'LESSON_DRAFT', 'QUIZ_GENERATION') |
related_entity_type | TEXT | NOT NULL |
related_entity_id | TEXT | NOT NULL |
provider | TEXT | NOT NULL |
model | TEXT | NOT NULL |
prompt_version | TEXT | NOT NULL |
request_id | TEXT | NULLABLE |
input_tokens | INTEGER | NOT NULL |
output_tokens | INTEGER | NOT NULL |
estimated_cost | REAL | NOT NULL |
latency_ms | INTEGER | NOT NULL |
status | TEXT | NOT NULL |
error_code | TEXT | NULLABLE |
input_r2_key | TEXT | NULLABLE |
output_r2_key | TEXT | NULLABLE |
created_at | TEXT | NOT NULL |
12.14. Audit Tables
ops_audit_events
| Column | Type | Constraints |
|---|---|---|
id | TEXT | PK |
organization_id | TEXT | FK |
actor_type | TEXT | NOT NULL (e.g., 'USER', 'SYSTEM') |
actor_id | TEXT | NOT NULL |
action_code | TEXT | NOT NULL |
entity_type | TEXT | NOT NULL |
entity_id | TEXT | NOT NULL |
previous_state_json | TEXT | NULLABLE |
new_state_json | TEXT | NULLABLE |
request_id | TEXT | NULLABLE |
ip_hash | TEXT | NULLABLE |
user_agent_summary | TEXT | NULLABLE |
occurred_at | TEXT | NOT NULL |
archive_r2_key | TEXT | NULLABLE |
Ví dụ Audit actions: CONTENT_CREATED, CONTENT_SUBMITTED, CONTENT_APPROVED, CONTENT_REJECTED, CONTENT_PUBLISHED, CONTENT_UNPUBLISHED, RECOMMENDATION_CREATED, RECOMMENDATION_OVERRIDDEN, SKILL_VERSION_CREATED, INDICATOR_VERSION_CREATED, ROLE_ASSIGNED, LEARNER_STATE_RECALCULATED.
13. Prototype Minimal Schema
Click to view detailed specifications & content
Đối với phiên bản hackathon prototype, không bắt buộc phải triển khai toàn bộ bảng kể trên. Bảng phân cấp ưu tiên P0/Rút gọn:
Được gộp & tối ưu (Danh mục bảng rút gọn)
users,roles,user_rolescourses,lessons,skills,indicators,prerequisitesclasses,enrollmentsquizzes,questions,question_options,question_indicator_mapssubmissions,submission_answersevidencelearner_indicator_states,learner_state_historycontent_items,content_versions,content_metadatacontent_reviews,quality_findings,publicationsrecommendations,recommendation_candidates,recommendation_reasons,teacher_overridesworkflow_records,ai_usage_records,audit_events
14. Recommended Prototype D1 Schema Simplification
Click to view detailed specifications & content
Thiết kế tinh gọn này giúp cân bằng tối ưu giữa tốc độ hackathon, khả năng demo, tính giải thích (Explainability) và khả năng nâng cấp sau pilot.
15. Index Design
Click to view detailed specifications & content
Để tối ưu hóa chi phí đọc và ghi của Cloudflare D1 (quy đổi từ số dòng quét/ghi), hệ thống cần triển khai các indexes sau:
15.1. Submission indexes
CREATE INDEX idx_submissions_student_time
ON lrn_submissions(student_id, submitted_at DESC);
CREATE INDEX idx_submissions_class_time
ON lrn_submissions(class_id, submitted_at DESC);
CREATE UNIQUE INDEX idx_submissions_idempotency
ON lrn_submissions(organization_id, idempotency_key);15.2. Evidence indexes
CREATE INDEX idx_evidence_student_indicator_time
ON evd_evidence(student_id, indicator_version_id, occurred_at DESC);
CREATE INDEX idx_evidence_source
ON evd_evidence(source_type, source_id);
CREATE INDEX idx_evidence_status
ON evd_evidence(evidence_status, received_at);15.3. Learner state indexes
CREATE UNIQUE INDEX idx_learner_current_indicator
ON evd_learner_indicator_states(
learner_model_id,
indicator_version_id
);
CREATE INDEX idx_learner_state_support
ON evd_learner_indicator_states(
state_label,
confidence
);15.4. Recommendation indexes
CREATE INDEX idx_recommendation_student_time
ON rec_recommendations(student_id, generated_at DESC);
CREATE INDEX idx_recommendation_class_time
ON rec_recommendations(class_id, generated_at DESC);
CREATE INDEX idx_recommendation_content
ON rec_recommendations(selected_content_version_id);
CREATE INDEX idx_recommendation_status_expiry
ON rec_recommendations(decision_status, expires_at);15.5. Content indexes
CREATE INDEX idx_content_metadata_filter
ON cnt_content_metadata(
course_id,
indicator_version_id,
difficulty,
language
);
CREATE INDEX idx_content_status
ON cnt_content_items(status);
CREATE INDEX idx_publication_status
ON rev_publications(publication_status, published_at);15.6. Review indexes
CREATE INDEX idx_review_queue
ON rev_content_reviews(review_status, started_at);
CREATE INDEX idx_quality_findings_open
ON rev_quality_findings(status, severity);16. Cloudflare R2 Object Model
Click to view detailed specifications & content
16.1. Bucket strategy
Trong prototype, chúng ta sử dụng ba buckets được quản lý độc lập:
eduone-content: Lưu trữ các file nội dung hoàn chỉnh (JSON), ảnh, tài liệu tĩnh của bài giảng.eduone-ai-artifacts: Lưu trữ vết toàn bộ các input/output thô từ AI LLMs phục vụ gỡ lỗi và kiểm định chi phí.eduone-exports: Lưu trữ các file xuất báo cáo tạm thời.
Lưu ý: Có thể gộp thành 1 bucket duy nhất trong hackathon nếu quản lý phân cấp bằng prefix.
16.2. R2 Key Naming Convention
Khóa lưu trữ luôn tuân thủ tiền tố cấu trúc tổ chức: organizations/{organizationId}/...
- Content:
organizations/org_eduone/content/{contentItemId}/versions/{versionNo}/content.json - AI Artifacts:
organizations/org_eduone/ai/{taskType}/{year}/{month}/{generationJobId}/input.json - Learner Snapshots:
organizations/org_eduone/learner-snapshots/{classId}/{studentId}/{snapshotId}.json
16.3. R2 Content Object Schema
Nội dung bài viết được lưu trữ dưới dạng một JSON thuần nhất trên R2:
{
"schemaVersion": "1.0",
"contentItemId": "cnt_loop_practice",
"contentVersionId": "ver_003",
"contentType": "PRACTICE_ACTIVITY",
"language": "vi",
"title": "Xác định số lần vòng lặp chạy",
"sections": [
{
"sectionId": "intro",
"type": "INTRODUCTION",
"title": "Mở đầu",
"body": "..."
},
{
"sectionId": "example",
"type": "EXAMPLE",
"title": "Ví dụ",
"body": "..."
}
],
"quiz": {
"questions": []
},
"source": {
"type": "AI_ASSISTED",
"generationJobId": "gen_001"
}
}16.4. Object immutability
Mọi thay đổi trên R2 đối với published content đều tạo ra version mới thay vì ghi đè trực tiếp. Điều này bảo vệ tính toàn vẹn của các recommendation lịch sử đã tham chiếu đến các nội dung đó.
16.5. R2 Security
Mọi hoạt động đọc/ghi đến R2 đều phải thông qua API Worker. Tuyệt đối không expose trực tiếp cấu trúc file ra ngoài client.
17. Cloudflare Vectorize Design
Click to view detailed specifications & content
17.1. Vectorize use cases
Lưu trữ các dữ liệu vector biểu diễn nội dung nhằm phục vụ:
- Tìm kiếm các học liệu liên quan phục vụ thiết kế nội dung (RAG).
- Phát hiện trùng lặp nội dung học liệu tự động.
- Truy xuất các ứng viên cho Recommendation Engine.
17.2. Index strategy
Tách biệt index phục vụ học tập và index nháp:
eduone-approved-content-v1(Chỉ chứa các vector của bài viết trạng tháiPUBLISHED).eduone-authoring-content-v1(Chứa các bản nháp đang xây dựng).
17.3. Vector record
Cấu trúc bản ghi vector lưu trữ:
{
"id": "cnt_001_ver_003_chunk_002",
"values": [0.012, -0.245, 0.887],
"metadata": {
"organizationId": "org_eduone",
"contentItemId": "cnt_001",
"contentVersionId": "ver_003",
"courseId": "crs_python",
"indicatorId": "ind_iteration_count",
"difficulty": "FOUNDATION",
"language": "vi",
"status": "PUBLISHED"
}
}17.4. Metadata indexes
Chỉ cấu hình metadata index trên Vectorize cho các trường thực tế dùng để lọc (courseId, indicatorId, difficulty, status, language).
17.5. Chunking & Embedding Lifecycle
Mỗi tài liệu bài giảng lớn được chia nhỏ theo ranh giới ngữ nghĩa (Semantic Section) thay vì số lượng ký tự cơ học trước khi gọi API tạo Embedding và upsert vào Vectorize. Khi một bài viết chuyển trạng thái unpublish, hệ thống sẽ tự động gỡ các vector tương ứng khỏi index.
18. Cache Design
Click to view detailed specifications & content
- Dữ liệu được phép Cache: Khung chương trình (Course Structure), Bản đồ kỹ năng (Skill Maps), Định nghĩa chỉ báo (Indicators), Nội dung bài giảng đã phê duyệt.
- Dữ liệu cấm Cache public: Learner state, Recommendation log, Submissions, AI prompts.
- Quy tắc Invalidation: Xóa cache tương ứng ngay lập tức khi phát sinh sự kiện Publish/Unpublish hoặc thay đổi phiên bản (Version Activated).
19. Data Flow — Quiz Submission
Click to view detailed specifications & content
Student submits quiz
↓
API Worker validates request
↓
Idempotency key checked
↓
Submission stored in D1
↓
Recommendation Update Workflow started
↓
Answers scored
↓
Evidence records created
↓
Learner state updated
↓
State history stored
↓
Recommendation generated
↓
Recommendation log stored
↓
Student UI receives new recommendation20. Data Flow — Content Creation
Click to view detailed specifications & content
Content request stored in D1
↓
Content Creation Workflow started
↓
Prompt assembled
↓
Full AI input stored in R2
↓
AI Gateway request
↓
Full AI output stored in R2
↓
Content item/version created in D1
↓
Structured content body stored in R2
↓
Quality checks executed
↓
Findings stored in D1
↓
Content moved to Ready for Review21. Data Flow — Human Approval
Click to view detailed specifications & content
Reviewer opens content
↓
D1 metadata loaded
↓
R2 content body loaded
↓
Quality findings displayed
↓
Reviewer completes checklist
↓
Review result stored
↓
If approved:
Publication record created
Content status updated
Index workflow triggered
↓
Content embedded
↓
Vectors inserted into approved index
↓
Cache invalidated
↓
Recommendation Engine may use content22. Data Flow — Content Unpublish
Click to view detailed specifications & content
Authorized user requests unpublish
↓
Publication marked UNPUBLISHED
↓
Audit event created
↓
Recommendation candidate cache invalidated
↓
Vector removal workflow started
↓
Existing active recommendations identified
↓
Recommendations marked stale if necessary
↓
Replacement recommendation generated23. Data Consistency Model
Click to view detailed specifications & content
- Strong Consistency (Đồng bộ tức thời): Submission acceptance, Review decisions, Role changes, Content status changes.
- Eventual Consistency (Bất đồng bộ/Trễ): Vector indexing, Analytics aggregates, Cache invalidation, AI usage reports.
24. Idempotency Design
Click to view detailed specifications & content
Đảm bảo hệ thống hoạt động ổn định khi mạng chập chờn hoặc các tác vụ Workflow bị retry. Mỗi hành động phải gửi kèm một idempotency_key duy nhất:
- Submission key:
submission:{studentId}:{quizVersionId}:{clientAttemptId} - Evidence key:
evidence:{submissionId}:{questionId}:{indicatorVersionId}
25. Workflow Step Data Contract
Click to view detailed specifications & content
Không truyền tải các payload văn bản lớn trực tiếp giữa các bước của Cloudflare Workflows. Chỉ truyền mã định danh và đường dẫn R2 key:
{
"contentRequestId": "ctr_001",
"generationJobId": "gen_001",
"inputR2Key": "organizations/org_eduone/ai/lesson/gen_001/input.json"
}26. Learner State Snapshot Design
Click to view detailed specifications & content
Khi sinh recommendation, hệ thống lưu một bản chụp trạng thái người học tại thời điểm đó (Snapshot) để phục vụ cho việc giải thích (Explainability) và đối soát về sau:
{
"snapshotId": "lms_001",
"studentId": "stu_001",
"classId": "cls_001",
"calculationVersion": "bkt-lite-1.0",
"createdAt": "2026-07-17T04:30:00Z",
"indicators": [
{
"indicatorId": "ind_iteration_count",
"mastery": 0.56,
"confidence": 0.72,
"evidenceCount": 4,
"recentResults": [0, 1, 0, 1]
}
]
}27. Recommendation Candidate Evaluation Model
Click to view detailed specifications & content
Việc đánh giá đề xuất bài học cho học sinh phải diễn ra có cấu trúc chặt chẽ thay vì phó mặc hoàn toàn cho LLM tự phát minh:
{
"contentVersionId": "ver_101",
"eligible": true,
"scores": {
"indicatorMatch": 1.0,
"difficultyFit": 0.9,
"prerequisiteFit": 1.0
},
"finalScore": 0.93,
"reasonCodes": ["TARGET_INDICATOR_MATCH", "DIFFICULTY_MATCH"]
}28. Content Status State Machine
Click to view detailed specifications & content
Trạng thái của học liệu chỉ được phép chuyển dịch theo đúng sơ đồ luồng quy định:
DRAFT ➔ AUTOMATED_CHECK_RUNNING ➔ READY_FOR_REVIEW ➔ IN_REVIEW ➔ APPROVED ➔ PUBLISHED ➔ UNPUBLISHED ➔ ARCHIVED29. Submission State Machine
Click to view detailed specifications & content
STARTED ➔ IN_PROGRESS ➔ SUBMITTED ➔ VALIDATING ➔ VALID ➔ SCORED ➔ EVIDENCE_CREATED ➔ PROCESSED30. Recommendation State Machine
Click to view detailed specifications & content
GENERATING ➔ ACTIVE ➔ (STARTED / COMPLETED / OVERRIDDEN / EXPIRED / STALE / CANCELLED)31. Data Versioning Strategy
Click to view detailed specifications & content
Mọi thay đổi thuật toán, chương trình học hay prompt template đều phải lưu số hiệu phiên bản đầy đủ:
- Phiên bản thuật toán:
calculationVersion: "learner-bayes-0.2" - Phiên bản prompt:
promptVersion: "quiz-generator-1.2"
32. Data Retention
Click to view detailed specifications & content
- Tài khoản người dùng: Suốt thời gian hoạt động.
- Submission / Evidence: 2-5 năm.
- AI Draft thô (R2): 90 - 180 ngày.
- Học liệu được duyệt: Vĩnh viễn (khi còn sử dụng).
33. Soft Delete vs Hard Delete
Click to view detailed specifications & content
- Soft Delete: Áp dụng cho các thực thể quan trọng (User, Course, Content, Quiz) bằng cách đổi trạng thái và ghi nhận thời gian xóa.
- Hard Delete: Chỉ áp dụng cho các file nháp tạm thời, file kết xuất hết hạn.
34. Privacy Classification
Click to view detailed specifications & content
Phân loại mức độ bảo mật thông tin:
- Class P0 (Public): Mô tả khóa học, học liệu đã xuất bản.
- Class P1 (Internal): Khung năng lực, mẫu prompt.
- Class P2 (Confidential): Kết quả học tập của học viên, đề xuất bài học, nhận xét của giáo viên.
- Class P3 (Restricted): Email, thông tin định danh cá nhân (PII), token xác thực.
Quy tắc: Tuyệt đối không gửi thông tin định danh P3 của học sinh vào các dịch vụ AI bên ngoài; luôn sử dụng student_id ẩn danh.
35. Data Anonymization for Hackathon
Click to view detailed specifications & content
Bộ dữ liệu demo hackathon phải sử dụng 100% dữ liệu ẩn danh, tên giả lập, không sử dụng dữ liệu thật của học sinh.
36. Seed Data Design
Click to view detailed specifications & content
Hệ thống prototype cần được cài đặt sẵn bộ dữ liệu seed tối thiểu bao gồm:
- 1 Tổ chức (EduOne).
- 20 học sinh với 6 kịch bản học tập khác nhau (học sinh mới, học sinh rỗng kiến thức cơ bản, học sinh có kết quả trái ngược,...).
- 2 giáo viên, 2 tác giả, 2 kiểm duyệt viên.
- 1 Khóa học Python với 3-5 chỉ báo năng lực (Indicators).
- 10-15 học liệu với đầy đủ các phiên bản trạng thái.
37. Data Migration Strategy
Click to view detailed specifications & content
Sử dụng các file SQL migration được đánh số thứ tự trong thư mục migrations/ để quản lý phiên bản cơ sở dữ liệu D1. Các file migration sau khi áp dụng là bất biến (immutable).
38. Import and Export
Click to view detailed specifications & content
Hệ thống hỗ trợ nhập/xuất danh sách học sinh, khung năng lực và ngân hàng câu hỏi qua định dạng CSV và JSON. File xuất được lưu tạm thời trên R2 với hạn định tự động xóa.
39. Backup and Recovery
Click to view detailed specifications & content
- Các file Migration và Seed Data được quản lý trực tiếp trên Git.
- Dữ liệu Vectorize và Learner Current State được thiết kế để có thể tái xây dựng (rebuild) hoàn toàn từ cơ sở dữ liệu D1 và R2 khi có sự cố xảy ra.
40. Data Observability
Click to view detailed specifications & content
Các chỉ số dữ liệu vận hành cần được theo dõi liên tục:
- Tỷ lệ Submission bị trùng lặp hoặc không hợp lệ.
- Tỷ lệ lỗi sinh dữ liệu Evidence.
- Số lượng đối tượng R2 bị mồ côi (Orphan objects).
41. Data Quality Rules
Click to view detailed specifications & content
Hệ thống áp dụng nghiêm ngặt các quy tắc chất lượng dữ liệu:
- DQ-001: Học liệu đã xuất bản bắt buộc phải có thông tin Course, Indicator, Độ khó và Người phê duyệt.
- DQ-002: Mọi bản ghi Evidence cập nhật điểm năng lực bắt buộc phải tương ứng với một Indicator Map hợp lệ.
42. Reconciliation Jobs
Click to view detailed specifications & content
Triển khai các tiến trình đối soát chạy tự động hàng ngày (Reconciliation Workflows):
- Kiểm tra học liệu đã xuất bản nhưng thiếu file nội dung thô trên R2 hoặc thiếu vector trên Vectorize.
- Kiểm tra các tác vụ AI đã hoàn thành nhưng thiếu artifact lưu trữ.
43. Data Access Patterns
Click to view detailed specifications & content
Thiết kế tối ưu hóa đường truyền dữ liệu cho các tác vụ phổ biến:
- Student Home: Đọc thông tin năng lực hiện tại, lấy bài học được gợi ý mới nhất, tải file nội dung từ R2.
- Teacher Dashboard: Xem nhanh danh sách lớp học và các khuyến nghị can thiệp.
44. Data Access Boundaries
Click to view detailed specifications & content
- Frontend: Không có quyền kết nối trực tiếp đến D1, R2, Vectorize hay AI Gateway.
- API Worker: Làm nhiệm vụ trung chuyển, xác thực danh tính và điều phối dữ liệu.
45. Transaction Design
Click to view detailed specifications & content
Áp dụng tính giao dịch atomic của SQLite/D1 cho các hoạt động cần tính toàn vẹn cao:
- Tạo submission: Phải đảm bảo lưu đồng thời bản ghi submission và danh sách câu trả lời chi tiết.
46. Error Recovery Patterns
Click to view detailed specifications & content
- Retryable (Lỗi thử lại được): Timeout API AI, timeout Vectorize, lỗi mạng tạm thời.
- Non-retryable (Không thử lại): Sai lệch cấu trúc Schema cơ sở dữ liệu, lỗi dữ liệu thô không đúng định dạng.
47. Data Design Decisions
Click to view detailed specifications & content
- DD-001: Cloudflare D1 là nguồn chân lý giao dịch chính (Relational Source of Truth).
- DD-002: Cloudflare R2 lưu trữ toàn bộ phần thân học liệu và các artifacts lớn để tránh D1 bị phình to.
- DD-003: Vectorize không lưu trữ dữ liệu nghiệp vụ chính thức.
- DD-006: Học liệu đã xuất bản là bất biến (Immutable).
48. Prototype Implementation Order
Click to view detailed specifications & content
Quy trình triển khai cơ sở dữ liệu prototype theo thứ tự 6 bước:
- Bước 1: Thiết lập bảng cấu trúc chương trình học, seed thông tin 20 học sinh và bài viết mẫu.
- Bước 2: Xây dựng phần Quiz, nộp bài (Submission) và sinh Evidence.
- Bước 3: Cập nhật trạng thái năng lực học sinh (Learner Model) và lưu lịch sử.
- Bước 4: Xây dựng bộ lọc gợi ý bài học (Recommendation Engine).
- Bước 5: Tích hợp tiến trình sinh bài học tự động bằng AI, lưu file R2 và kiểm tra chất lượng.
- Bước 6: Đồng bộ hóa Vectorize phục vụ tìm kiếm thông minh và kết xuất báo cáo kiểm toán (Audit).
49. Acceptance Criteria — Part 2
Click to view detailed specifications & content
Thiết kế dữ liệu được đánh giá đạt chuẩn khi thỏa mãn đầy đủ các tiêu chí:
- Xác định rõ ràng Data Owner cho từng Bounded Context.
- Đảm bảo học liệu chưa được duyệt không bao giờ bị Recommendation Engine quét trúng.
- Cơ sở dữ liệu Vectorize có khả năng tái thiết kế hoàn toàn từ D1 và R2.
- Thông tin dữ liệu chạy thử (Demo) được ẩn danh hóa an toàn.
50. Summary Architecture
Click to view detailed specifications & content
D1
Transactional Source of Truth
│
┌──────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
Curriculum Learning Content
Metadata Evidence Metadata
│ │ │
│ ▼ │
│ Learner State │
│ │ │
└──────────────────────┼──────────────────────┘
▼
Recommendation
│
Recommendation Log
│
┌─────────────────┴─────────────────┐
▼ ▼
R2 Vectorize
Content Bodies & Assets Semantic Search Index
AI Artifacts Published Content Vectors
Snapshots Metadata-filtered Retrieval
│ │
└─────────────────┬─────────────────┘
▼
Cloudflare Workflows
Durable Multi-step Processing51. Conclusion
Click to view detailed specifications & content
Kiến trúc dữ liệu của EduOne Adaptive Learning Engine tuân thủ nguyên lý: D1 lưu trữ sự thật giao dịch quan hệ, R2 lưu giữ tài liệu lớn, Vectorize phục vụ tìm kiếm ngữ nghĩa, và Cloudflare Workflows đảm nhận vai trò điều phối an toàn.
52. English Keywords
Click to view detailed specifications & content
Domain Model, Bounded Context, Aggregate, Data Architecture, D1, R2, Vectorize, Data Ownership, Eventual Consistency, Idempotency, Versioning, Recommendation Snapshot, Content Governance