This commit is contained in:
2026-07-16 09:53:14 +07:00
parent 0fc112a2e8
commit 29cec708a3
1236 changed files with 212848 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
# Online Lesson Review Note Visibility Fix Report
## 1. Executive Summary
Fixed the online lesson review note visibility leak by filtering internal workflow fields at the DTO serialization layer and gating the detail UI with a permission-derived capability. General users can still view published lesson content, but they no longer receive or render internal review data such as review comments, reviewer IDs, approval IDs, and workflow timestamps.
## 2. Problem Found
The online lesson detail page showed the internal review note section when `review_comment` existed. The same API serializer was used for learner-facing and back-office responses, so public/general users could also receive internal workflow data in network responses.
## 3. Root Cause
`serializeOnlineLesson()` always included workflow fields regardless of the current user's permissions. The detail component then rendered `review_comment` based only on whether the field had a value.
## 4. Data Flow Before Fix
Database `online_lessons.review_comment` and workflow actor fields were selected by `getBaseSelect()`, serialized by `serializeOnlineLesson()`, returned by `/api/online-lessons` and `/api/online-lessons/[id]`, cached by TanStack Query, and rendered by `OnlineLessonDetailPage`.
## 5. Permission Rule Applied
Internal review data is included only when `canReadAllContent('online_lesson', permissions)` returns true. This maps to the existing `online_lesson:read_all` permission and avoids adding new hard-coded role checks.
## 6. Files Changed
`src/features/online-lessons/server/online-lesson-data.ts`
- Added `includeInternalReviewData` serialization option.
- Public serialization omits internal workflow fields.
- List responses now include internal fields only for users with online lesson read-all permission.
`src/app/api/online-lessons/[id]/route.ts`
- Detail GET now serializes public or internal DTO based on `canReadAllContent`.
- Removed an unused local variable flagged by lint.
`src/features/online-lessons/api/types.ts`
- Marked internal workflow fields as optional because public DTOs intentionally omit them.
`src/app/dashboard/online-lessons/[id]/page.tsx`
- Computes `canViewInternalReviewData` on the server from existing permissions and passes it to the client detail component.
`src/features/online-lessons/components/online-lesson-detail-page.tsx`
- Renders the review note section only when `canViewInternalReviewData` is true.
- Hides creator metadata from the learner-facing detail header.
## 7. API Changes
For users without `online_lesson:read_all`, `/api/online-lessons` and `/api/online-lessons/[id]` no longer include these internal fields:
- `review_comment`
- `submitted_at`
- `submitted_by`
- `reviewed_at`
- `reviewed_by`
- `approved_at`
- `approved_by`
- `published_by`
- `created_by`
- `created_by_name`
- `updated_by`
- `updated_by_name`
Back-office users with `online_lesson:read_all` continue to receive these fields.
## 8. UI Changes
The user-facing detail page no longer displays the review note block for general users. Back-office users with the permission-derived capability can still see review notes in the detail view and form/edit workflow.
## 9. DTO and Type Changes
The shared `OnlineLesson` contract now treats internal workflow fields as optional so public DTOs can omit them without sending `null` placeholders or leaking field names.
## 10. Test Results
- `npm run lint -- src/features/online-lessons/api/types.ts src/features/online-lessons/server/online-lesson-data.ts src/app/api/online-lessons/[id]/route.ts src/app/dashboard/online-lessons/[id]/page.tsx src/features/online-lessons/components/online-lesson-detail-page.tsx` passed.
- `npx tsc --noEmit --pretty false` passed.
- `npm run build` passed.
## 11. Security Verification
The protection is enforced server-side before JSON serialization, so general users no longer receive internal review fields in API responses. The UI guard is a second layer and uses a capability computed from the same permission rule.
## 12. Regression Check
Existing workflow mutations still use the default internal serializer for create/update/audit flows. Review, return, reject, approve, publish, and archive behavior was not changed.
## 13. Remaining Risks
No automated browser test was added for inspecting the exact network payload. Manual verification should still include logging in as a general user, opening a published lesson, and confirming the response does not include `review_comment` or workflow actor fields.