- Given Đăng nhập thành công lần thứ hai trên một trình duyệt di động chưa cài đặt
- When Màn hình chính của lớp vỏ hiển thị
- Then Thẻ "Thêm Trường Số vào màn hình chính" xuất hiện; trên Android và desktop, thẻ mở hộp thoại cài đặt của trình duyệt; trên iOS, thẻ mở hướng dẫn ba bước có hình; thẻ ẩn được trong 14 ngày; sau khi cài, ứng dụng mở ở chế độ standalone với biểu tượng và màn hình khởi động theo Cloud theme.
PRD 17 · Ứng dụng di động
Một mã nguồn duy nhất cho giao diện di động của Trường Số với bốn lớp vỏ theo vai trò (quản lý, giáo viên, tư vấn viên, phụ huynh và học viên), phát hành dưới dạng PWA cài đặt được ở P1 và đóng gói thành ứng dụng gốc iOS/Android ở P2. Tài liệu quy định phạm vi dữ liệu ngoại tuyến, quy tắc xung đột khi đồng bộ, thông báo đẩy kèm liên kết sâu, xác thực lại bằng sinh trắc học, sổ đăng ký thiết bị và ngân sách hiệu năng trên mạng 3G.
Xuất xứ / Prompt / Giới hạn
Tài liệu do trợ lý AI soạn trong một phiên làm việc ngày 16/09/2026, mở rộng bộ PRD theo yêu cầu gốc được trích nguyên văn ở trang mục lục. Đây là bản đề xuất để đội thảo luận, chưa phải quyết định của đội sản phẩm.
Nguồn
- Nghiên cứu công khai về đối thủ cạnh tranh (PSE ONE, pse4.one), mã nguồn
center-crm-frontendvà đặc tả OpenAPI/v3trên staging (182 endpoint), tính đến ngày 10/09/2026. - Nhãn existing / extend / new trong trang được xác định bằng cách đối chiếu với đặc tả
/v3trên staging tại thời điểm trên. - Đợt quét thứ hai các nguồn công khai của PSE ONE ngày 16/09/2026 (trang tính năng, bảng phí dịch vụ, mục hướng dẫn sử dụng).
- Tham chiếu đối thủ cạnh tranh: PSE ONE (pse4.one, khảo sát công khai ngày 16/09/2026) giới thiệu ứng dụng di động là điểm khác biệt chính, chạy trên desktop, laptop, máy tính bảng, Android và iOS, với ba ứng dụng riêng cho phụ huynh (lịch học, điểm danh, kết quả học tập, học phí), học viên (thông báo, tài liệu học tập, đánh giá khoá học) và giáo viên (lịch dạy, điểm danh, nhập đánh giá, báo cáo sự cố), cùng một ứng dụng giám sát cho chủ trung tâm.
Giới hạn
- Cần xác minh khi khảo sát trực tiếp trong ứng dụng, vì đăng nhập tự động vào sản phẩm tham chiếu chưa được cấp phép trong phiên soạn:
- Ứng dụng di động của đối thủ là ứng dụng gốc trên cửa hàng hay web đóng gói; có hoạt động khi mất mạng không và dữ liệu nào được lưu trên máy.
- Ba ứng dụng phụ huynh, học viên và giáo viên của đối thủ là ba ứng dụng riêng trên cửa hàng hay một ứng dụng phân vai sau đăng nhập.
- "Thông báo và nhắc nhở thông minh" gồm những loại nào, gửi qua kênh nào (thông báo đẩy, Zalo, SMS) và người dùng có tắt được từng loại không.
- Ứng dụng giám sát cho chủ trung tâm hiển thị số liệu nào theo thời gian thực và có tách theo chi nhánh không.
- Đối thủ có giới hạn số thiết bị đăng nhập, có màn hình quản lý thiết bị và xác thực sinh trắc học không.
- "Báo cáo sự cố" của giáo viên trong ứng dụng đối thủ gồm những trường nào và ai nhận báo cáo.
Thiết kế đề xuất
Sáu màn hình di động 390 px cho bốn lớp vỏ vai trò trên cùng một mã nguồn và một màn hình desktop cho sổ đăng ký thiết bị; điều quan trọng nhất là mỗi lớp vỏ chỉ chứa việc trong ngày của vai trò đó, còn trạng thái mạng, hàng đợi đồng bộ và xung đột luôn hiện bằng chữ ngay trên màn hình.






