LMS Maritime - Sổ tay học code và bảo vệ
Tài liệu này dùng để học nhanh codebase trước ngày báo cáo: hiểu kiến trúc, nắm các luồng chính, biết chạy local, biết sửa code có kiểm chứng, và trả lời được các câu hỏi thường gặp về hệ thống LMS Hàng Hải.
1. Học Nhanh Trong 5 Phút
Đây là hệ thống LMS phục vụ đào tạo hàng hải. Hệ thống có bốn vai trò chính: ADMIN, ORG_ADMIN, TEACHER và STUDENT. Frontend viết bằng Angular, backend viết bằng Spring Boot, dữ liệu lưu trong PostgreSQL.
Câu giới thiệu ngắn khi thầy hỏi
"Dự án của em là nền tảng LMS cho đào tạo hàng hải, bao gồm quản lý khóa học, bài học, lớp học, ghi danh, quiz, bài tập, tiến độ học tập, thanh toán, PWA offline và video adaptive. Backend theo Clean Architecture/DDD, frontend theo Angular Signals và lazy-loaded routes."
Một request đi như thế nào?
- Người dùng thao tác trên Angular component.
- Component gọi service hoặc API client.
- Interceptor gắn JWT và base URL.
- Spring Controller nhận request.
- UseCase xử lý nghiệp vụ.
- Repository Adapter đọc/ghi PostgreSQL qua JPA Entity.
- DTO trả về UI, Angular signal cập nhật màn hình.
Thông tin cần nhớ
| Mục | Giá trị |
|---|---|
| Local frontend | http://localhost:4200 |
| Local backend | http://localhost:8088 |
| Swagger | http://localhost:8088/swagger-ui |
| Production | https://holilihu.online |
| Production media | https://media.holilihu.online |
| Tài khoản teacher | teacher@maritime.edu / redacted-local-seed |
| Tài khoản student | student@maritime.edu / redacted-local-seed |
| Tài khoản admin | admin@maritime.edu / redacted-local-seed |
2. Cách Chạy Local
Cách khuyến nghị là chạy PostgreSQL và backend bằng Docker, còn frontend chạy local bằng Node để sửa UI nhanh hơn.
2.1. Kiểm tra trước khi chạy
git status --short --branch
docker --version
node -v
npm -v
java -version
2.2. Chạy backend và database bằng Docker
cd E:\Sach\Sua\LMS_hohulili
Copy-Item .env.dev.example .env
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d db backend
2.3. Kiểm tra backend đã chạy
curl.exe -s http://localhost:8088/actuator/health
curl.exe -s "http://localhost:8088/api/v3/courses?page=0&size=1"
Kết quả health mong muốn:
{"status":"UP"}
2.4. Chạy frontend
cd E:\Sach\Sua\LMS_hohulili\fe
npm install
npm start
Mở trình duyệt tại:
http://localhost:4200
2.5. Chạy toàn bộ stack bằng Docker
Cách này phù hợp khi cần môi trường gần production hơn, nhưng sửa UI sẽ chậm hơn.
cd E:\Sach\Sua\LMS_hohulili
Copy-Item .env.dev.example .env
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build --wait
2.6. Tắt local stack
cd E:\Sach\Sua\LMS_hohulili
docker compose -f docker-compose.yml -f docker-compose.dev.yml down
docker compose ... down -v.
3. Khi Thầy Bảo Sửa Code Ngay
Khi thầy yêu cầu sửa một lỗi nhỏ trong lúc báo cáo, cần làm theo quy trình gọn: xác định màn hình, tìm đúng file, sửa đúng phạm vi, build/test, rồi refresh browser.
3.1. Quy trình an toàn
- Ghi lại URL, màn hình và hành động gây lỗi.
- Chạy
git status --short --branchđể biết repo có file đang sửa không. - Tìm route, component hoặc controller liên quan bằng
rg. - Sửa ít nhất có thể, không refactor lớn trong lúc demo.
- Chạy test hoặc build đúng phạm vi.
- Refresh browser và nói rõ bằng chứng đã kiểm chứng.
3.2. Lệnh tìm code nhanh
cd E:\Sach\Sua\LMS_hohulili
rg "teacher/courses" fe/src/app
rg "CourseEditor" fe/src/app/features/teacher
rg "@GetMapping|@PostMapping|@PutMapping|@PatchMapping" backend/src/main/java/com/example/lms
rg "api/v3/courses|teacher/courses|video-assets" backend/src/main/java/com/example/lms fe/src/app
3.3. Nếu sửa frontend
cd E:\Sach\Sua\LMS_hohulili\fe
npm run build
Các file hay dùng khi sửa UI:
| Cần sửa | File/thư mục |
|---|---|
| Route tổng | fe/src/app/app.routes.ts |
| Teacher route | fe/src/app/features/teacher/teacher.routes.ts |
| Student route | fe/src/app/features/student/student.routes.ts |
| Auth/JWT state | fe/src/app/core/services/auth.service.ts |
| Gọi API | fe/src/app/api/client/ và fe/src/app/api/endpoints/ |
| Course editor | fe/src/app/features/teacher/course-editor/ |
| Learning page | fe/src/app/features/learning/ |
3.4. Nếu sửa backend
cd E:\Sach\Sua\LMS_hohulili\backend
mvn -DskipTests compile -B
mvn test -B
Các file hay dùng khi sửa backend:
| Cần sửa | File/thư mục |
|---|---|
| Security/JWT | backend/src/main/java/com/example/lms/config/ |
| Auth/user | backend/src/main/java/com/example/lms/identity/ |
| Khóa học/bài học | backend/src/main/java/com/example/lms/course_authoring/ |
| Lớp học/tiến độ/video | backend/src/main/java/com/example/lms/learning_delivery/ |
| Quiz/bài tập/chấm điểm | backend/src/main/java/com/example/lms/assessment/ |
| Upload/payment/shared | backend/src/main/java/com/example/lms/shared/ |
3.5. Trước khi commit hoặc nộp PR
git status --short
git diff --stat
git diff
cd fe; npm run build
cd ..\backend; mvn -DskipTests compile -B
.env*, secret, screenshot tạm, cache, build output
hoặc Unity cache trong artifacts/. Khi cần commit, luôn xem kỹ
git status --short -uall.
4. Kiến Trúc Tổng Quan
Hệ thống chia thành ba lớp lớn: frontend, backend, database/storage.
Backend modules
| Module | Vai trò | Ví dụ nghiệp vụ |
|---|---|---|
identity | Người dùng, role, JWT, tổ chức | Login, invite, org admin |
course_authoring | Tạo và duyệt khóa học | Course, chapter, lesson, publication |
learning_delivery | Học tập, lớp, tiến độ, video | Enrollment, progress, certificate, video asset |
assessment | Đánh giá | Quiz, question bank, assignment, grading |
communication | Giao tiếp | Messages, announcements |
ai_assistant | Trợ lý AI/Wiii | Chat sessions, token exchange, AI bridge |
shared | Dùng chung | Upload, payment, audit log, outbox |
Frontend modules
| Thư mục | Vai trò |
|---|---|
fe/src/app/api | Khai báo endpoint, DTO type, API client, interceptor |
fe/src/app/core | Service dùng chung: auth, PWA, upload, SEO, notification |
fe/src/app/features | Màn hình theo domain: teacher, student, admin, learning, courses |
fe/src/app/shared | Component UI dùng lại |
fe/src/app/state | Global state, course state và class state |
5. Frontend Angular
Frontend dùng Angular 20.3, standalone component mặc định, Signals, inject(),
@if/@for và ChangeDetectionStrategy.OnPush.
Route map quan trọng
| URL | Ý nghĩa | File route |
|---|---|---|
/ | Trang chủ public | fe/src/app/app.routes.ts |
/courses | Danh sách khóa học public | fe/src/app/app.routes.ts |
/courses/:id | Chi tiết khóa học public | fe/src/app/app.routes.ts |
/teacher/courses | Teacher dashboard | fe/src/app/features/teacher/teacher.routes.ts |
/teacher/courses/:id/editor | Course editor | fe/src/app/features/teacher/course-editor/course-editor.routes.ts |
/student/courses | Khóa học của học viên | fe/src/app/features/student/student.routes.ts |
/student/learn | Learning shell | fe/src/app/features/learning/learning.routes.ts |
/admin | Quản trị hệ thống | fe/src/app/features/admin/admin.routes.ts |
Pattern component cần nắm
@Component({
selector: 'app-example',
imports: [CommonModule],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@if (isLoading()) {
<p>Đang tải</p>
} @else {
@for (item of items(); track item.id) {
<div>{{ item.name }}</div>
}
}
`
})
export class ExampleComponent {
private service = inject(MyService);
items = signal<Item[]>([]);
itemCount = computed(() => this.items().length);
}
6. Backend Clean Architecture / DDD
Backend không để controller thao tác trực tiếp với database. Controller gọi UseCase, UseCase dùng repository port, còn Infrastructure adapter mới nối với JPA.
Quy tắc vàng
*JpaEntity, không trỏ tới domain model.
Nếu sai sẽ gây lỗi Not a managed type.
Ví dụ câu trả lời
"Em tách domain model và JPA entity để domain không bị phụ thuộc framework. Nếu sau này đổi persistence, business rule vẫn nằm trong domain/use case. Infrastructure chỉ là lớp chuyển đổi và đọc ghi database."
7. Database
Database là PostgreSQL 16, migration bằng Flyway trong
backend/src/main/resources/db/migration/. Các bảng chính gồm:
schema hiện có 78 application tables và 2 materialized views
theo catalog sinh từ migration.
| Nhóm bảng | Bảng tiêu biểu |
|---|---|
| Người dùng/tổ chức | users, organizations, organization_invites, user_external_identities |
| Khóa học | courses, chapters, lessons, sections, course_publications |
| Lớp học | learning_classes, class_teachers, enrollments, student_lesson_progress |
| Đánh giá | quizzes, questions, quiz_attempts, assignments, assignment_submissions |
| Video/upload | upload_sessions, file_attachments, video_assets, video_renditions, video_progress |
| Thanh toán | payment_transactions, revenue_splits, payout_requests, teacher_bank_accounts |
Lệnh xem database local
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec db psql -U lms -d lms
\dt
select count(*) from users;
select count(*) from courses;
Nếu dùng DBeaver local: host localhost, port 5432,
database lms, user lms, password lms
khi chạy dev compose mặc định.
8. Các Luồng Chính Cần Thuộc
8.1. Đăng nhập và phân quyền
features/auth8.2. Teacher tạo khóa học
/teacher/course-creationcourse-editor.store.tscourse_authoring8.3. Admin duyệt khóa học
8.4. Student học bài
/student/coursesfeatures/learning8.5. Quiz và assignment
| Luồng | Teacher | Student | Backend |
|---|---|---|---|
| Quiz | Tạo quiz, question, gắn vào lesson/class | Làm attempt, nộp đáp án, xem kết quả | assessment: quiz, questions, attempts |
| Assignment | Tạo bài tập, rubric, xem submission, chấm điểm | Nộp bài, xem feedback/điểm | assessment: assignments, submissions, grading audit |
9. Upload, Video, Offline
9.1. Upload tài liệu, ảnh, video
Upload hiện đại không đẩy file lớn qua backend trực tiếp. Hệ thống dùng presigned upload:
9.2. Video adaptive
Video nội bộ dùng Cloudflare R2 private + Shaka Packager để tạo HLS/DASH. Production có dedicated video worker để ingest video, tránh để web backend bị nghẽn.
| Thành phần | Vai trò |
|---|---|
video_assets | Bản ghi video gốc và metadata |
video_renditions | Các bản encode/chất lượng |
video_ingest_jobs | Hàng đợi xử lý video |
media.holilihu.online | Media domain qua Cloudflare Worker edge auth |
9.3. Offline/PWA
Offline là dữ liệu cục bộ trên từng thiết bị. Dữ liệu học offline nằm trong IndexedDB/Dexie, tiến độ sync theo hướng cộng dồn và tiến lên, không ghi đè lùi tiến độ trên server.
File nên đọc:
fe/src/app/core/db/lms-offline.db.tsfe/src/app/core/services/course-download.service.tsfe/src/app/core/services/offline-sync.service.tsfe/src/app/api/interceptors/offline.interceptor.ts
10. Bảo Mật Và Phân Quyền
Bảo mật chính gồm JWT, route guards, backend method security, CORS/CSP, rate limiting và tách role theo quyền.
| Vai trò | Quyền chính |
|---|---|
ADMIN | Quản trị hệ thống, settings, logs, xóa user/course |
ORG_ADMIN | Duyệt khóa học, quản lý teacher/student, analytics vận hành |
TEACHER | Tạo khóa học, lớp học, bài tập, quiz, chấm điểm |
STUDENT | Học, làm quiz/bài tập, thanh toán, xem kết quả |
Files quan trọng
backend/src/main/java/com/example/lms/config/SecurityConfig.javabackend/src/main/java/com/example/lms/config/JwtAuthenticationFilter.javafe/src/app/core/guards/role.guard.tsfe/src/app/api/interceptors/auth.interceptor.ts
11. Debug Nhanh
Backend không lên
docker compose -f docker-compose.yml -f docker-compose.dev.yml logs backend --tail=100
docker compose -f docker-compose.yml -f docker-compose.dev.yml ps
Not a managed type: JPA repository đang trỏ tới domain model thay vì*JpaEntity.- DB connection fail: kiểm tra container
dbcó healthy không. - R2/access key fail ở dev: kiểm tra config dev và biến môi trường dev.
Frontend không gọi được API
curl.exe -s http://localhost:8088/actuator/health
rg "apiUrl|baseUrl|localhost:8088" fe/src/environments fe/src/app
Port bị chiếm
netstat -ano | findstr :4200
netstat -ano | findstr :8088
Build frontend lỗi
cd E:\Sach\Sua\LMS_hohulili\fe
npm run build
Test backend quá chậm
cd E:\Sach\Sua\LMS_hohulili\backend
mvn -DskipTests compile -B
Khi sửa logic quan trọng, cần chạy test liên quan hoặc full mvn test -B.
12. Mở Code Để Sửa Khi Cần
Cách học dự án nhanh nhất là mở theo luồng người dùng, không mở ngẫu nhiên từng file. Khi thầy chỉ một màn hình bất kỳ, hãy truy ngược theo chuỗi: route → component → service/store → API endpoint → controller → use case → repository → migration/database.
12.1. Mở project bằng VS Code
cd E:\Sach\Sua\LMS_hohulili
code .
Nên mở 3 terminal trong VS Code:
| Terminal | Dùng để làm gì | Lệnh thường dùng |
|---|---|---|
| Terminal 1 | Backend, Docker, database | docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d db backend |
| Terminal 2 | Frontend Angular | cd fe && npm start |
| Terminal 3 | Tìm code, build, test | rg "course-editor|video-assets|submit-for-approval" fe/src backend/src |
artifacts/. Đây là thư mục lớn, có thể chứa build/cache/tài nguyên tạm.
Khi commit hoặc nộp PR, chỉ stage đúng file mình sửa.
12.2. Mở backend bằng IntelliJ IDEA
Backend là Maven project. Có thể mở thẳng thư mục backend/ bằng IntelliJ để IDE nhận Java 21,
Spring Boot, Maven dependency và test runner. Nếu mở bằng VS Code vẫn được, nhưng IntelliJ dễ đọc luồng
Controller → UseCase → Repository hơn.
cd E:\Sach\Sua\LMS_hohulili\backend
mvn -DskipTests compile -B
12.3. Mở database bằng DBeaver
DBeaver phù hợp để xem sơ đồ tổng, bảng, khóa ngoại và dữ liệu mẫu. Với local Docker, kết nối thường là:
| Trường | Giá trị local thường dùng |
|---|---|
| Host | localhost |
| Port | 5432 |
| Database | lms |
| User | lms |
| Password | Lấy từ .env local, không đưa vào tài liệu hoặc commit. |
12.4. Cách tìm đúng file trong Angular
cd E:\Sach\Sua\LMS_hohulili
rg "path: 'curriculum'|course-editor|teacher-dashboard" fe/src/app
rg "updateCourseInfo|submitForApproval|getCourseDraft" fe/src/app/features/teacher
rg "#0056D2|--c-primary|--c-accent|bg-\[" fe/src
Các màn teacher/course editor quan trọng nằm ở:
fe/src/app/features/teacher/teacher.routes.ts: route lớn của teacher.fe/src/app/features/teacher/course-editor/course-editor.routes.ts: route coninfo,curriculum,competency,settings,classes.fe/src/app/features/teacher/course-editor/store/course-editor.store.ts: state, cache, readiness checklist, optimistic UI.fe/src/app/features/teacher/course-editor/services/course-authoring.service.ts: DTO và các API gọi backend.
12.5. Cách tìm đúng file trong backend
rg "@RequestMapping|@GetMapping|@PostMapping|@PutMapping|@PatchMapping|@DeleteMapping" backend/src/main/java/com/example/lms
rg "submitForApproval|createCourse|updateCourse" backend/src/main/java/com/example/lms/course_authoring
rg "video-assets|adaptive|playback" backend/src/main/java/com/example/lms/learning_delivery
Backend đi theo Clean Architecture/DDD. Nếu sửa nghiệp vụ, ưu tiên sửa ở application/usecase
hoặc domain/model. Controller chỉ nhận request, kiểm quyền, validate nhẹ và gọi use case.
13. Kịch Bản Sửa Code Hay Gặp
13.1. Đổi màu hoặc giao diện
| Muốn đổi | Sửa ở đâu | Cách kiểm tra |
|---|---|---|
| Màu chủ đạo toàn app | fe/src/styles.scss và fe/src/styles/_variables.scss | cd fe && npm run build, mở http://localhost:4200 |
| Màu Angular Material | mat.theme(...) trong fe/src/styles.scss | Mở các dialog/input/material control. |
| Màu riêng một nút/card | File .html hoặc .scss của component đó | Tìm bằng rg "#0056D2|bg-\[|text-\[" fe/src/app |
| Tránh nháy layout lúc load | fe/src/styles/critical.scss | Reload hard refresh và quan sát màn đầu. |
13.2. Đổi logic frontend
Ví dụ thầy yêu cầu: "đổi điều kiện cho phép publish course". Cách lần:
- Tìm chữ đang hiển thị hoặc action button trong template:
rg "publish|submitForApproval|Gửi duyệt" fe/src/app. - Mở component hoặc store liên quan, thường là
CourseEditorStorehoặc page trongcourse-editor/pages/. - Nếu logic là state UI, sửa signal/computed trong frontend.
- Nếu logic là nghiệp vụ thật, sửa backend use case để không bị bypass bằng API.
- Chạy
cd fe && npm run build; nếu có backend đổi thì chạy thêmcd backend && mvn -DskipTests compile -B.
inject(), input()/output(), control flow @if/@for,
ChangeDetectionStrategy.OnPush, không thêm standalone: true vì Angular 20 đã mặc định standalone.
13.3. Đổi logic backend
Ví dụ thầy yêu cầu: "khóa học trả phí phải có giá lớn hơn 0". Luồng sửa đúng:
TeacherCoursesControllerV3CourseDTOsCourseAuthoringUseCaseCourse
Nếu chỉ đổi rule, thường sửa ở application/usecase hoặc domain/model.
Nếu thêm cột/bảng, tạo migration mới trong backend/src/main/resources/db/migration/,
ví dụ V136__add_course_field.sql. Không dựa vào ddl-auto để production tự sinh schema.
13.4. Thêm trường mới vào Course
| Bước | File cần xem |
|---|---|
| 1. Thêm cột DB | backend/src/main/resources/db/migration/Vxxx__... |
| 2. Thêm JPA field | course_authoring/infrastructure/persistence/entity/*Course*JpaEntity.java |
| 3. Map domain/DTO | infrastructure/persistence/mapper/ và application/dto/ |
| 4. Sửa use case | CourseAuthoringUseCase, GetCourseDraftUseCase |
| 5. Sửa Angular DTO/service | course-authoring.service.ts |
| 6. Sửa UI form | course-editor/pages/course-info hoặc page liên quan. |
13.5. Sửa tiếng Việt và i18n/ARB
Dự án hiện là Angular, không dùng file .arb kiểu Flutter. Phần lớn chữ tiếng Việt đang nằm trực tiếp
trong template/component, route title, toast message và backend response message. Khi cần sửa chữ:
rg "Từ cần sửa|Không thể|Gửi duyệt|Khóa học" fe/src backend/src
Nếu sau này muốn i18n chuẩn, nên thiết kế riêng bằng Angular i18n hoặc JSON translation files. Không tự thêm lẻ tẻ một hệ ARB vào giữa dự án khi chưa có quyết định kiến trúc.
13.6. Wiii/Pointy và metadata DOM an toàn
LMS đã có các target như data-wiii-id, data-wiii-click-safe,
data-wiii-click-kind ở teacher dashboard, course creation, course editor sidebar,
section editor và preview dialog. Chỉ gắn data-wiii-click-safe="true" cho thao tác điều hướng,
mở panel hoặc form step an toàn. Không gắn safe cho submit quiz, delete, publish, enroll, grade, payment.
rg "data-wiii-id|data-wiii-click-safe|data-wiii-click-kind" fe/src/app/features/teacher fe/src/app/features/ai-chat
14. Shaka, ABR, Media Và Upload
14.1. Phân biệt ARB và ABR
Nếu hỏi về ARB theo nghĩa file dịch ngôn ngữ thì dự án hiện không dùng ARB. Nếu hỏi về ABR, đó là Adaptive Bitrate: trình phát tự đổi chất lượng video theo băng thông và tình trạng buffer.
14.2. Frontend Shaka Player nằm ở đâu?
| File | Vai trò |
|---|---|
fe/src/app/features/learning/components/adaptive-video-player/adaptive-video-player.component.ts | Khởi tạo Shaka, load HLS/DASH, cấu hình ABR, chọn chất lượng thủ công. |
fe/src/app/core/utils/video-stream-recovery.ts | Quyết định khi nào refresh playback URL sau lỗi 401/403/404/5xx. |
fe/src/app/core/utils/video-offline-policy.ts | Phân biệt video nội bộ có thể offline và video external/YouTube online-only. |
14.3. Các dòng ABR quan trọng
rg "abr:|defaultBandwidthEstimate|switchInterval|selectQuality|resolveAdaptivePlayUrl" fe/src/app/features/learning/components/adaptive-video-player
| Thiết lập | Ý nghĩa |
|---|---|
abr.enabled: true | Bật tự động chọn chất lượng. |
defaultBandwidthEstimate: 900_000 | Ước lượng ban đầu khoảng 900 Kbps để tránh nhảy ngay lên chất lượng quá cao. |
switchInterval: 8 | Khoảng thời gian giữa các lần cân nhắc đổi chất lượng. |
selectQuality(null) | Quay lại chế độ tự động. |
selectQuality(q) | Tắt ABR và chọn track theo độ phân giải. |
14.4. Backend đóng gói video bằng Shaka như thế nào?
video_assetsVideoAssetIngestService| File/config | Ý nghĩa |
|---|---|
backend/Dockerfile | Cài FFmpeg, libx264 và tải Shaka Packager binary. |
backend/src/main/resources/application.yml | Các biến app.video.*: token, segment TTL, profile, media domain. |
VideoAssetIngestService | Chọn profile SAVER, STANDARD, HIGH, gọi FFmpeg và Shaka. |
ShakaPackagerService | Gọi command packager, tạo manifest HLS/DASH và kiểm output. |
AdaptiveVideoPlaybackController | Serve manifest/object qua token playback. |
14.5. Muốn đổi chất lượng encode hoặc profile
Có hai lớp cần phân biệt:
- Profile tạo file: chỉnh
VIDEO_ADAPTIVE_PROFILES,VIDEO_OFFLINE_PROFILES,VIDEO_ADAPTIVE_SEGMENT_DURATION_SECONDS,VIDEO_FFMPEG_PRESET. - Hành vi phát trên trình duyệt: chỉnh ABR trong
adaptive-video-player.component.ts.
rg "VIDEO_ADAPTIVE_PROFILES|VIDEO_OFFLINE_PROFILES|VIDEO_FFMPEG_PRESET|adaptive-segment" backend docker-compose*.yml docs
14.6. Smoke test video local
- Chạy backend và frontend local.
- Đăng nhập teacher, upload video vào lesson hoặc section.
- Kiểm tra asset có trạng thái xử lý xong.
- Đăng nhập student, mở bài học có video.
- Mở DevTools Network, kiểm tra có request
master.m3u8hoặcmanifest.mpd. - Thử menu chất lượng:
Tự động,360p,720pnếu có.
15. Kiểm Thử Trước Khi Nộp Hoặc Báo Cáo
15.1. Baseline nhanh
cd E:\Sach\Sua\LMS_hohulili\fe
npm run build
cd E:\Sach\Sua\LMS_hohulili\backend
mvn -DskipTests compile -B
cd E:\Sach\Sua\LMS_hohulili
docker compose -f docker-compose.yml -f docker-compose.dev.yml config -q
curl.exe -s http://localhost:8088/actuator/health
15.2. Khi sửa frontend
- Chạy
cd fe && npm run build. - Mở
http://localhost:4200, đăng nhập đúng role và bấm flow vừa sửa. - Nếu sửa PWA/offline/video/payment, cân nhắc chạy
cd fe && npm run test:e2e:smoke.
15.3. Khi sửa backend
- Chạy
cd backend && mvn -DskipTests compile -Btrước để bắt lỗi compile. - Nếu sửa use case hoặc rule, chạy test liên quan bằng Maven.
- Nếu sửa schema, chạy lại Docker DB local từ trạng thái sạch hoặc kiểm Flyway migration.
15.4. Checklist trước khi nói "done"
| Cần kiểm | Bằng chứng nên có |
|---|---|
| Build frontend | npm run build pass. |
| Compile/backend test | mvn -DskipTests compile -B hoặc test liên quan pass. |
| Runtime local | /actuator/health trả {"status":"UP"}. |
| Flow UI | Ảnh chụp hoặc mô tả màn đã smoke: login, tạo course, upload, học bài. |
| Không commit rác | git status --short chỉ có file cần nộp, không có .env, cache, build output. |
16. Câu Hỏi Bảo Vệ Thường Gặp
Vì sao tách frontend và backend?
Để UI và business API độc lập. Frontend Angular tối ưu trải nghiệm người dùng, backend Spring Boot đảm nhận security, transaction và nghiệp vụ.
Vì sao dùng Clean Architecture/DDD?
Vì hệ thống LMS có nhiều nghiệp vụ: course, learning, assessment, payment, video. Tách domain/use case/infrastructure giúp code dễ bảo trì, dễ test, và tránh việc controller hoặc JPA bị trộn với business rule.
Vì sao dùng publication snapshot?
Teacher có thể sửa bản nháp mà không ảnh hưởng học viên đang học. Học viên đọc nội dung đã công bố/approved, còn bản nháp mới chỉ ra ngoài sau khi submit và admin duyệt.
Vì sao upload file qua presigned URL?
File lớn không nên đi qua backend web request. Presigned upload cho phép browser upload trực tiếp lên storage, backend chỉ quản lý session, quyền truy cập và metadata.
Vì sao video có worker riêng?
Encode/packaging video tốn CPU và thời gian. Tách dedicated video worker giúp backend web vẫn phục vụ user ổn định khi có nhiều video đang ingest.
Nếu thầy hỏi "em đóng góp phần nào?"
Hãy trả lời theo module/luồng mình nắm chắc. Ví dụ: "Em nắm luồng teacher tạo khóa học, student học bài, upload/video, và cách backend DDD xử lý từ controller đến database."
17. Lịch Học Tới Ngày 20
| Ngày | Nội dung | Kết quả cần đạt |
|---|---|---|
| Ngày 1 | Kiến trúc tổng quan + chạy local | Nói được request flow và mở được app local |
| Ngày 2 | Auth/role/JWT + route guards | Giải thích được phân quyền bốn role |
| Ngày 3 | Teacher course editor | Chỉ được file UI, store, API, backend course use case |
| Ngày 4 | Student learning + progress | Giải thích được publication/progress/offline |
| Ngày 5 | Quiz/assignment/grading | Nắm bảng DB và backend module assessment |
| Ngày 6 | Video/upload/payment/admin | Trả lời được các câu hỏi khó về runtime |
| Ngày 7 | Luyện demo và sửa lỗi nhỏ | Chạy build/test, sửa UI/API nhỏ tự tin |