# Student Portal Links Audit

Date: 2026-05-05

## Status

The active student portal routes are protected and the core pages render successfully for a completed student profile:

- `/portal`
- `/portal/courses`
- `/portal/schedule`
- `/portal/payments`
- `/portal/certificates`
- `/portal/profile`
- `/portal/support`
- `/portal/notifications`

Guests are redirected to login, and admin/teacher users are forbidden from entering the student portal as students.

## Fixed Issues

### Certificate verification route

The certificates page was using the old route name `certificate.verify`, but the real public verification route is `certificates.verify`.

Fix:

- Updated certificate verification links.
- Updated the LinkedIn certificate URL to use the same valid verification route.

Files:

- `resources/views/livewire/student/my-certificates-page.blade.php`

### Support quick actions

The support page had non-functional `href="#"` quick actions.

Fix:

- Replaced dummy links with real internal anchors:
  - `#support-form`
  - `#support-faq`
  - `#support-status`
- Added matching sections so the actions scroll to meaningful content.

Files:

- `resources/views/livewire/student/support-page.blade.php`

### Course details modal

The courses page tried to open course details from an undefined in-memory property, which could break the Livewire action.

Fix:

- Replaced the undefined property lookup with a secure database lookup.
- The lookup is scoped to the authenticated student through the registration ownership relation.

Files:

- `app/Livewire/Student/MyCoursesPage.php`

### Schedule course filter

The schedule page was filtering courses through the wrong relationship level, which could cause invalid SQL or empty filters.

Fix:

- Filtered courses through the student's registrations directly.
- Added deterministic ordering by localized course title.

Files:

- `app/Livewire/Student/MySchedulePage.php`

### Notification dropdown

The legacy notification dropdown had a `href="#"` "view all" link.

Fix:

- Linked it to `student.notifications`.

Files:

- `resources/views/livewire/student/notification-dropdown.blade.php`

### Legacy dashboard safety

The older student dashboard view referenced an obsolete certificate download route and legacy certificate fields.

Fix:

- Switched to the signed student certificate download route.
- Updated certificate title/serial references to the current model relationships.

Files:

- `resources/views/livewire/student/dashboard.blade.php`
- `app/Livewire/Student/Dashboard.php`

### Security center routes

The `/portal/security/2fa` page was calling `User::securityRecoveryCodes()`, but the relationship was missing. Security tables are polymorphic through `morphs('user')`, so the user model must expose polymorphic relations.

Fix:

- Added `securityRecoveryCodes()`.
- Corrected security center relations to use `morphOne` / `morphMany` instead of plain `hasOne` / `hasMany`.

Files:

- `app/Models/User.php`

## Verification

Added regression coverage for:

- Support quick actions do not use dummy `href="#"` links.
- Certificates use the real `certificates.verify` route.
- Students can open only their own course details.
- Students cannot open another student's course details.
- Schedule course filters are scoped through the authenticated student's registrations.
- Secondary portal routes render: notifications, security, 2FA, sessions, events, privacy consents, data requests, and data export.
- Course workspace is scoped to the authenticated student's own enrollment.

Command:

```bash
php artisan test tests\Feature\Student\StudentPortalLinksAuditTest.php tests\Feature\Student\StudentPortalRoutesTest.php tests\Feature\Student\StudentPortalNavigationTest.php tests\Feature\StudentDashboardTest.php --stop-on-failure
```

Result:

- 18 tests passed.
- 72 assertions passed.