deep_link tới phiếu điểm danh, không có số tiền hay tên đầy đủ (quy tắc 7); danh sách thông báo theo nhóm với dấu chưa đọc, mục vừa chạm được tô nền và đánh dấu đã đọc, thanh thông báo tối cho phép hoàn tác (MOB-03).
1Mục đích
Phần lớn thao tác hằng ngày của một trung tâm không diễn ra trước máy tính: giáo viên điểm danh trong lớp, quản lý chi nhánh phê duyệt khi di chuyển giữa các cơ sở, tư vấn viên gọi điện từ điện thoại, phụ huynh mở Trường Số sau khi nhận một tin nhắn Zalo. Trường Số hiện là một ứng dụng web đáp ứng (responsive) dùng chung cho mọi vai trò, chưa cài đặt được lên màn hình chính, chưa hoạt động khi mất mạng và chưa gửi được thông báo đẩy. Tài liệu này quy định một giao diện di động dùng chung mã nguồn với web, chia thành các lớp vỏ (shell) theo vai trò, mỗi lớp vỏ chỉ chứa những việc mà vai trò đó cần làm trong ngày.
Quyết định nền tảng: PWA trước ở P1 (cài đặt được, service worker, đồng bộ nền, Web Push trên Android và desktop, Web Push trên iOS 16.4 trở lên sau khi cài lên màn hình chính); đóng gói bằng Capacitor ở P2 để có mặt trên App Store và Google Play và để thông báo đẩy trên iOS hoạt động ổn định. Không viết lại giao diện bằng công nghệ gốc.
Trong phạm vi
- Bốn lớp vỏ theo vai trò trên cùng một mã nguồn: Quản lý (chủ trung tâm, quản lý chi nhánh), Giáo viên, Tư vấn viên, Phụ huynh và học viên; thanh tab dưới cùng tối đa năm mục.
- PWA cài đặt được: manifest, service worker, lời mời cài đặt, hướng dẫn riêng cho iOS.
- Phạm vi dữ liệu ngoại tuyến, hàng đợi ghi ngoại tuyến và quy tắc giải quyết xung đột khi đồng bộ.
- Thông báo đẩy kèm liên kết sâu (deep link); sổ đăng ký thiết bị, thu hồi thiết bị và phiên đăng nhập; xác thực lại bằng sinh trắc học.
- Ngân sách hiệu năng trên mạng 3G, kế thừa PRD 12.
- Ứng dụng gốc iOS/Android ở P2: đóng gói Capacitor, thông báo đẩy qua APNs và FCM, phát hành lên cửa hàng.
Ngoài phạm vi
- Nghiệp vụ của từng mô-đun (điểm danh, điểm số, sổ đầu bài, công việc, cổng phụ huynh) đã được quy định ở PRD tương ứng; tài liệu này chỉ quy định cách chúng xuất hiện và hoạt động trên di động.
- Ứng dụng học tập FLYER của học viên và ứng dụng giáo viên FLYER hiện có.
- Máy tính bảng chế độ kiosk cho lễ tân, check-in bằng mã QR (P3); chat hai chiều giáo viên và phụ huynh (P3, PRD 07).
Ma trận tính năng theo vai trò và giai đoạn
| Tính năng | Quản lý | Giáo viên | Tư vấn viên | Phụ huynh | PRD |
|---|---|---|---|---|---|
| Số liệu hôm nay, cảnh báo | P1 | không | P1 (chỉ tiêu) | không | 09 |
| Phê duyệt giảm giá, đơn xin nghỉ, sự cố | P1 | không | không | không | 05, 16 |
| Việc của tôi; đơn xin nghỉ, báo cáo sự cố | P1 | P1 | P1 | xin phép nghỉ P1 | 16, 04 |
| Lịch dạy hôm nay / lịch học | P1 | P1 | P1 (học thử) | P1 | 03, 07 |
| Điểm danh ngoại tuyến, đồng bộ nền | điểm danh thay P1 | P1 | không | xem P1 | 04 |
| Nhập điểm, nhận xét; sổ đầu bài | xem P1 | P1 (ngoại tuyến) | không | kết quả, tài liệu P1 | 13, 14 |
| Hàng đợi gọi, gọi từ ứng dụng, khách hàng nguội | không | không | P1 | không | 01 |
| Học phí, thanh toán QR | xem công nợ P1 | không | không | P1 | 05, 07 |
| Thông báo đẩy: Web Push / qua cửa hàng | P1 / P2 | P1 / P2 | P1 / P2 | P1 / P2 | 17 |
| Sinh trắc học: WebAuthn / gốc | P1 / P2 | P1 / P2 | P1 / P2 | P2 | 17, 12 |
| Sổ đăng ký thiết bị, thu hồi | P1 (toàn tenant) | P1 (của bản thân) | P1 (của bản thân) | P1 (của bản thân) | 17 |
| Ứng dụng gốc trên cửa hàng | P2 | P2 | P2 | P2 | 17 |
2Hiện trạng
Trường Số chưa có ứng dụng trên cửa hàng và chưa có cấu hình PWA. PRD 04 và PRD 07 đã giả định một PWA giáo viên có hàng đợi điểm danh ngoại tuyến và một cổng phụ huynh đăng nhập bằng OTP; tài liệu này quy định hai giả định đó thành nền tảng chung.
| Năng lực hiện có | Endpoint | Giữ lại? |
|---|---|---|
| Hồ sơ người dùng, quyền, chi nhánh được truy cập | GET /v3/crm/me, /v3/crm/me/permissions, /v3/crm/me/accessible-schools | existing · giữ; quyết định lớp vỏ được hiển thị |
| Kế hoạch hôm nay | GET /v3/crm/me/today-plan | existing · giữ; PRD 09 và 16 bổ sung mục điểm danh, phê duyệt, việc được giao |
| Thông báo trong ứng dụng: danh sách, số chưa đọc, đã đọc, đọc tất cả, lưu trữ | GET /v3/crm/me/notifications, /unread-count, /read, /read-all, /archive | existing · giữ; thêm deep_link, category |
| Báo cáo học tập và báo cáo tuần cho phụ huynh | GET /v3/parent/learner/{id}/weekly-report, /report | existing · giữ; tab Kết quả của phụ huynh |
| Cờ tính năng phía học viên | GET /v3/learner/feature-configs | existing · giữ; mẫu cho cờ tính năng theo lớp vỏ |
| Manifest, service worker, đồng bộ nền, Web Push, sổ đăng ký thiết bị, đóng gói gốc | không có | new |
3User story và tiêu chí chấp nhận
- Given Ứng dụng đã mở ít nhất một lần trong ngày khi có mạng nên lịch dạy và danh sách lớp của các buổi học trong ngày đã lưu trên máy
- When Mở phiếu điểm danh khi không có mạng, đánh dấu và chọn Lưu
- Then Phiếu vào hàng đợi ngoại tuyến với
client_saved_at; buổi học hiển thị chip "Chưa đồng bộ" và banner "1 mục chờ đồng bộ"; khi có mạng, service worker gửi hàng đợi bằng Background Sync hoặc ngay khi ứng dụng mở lại; từng mục hiển thị Đã đồng bộ hoặc Xung đột; trường hợp thành công không cần thao tác thêm.
- Given Thiết bị đã đăng ký nhận thông báo đẩy và phát sinh sự kiện có thông báo (buổi học chưa điểm danh, đơn xin nghỉ chờ duyệt, việc được giao, phiếu thu mới)
- When Chạm vào thông báo trên màn hình khoá hoặc khay thông báo
- Then Ứng dụng mở đúng route trong
deep_link(ví dụ/teach/sessions/:id/attendance) kể cả khi chưa chạy; nếu phiên đã hết hạn, ứng dụng đăng nhập lại rồi tiếp tục tới route đó; thông báo được đánh dấu đã đọc qua/v3/crm/me/notifications/read; mỗi thông báo thuộc một nhóm (category) để tắt từng nhóm trong Cài đặt thông báo.
- Given Vai trò owner hoặc branch_manager, đã chọn chi nhánh hoặc "Tất cả chi nhánh"
- When Mở tab Hôm nay rồi tab Phê duyệt của lớp vỏ Quản lý
- Then Tab Hôm nay hiển thị thẻ số liệu từ PRD 09 (buổi học đã điểm danh x/y, học viên vắng, thu trong ngày, lead mới, học thử) và cảnh báo (chưa điểm danh quá 2 giờ, vắng liên tiếp, học phí quá hạn), mỗi thẻ mở được danh sách chi tiết và được lưu trên máy để mở lại tức thì; tab Phê duyệt liệt kê yêu cầu giảm giá (PRD 05), đơn xin nghỉ và báo cáo sự cố (PRD 16) với người gửi, đối tượng, thời gian chờ, hai nút Duyệt và Từ chối (từ chối cần lý do), ghi nhật ký theo PRD 12; yêu cầu vượt hạn mức của vai trò hiển thị nhãn "Cần chủ trung tâm" và không có nút Duyệt.
- Given Hàng đợi gọi của bản thân từ PRD 01 (gọi lại đã hẹn, lead mới chưa liên hệ, khách hàng nguội quá 14 ngày)
- When Chọn Gọi trên một dòng
- Then Trình quay số của điện thoại mở với số đầy đủ (giao diện chỉ hiển thị số đã che một phần); khi quay lại ứng dụng, phiếu kết quả cuộc gọi hiện lên với thời điểm bắt đầu, thời lượng ước tính và các kết quả có sẵn của PRD 01; lưu phiếu tạo một tương tác loại Call trên lead; phiếu chưa hoàn tất được nhắc lại sau 10 phút; lead có cờ Không gọi không có nút Gọi.
- Given Đã đăng nhập bằng OTP theo PRD 07; học viên có sổ đầu bài (PRD 14) và điểm đã công bố (PRD 13)
- When Mở tab Học tập của học viên
- Then Thấy Tài liệu bài học (theo buổi học: tiêu đề, nội dung đã dạy, bài tập về nhà, tệp đính kèm giáo viên đã đánh dấu chia sẻ) và Kết quả (điểm, nhận xét đã công bố, báo cáo tuần và báo cáo học tập từ
/v3/parent/learner/{id}/weekly-reportvà/report); tệp đính kèm mở trong trình xem của ứng dụng và chỉ tải khi chọn; nội dung chưa công bố không bao giờ xuất hiện.
- Given Thiết bị hỗ trợ sinh trắc học và người dùng đã bật "Mở khoá bằng vân tay hoặc khuôn mặt" trong Tài khoản
- When Ứng dụng trở lại nền trước sau hơn 5 phút (nhân sự) hoặc 30 phút (phụ huynh), hoặc trước khi mở màn hình có dữ liệu tài chính và liên hệ phụ huynh
- Then Màn hình khoá che nội dung và yêu cầu xác thực qua WebAuthn (P1) hoặc API sinh trắc học gốc (P2); thành công thì tiếp tục tại màn hình đang mở; thất bại ba lần thì đăng nhập lại bằng mật khẩu hoặc OTP; ảnh xem trước trong bộ chuyển đa nhiệm của hệ điều hành được che trống.
- Given Đăng nhập trên một thiết bị lần đầu
- When Ứng dụng khởi động sau đăng nhập
- Then Thiết bị được đăng ký qua
POST /v3/crm/me/devices(tên, nền tảng, phiên bản, token đẩy nếu có); nhật ký ghi "đăng nhập từ thiết bị mới" và các thiết bị khác của cùng người dùng nhận thông báo; trong Tài khoản, người dùng thấy danh sách thiết bị và chọn Thu hồi để đăng xuất từ xa; chủ trung tâm thấy thiết bị của toàn tenant; thiết bị bị thu hồi nhận 401 kèmDEVICE_REVOKEDở lần gọi API tiếp theo và xoá toàn bộ dữ liệu ngoại tuyến trên máy.
- Given Bản đóng gói Capacitor của cùng mã nguồn web đã phát hành lên hai cửa hàng
- When Phụ huynh cài từ cửa hàng và đăng nhập bằng OTP
- Then Ứng dụng hoạt động như bản PWA; thông báo đẩy đi qua APNs hoặc FCM; liên kết
https://truongso.net/m/...trong tin nhắn Zalo mở thẳng ứng dụng gốc (Universal Links, App Links); nội dung web cập nhật từ máy chủ mà không phát hành lại trừ khi đổi plugin gốc; bản cũ hơn phiên bản tối thiểu nhận màn hình yêu cầu cập nhật khi khởi động.
4Màn hình
Sau đăng nhập, ứng dụng đọc /v3/crm/me và /v3/crm/me/permissions để chọn lớp vỏ: quyền quản lý chi nhánh vào Quản lý, có TeacherProfile và lớp được phân công vào Giáo viên, có SaleProfile vào Tư vấn viên; người dùng nhiều vai trò có bộ chuyển lớp vỏ trong tab Tài khoản, lớp vỏ dùng gần nhất được ghi nhớ. Phụ huynh vào /parent theo PRD 07. Thành phần dùng chung: thanh tiêu đề có bộ chuyển chi nhánh, chuông thông báo với số chưa đọc từ /unread-count, banner mạng và đồng bộ (mở danh sách hàng đợi với trạng thái Chờ, Đang gửi, Đã đồng bộ, Xung đột, Lỗi và nút Thử lại tất cả), màn hình khoá sinh trắc học.
| Lớp vỏ | Thanh tab | Ghi chú |
|---|---|---|
| Quản lý | Hôm nay · Cảnh báo · Phê duyệt · Việc của tôi · Tài khoản | bộ chuyển chi nhánh ở thanh tiêu đề |
| Giáo viên | Hôm nay · Lịch tuần · Lớp của tôi · Việc của tôi · Tài khoản | giữ cấu trúc PRD 04, thêm Việc của tôi |
| Tư vấn viên | Hôm nay · Hàng đợi gọi · Khách hàng · Học thử · Tài khoản | Hôm nay gồm chỉ tiêu và today-plan |
| Phụ huynh | Trang chủ · Lịch học · Học tập · Học phí · Thông báo | Học tập gộp Điểm danh, Tài liệu, Kết quả |
Danh sách buổi học hôm nay theo PRD 04, thêm chip đồng bộ (Đã đồng bộ, Chờ đồng bộ, Xung đột). Trang buổi học có ba phân đoạn: Điểm danh (PRD 04), Sổ đầu bài (PRD 14: nội dung đã dạy, bài tập về nhà, tệp đính kèm, công tắc chia sẻ phụ huynh), Điểm (PRD 13: nhập điểm và nhận xét theo danh sách, lưu nháp ngoại tuyến, công bố khi có mạng). Đơn xin nghỉ và Báo cáo sự cố (PRD 16) nằm trong menu ba chấm và trong tab Việc của tôi. Cả ba phân đoạn đọc được ngoại tuyến khi buổi học thuộc phạm vi đã lưu (mục 5).
Bốn phần: Gọi lại đã hẹn (sắp theo giờ hẹn, quá giờ hiển thị Quá giờ), Chưa liên hệ (lead mới được giao, sắp theo mức ưu tiên), Khách hàng nguội (không có tương tác quá 14 ngày theo ngưỡng của tenant, sắp theo giá trị cơ hội), Học thử hôm nay (kèm trạng thái xác nhận và nút Nhắn Zalo). Mỗi dòng: tên phụ huynh, học viên dự kiến, nguồn, nút Gọi, nút Ghi chú; phiếu kết quả cuộc gọi hiện dạng bottom sheet. Hàng đợi lưu trên máy để đọc ngoại tuyến; phiếu ghi khi ngoại tuyến vào hàng đợi đồng bộ. Trạng thái rỗng theo từng phần.
Ba phân đoạn: Điểm danh (lịch tháng theo PRD 04), Tài liệu (theo buổi học: ngày, tiêu đề, nội dung đã dạy, bài tập về nhà, tệp đính kèm kèm kích thước), Kết quả (bảng điểm đã công bố theo kỳ, nhận xét, nút mở báo cáo tuần). Trạng thái rỗng: "Giáo viên chưa đăng tài liệu cho lớp này". Học viên người lớn thấy cùng màn hình cho chính bản thân.
Bảng: thiết bị (tên do hệ điều hành cung cấp hoặc người dùng đặt, nhãn "Thiết bị này"), nền tảng (chip Android PWA / iOS PWA / iOS gốc / Android gốc / Web), thông báo đẩy (Đang bật / Đã tắt / Không hỗ trợ), hoạt động gần nhất (thời điểm, thành phố suy ra từ IP), thao tác Đổi tên · Thu hồi. /manage/devices dành cho chủ trung tâm: toàn bộ thiết bị nhân sự trong tenant, lọc theo nhân sự, chi nhánh, trạng thái; nhân sự Đã nghỉ còn thiết bị hoạt động được đưa lên đầu với nhãn Cần thu hồi.
5Quy tắc nghiệp vụ
- Một mã nguồn: các lớp vỏ di động là route trong center-crm-frontend, dùng chung thành phần, file message vi/en và lớp gọi API với desktop; bản đóng gói gốc ở P2 tải cùng bundle web.
- Lớp vỏ được chọn theo quyền, không theo kích thước màn hình; giao diện desktop đầy đủ luôn truy cập được qua mục "Mở bản đầy đủ" trong Tài khoản.
- Phạm vi dữ liệu ngoại tuyến theo vai trò và thời gian: giáo viên lưu lịch dạy, danh sách lớp, phiếu điểm danh, sổ đầu bài và điểm nháp của các buổi học từ hôm qua đến hết ngày mai; quản lý lưu số liệu hôm nay và cảnh báo; tư vấn viên lưu hàng đợi gọi trong ngày; phụ huynh lưu lịch học tuần hiện tại và thông báo 30 ngày. Không lưu ngoại tuyến số điện thoại phụ huynh đầy đủ, số CCCD, hoá đơn và dữ liệu tài chính.
- Dữ liệu ngoại tuyến được mã hoá bằng khoá gắn với phiên đăng nhập trên thiết bị và bị xoá khi đăng xuất, khi thiết bị bị thu hồi, hoặc sau 7 ngày không mở ứng dụng.
- Mọi thao tác ghi ngoại tuyến vào hàng đợi với
client_saved_atvàidempotency_key; máy chủ xử lý lô theo thứ tự thời gian trên máy và trả kết quả từng mục; nhiều thao tác trên cùng đối tượng trong hàng đợi được gộp thành thao tác cuối. - Xung đột theo loại dữ liệu: phiếu điểm danh dùng
versiontheo PRD 04, bản gửi sau với version cũ nhận 409 và người dùng chọn cách xử lý; sổ đầu bài và nhận xét áp dụng "lần ghi sau cùng thắng" theoclient_saved_atkèm lịch sử; điểm đã công bố không bao giờ bị ghi đè từ hàng đợi ngoại tuyến, chỉ bản nháp được đồng bộ; kết quả cuộc gọi và đơn xin nghỉ là bản ghi mới, chỉ chống trùng bằngidempotency_key. - Thông báo đẩy chỉ mang tiêu đề, một dòng tóm tắt và
deep_link; không chứa số điện thoại, số tiền hay tên đầy đủ của học viên trên màn hình khoá (dùng tên viết tắt). - Thông báo đẩy cho phụ huynh tuân theo khung giờ yên tĩnh 21:30–07:00 của PRD 07; nhân sự mặc định không có khung giờ yên tĩnh nhưng tự đặt được; nhắc điểm danh 21:00 của PRD 04 vẫn gửi.
- Một người dùng có tối đa 5 thiết bị hoạt động, thiết bị cũ nhất bị thu hồi khi vượt quá; token đẩy bị xoá sau 3 lần gửi thất bại liên tiếp với mã "không còn đăng ký".
- Phiên đăng nhập di động kế thừa PRD 12: hết hạn sau 30 ngày không hoạt động, đổi mật khẩu thu hồi các phiên khác; xác thực sinh trắc học không thay thế yếu tố xác thực thứ hai bắt buộc với owner và accountant.
- Ngân sách hiệu năng trên 3G (1,6 Mbps, độ trễ 300 ms, Android tầm trung đời 2022): khởi động lạnh đến khi tương tác được ≤ 4,0 giây; khởi động từ bộ đệm ≤ 1,0 giây; mở phiếu điểm danh trong phạm vi đã lưu ≤ 500 ms; JS ban đầu của mỗi lớp vỏ ≤ 200 KB gzip; phản hồi today-plan ≤ 50 KB; hình ảnh dạng webp theo kích thước màn hình. Ngưỡng API của PRD 12 vẫn áp dụng.
- Cờ tính năng theo lớp vỏ đọc từ cấu hình tenant khi khởi động; tính năng bị tắt biến mất khỏi thanh tab thay vì báo lỗi. Mọi chuỗi nằm trong file message (quyết định D9).
6Mô hình dữ liệu
| Thực thể | Trường | Ghi chú |
|---|---|---|
| device | id uuid; tenant_id; user_id null; parent_account_id null; name; platform enum(web, android_pwa, ios_pwa, android_native, ios_native); app_version; os_version; install_mode enum(browser, standalone, native); push_provider enum(webpush, fcm, apns) null; push_token null; push_status enum(active, disabled, unsupported, failed); device_fingerprint; last_seen_at; registered_at; revoked_at null; revoked_by null | new; unique (user_id | parent_account_id, device_fingerprint) |
| notification (mở rộng) | + category enum(attendance, approval, task, finance, admissions, parent, system); + deep_link; + push_sent_at null; + push_result enum(sent, failed, skipped) null; + collapse_key | extend |
| notification_preference | id; tenant_id; user_id | parent_account_id; category; push bool; in_app bool; quiet_from; quiet_to | new; mặc định bật toàn bộ |
| sync_batch | id uuid; tenant_id; school_id; user_id; device_id; received_at; item_count; ok_count; conflict_count; error_count | new; lưu 30 ngày |
| sync_item | id; batch_id; idempotency_key (unique theo tenant); type enum(attendance_sheet, lesson_log, grade_draft, call_result, leave_request, incident_report); target_id; client_saved_at; base_version null; payload jsonb; result enum(applied, merged, conflict, rejected); result_detail; server_version | new |
| offline_queue, offline_cache_manifest (trên máy, IndexedDB) | queue: key; type; target_id; payload; client_saved_at; idempotency_key; status enum(pending, sending, done, conflict, error); attempts. manifest: scope enum(teacher, manager, sales, parent); cached_at; expires_at; entries [{route, etag}] | không có trên máy chủ; mã hoá theo mục 5 |
| mobile_policy (cấu hình tenant) | max_devices_per_user (5); biometric_relock_minutes_staff (5); biometric_relock_minutes_parent (30); offline_retention_days (7); cold_lead_days (14); finance_requires_biometric bool; shell_features {manager, teacher, sales, parent: [feature_key]} | lưu trong cấu hình trường (PRD 10) |
Phạm vi: device và notification_preference thuộc tenant; sync_batch và sync_item mang school_id của chi nhánh phát sinh dữ liệu để quản lý chi nhánh xem được lịch sử đồng bộ của giáo viên trong chi nhánh; thiết bị của phụ huynh không có school_id vì một tài khoản phụ huynh có thể có con ở nhiều chi nhánh.
7Hợp đồng API
| Method | Path | Mục đích | Trạng thái |
|---|---|---|---|
| GET | /v3/crm/me · /v3/crm/me/permissions · /v3/crm/me/accessible-schools | chọn lớp vỏ, phạm vi chi nhánh | existing |
| GET | /v3/crm/me/today-plan | tab Hôm nay của Quản lý và Tư vấn viên | existing |
| GET / POST | /v3/crm/me/notifications · /unread-count · /read · /read-all · /archive | trung tâm thông báo; thêm tham số category và trường deep_link | extend |
| GET | /v3/parent/learner/{id}/weekly-report · /report | tab Kết quả của phụ huynh | existing |
| GET | /v3/learner/feature-configs | cờ tính năng phía học viên; không đổi | existing |
| POST | /v3/crm/me/devices | {name, platform, app_version, os_version, install_mode, device_fingerprint, push_provider?, push_token?} → device; idempotent theo fingerprint | new |
| GET / PATCH / DELETE | /v3/crm/me/devices[/{id}] | thiết bị của bản thân; đổi tên; thu hồi; PUT /{id}/push-token làm mới token | new |
| GET / DELETE | /v3/school/devices[/{id}] | chủ trung tâm: thiết bị toàn tenant, lọc staff_id, school_id, status; thu hồi | new |
| GET / PUT | /v3/crm/me/notification-preferences | bật tắt theo nhóm, khung giờ yên tĩnh; POST /v3/crm/push/test gửi thông báo thử | new |
| GET | /v3/crm/me/offline-bundle?scope=teacher|manager|sales&date= | một phản hồi gộp toàn bộ dữ liệu trong phạm vi ngoại tuyến của vai trò, kèm etag từng phần | new |
| POST | /v3/crm/sync/batch | {device_id, items: [{idempotency_key, type, target_id, client_saved_at, payload, base_version?}]} → {batch_id, results: [{idempotency_key, result, server_version, detail}]}; tối đa 50 mục; từng mục uỷ quyền tới endpoint nghiệp vụ của PRD 04, 13, 14, 16, 01 | new |
| GET / POST / DELETE | /v3/parent/me/devices[/{id}] | thiết bị của phụ huynh, cùng hợp đồng như nhân sự | new |
| GET | /v3/parent/learner/{id}/lesson-logs · /grades | tài liệu bài học đã chia sẻ (PRD 14), kết quả đã công bố (PRD 13) | new |
| GET / PUT | /v3/teacher/school-config | bổ sung khối mobile_policy và phiên bản ứng dụng tối thiểu theo nền tảng (P2) | extend |
Thông báo đẩy do một worker phía máy chủ gửi: mỗi bản ghi thông báo mới có category được bật trong tuỳ chọn của người nhận sinh một lượt gửi tới mọi thiết bị hoạt động qua Web Push (VAPID), FCM hoặc APNs; kết quả ghi vào push_result. Liên kết sâu dùng cùng đường dẫn cho PWA và ứng dụng gốc.
8Phân quyền
| Mã quyền | owner | branch_manager | admissions | academic_admin | accountant | teacher | parent |
|---|---|---|---|---|---|---|---|
mobile.shell.manager | tất cả | chi nhánh | không | chi nhánh (không có Phê duyệt) | chi nhánh (số liệu tài chính) | không | không |
mobile.shell.teacher | khi có lớp được phân công | khi có lớp được phân công | không | không | không | có | không |
mobile.shell.sales | có | chi nhánh | lead của bản thân hoặc nhóm | không | không | không | không |
mobile.shell.parent | không | không | không | không | không | không | con của bản thân |
mobile.offline | có | có | có | có | không (dữ liệu tài chính) | có | có |
mobile.sync.override | có | chi nhánh | lead của bản thân | chi nhánh | không | buổi của bản thân trong 24 giờ | không |
devices.view_own, devices.revoke_own | có | có | có | có | có | có | có |
devices.view_all, devices.revoke_any, devices.sync_history | có | chi nhánh | không | chỉ sync_history, chi nhánh | không | chỉ sync_history của bản thân | không |
mobile.policy | có | không | không | không | không | không | không |
9Sự kiện phân tích
| Sự kiện | Thuộc tính |
|---|---|
| app_launched / install_completed | shell, platform, install_mode, cold_start_ms, from_push, network (offline|3g|4g|wifi) |
| offline_write_queued | type, shell, queue_length |
| sync_batch_completed | item_count, ok_count, conflict_count, error_count, seconds_offline, trigger (background|foreground|manual) |
| sync_conflict_resolved | type, resolution (keep_server|override), by_role |
| push_permission_granted / push_permission_denied | shell, platform |
| push_delivered / push_opened | category, provider, seconds_to_open, deep_link_route |
| biometric_enabled / biometric_relock / biometric_failed | shell, method (webauthn|native), attempts |
| device_registered / device_revoked | platform, by (self|owner|limit), active_devices |
| mobile_approval_actioned | type (discount|leave|incident), action, seconds_waiting |
| parent_material_opened | kind (lesson_log|attachment|grade|weekly_report), file_size_bucket, network |
| perf_budget_exceeded | metric (cold_start|warm_start|sheet_open|bundle), value, budget, network |
Chỉ số theo dõi hằng tuần trên PRD 09: tỷ lệ giáo viên điểm danh từ di động, tỷ lệ phiếu lưu khi ngoại tuyến, tỷ lệ mở thông báo đẩy theo nhóm, số thiết bị hoạt động trên mỗi nhân sự, p75 thời gian khởi động lạnh theo nền tảng.
10Trường hợp biên
- Giáo viên dạy hai chi nhánh trong cùng ngày: gói ngoại tuyến chứa buổi học của cả hai chi nhánh; bộ chuyển chi nhánh không ảnh hưởng đến lớp vỏ Giáo viên.
- iOS xoá dữ liệu của PWA sau 7 ngày không dùng: trùng với thời hạn giữ dữ liệu ngoại tuyến; hàng đợi chưa gửi quá 7 ngày được coi là mất và người dùng được thông báo khi mở lại bằng danh sách các buổi học chưa có điểm danh.
- Thông báo đẩy đến trước khi dữ liệu liên quan có trên thiết bị: liên kết sâu mở màn hình ở trạng thái tải; nếu đối tượng đã bị xoá, hiển thị "Mục này không còn tồn tại" và quay về tab Hôm nay.
- Hai giáo viên (chính và dạy thay) cùng điểm danh ngoại tuyến một buổi học: lô đến sau nhận 409 theo PRD 04; giáo viên dạy thay được ưu tiên khi đã được phân công, người còn lại thấy màn hình xung đột.
- Nhân sự chuyển trạng thái Đã nghỉ (PRD 06): toàn bộ thiết bị của người đó bị thu hồi tự động vào cuối ngày kết thúc và được ghi nhật ký.
- Trình duyệt không hỗ trợ Background Sync (Safari): hàng đợi gửi khi ứng dụng được mở hoặc trở lại nền trước; banner ghi rõ "Mở ứng dụng để đồng bộ".
11Câu hỏi còn mở
- PRD 07 xếp cổng phụ huynh vào P2, trong khi tài liệu này đưa phần hiển thị trên di động của cổng phụ huynh lên P1 vì dùng chung lớp vỏ; cần thống nhất lại giai đoạn của PRD 07 hoặc thu hẹp phần phụ huynh ở P1 xuống lịch học và điểm danh.
- Ứng dụng gốc ở P2 nên là một ứng dụng duy nhất có bộ chuyển lớp vỏ hay hai ứng dụng riêng (nhân sự và phụ huynh)? Đề xuất: hai ứng dụng cùng mã nguồn để mô tả trên cửa hàng và quyền hệ điều hành được tách bạch.
- Có nên tích hợp cổng phụ huynh vào ứng dụng phụ huynh FLYER hiện có thay vì phát hành ứng dụng phụ huynh Trường Số riêng (câu hỏi đã nêu ở PRD 07)?
- Gọi từ ứng dụng có cần tổng đài (SIP hoặc gọi qua Internet) để ghi âm và tính cước tập trung không, hay trình quay số của điện thoại là đủ cho P1?
Trường Số (truongso.net) · Nội bộ FLYER