Sơ đồ hệ thống

Trang này gom các sơ đồ nên mở khi cần trả lời nhanh trước hội đồng. Nếu cần nhìn cây thư mục hoặc luồng mở file để sửa code, mở Sơ đồ thư mục và luồng file. Nếu cần truy ngược file chi tiết, hãy mở song song Source map, API endpoint indexFull File CodeMap.

Runtime tổng quan

flowchart LR
  User["Student / Teacher / Admin"]
  Browser["Angular 20 PWA
Signals, routes, guards"] API["Spring Boot API
Clean Architecture / DDD"] DB["PostgreSQL 16
Flyway migrations"] R2["Cloudflare R2
files, video packages"] Worker["Dedicated video-worker
ingest/package"] Edge["Caddy + Cloudflare Worker
HTTPS, media auth"] Wiii["Wiii iframe/API
AI assistant + Pointy"] User --> Browser Browser --> API Browser -. postMessage .-> Wiii API --> DB API --> R2 API --> Worker Worker --> R2 Edge --> API Edge --> R2

Backend Clean Architecture

flowchart TB
  Controller["infrastructure/web
REST Controller"] UseCase["application/usecase
Business orchestration"] Domain["domain/model + valueobject
Pure domain, no JPA"] Port["domain/repository
Repository port"] Adapter["infrastructure/persistence
Adapter + Mapper"] JpaEntity["infrastructure/persistence/entity
*JpaEntity"] JpaRepo["Spring Data JpaRepository
JpaEntity only"] Postgres["PostgreSQL"] Controller --> UseCase UseCase --> Domain UseCase --> Port Port --> Adapter Adapter --> JpaEntity Adapter --> JpaRepo JpaRepo --> Postgres

Điểm phải nhớ: lỗi Not a managed type thường xảy ra khi JpaRepository dùng domain model thay vì *JpaEntity.

Database theo domain

Sơ đồ này gom bảng theo domain để dễ trình bày. Khi cần quan hệ khóa ngoại chi tiết, mở ảnh ERD trong [DB sống và ERD DBeaver](database-live-snapshot.html).
Mở SVG
Sơ đồ database LMS theo domain

Publication versioning

sequenceDiagram
  autonumber
  participant T as Teacher
  participant FE as Angular course editor
  participant API as CourseAuthoringControllerV3
  participant PUB as CoursePublicationService
  participant ADM as Admin approval
  participant LD as Learning delivery

  T->>FE: Edit draft chapter/lesson/content block
  FE->>API: Save draft changes
  T->>FE: Submit for approval
  FE->>API: POST submit-for-approval
  API->>PUB: Build publication snapshot
  ADM->>API: Approve course
  API->>PUB: Mark approved publication version
  LD->>PUB: Read learner-facing snapshot

Wiii safe action contract

sequenceDiagram
  autonumber
  participant Host as LMS host page
  participant Bridge as WiiiContextService
  participant Wiii as Wiii iframe
  participant UI as Safe DOM target

  Host->>Bridge: Register route, user role, course/lesson context
  Bridge->>Wiii: postMessage wiii:page-context
  Wiii->>Bridge: Request action by data-wiii-id
  Bridge->>UI: Verify data-wiii-click-safe=true
  alt Safe navigation or preview action
    Bridge->>UI: Click or open preview
    Bridge->>Wiii: Return observed result
  else Dangerous mutation
    Bridge-->>Wiii: Reject with requires-human-review
  end

Các hành động như submit quiz, delete, publish, enroll, grade, payment và mutate dữ liệu nguy hiểm không được tự động click.

Video, storage và offline

flowchart LR
  Teacher["Teacher upload video"]
  Upload["Presigned upload session"]
  R2Raw["R2 raw object"]
  Ingest["Video ingest job"]
  Shaka["Shaka Packager
HLS/DASH"] R2Pkg["R2 packaged manifests
segments"] Player["AdaptiveVideoPlayerComponent"] Offline["Dexie / IndexedDB
offline profile"] Progress["Progress sync queue"] Teacher --> Upload Upload --> R2Raw R2Raw --> Ingest Ingest --> Shaka Shaka --> R2Pkg R2Pkg --> Player Player --> Offline Offline --> Progress

Payment confirmation

sequenceDiagram
  autonumber
  participant S as Student
  participant FE as Angular payment UI
  participant API as PaymentControllerV3
  participant Provider as VNPay / SePay
  participant Enroll as Enrollment use case

  S->>FE: Choose paid course
  FE->>API: Create payment request
  API->>Provider: Create redirect or QR
  Provider-->>FE: Return redirect/QR
  Provider->>API: Callback/webhook
  API->>API: Verify signature / transaction content
  API->>Enroll: Activate enrollment when paid
  FE->>API: Poll or reload payment status

Khi bị hỏi nên mở file nào

Câu hỏi Mở trang Từ khóa search
Vì sao backend không trộn JPA vào domain? Backend Not a managed type, JpaEntity, CourseRepositoryAdapter
Khóa học sửa xong vì sao học viên chưa thấy? Publication versioning submit-for-approval, CoursePublicationService
AI Wiii có tự publish/xóa được không? Wiii integration data-wiii-click-safe, WiiiContextService
Video chạy adaptive/offline ra sao? Video và offline ShakaPackagerService, AdaptiveVideoPlayerComponent
Payment xác nhận thế nào? Payment và revenue PaymentControllerV3, sepay/webhook