# Student Portal Audit Report

Date: 2026-05-05

## Executive Status

Overall status: partially implemented, but not yet aligned with the requested `/portal` contract.

- Routing protection exists globally through `bootstrap/app.php`, but current student URLs are legacy root-level URLs such as `/dashboard`, `/courses`, `/my-schedule`, and `/payments`.
- Student data queries mostly filter by authenticated user, but some authorization is implemented manually inside components instead of formal policies.
- The layout is shared through `resources/views/layouts/student.blade.php`, but the portal shell still mixes old names, duplicated menus, and a broken/legacy topbar include.
- Several menu labels use `student_nav.php` and `student.php`, while the requested `portal.php` namespace is missing.
- Material download is currently instructor-focused and does not yet provide a student portal route with a dedicated `MaterialPolicy`.

## 1. Routes Protection

Evidence:

- `bootstrap/app.php` loads `routes/student.php` inside middleware: `web`, `auth`, `student_portal`, `profile_completed`.
- `app/Http/Middleware/StudentPortalMiddleware.php` allows users with role column `student` or Spatie role `student`.
- The same middleware also allows `super_admin`, which is useful for support but conflicts with the requested rule that admin access should be outside scope unless impersonation exists.

Findings:

- `/portal`, `/portal/courses`, `/portal/schedule`, `/portal/payments`, `/portal/certificates`, `/portal/profile`, and `/portal/support` are not the canonical routes yet.
- Current canonical routes are `/dashboard`, `/courses`, `/my-schedule`, `/payments`, `/my-certificates`, `/profile`, `/support`.
- `CompleteProfilePage` is protected by the same route group and excluded from `profile_completed`, which is correct.

Risk:

- Medium. Navigation and documentation can drift, and public support/training links may break when the expected `/portal` URLs are used.

Required fix:

- Move canonical student pages under `/portal`.
- Keep legacy URLs as safe redirects for backward compatibility.
- Decide whether `super_admin` can enter the portal directly. If no impersonation feature is active, block non-student users from portal routes.

## 2. Student Data Isolation

Evidence:

- `GetStudentCourses` uses `Auth::id()` and `StudentCoursesQuery` filters enrollments through `registration.user_id`.
- `GetStudentSchedule` filters enrollments by `registration.user_id` and `status = confirmed`.
- `GetStudentPayments` filters payments through `registration.user_id`.
- `MyCertificatesPage` filters certificates by `user_id = auth()->id()`.
- `CoursePlayer::mount()` manually checks ownership through `enrollment.registration.user_id`.

Findings:

- The core read paths are mostly user-scoped.
- There is no `EnrollmentPolicy`.
- `SessionPolicy` has teacher/admin access logic, but no `viewInPortal` method for students.
- `PaymentPolicy` supports student ownership, but ownership does not yet include all possible enrollment/payment paths.
- `MaterialPolicy` is missing.

Risk:

- Medium to High. Manual checks reduce IDOR risk in some components, but missing policies make future components easy to implement incorrectly.

Required fix:

- Add `EnrollmentPolicy::view`.
- Add `SessionPolicy::viewInPortal`.
- Add `MaterialPolicy::download`.
- Register all policies in `AppServiceProvider`.
- Use `authorize()` in Livewire `mount()` where a route model is accepted.

## 3. Layout Consistency

Evidence:

- Student components mostly use `->layout('layouts.student')`.
- `resources/views/layouts/student.blade.php` uses `<x-portal.sidebar type="student" />` but includes `layouts.partials.student-topbar`, while the project also has `components/portal/topbar.blade.php`.
- `resources/views/components/portal/sidebar.blade.php` contains admin, finance, instructor, and student menu logic in one large component.
- Student menu uses `student_nav` and `dz_terms.payment`, not a unified `portal` namespace.

Findings:

- There is one student layout, but it is not the requested `resources/views/layouts/portal.blade.php`.
- The sidebar component is overloaded and difficult to audit.
- Mobile bottom navigation is not present in the student layout.
- The layout has a duplicated closing `</style>`.

