Luồng nghiệp vụ

Trang này là bản “đi theo request” để trả lời khi thầy hỏi: người dùng bấm ở UI thì code nào chạy, backend xử lý ra sao, dữ liệu nằm ở bảng nào, và điểm kiểm soát an toàn là gì.

Sơ đồ tổng quan 12 luồng cốt lõi

flowchart LR
  Login["Đăng nhập
JWT + role"] Teacher["Giảng viên
soạn khóa học"] Review["Admin/ORG_ADMIN
duyệt course"] Learn["Học viên
enroll + học bài"] Assess["Quiz / assignment
submit + grade"] Upload["Upload tài liệu/video
presigned + ingest"] Video["Video + offline
Shaka + PWA"] Payment["Thanh toán
VNPay/SePay"] Wiii["Wiii/AI
safe action + preview"] STCW["STCW
competency mapping"] Notify["Thông báo
message/announcement"] Audit["Audit + DB
log, snapshot, schema"] Login --> Teacher Login --> Learn Teacher --> Upload --> Video Teacher --> Review --> Learn Learn --> Assess Payment --> Learn Wiii --> Teacher Wiii --> Learn Teacher --> STCW Review --> Audit Assess --> Audit Notify --> Learn

Sơ đồ này không thay thế chi tiết bên dưới. Nó là bản nhớ nhanh: mỗi nghiệp vụ đều phải đi qua UI, API/client hoặc store, controller/use case, database và một invariant an toàn.

Cách đọc một flow

Lớp Câu hỏi cần trả lời Nơi tra
UI User bấm ở màn nào, route nào? Vị trí file code, fe/src/app/features/...
Frontend service/state Component gọi service/store nào? fe/src/app/api, fe/src/app/core, feature service
Backend controller Endpoint nào nhận request? API endpoint index
Application/domain Use case nào quyết định nghiệp vụ? application/usecase, domain model/repository port
Database Bảng/cột nào đổi? SQL schema catalog
Safety invariant Điều gì không được vi phạm? Roles, ownership, publication snapshot, payment truth

Auth và phân quyền

sequenceDiagram
  autonumber
  participant U as User
  participant FE as Angular AuthService
  participant API as AuthControllerV3
  participant JWT as JWT service
  participant DB as users / roles
  U->>FE: Nhập email + mật khẩu
  FE->>API: POST /auth/login
  API->>DB: Kiểm tra user, role, trạng thái
  API->>JWT: Tạo access token
  JWT-->>API: JWT đã ký
  API-->>FE: Token + profile
  FE-->>U: Điều hướng theo role
Login/Register UI
-> AuthService / auth API client
-> AuthControllerV3
-> JWT service + user repository
-> JwtAuthenticationFilter on later requests
-> SecurityConfig + @PreAuthorize + role guards
Phần File/bảng chính
Frontend fe/src/app/core/services/auth.service.ts, fe/src/app/core/guards/role.guard.ts
Backend AuthControllerV3, JwtAuthenticationFilter, SecurityConfig
Database users, organizations, login_attempts, user_external_identities
Invariant UI guard chỉ là lớp tiện dụng; backend security mới là lớp quyết định.

Câu trả lời ngắn: LMS dùng JWT. Sau login, frontend lưu token và interceptor gắn token vào request. Backend đọc token qua JwtAuthenticationFilter, sau đó controller/use case bị khóa bằng role và ownership guard.

Teacher tạo và sửa khóa học

sequenceDiagram
  autonumber
  participant T as Teacher
  participant UI as Course editor
  participant Store as CourseEditorStore
  participant API as Course authoring API
  participant UC as Use case
  participant DB as courses / chapters / lessons
  T->>UI: Tạo hoặc sửa course draft
  UI->>Store: Cập nhật form, curriculum, content blocks
  Store->>API: Save chapter/lesson/section/content
  API->>UC: Validate role + ownership + draft rules
  UC->>DB: Ghi draft
  DB-->>UC: Entity đã lưu
  UC-->>Store: DTO mới nhất
  Store-->>UI: Render trạng thái đã lưu
Teacher dashboard
-> Course editor route
-> CourseEditorStore
-> CourseAuthoringService/API client
-> CourseAuthoringControllerV3
-> CourseAuthoring use cases
-> courses / chapters / lessons / sections
Phần File/bảng chính
Frontend teacher.routes.ts, course-editor.routes.ts, course-editor.store.ts
Backend CourseAuthoringControllerV3, TeacherCoursesControllerV3
Database courses, chapters, lessons, sections, lesson_attachments
Invariant Teacher sửa draft. Học viên không đọc trực tiếp draft nếu course đã qua publication.

Điểm dễ nhầm: content_blocks là cột JSONB trong lessons, không phải bảng riêng.

Submit, review, approve và publication

sequenceDiagram
  autonumber
  participant T as Teacher
  participant A as Admin/ORG_ADMIN
  participant API as Course review API
  participant Pub as CoursePublicationService
  participant Draft as Draft tables
  participant Snap as course_publications
  participant L as Learner UI
  T->>API: Submit draft for approval
  API->>Draft: Validate course completeness
  API-->>A: Course chờ duyệt
  A->>API: Approve hoặc reject
  API->>Pub: Nếu approve, tạo snapshot
  Pub->>Draft: Đọc courses/chapters/lessons hiện tại
  Pub->>Snap: Ghi publication version
  L->>Snap: Đọc nội dung học viên thấy
Teacher submit-for-approval
-> backend validate draft
-> Admin/ORG_ADMIN review
-> approve/reject
-> CoursePublicationService tạo hoặc cập nhật snapshot
-> learner-facing page đọc course_publications
Phần File/bảng chính
Frontend Teacher course editor, admin course review pages
Backend CoursePublicationService, CoursePublicationJpaEntity, admin course controller/use case
Database course_publications, courses, learning_classes
Invariant Sửa draft không tự động làm học viên thấy nội dung mới. Phải submit/approve và class phải trỏ đúng publication.

Câu trả lời ngắn: LMS tách draft và snapshot. course_publications là bản học viên đọc, giúp course đã duyệt ổn định dù teacher tiếp tục sửa draft.

Student xem course, enroll và học bài

sequenceDiagram
  autonumber
  participant S as Student
  participant UI as Course detail / learning page
  participant API as Enrollment + learning API
  participant Pay as Payment truth
  participant Pub as course_publications
  participant Prog as progress tables
  S->>UI: Mở course
  UI->>API: Check entitlement
  API->>Pay: Nếu paid course, kiểm tra giao dịch đã verified
  API->>Pub: Lấy publication hợp lệ
  UI-->>S: Mở bài học
  S->>UI: Hoàn thành lesson/section
  UI->>API: Mark progress
  API->>Prog: Ghi student_lesson_progress
Course detail
-> entitlement check
-> free/self enroll hoặc payment flow
-> learning route
-> lesson/section complete
-> progress API
-> student_lesson_progress / enrollments
Phần File/bảng chính
Frontend features/courses, features/student, features/learning/pages/course-learning.component.*
Backend StudentEnrollmentControllerV3, progress controllers/use cases
Database learning_classes, enrollments, student_lesson_progress, certificates
Invariant Student chỉ học khi có entitlement hợp lệ: free, enrolled, paid, hoặc được activate trong lớp.

Nếu hỏi “vì sao student đã trả tiền mà chưa học được”, kiểm tra payment_transactions, enrollment/activation và delivery mode.

Quiz, assignment và grading

sequenceDiagram
  autonumber
  participant T as Teacher
  participant S as Student
  participant UI as Assessment UI
  participant API as Assessment controllers
  participant UC as Assessment use cases
  participant DB as quiz / assignment tables
  participant Audit as grading_audit_log
  T->>API: Tạo quiz/assignment/rubric
  API->>DB: Lưu cấu hình đánh giá
  S->>UI: Làm bài / nộp bài
  UI->>API: Submit attempt/submission
  API->>UC: Validate window, attempt, ownership
  UC->>DB: Lưu kết quả
  T->>API: Chấm hoặc phản hồi
  API->>Audit: Ghi audit khi grade thay đổi
Teacher tạo quiz/assignment/rubric
-> Assessment controllers
-> questions / quizzes / assignments
-> Student attempt/submission
-> auto grade hoặc teacher grade
-> grading_audit_log + progress/analytics
Phần File/bảng chính
Frontend Teacher assessment pages, student assignment/quiz pages
Backend QuizControllerV3, QuestionControllerV3, AssignmentControllerV3, AssignmentSubmissionControllerV3
Database questions, question_options, quizzes, quiz_attempts, assignments, assignment_submissions, assignment_rubrics, grading_audit_log
Invariant Wiii/Pointy không được tự submit quiz hoặc grade. Grade cần role/ownership và audit.

Điểm cần nhớ: question rich content nằm ở questions.content_blocks JSONB; rubric data có ở assignment/rubric/submission tùy flow.

Upload tài liệu, file và video

sequenceDiagram
  autonumber
  participant U as Teacher/UI
  participant FE as PresignedUploadService
  participant API as Upload API
  participant Store as R2/S3-compatible storage
  participant DB as upload_sessions / files / video_assets
  participant Worker as Video worker
  U->>FE: Chọn Word/PDF/video
  FE->>API: Init upload session
  API->>DB: Tạo upload_sessions
  API-->>FE: Presigned URL + session id
  FE->>Store: Upload trực tiếp binary
  FE->>API: Confirm/attach
  API->>DB: Gắn file/video asset
  API->>Worker: Nếu video, tạo ingest job
  Worker->>Store: Package HLS/DASH
  Worker->>DB: Cập nhật renditions/manifests
User chọn file
-> PresignedUploadService
-> backend tạo upload_sessions
-> browser upload lên storage
-> backend attach file/video asset
-> nếu video: ingest job -> Shaka package -> renditions/manifests
Phần File/bảng chính
Frontend presigned-upload.service.ts, upload adapter, course editor media UI
Backend PresignedUploadUseCase, VideoAssetControllerV3, VideoAssetIngestService, VideoAssetIngestScheduler
Database upload_sessions, file_attachments, video_assets, video_renditions, video_ingest_jobs
Invariant Upload lớn không đi qua web backend như binary stream dài; video ingest chạy tách khỏi request UI.

Video playback và offline/PWA

sequenceDiagram
  autonumber
  participant L as Learner
  participant Player as AdaptiveVideoPlayer
  participant API as Playback API
  participant Edge as media.holilihu.online
  participant Cache as IndexedDB/Dexie
  participant DB as video_progress
  L->>Player: Mở bài có video
  Player->>API: Xin playback URL/token
  API-->>Player: Signed manifest URL
  Player->>Edge: Tải HLS/DASH manifest + segments
  Player->>DB: Gửi progress khi học
  L->>Player: Download offline nếu được phép
  Player->>Cache: Lưu cache có kiểm soát
  Cache-->>API: Sync progress khi online lại
Learning page
-> Adaptive video player
-> signed playback/media auth
-> HLS/DASH manifest + segments
-> progress tracking
-> optional offline download into IndexedDB/Dexie
-> offline sync queue khi online lại
Phần File/bảng chính
Frontend adaptive-video-player, course-download.service.ts, offline-video.service.ts, offline-sync.service.ts, lms-offline.db.ts
Backend VideoAssetPresentationService, video progress use cases, media auth/filter/service
Database video_assets, video_renditions, video_progress, client_offline_storage_telemetry
Invariant Offline là cache có kiểm soát, không phải nguồn dữ liệu chính. Progress cuối cùng vẫn phải sync về backend.

Payment, refund và revenue

sequenceDiagram
  autonumber
  participant S as Student
  participant FE as Payment UI
  participant API as PaymentControllerV3
  participant GW as VNPay/SePay
  participant DB as payment_transactions
  participant Enroll as Enrollment use case
  S->>FE: Chọn thanh toán course
  FE->>API: Tạo payment transaction
  API->>GW: Tạo URL/QR theo gateway
  GW-->>S: User thanh toán
  GW->>API: IPN/webhook/callback
  API->>GW: Verify chữ ký/nội dung
  API->>DB: Mark COMPLETED nếu hợp lệ
  API->>Enroll: Kích hoạt entitlement/enrollment
Student chọn khóa trả phí
-> Payment UI / QR / redirect
-> PaymentControllerV3
-> VNPay IPN hoặc SePay webhook
-> backend verify signature/content
-> payment_transactions COMPLETED
-> enroll/activate entitlement
-> revenue_splits / payout_requests nếu cần
Phần File/bảng chính
Frontend fe/src/app/features/payment, fe/src/app/api/client/payment.api.ts
Backend PaymentControllerV3, ProcessVnPayIpnUseCase, ProcessSepayWebhookUseCase, payment scheduler
Database payment_transactions, org_payment_configs, teacher_bank_accounts, revenue_splits, payout_requests
Invariant Browser callback không tự quyết định đã trả tiền. Backend verify gateway/webhook mới là sự thật.

Communication và notification

Student/teacher mở message/announcement
-> conversation/message APIs
-> conversations / messages
-> read/reaction/recall state
-> notification/announcement read tracking
Phần File/bảng chính
Frontend features/communication, student/teacher message surfaces
Backend communication controllers/use cases
Database conversations, messages, message_reactions, announcements, announcement_reads, notifications
Invariant Message visibility phải đi theo class/course/user scope.

AI/Wiii và safe action

sequenceDiagram
  autonumber
  participant Page as LMS page
  participant W as Wiii iframe
  participant Ctx as WiiiContextService
  participant Preview as Preview/diff UI
  participant API as LMS backend
  participant DB as Course draft tables
  Page->>Ctx: Thu thập data-wiii-id + safe capabilities
  Ctx->>W: postMessage context
  W->>Page: Request point/click/action
  Page->>Page: Chỉ cho click nếu data-wiii-click-safe=true
  W->>Preview: Sinh lesson draft/patch
  Preview-->>Page: Teacher xem diff
  Page->>API: Apply khi teacher xác nhận
  API->>DB: Mutate draft qua authorization/use case
LMS page context
-> Wiii iframe
-> WiiiContextService gửi context + safe capabilities
-> Wiii request action by data-wiii-id
-> LMS chỉ cho click nếu data-wiii-click-safe=true
-> preview/diff trước apply nội dung tạo bởi AI
Phần File/bảng chính
Frontend features/ai-chat/infrastructure/api/wiii-context.service.ts, chat-panel.component.*
Backend AiAssistantControllerV3, AiTokenControllerV3, Wiii service auth/integration controllers
Database chat_sessions, chat_messages, ai_insights, ai_alerts
Invariant Wiii không được tự submit quiz, delete, publish, enroll, grade, payment hoặc mutate dữ liệu nguy hiểm.

STCW/competency mapping

Seed/admin tạo standard
-> Teacher map lesson to competency
-> Course competency matrix
-> export/report coverage
Phần File/bảng chính
Frontend fe/src/app/features/teacher/competency-map/competency-map.component.ts
Backend CompetencyMappingController, GetCourseCompetencyMapUseCase, UpdateLessonCompetenciesUseCase
Database maritime_standards, standard_competencies, lesson_competency_mappings
Invariant Mapping là evidence đào tạo, không thay thế nội dung lesson; nó chứng minh coverage theo chuẩn.

Admin/ORG_ADMIN operations

Admin dashboard
-> user/course/payment/analytics settings
-> backend role checks
-> audit/log/state changes
Role Được làm Không nên nhầm
ADMIN System settings, delete user/course, toàn quyền Dùng cho thao tác hệ thống nhạy cảm
ORG_ADMIN Vận hành, review course, user CRUD teacher/student, analytics Không promote/sửa ADMIN hoặc ORG_ADMIN
TEACHER Authoring, grading, class management trong scope Không duyệt/publish trực tiếp nếu flow yêu cầu admin
STUDENT Learn, submit, pay, message Không grade/enroll người khác

Checklist khi debug một flow

  1. Xác định route và component đang render.
  2. Tìm service/store gọi API.
  3. Tìm endpoint trong controller.
  4. Tìm use case hoặc service nghiệp vụ.
  5. Tìm repository/entity/bảng DB liên quan.
  6. Kiểm role/ownership/publication/payment invariant.
  7. Chạy smoke nhỏ: request API, UI click, hoặc query DB tùy lỗi.