SP-629 (Viettel Academy B2B course licensing) merged 2026-08-25 (PR #311) and released to production in v0.0.40 (2026-08-30). Follow-ups: the standalone B2B console (#321) and partner course requests (#348) shipped in v0.0.40; further console follow-ups (#424) shipped in v0.0.47 (2026-09-09).
Status checked 2026-09-09 against git tags and Jira. Index of all reports: https://skillpixel.atlassian.net/wiki/x/A4BJCw
→ Beta verification report (after merge + deploy)
→ Beta verification in real Chrome (Skill Pixel profile)
Walkthrough summary
# Viettel Academy B2B licensing walkthrough ## Result - Pass: 24 - Warn: 0 - Fail: 0 - Total: 24 The final refresh cleared the last warning. Viettel now uses its own header wordmark and red Viettel tab icon, Mekong keeps the default SkillPixel mark with its own tenant name, and the default tenant still shows the standard SkillPixel brand. Licensed READING and QUIZ lessons now render read-only previews on Mekong, while the course `/edit` route remains notice-only. ## Issues - None. ## Could not verify - Nothing. All 24 walkthrough entries are verified as passing. ## Scratch data left in place - Added `partner.qa@mekongenergy.vn` as a Mekong partner administrator. - Updated HD-2026-MKE-001 notes to `QA walkthrough note`. - Created Song Da Power Academy with slug `song-da-power-academy` and administrator `admin@songda.example`. - Created active contract HD-2026-SDA-001 for 20 seats and 50,000,000 VND. - Licensed `An toàn thông tin cho người lao động` to Song Da, then successfully revoked that licence. The row now shows `Đã thu hồi` and no revoke button. - Deleted the temporary QA-TEST-001 payment, leaving HD-2026-MKE-001 at 90,000,000 VND collected and 30,000,000 VND outstanding.
Fixes applied during verification and final gates
Branch demo/viettel-b2b (local, not pushed) — 37 commits on top of origin/main c4318ca7. Fixes made during this verification (newest first): - a265aaf1 fix(frontend): read-only lesson preview for licensed copies - 5b13aa22 fix(frontend): show tenant wordmark logos unclipped in header and footer - f3caa9da chore(seed): give Viettel Academy its logo and favicon - ae6add9a fix(frontend): keep B2B admin tables and dialogs inside the viewport - 6fa25a0b fix(frontend): hide editing controls on licensed copies - 031a0b4a fix(frontend): stable B2B revenue bars and full-width partner table - ba3acbcc fix(b2b): eager-load license relations before building responses Gates on the final tree: backend ruff lint + yarn test:unit; frontend eslint + yarn build (tsc -b + vite). Results are appended below by the orchestrator. Final gate results (final tree, after all fixes): - backend: ruff "All checks passed!"; yarn test:unit → 2429 passed, 0 failed - frontend: eslint 0 errors (11 pre-existing warnings in untouched files); yarn build (tsc -b + vite) ✓ built in 12.34s; yarn i18n:interface produces no diff - migration: single alembic head c5d8a3e17f24; seed chain base → viettel → historyclass verified on lms_db_va
Steps
- 01 Viettel Academy landing and catalogue PASS
- 02 Viettel admin sidebar and B2B licensing navigation PASS
- 03 B2B licensing overview PASS
- 04 B2B partners list PASS
- 05 Mekong Energy Academy partner detail PASS
- 06 Add a partner administrator PASS
- 07 B2B contracts list and filters PASS
- 08 Seeded contract detail, licences, and payments PASS
- 09 Add and delete a contract payment PASS
- 10 Edit and persist contract notes PASS
- 11 Create a provisioned partner PASS
- 12 Create an active Song Da contract PASS
- 13 Licence a Viettel course to Song Da PASS
- 14 Revoke the Song Da course licence PASS
- 15 Mekong partner catalogue PASS
- 16 Mekong admin navigation gating PASS
- 17 Mekong licensed-content dashboard PASS
- 18 Licensed course read-only instructor views PASS
- 19 Licensed courses in the instructor list PASS
- 20 Default SkillPixel admin feature gating PASS
- 21 Mobile B2B overview and contract layout PASS
- 22 Tenant bootstrap API spot checks PASS
- 23 Default-window overflow audit PASS
- 24 Default-window contract dialog fit PASS
01 Viettel Academy landing and catalogue PASS
http://viettel.localhost:3000/
The header brand link shows the red "viettel academy" wordmark image by itself, with no SkillPixel "S" mark or separate Viettel Academy text label beside it. The browser tab favicon is the red Viettel V-shaped mark, not the SkillPixel "S". The red Viettel Academy landing page lists exactly "An toàn thông tin cho người lao động" and "Quản trị dự án cho doanh nghiệp viễn thông".

02 Viettel admin sidebar and B2B licensing navigation PASS
http://viettel.localhost:3000/admin/users
The admin header again shows the red "viettel academy" wordmark image by itself, with no SkillPixel "S" mark or separate Viettel Academy text label beside it; the signed-in avatar is shown at the far right. The sidebar contains the Vietnamese B2B group "Cấp phép B2B" with "Tổng quan", "Đối tác", and "Hợp đồng" links. The page is signed in as Developer Admin.

03 B2B licensing overview PASS
http://viettel.localhost:3000/admin/b2b
The current scratch state shows 2 partners, 2 active contracts, 3 licensed courses, 8 partner learners, 8 / 70 seats, 170.000.000 ₫ contracted, 90.000.000 ₫ collected, 80.000.000 ₫ outstanding, and 7.320.000 ₫ of B2C revenue over 12 months. The monthly chart now has 8 visible `.recharts-bar-rectangle path` elements: two B2B bars aligned with June and July 2026 and six B2C bars across recent months. The partner breakdown table is 1,166px wide from x=417 to x=1,583; its final "Đã thu" header and 90.000.000 ₫ cell both end at x=1,583 within the 1,744px viewport, so every column is visible without clipping.

04 B2B partners list PASS
http://viettel.localhost:3000/admin/b2b/partners
The Mekong Energy Academy row is present with slug "mekong-energy", green "Đang hoạt động" status, hostname mekong.localhost:3000, and admins skillpixelad@gmail.com plus skillpixeldeveloper@gmail.com. It reports 1 contract, 2 licences, 8 learners, and 90.000.000 ₫ collected.

05 Mekong Energy Academy partner detail PASS
http://viettel.localhost:3000/admin/b2b/partners/c4d7f2b8-6e19-4a50-8b3c-2f6a9d1e7c40
The info card shows Mekong Energy Academy as "Đang hoạt động", slug mekong-energy, hostname mekong.localhost:3000, 8 learners, and 90.000.000 ₫ collected. Admins are skillpixelad@gmail.com and skillpixeldeveloper@gmail.com. The contract section shows HD-2026-MKE-001 active for 25/05/2026–25/05/2027 with 8 / 50 seats, 2 licences, 120.000.000 ₫ value, 90.000.000 ₫ collected, and 30.000.000 ₫ outstanding; the course section shows both seeded licences with 6/2 and 5/1 learner/completion counts and snapshot dates 25/05/2026 and 16/06/2026.

06 Add a partner administrator PASS
http://viettel.localhost:3000/admin/b2b/partners/c4d7f2b8-6e19-4a50-8b3c-2f6a9d1e7c40
The add-admin form accepted partner.qa@mekongenergy.vn. A success toast said the address now has partner administrator access, and the address appeared in the administrator list alongside skillpixelad@gmail.com and skillpixeldeveloper@gmail.com.

07 B2B contracts list and filters PASS
http://viettel.localhost:3000/admin/b2b/contracts
The document scrollWidth and window.innerWidth are both exactly 1,744px. The full ten-column table is visible from x=393 to x=1,607, including the last "Hành động" column, and the header "Thêm hợp đồng" button is fully visible from x=1,452.65625 to x=1,608 without horizontal page scroll. HD-2026-MKE-001 still shows Mekong Energy Academy, "Đang hiệu lực", 25/05/2026 to 25/05/2027, 8 / 50 seats, 2 licences, 120.000.000 ₫ value, 90.000.000 ₫ collected, and 30.000.000 ₫ outstanding.

08 Seeded contract detail, licences, and payments PASS
http://viettel.localhost:3000/admin/b2b/contracts/d1a5c3e7-8b24-4f69-9c07-3e5b8d2a6f11
HD-2026-MKE-001 is active for 25/05/2026–25/05/2027 with 8 / 50 seats, 2 licences, 120.000.000 ₫ contracted, 90.000.000 ₫ collected, and 30.000.000 ₫ outstanding. The Licensed courses tab shows Quản trị dự án cho doanh nghiệp viễn thông at 6 learners, 2 completions, snapshot 25/05/2026 and An toàn thông tin cho người lao động at 5 learners, 1 completion, snapshot 16/06/2026. The Payments tab shows the two seeded payments: 30.000.000 ₫ dated 25/07/2026 with reference UNC-2026-0517 and 60.000.000 ₫ dated 25/06/2026 with reference UNC-2026-0412.


09 Add and delete a contract payment PASS
http://viettel.localhost:3000/admin/b2b/contracts/d1a5c3e7-8b24-4f69-9c07-3e5b8d2a6f11
A 30.000.000 ₫ payment dated 25/08/2026 with reference QA-TEST-001 was recorded successfully; the header updated to 120.000.000 ₫ collected and 0 ₫ outstanding. After confirming deletion of that exact row, the success toast appeared, QA-TEST-001 was absent from the table, and the header returned to 90.000.000 ₫ collected and 30.000.000 ₫ outstanding.


10 Edit and persist contract notes PASS
http://viettel.localhost:3000/admin/b2b/contracts/d1a5c3e7-8b24-4f69-9c07-3e5b8d2a6f11
The Edit contract dialog accepted the notes value "QA walkthrough note" and saved it. After a full page reload, reopening the dialog showed the same note, confirming that the change persisted.


11 Create a provisioned partner PASS
http://viettel.localhost:3000/admin/b2b/partners
The partners page has document scrollWidth = 1,744px and window.innerWidth = 1,744px, and the exact `main *` overflow check is false. The full nine-column table runs from x=393 to x=1,607, including the final "Hành động" column. Song Da Power Academy remains "Chờ SkillPixel kích hoạt" with hostname "Chưa được cấp", admin@songda.example, 1 contract, 1 licence, 0 learners, and 0 ₫ collected; Mekong Energy Academy remains fully visible in the other row.


12 Create an active Song Da contract PASS
http://viettel.localhost:3000/admin/b2b/contracts
The contracts list has document scrollWidth = 1,744px and window.innerWidth = 1,744px; the full table and final column end at x=1,607 with no horizontal page scroll. HD-2026-SDA-001 remains "Đang hiệu lực" for Song Da Power Academy with 0 / 20 seats, 1 licence, 50.000.000 ₫ value, 0 ₫ collected, and 50.000.000 ₫ outstanding. The "Hợp đồng mới" dialog spans y=106.375 to y=886.625 within window.innerHeight = 993px, and its "Huỷ" and "Tạo mới" footer buttons both end at y=861.625 and are visible.


13 Licence a Viettel course to Song Da PASS
http://viettel.localhost:3000/admin/b2b/contracts/f7e8fa28-8555-4f5f-aaf5-1686e2464557
Searching the course picker for "Khoá học" returned the empty-state message even though two published courses were available when the search was cleared. After clearing the search, the first course, "An toàn thông tin cho người lao động", was licensed successfully. The row is active as "Đang cấp phép" with copy slug an-toan-thong-tin-cho-nguoi-lao-dong, 0 learners, 0 completions, and snapshot date 25/08/2026. (Reviewer note: the search term "Khoá học" came from the walkthrough script and matches neither seeded title — the picker filters by title substring, so the empty state was correct. Licensing itself succeeded.)

14 Revoke the Song Da course licence PASS
http://viettel.localhost:3000/admin/b2b/contracts/f7e8fa28-8555-4f5f-aaf5-1686e2464557
Revoking "An toàn thông tin cho người lao động" on HD-2026-SDA-001 succeeded. The licence row changed from "Đang cấp phép" to the REVOKED label "Đã thu hồi", the success toast read "Đã thu hồi giấy phép.", and the revoke button disappeared, so no second click was available or required. A hard reload of Mekong still showed its two separate seeded courses, "An toàn thông tin cho người lao động" and "Quản trị dự án cho doanh nghiệp viễn thông", both marked "Miễn phí".

15 Mekong partner catalogue PASS
http://mekong.localhost:3000/
The Mekong header shows the default blue SkillPixel "S" mark followed by the text "Mekong Energy Academy"; it does not show the Viettel wordmark. The catalogue lists exactly the two seeded licensed courses, "An toàn thông tin cho người lao động" and "Quản trị dự án cho doanh nghiệp viễn thông". Both cards display "Miễn phí".

16 Mekong admin navigation gating PASS
http://mekong.localhost:3000/admin
After Google sign-in as skillpixeldeveloper@gmail.com, the Mekong admin sidebar includes the localized Licensed content link "Nội dung được cấp phép" under Học tập. The sidebar has no "Cấp phép B2B" group and no Overview, Partners, or Contracts links.

17 Mekong licensed-content dashboard PASS
http://mekong.localhost:3000/admin/licensed-content
The page identifies Viettel Academy as the licensor and shows one active contract, HD-2026-MKE-001, for 25/05/2026–25/05/2027 with 8 / 50 seats used and a progress bar. The table contains exactly the two seeded licences: Quản trị dự án cho doanh nghiệp viễn thông with 6 learners, 2 completions, snapshot 25/05/2026, and An toàn thông tin cho người lao động with 5 learners, 1 completion, snapshot 16/06/2026. Both course records and licences are shown as published/active.

18 Licensed course read-only instructor views PASS
http://mekong.localhost:3000/instructor/courses/quan-tri-du-an-cho-doanh-nghiep-vien-thong/chapters/ch905_mke_qtda_01/reading/ls909_mke_qtda_r1
The Mekong header shows the default blue SkillPixel "S" mark followed by "Mekong Energy Academy", with no Viettel wordmark. In the expanded "Khởi tạo và lập kế hoạch" chapter, the READING lesson "Điều lệ dự án và các bên liên quan" renders a read-only "Bài đọc" preview with the full article text. The QUIZ lesson "Trắc nghiệm - Khởi tạo và lập kế hoạch" renders a read-only "Quiz" preview with its description, four questions, and answer options; neither preview has a form or save, add, or delete controls. The `/edit` page still shows only the Viettel Academy read-only notice and "Xem nội dung khoá học", with no editor form.


19 Licensed courses in the instructor list PASS
http://mekong.localhost:3000/instructor/courses
The instructor list contains exactly two licensed course cards, and both show the badge "Cấp phép bởi Viettel Academy". Each card is published, open for enrollment, free, and exposes only "Xem nội dung khoá học"; the page contains 0 "Cài đặt" or Manage controls.

20 Default SkillPixel admin feature gating PASS
http://localhost:3000/admin/users
The default tenant header remains unchanged: it shows the blue SkillPixel "S" mark followed by the blue "SkillPixel" name. The admin sidebar contains only the People, Learning, Business, and Platform groups. It has no B2B licensing group and no Licensed content link.

21 Mobile B2B overview and contract layout PASS
http://viettel.localhost:3000/admin/b2b
At a 360 × 800 viewport, both the B2B overview and HD-2026-MKE-001 detail kept document and body scroll widths at exactly 360px, so neither page had horizontal page scroll. The overview contained two internal overflow-x-auto wrappers measuring 262/553px and 262/719px; the contract table used one 310/1128px wrapper. The normal browser viewport was restored after capture.


22 Tenant bootstrap API spot checks PASS
http://localhost:8123/api/v1/tenant/bootstrap
The Mekong bootstrap response contains licensor.name = "Viettel Academy" and identifies tenant slug mekong-energy. The Viettel bootstrap response lists "b2b_licensing" in enabled_features alongside certificates and docx.import.
23 Default-window overflow audit PASS
http://viettel.localhost:3000/admin/b2b/contracts
The default window.innerWidth was recorded once as 1,744px and was not changed. Every audited page reported document scrollWidth = 1,744px, window.innerWidth = 1,744px, and false for the exact `main *` right-edge overflow check: Viettel overview, partners list, Mekong partner detail, contracts list, HD-2026-MKE-001 Licensed courses tab, HD-2026-MKE-001 Payments tab, and Mekong Licensed content. The screenshot is the contracts page because all seven checks passed.

24 Default-window contract dialog fit PASS
http://viettel.localhost:3000/admin/b2b/contracts/d1a5c3e7-8b24-4f69-9c07-3e5b8d2a6f11
At window.innerHeight = 993px, the New contract dialog spans y=106.375 to y=886.625 and fits; its "Huỷ" and "Tạo mới" footer buttons end at y=861.625 and are visible. The HD-2026-MKE-001 Edit contract dialog spans y=162.75 to y=830.25 and also fits; its "Huỷ" and "Lưu" footer buttons end at y=805.25 and are visible.
