Skip to content

Student Course Route Rehearsals

Scope

These rehearsals are non-default gateway proofs for the course-service student course list/detail and progress routes. They keep deploy/gateway/routes.json legacy-safe while validating native route-table examples for the next student-course cutover slice.

When the opt-in detail route records a completed lesson, student-web updates the completed lesson state and displayed progress from the successful progress write. It does not immediately issue a second detail GET; the next route load remains the owner-service refresh point. This removes one serial Gateway round trip from the common completion action without changing the non-default route or bypassing course-service.

Static route-table proof is not enough for public promotion. Public student course promotion still needs live gateway proof, browser proof from the real student frontend, and rollback notes.

Static Targets

Run the route-table guards first:

bash
make test-student-course-routes
make test-student-course-progress-routes

The read guard validates:

  • deploy/gateway/routes.student-courses-read-native-example.json
  • deploy/gateway/routes.student-courses-read-native-localhost-example.json

The progress guard validates:

  • deploy/gateway/routes.student-course-progress-native-example.json
  • deploy/gateway/routes.student-course-progress-native-localhost-example.json

Both guards also verify the default route table keeps broad student course, course, public catalog, and fallback routes legacy-proxied.

The student-web client keeps normal /student/courses and /student/courses/:id navigation on fixture data. It sends course owner reads and progress writes only with the explicit candidate query:

text
/student/courses?studentCourseGateway=native

Use that query only with a matching non-default student-course table. This prevents the native-only read/write set from reaching the default legacy-proxied Gateway table.

Runtime Proof Gate

Before any default /api/student/courses* route promotion, the owning slice must add named live and browser smoke targets that prove frontend-through-gateway traffic, not only static route JSON.

Minimum live proof:

  • gateway started with the matching non-default localhost route table
  • course-service running locally
  • seeded student token and organization id
  • list/detail reads observed with X-Hoctapaz-Gateway-Route
  • progress write smoke uses disposable course/lesson/material fixtures or an explicit no-write guard mode

Minimum browser proof:

  • opens the real student course page through the frontend
  • seeds browser auth/organization state the same way the app reads it
  • observes GET /api/student/courses through the expected native route
  • records artifacts under output/playwright/

Named browser smoke:

bash
STUDENT_COURSE_BROWSER_SELF_TEST=1 make test-student-course-browser

Live browser mode:

bash
STUDENT_COURSE_BROWSER_AUTHORIZATION='Bearer <student-token>' \
STUDENT_COURSE_BROWSER_ORGANIZATION_ID=<org-id> \
STUDENT_COURSE_BROWSER_DETAIL_ID=auto \
make test-student-course-browser

The live browser smoke exercises the real /student/courses page. It fails when the page does not emit /api/student/courses through api-gateway, or when the frontend, gateway, course-service, token, or organization state is not seeded for the rehearsal.

Completion Latency Regression (2026-07-13)

pnpm exec playwright test -c playwright.config.ts tests/frontend/student-smoke.spec.ts --project=chromium now uses the real student-web with a scoped Gateway intercept and browser session/organization state. It verifies that a native detail request settles, one progress POST returns success, the page changes to 100% hoàn thành, and the number of detail reads does not increase after the write. React development mode may make more than one initial effect request, so the browser test snapshots that settled baseline rather than claiming a global initial request count. The paired Vitest test requires exactly one detail GET plus one progress POST.

This is a browser regression for the frontend latency path, not a replacement for the existing live non-default Gateway proof and not default route promotion evidence.

Gateway Write Timeout Recovery (2026-07-14)

The opt-in student-course client bounds its Gateway list/detail reads and progress/material writes to eight seconds. A timed-out progress write aborts the browser request, restores the completion button, and shows the existing retry notice instead of leaving the student in the Đang ghi nhận state. packages/ui/src/modules/student/student-dashboard.test.tsx exercises the aborted POST with a real AbortSignal and asserts that the retry control is available again.

This is client-side regression evidence for the non-default candidate only. It does not contact a Gateway runtime, change the route tables, or promote the default student-course routes.

Captured Local Rehearsal

On 2026-07-13, the localhost read table was verified with an active-enrollment fixture in an in-memory course-service at :8086, api-gateway at :18085, and the real student-web at :5213. The browser smoke observed student-courses-list/native_read and student-courses-detail/native_read. It captured response headers, payloads, and desktop/mobile pages under output/playwright/student-course-browser-proof-20260713/.

The frontend sends Authorization and X-Organization-Id; Gateway preflight must allow both headers. This rehearsal added that missing organization header to the central CORS policy. The proof remains a local non-default rehearsal and does not promote deploy/gateway/routes.json. The current client guard is covered by packages/ui/src/modules/student/student-dashboard.test.tsx: normal course routes make no request with a stored session, while the explicit query uses the candidate Gateway request shape.

Captured Workflow Rehearsal

The dedicated workflow tables combine the exact list/detail reads with only three student writes: lesson progress, video progress, and material view. On 2026-07-13, the real detail UI was exercised with the localhost workflow table, an active-enrollment fixture, and signed STUDENT session. It observed:

  • student-course-lesson-progress/native_write for progressPercent=100, followed by an owner detail refresh at 100%.
  • student-course-material-view/native_write for the selected material.

Desktop and 390px mobile pages are in output/playwright/student-course-workflow-proof-20260713/; the mobile document width stayed at 390px. The workflow table remains a rehearsal-only alternative to deploy/gateway/routes.json.

Rollback

Rollback is switching the gateway back to:

bash
GATEWAY_ROUTE_TABLE=deploy/gateway/routes.json

After rollback, rerun the static targets above and confirm the default table does not contain active native student-courses-* route names.

Go-platform documentation is generated from repository Markdown.