Risk:

- Medium. UX inconsistency and layout fragility, especially on mobile.

Required fix:

- Create `resources/views/layouts/portal.blade.php`.
- Keep `layouts.student` as a compatibility wrapper or switch student pages to `layouts.portal`.
- Create focused portal navigation data/partials for student only.
- Add mobile bottom navigation.

## 4. Broken or Incomplete Menu Links

Evidence:

- Student menu links exist for dashboard, courses, schedule, payments, certificates, profile, support.
- Route names are present, but current route paths do not match `/portal`.
- Topbar dropdown has `href="#"` for profile/settings instead of real student routes.

Findings:

- Menu is functional but not fully polished.
- Some topbar actions are placeholders.

Risk:

- Low to Medium. Main navigation works, but secondary navigation is confusing.

Required fix:

- Replace placeholder profile/settings links with real routes.
- Add active states for `/portal/*`.
- Add mobile bottom nav with five core actions.

## 5. RTL/LTR

Evidence:

- Layout HTML sets `dir` based on locale.
- Sidebar positions itself right for Arabic and left for non-Arabic.
- Many Blade views use logical Tailwind classes such as `start`, `end`, `ps`, `pe`.

Findings:

- RTL is partially good.
- Some older views still contain fixed English/left/right assumptions or inline SVG arrows.

Risk:

- Low to Medium. Usable, but polish issues remain.

Required fix:

- Use logical spacing consistently in the new portal layout.
- Rotate directional icons with `rtl:rotate-180` where needed.

## 6. Hardcoded Strings / i18n

Evidence:

- `student_nav.php` and `student.php` exist for AR/FR.
- Requested `portal.php` namespace is missing.
- Some older student views and dropdowns contain hardcoded labels or placeholder strings.

Findings:

- i18n exists but is fragmented.

Risk:

- Medium. New portal work can introduce untranslated text or inconsistent labels.

Required fix:

- Add `lang/ar/portal.php` and `lang/fr/portal.php`.
- Move the requested menu/action/status labels into `portal.*`.
- Keep existing keys as fallback where refactoring all pages is not safe in one pass.

## 7. UI Consistency

Evidence:

- Student pages use a mix of `x-ui.card`, custom cards, older portal shells, and several large Blade files.
- Dashboard and payments received recent visual work, but the shell itself is still older.

Findings:

- Pages are serviceable but not consistently mobile-first.
- The layout needs a cleaner shell before deeper per-page redesign.

Risk:

- Medium. Page-level polish will be undermined by inconsistent shell/nav.

Required fix:

- First pass: route/layout/nav/RBAC foundation.
- Second pass: page-by-page UX refinement after the shell is stable.

## 8. Files That Need Modification

Priority files:

- `routes/student.php`
- `app/Http/Middleware/StudentPortalMiddleware.php`
- `app/Policies/EnrollmentPolicy.php`
- `app/Policies/SessionPolicy.php`
- `app/Policies/PaymentPolicy.php`
- `app/Policies/MaterialPolicy.php`
- `app/Providers/AppServiceProvider.php`
- `resources/views/layouts/portal.blade.php`
- `resources/views/layouts/student.blade.php`
- `resources/views/components/portal/sidebar.blade.php`
- `resources/views/components/portal/topbar.blade.php`
- `lang/ar/portal.php`
- `lang/fr/portal.php`
- `app/Livewire/Student/CoursePlayer.php`
- `app/Application/DTOs/Student/MyCourses/StudentCourseCardDTO.php`
- `app/Http/Controllers/Instructor/MaterialDownloadController.php` or a new student material controller

Recommended test files:

- `tests/Feature/Student/StudentPortalRoutesTest.php`
- `tests/Feature/Student/StudentPortalAuthorizationTest.php`
- `tests/Feature/Student/StudentPortalNavigationTest.php`

