Phiên rà soát hub ngày 15/06/2026 · 12 mục + 1 ghi chú · cập nhật 16/06/2026 · DRAFT — INTERNAL · không phân phối
I3 · I5 · I7 · I9 · I10 — XONG & ĐÃ TRIỂN KHAI (hub sống). I6 — đã xây công cụ + áp 25-26 (chờ cấp quyền ghi DB). I11 — đã rà (Trao gửi yêu thương). I12 — chờ xác nhận điều phối viên.
allocation_apply.py + ghi chú đối chiếu đã đăng. Áp 25-26 đã kiểm trên bản sao + sao lưu DB; chờ cấp quyền ghi bucket sống. 23-24/24-25 cần học bạ theo năm (I12).Mỗi mục là một nhận xét khi xem hub sống, kèm chẩn đoán, cách sửa, quyết định và trạng thái. Tên học sinh, mã hồ sơ và email đã được ẩn (trang này công khai).
| Mã | Việc | Trạng thái |
|---|---|---|
| I1 | Tài khoản nhân viên (1 khu vực) vẫn thấy tab/khu vực không được cấp quyền — rà soát phân quyền chéo khu vực | XONG |
| I2 | Tạo tài khoản: "Chưa cấu hình gửi email" — đặt mật khẩu qua liên kết sao chép | KHÔNG SỬA |
| I3 | "Phúc lợi theo nguồn tài trợ": Quỹ Thành Nhân hiển thị Tổng = 0 dù có thỏa thuận | XONG · TRIỂN KHAI |
| I4 | Thêm 2 biểu mẫu Google (Phiếu hoạt động + Khảo sát học sinh) vào tab Trợ giúp | XONG |
| I5 | Kiểm tra luồng đổi trạng thái học sinh + rà các hàm ít dùng có chạy đúng không | XONG · TRIỂN KHAI |
| I6 | Nạp bảng phân bổ học bổng theo học sinh (lớp/trường/năm) vào Drive + tính số tiền mỗi em | 25-26 SẴN SÀNG · chờ ghi DB |
| I7 | Phúc lợi: hiển thị 2 giá trị — trong kỳ (năm học hiện tại) + lũy kế | XONG · TRIỂN KHAI |
| I8 | Phúc lợi theo trường: vì sao các trường THCS số tiền nhỏ? (đã giải thích; cùng gốc I3, sửa qua I6) | ĐÃ TRẢ LỜI |
| I9 | BC phân tích: bổ sung số lượng học sinh theo lứa | XONG · TRIỂN KHAI |
| I10 | Danh sách em theo chương trình: thêm cột lớp + số lượng mỗi nhóm | XONG · TRIỂN KHAI |
| I11 | Xem xét bảng "chương trình khác" (Trao gửi yêu thương) và cách đưa vào hệ thống | ĐÃ RÀ · chờ nạp |
| I12 | Rà soát dữ liệu CETB: 85/317 tài liệu Drive chưa nạp (27 phiếu PDF của LTV, học bạ thiếu năm ở Đại An/Vĩnh Hào, SE chỉ có 2/6 trường, TDTT chưa mô hình hoá) | CHƯA LÀM |
| N1 | Ghi chú quyết định: Google Forms là cổng tải lên (sign-in OK) — không sửa code, có 2 thiết lập cần xác minh | GHI NHẬN |
Page: /care (Quản lý học sinh) · screenshot 2026-06-15 (tài khoản test, avatar "TT").
User comment (verbatim):
User's interface still show un-authorised tabs. Picture is a student-access only account. Double check and make sure all works consistently.
Read & root-cause:
request.state.granted_modules (app/templates/hub/base.html:33-56): một tài khoản chỉ có khu vực care sẽ không thấy link Hoạt động / Kế hoạch nội dung / Bài đợi duyệt / Tài trợ & tài chính.app/hub.py:342-358) chuyển hướng 303 → /khong-co-quyen nếu khu vực không được cấp; bản đồ đường dẫn ở _PATH_MODULES (app/hub.py:89-106).app/templates/base.html:129-134 hiển thị KHÔNG điều kiện — nhưng đây ĐÚNG: cấp quyền care = toàn bộ khu vực học sinh (xác nhận của user, xem dưới).Decision (user, 2026-06-15): Cấp quyền care = toàn bộ 4 tab khu vực học sinh (roster + phân tích + báo cáo + cảnh báo). KHÔNG ẩn các tab care. Vấn đề thực = đảm bảo các khu vực không được cấp (content / finance) không thể vào được qua URL trực tiếp và không lọt link nào.
Câu hỏi mở: ảnh chụp là phiên care-only hay phiên admin? Nếu admin thì các tab là đúng và không có lỗi. Xác minh sống sẽ chốt.
Fix đề xuất (sau xác minh):
/plan, /review, /trips, /finance đều 303 → /khong-co-quyen; /survey + /care/* đều mở được. Ghi lại link nào trong trang care trỏ chéo khu vực._PATH_MODULES, hoặc middleware chưa phủ một sub-app mount).Chặn bởi: mật khẩu tài khoản test (hoặc cho phép tôi đặt mật khẩu qua luồng liên kết) để probe URL sống.
Trạng thái (user, 2026-06-15): XONG — user xác nhận đã hoàn tất phân quyền chéo khu vực.
Page: /quan-tri/nguoi-dung (Quản lý tài khoản) · screenshot 2026-06-15.
User comment (verbatim):
The email account notifications and password setup are not in place I believed. Just tried to create one.
Read & root-cause:
app/hub.py:525-576). Liên kết đặt mật khẩu được sinh, ký, có hạn (care_auth.make_setpw_token, tools/care_auth.py:167-185; xác thực read_setpw_token, 188-210).tools/mailer.py) đã xây nhưng trơ vì chưa đặt HMT_SMTP_HOST + HMT_SMTP_FROM. Khi đó make_mailer() trả None → admin sao chép liên kết và gửi tay (app/templates/hub/users_admin.html:16-24).password_hash='' = "Chờ đặt mật khẩu"; sau khi đặt → "Đang hoạt động" (tools/care_auth.py:242-253; UI users_admin.html:58).Decision (user, 2026-06-15): giữ luồng sao-chép-liên-kết (copy-link only). Không đổi code. Bật email sau này chỉ là đặt 2 secret HMT_SMTP_HOST + HMT_SMTP_FROM (+ user/pass/TLS) lên Cloud Run.
Lưu ý (flag): domain trong liên kết mời là hub-dev.hoamattroi.org — xác nhận đây là URL bạn thực sự phát cho người dùng. Nếu vẫn ở URL dev, người được mời sẽ đặt mật khẩu trên môi trường dev chứ không phải prod.
Page: báo cáo "Phúc lợi theo nguồn tài trợ" (bảng Nguồn · Số mục · Tổng VND) · screenshot 2026-06-15.
User comment (verbatim):
Why don't we have amounts for Quỹ Thành Nhân. All the agreements are in place.
Read & root-cause (đã truy nguyên):
amount_vnd=NULL (không bịa một mức chia tiền cho từng em, theo claims.md). Tiền của thỏa thuận nằm trên dòng register_entry (kind=funding), không trên từng dòng học sinh.benefit per-student (tools/benefit_report.py:170-172 → _group_by bỏ qua NULL ở 129-152). Vì vậy Quỹ Thành Nhân: Số mục = 44 / 108 / 181 (đếm dòng) nhưng Tổng = 0 (mọi amount đều NULL).tools/benefit_report.py:253-255; fetch funding 107-126).Decision (user, 2026-06-15): Gộp tổng thỏa thuận vào bảng theo nguồn — để Quỹ Thành Nhân hiển thị số tiền cam kết thật thay vì 0.
Fix:
tools/benefit_report.py, mở rộng tổng hợp "Theo nguồn tài trợ" sao cho mỗi nguồn = (tổng amount_vnd per-student) + (tổng amount_vnd các dòng register_entry funding khớp), khóa theo chuỗi funding_source.funding_source (170-172 gộp với 107-126).benefit_report.py:408-437) để khẳng định số tiền thỏa thuận xuất hiện trong bảng theo nguồn (hiện chỉ kiểm tên nguồn).Không chặn: hoàn toàn tự chứa, không cần thông tin đăng nhập — sẵn sàng làm trước.
Page: /tro-giup (Trợ giúp & công cụ).
User request (verbatim):
I also want to publish the 2 google forms to Trợ giúp tab.
Quyết định (user, 2026-06-15): hai biểu mẫu = Phiếu thông tin hoạt động (điều phối viên) + Phiếu khảo sát học sinh. (Form thứ ba — Đăng ký tài trợ — không chọn lần này.)
Đã làm:
/tro-giup (app/hub.py) dựng danh sách forms: id phiếu hoạt động đọc từ HMT_BRIEF_FORM_ID (đã có trong .env); id khảo sát đọc từ HMT_SURVEY_FORM_ID với giá trị mặc định là id đã cấp (chưa có trong .env). Cả hai render link …/viewform.app/templates/hub/tro_giup.html: thêm mục "Biểu mẫu Google" dưới "Mẫu văn bản", dùng lại lưới tpl-card + mẫu link ngoài target="_blank" rel="noopener" ↗ như tab Pháp lý.Kiểm thử: ruff sạch · 42/42 test hub pass · render sống trả 200 với cả hai link biểu mẫu.
Lưu ý:
forms_provision.py --apply, xem _system/forms/PROVISIONING.md). User chọn biết điều này.HMT_SURVEY_FORM_ID vào .env để bỏ giá trị mặc định cứng trong code.management-hub (deploy -Only management-hub, ~2 phút) để hiển thị trên hub sống — hành động ra ngoài, cần go-ahead theo từng lần (workspace-ethics.md §2).User comment (verbatim):
check if the status update functions works. Actually check all other functions that we havent touched on much whether they are working.
Read: phần lớn đợt rà soát vừa qua chỉnh chữ/giao diện; các hành động back-end ít được chạy thật. Cần một lượt kiểm tra hoạt động: xác nhận luồng đổi trạng thái học sinh chạy trọn vẹn (form → ghi DB → phụ tải ghi danh → ghi nhật ký profile_entry → banner/danh sách phản ánh trạng thái mới), rồi quét các hàm ít dùng khác.
Mục tiêu chính — đổi trạng thái (T17): route child_transition (app/main.py:819-916): graduate-cetb-to-nbtl, graduate-exit, graduate-continue, transfer-school, pause, withdraw, reactivate. Liên quan đổi danh mục trạng thái vừa làm (punch list 13/06 · P28) — kiểm lại các bước chuyển vẫn ra trạng thái hợp lệ.
Quét thêm (chốt khi làm): sửa lớp/trường ở trang chi tiết; nạp học bạ 1 PDF → school_doc_extract → duyệt; tạo lại sổ tay; trình tạo báo cáo /reports; xét chọn /survey; quản lý tài khoản (tạo/mời/cấp quyền); hành động donor/finance nếu vào được.
Cách kiểm (đề xuất): đọc test sẵn có trước (tests/test_app.py…), rồi chạy thử trên bản sao DB nháp — không động DB sống nếu chưa backup + quiesce (care-data.md rule 5). Ghi lại cái nào chạy / hỏng.
Trạng thái: chưa chạy lượt kiểm tra.
User comment (verbatim):
This link shows the amount of fund allocated to each student (different with grade) to each school and each year. We need to bring this document to the Drive (at the right place) and calculate the amount of each student of the relevant year — [Drive-sheet-id]
Read: một Google Sheet ngoài chứa lịch phân bổ tài trợ — số tiền mỗi em, thay đổi theo lớp, theo trường, theo năm. Hai phần:
care-data.md rule 2: Truong/<trường>/<năm-học>/), nhưng bản chất là hồ sơ tài trợ = cầu bien-ban-tai-tro (toả ra dòng benefit mỗi em + nối funding_source).benefit mỗi em, kèm source_ref về sheet đã nạp.Mở (chốt khi làm): link riêng tư — đọc qua đường SA (SA đã có quyền), không WebFetch; "năm" = năm học hay lứa?; lớp-của-từng-năm lấy từ lịch sử học bạ; ghi DB sống cần backup + quiesce + dry-run + provenance (care-data.md rule 5). Gắn với I8 (vì sao THCS nhỏ).
Trạng thái: chưa làm — cần xem cấu trúc sheet trước.
Page: /analytics (Phân tích).
User comment (verbatim):
Chị đang xem BC phân tích (on the hub page) mục phúc lợi em cho 2 giá trị: trong kỳ (trong năm học hiện tại) và lũy kế (từ đầu đến giờ) nhé
Read: mọi con số phúc lợi trên trang hiện chỉ là lũy kế — lifetime_total (app/main.py:1586-1588) và bảng theo trường/nguồn (main.py:1528-1578) đều SUM(amount_vnd) không lọc năm. Cần hiện hai giá trị: trong kỳ (năm học hiện tại) và lũy kế, cho stat Tổng phúc lợi + (nên có) bảng theo trường/nguồn.
Mở: "trong kỳ" = năm học (vd 2025-2026); cần mỗi dòng benefit có năm/kỳ để lọc; chốt ranh giới năm học VN (~T9→T8).
Trạng thái: chưa làm.
Page: /analytics · bảng "Phúc lợi theo trường".
User comment (verbatim):
Is the per school amount for all years or just one year? how do these figures come together? why other THCS show small amount?
Trả lời (từ code, 2026-06-15):
main.py:1528-1537) cộng benefit.amount_vnd mỗi trường, không lọc năm → lũy kế toàn thời gian. (I7 thêm phần trong-kỳ.)benefit.amount_vnd của HS trường đó. Theo nguồn = tiền per-line cộng cam kết register_entry funding gộp vào (main.py:1545-1578) — nên bảng nguồn lớn hơn nhiều.amount_vnd=NULL — tiền cam kết nằm trên register_entry (theo nguồn/lứa), không trên dòng học sinh. Nên bảng theo trường chỉ bắt tiền mặt per-line (giải thưởng nhỏ). THCS không có số tiền per-student → chỉ hiện tiền thưởng nhỏ (7tr/5tr/6tr/4,9tr); THPT lớn vì các em có amount_vnd per-student (186tr/239tr). ⇒ cột theo-trường không so sánh được giữa các trường hiện nay.Cùng gốc với I3 (Quỹ Thành Nhân Tổng=0): cả hai do tiền cam kết nằm trên register, không per-student. I6 (nạp sheet phân bổ → ghi số tiền per-student mỗi năm) là cái sửa triệt để để mọi trường so sánh được.
Trạng thái: đã trả lời; phần sửa dữ liệu theo I6.
Page: /analytics.
User comment (verbatim):
BC phân tích bổ sung cho chị thêm SL HS theo lứa nữa nhé
Read: trang có "Số học sinh theo trường" nhưng chưa có theo lứa (lứa = năm vào chương trình, child.cohort_year; khác năm học). Thêm thẻ "Số học sinh theo lứa" tương tự thẻ theo-trường: query GROUP BY c.cohort_year + một chartcard nữa.
Trạng thái: chưa làm.
Page: danh sách học sinh nhóm theo chương trình.
User comment (verbatim):
Chị mới xem BC theo trường, danh sách cuối cùng các em theo chương trình em bổ sung thêm lớp, và số lượng các em nhé
Read: trong danh sách nhóm theo chương trình, thêm (1) cột lớp (class_label) và (2) số lượng mỗi nhóm chương trình — đếm mỗi nhóm đã có ở nhóm theo trường (· 38 em), nhân bản sang nhóm theo chương trình. Query roster đã chọn c.class_label nên chủ yếu là template.
Mở: class_label là lớp hiện tại; xác nhận với user có muốn lớp lúc vào thay vì lớp mới nhất không.
Trạng thái: chưa làm.
User comment (verbatim):
this is another program. we need review and consider how to bring it into the system — [Drive-sheet-id]
Read: một Google Sheet cho chương trình khác ngoài ba chương trình đã có (Cùng em tiến bước, Nâng bước tương lai, Trao gửi yêu thương) + track Hoa Sữa NBTL đã nạp. Cần xem + thiết kế tích hợp: hiểu sheet chứa gì (học sinh? tài trợ? mô hình khác?), rồi quyết cách ánh xạ vào care store / hub (slug chương trình mới, nạp roster, phúc lợi, sổ).
Mở (sau khi xem sheet): link riêng tư — mở qua SA, không WebFetch; là chương trình mới trong mô hình 8 cánh hay track khác cấu trúc (như Hoa Sữa HVK<k> cần parser riêng)?; nạp roster cần backup + quiesce + dry-run + provenance. Gắn với I6 (sheet phân bổ) và pattern nạp cohort Hoa Sữa.
Trạng thái: chưa làm — cần xem sheet trước khi lập kế hoạch tích hợp.
User comment (verbatim):
review the CETB folders in this [Drive-folder-id]. Check if all documents have been sourced to Drive and if all the information/data ingested/recorded. I believe there are many documents not reflected such as PDF score cards. Also find which schools/cohorts miss out any important information that you need from users?
Cách làm (chỉ đọc): duyệt 3 thư mục CETB 20xx-20xx/<trường>/ trong Drive "Thông tin học sinh" (317 tệp) và đối chiếu từng Drive file id với care DB sống (source_doc ∪ source_file ∪ essay_score ∪ school_report.source_pdf), kèm rà phủ theo trường/lứa. DB sống copy ra scratch rồi xoá; không ghi gì lên Drive/bucket.
Kết quả: 232/317 tệp đã nạp, 85 chưa. Đã đủ: bài viết (156), phiếu cảm xúc-xã hội (60), tài trợ (13), phúc lợi (học bổng 352 dòng + thưởng 162 dòng) ở cả 6 trường. 85 tệp chưa nạp chia làm thiếu dữ liệu thật và chỉ thiếu nguồn gốc (tệp chưa vào sổ source_doc nhưng dữ liệu đã trích — cùng gốc P17 ở punch list 13/06). CETB = 230 em, 6 trường, lứa 2023/2024/2025.
I12.1 — 27 "Phiếu học tập" PDF của LTV (2024-2025) chưa nạp. Thư mục CETB 2024-2025/THPT LTV/PHIẾU HỌC TẬP CỦA 27 HỌC SINH QUỸ HMT/ có 27 phiếu điểm PDF từng em; không có trong DB. Đây chính là "PDF score cards chưa phản ánh". Xử lý: phân loại theo em → school_doc_extract (đường nạp hàng loạt P20) → duyệt → lưu source_doc kind=student vào Tai-lieu-goc/ từng em.
I12.2 — Thiếu học bạ theo năm. 24/230 em CETB chưa có học bạ nào (Vĩnh Hào 9, Đại An 7, Tam Thanh 6, LTV 1, Nguyễn Bính 1; Tân Khánh 0). Hai lỗ hổng trọn năm có nguồn đang nằm chưa nạp trên Drive: Đại An — lứa 2024 (25 em): kết quả 2024-2025 chưa nạp (DB chỉ có 2025-2026; Drive có BCKQ năm 24-25 chưa nạp); Vĩnh Hào — kết quả 2025-2026 chưa nạp (DB có 2024-2025; Drive có BCKQ năm 25-26 chưa nạp).
I12.3 — Phiếu cảm xúc-xã hội (SE) chỉ có ở 2/6 trường. SE chỉ có nguồn ở Tam Thanh + Đại An (2025-2026). Tân Khánh, Vĩnh Hào, LTV, Nguyễn Bính không có SE nào — đây là thiếu nguồn từ điều phối viên, không phải lỗi nạp.
I12.4 — TDTT (thể thao) có trên Drive nhưng chưa mô hình hoá. Hầu hết trường có sheet TDTT mỗi năm (cánh 5 — sức khỏe thể chất); chưa nạp và chưa có doc_type. Cần quyết: ghi nhận thành profile_entry (cánh 5)/phúc lợi, hay chỉ lưu nguồn.
I12.5 — ~50 sheet tổng hợp chưa vào sổ nguồn (cùng gốc P17). Sheet roster/KQ/thưởng/TDTT theo trường-năm phần lớn không có trong source_doc dù dữ liệu đã trích → mọi dòng hiện "Nguồn gốc —". Vào sổ kind=consolidated + gắn source_ref khi làm P17.
Cần từ người dùng:
BCKQ năm 24-25 là bản kết quả cuối năm để nạp cho lứa 2024.BCKQ năm 25-26 (kết quả năm hiện tại).Trạng thái: chưa làm — chờ dữ liệu/quyết định từ người dùng; việc nạp giá trị cao nhất kế tiếp = 27 phiếu PDF của LTV qua đường P20.
Bối cảnh: hỏi Google có cổng tải-lên an toàn cắm-sẵn không — không có (Google không có sản phẩm tải-lên có thương hiệu, không cần đăng nhập). "Hub upload (preferred)" trong care-data.md là thứ gần nhất ta sở hữu.
Quyết định (admin, 2026-06-15): chọn Google Forms làm cổng cho điều phối viên/nhà trường, chấp nhận yêu cầu đăng nhập Google. Người nộp đa số không có tài khoản tổ chức — Gmail cá nhân là được, không bắt buộc @hoamattroi.org.
Lý do giữ thiết kế tách rời (folder-link upload): ràng buộc thật của Forms file-upload là bức tường đăng nhập, không phải bất khả thi. Forms có câu hỏi tải file, nhưng (a) người trả lời phải đăng nhập, (b) SA của ta không tạo được (Forms.create() → 500; người tạo, SA --sync), (c) file rơi vào Drive của người tải, không phải care bucket. ⇒ giữ đường folder-link vì lý do tài khoản/quota/SA, không phải vì giới hạn cứng của Forms.
Hai thiết lập cần xác minh khi form lên sống (cho người nộp không tài khoản):
Thiết lập "Anyone with the link" trên form school-report (HMT_SCHOOL_REPORT_FORM_ID, khác form khảo sát ở I4) đã thỏa #1.
Cờ chuyển hội đồng quản trị: tài liệu chăm sóc đi qua một tài khoản Google ngoài Foundation trên đường nạp vào (gật đầu firewall / care-data.md §3) — cái giá của đường Forms-sign-in so với trang upload trên hub.
Không sửa code: registry, service school_report, đường upload tách rời đều không đổi. Đã lưu vào memory forms-as-upload-portal-decision.