# URLS_AND_PORTALS

Complete reference of every URL/route in the platform, grouped by area. All URLs are real and generated from the actual route table (`php artisan route:list`). No invented URLs.

- **Base URL:** `http://localhost`
- **Example tenant values used below:** `{schoolId}` = `1` (Greenfield Academy), `{schoolSlug}` = `greenfield-academy`, `{student}` = `3`, `{term}` = `1`
- Route names are shown as `name:` — use them in Blade (`route('...')`) rather than hard-coding paths.

---

## 1. Public Pages (no login required)

School-facing public website. Two parallel systems exist: the **legacy public pages** (rendered with `layouts/public.blade.php`) and the newer **CMS-driven website** (`layouts/website.blade.php`), both served under `/school/{schoolSlug}/...`.

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| Public | Landing page | `/school/greenfield-academy` · `route('public.home', $slug)` | School homepage | None |
| Public | About page | `/school/{schoolSlug}/about` · `public.about` | School information | None |
| Public | Academics page | `/school/{schoolSlug}/academics` · `public.academics` | Academic programmes overview | None |
| Public | Leadership / staff directory | `/school/{schoolSlug}/staff` · `public.staff` · also `/school/{schoolSlug}/leadership` · `public.leadership` | Leadership & staff listings | None |
| Public | Admissions info | `/school/{schoolSlug}/admissions` · `public.admissions` | Admission requirements & process | None |
| Public | News index | `/school/{schoolSlug}/news` · `public.news` | Published news articles | None |
| Public | News article | `/school/{schoolSlug}/news/{slug}` · `public.news-article` | Single news article | None |
| Public | Events index | `/school/{schoolSlug}/events` · `public.events` | Upcoming/past events | None |
| Public | Event detail | `/school/{schoolSlug}/events/{slug}` · `public.event` | Single event page | None |
| Public | Gallery index | `/school/{schoolSlug}/gallery` · `public.gallery` | Photo albums | None |
| Public | Album detail | `/school/{schoolSlug}/gallery/{slug}` · `public.album` | Photos inside one album | None |
| Public | Downloads list | `/school/{schoolSlug}/downloads` · `public.downloads` | Downloadable files | None |
| Public | Download file | `/school/{schoolSlug}/downloads/{id}` · `public.download-file` | Streams a download | None |
| Public | FAQs | `/school/{schoolSlug}/faqs` · `public.faqs` | Frequently asked questions | None |
| Public | CMS page | `/school/{schoolSlug}/pages/{slug}` · `public.page` | Custom CMS-managed page | None |
| Public | Contact form | GET+POST `/school/{schoolSlug}/contact` · `public.contact` / `public.store-contact` | Contact details + message form | None |
| Public | Online application form | GET+POST `/apply/{slug}` · `public.apply` / `public.apply.submit` | Student application submission | None |
| Public | Track application | GET+POST `/school/{schoolSlug}/track-application` · `public.track` / `public.track.submit` | Applicants track their status | None |
| Public | Result verification | `/verify-result/{code}` · `result.verify` | Verifies published report cards by code | None |
| Public | SEO files | `/school/{schoolSlug}/robots.txt` · `public.robots`; `/school/{schoolSlug}/sitemap.xml` · `public.sitemap` | Search-engine files | None |
| Public | Portal login entry | `/school/{schoolId}/portal/login/{role?}` · `portal.login` | Login for students & parents (`role` = `parent` optional) | None |
| Public | Admin/staff login entry | `/school/{schoolId}/login` · `school.login`; staff variant `/school/{schoolId}/login/staff` · `school.login.staff` | Admin & staff sign-in forms | None |

---

## 2. Platform Administration

Super-admin console managing all tenants. Guard: `platform`. Every URL below requires a **Platform Administrator** account.

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| Platform Admin | Login | GET+POST `/platform/login` · `platform.login` / `platform.login.submit` | Platform sign-in | None |
| Platform Admin | Forgot/reset password | `/platform/forgot-password` · `platform.password.request` (+POST `.email`); `/platform/reset-password/{token}` · `platform.password.reset`; POST `platform.password.update` | Password recovery flow | None / token |
| Platform Admin | Logout | POST `/platform/logout` · `platform.logout` | End session | Platform Admin |
| Platform Admin | Dashboard | `/platform` · `platform.dashboard` | KPIs: schools, active schools, users, revenue | Platform Admin |
| Platform Admin | Schools list | `/platform/schools` · `platform.schools.index` | All registered schools | Platform Admin |
| Platform Admin | Create school | GET+POST `/platform/schools/create` → store at `/platform/schools` · `platform.schools.create` / `platform.schools.store` | Onboard new tenant | Platform Admin |
| Platform Admin | School detail | `/platform/schools/{school}` · `platform.schools.show` | Tenant profile + stats | Platform Admin |
| Platform Admin | Edit school | GET `/platform/schools/{school}/edit` · PUT/PATCH `/platform/schools/{school}` · `platform.schools.edit` / `platform.schools.update` | Update tenant record | Platform Admin |
| Platform Admin | Change school status | PATCH `/platform/schools/{school}/status` · `platform.schools.update-status` | Activate/suspend/pending | Platform Admin |
| Platform Admin | Delete school | DELETE `/platform/schools/{school}` · `platform.schools.destroy` | Remove tenant | Platform Admin |
| Platform Admin | School subscriptions | `/platform/schools/{school}/subscriptions` · `platform.schools.subscriptions` | Subscriptions of one school | Platform Admin |
| Platform Admin | Plans list | `/platform/plans` · `platform.plans.index` | Subscription plan catalogue | Platform Admin |
| Platform Admin | Create/edit/delete plan | `/platform/plans/create` (+POST `/platform/plans`); `/platform/plans/{plan}/edit` (+PUT/PATCH, DELETE) · `platform.plans.*` | Manage plans | Platform Admin |
| Platform Admin | Subscriptions list | `/platform/subscriptions` · `platform.subscriptions.index` (+POST store) | All subscriptions | Platform Admin |
| Platform Admin | Subscription detail | `/platform/subscriptions/{subscription}` · `platform.subscriptions.show` | One subscription | Platform Admin |
| Platform Admin | Renew/cancel subscription | POST `/platform/subscriptions/{subscription}/renew` · `.cancel` | Lifecycle actions | Platform Admin |
| Platform Admin | Admin users list | `/platform/users` · `platform.users.index` (+POST store) | Platform administrator accounts | Platform Admin |
| Platform Admin | Create/edit/delete admin user | `/platform/users/create`; `/platform/users/{user}/edit` (+PUT/PATCH, DELETE) · `platform.users.*` | Manage admin accounts | Platform Admin |
| Platform Admin | My Profile | GET+PATCH `/platform/profile` · `platform.profile.show` / `platform.profile.update` | Update own name & phone | Platform Admin |
| Platform Admin | Change own password | PATCH `/platform/profile/password` · `platform.profile.password` | Verify current password + set new | Platform Admin |
| System | Routes & permissions reference | `/system/routes` · `system.routes` | Auto-generated inventory of every URL with permitted roles; searchable | Non-production env **or** any authenticated user (else 404) |

---

## 3. School Administration

Main school management console. Guard: `school`. All URLs are prefixed with `/school/{schoolId}` (e.g. `/school/1/...`). Access requires an authenticated **school admin** (or permitted staff user); module visibility further depends on Role Permissions.

### 3.1 Dashboard & core records

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Dashboard | `/school/1` · `school.dashboard` | Stats, recent students, quick actions | School Admin |
| School Admin | Staff workspace home | `/school/{schoolId}/staff/dashboard` · `school.staff.dashboard` | Non-admin staff landing page | Staff (non-admin roles) |

### 3.2 Student Management

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Students list | `/school/{schoolId}/students` · `school.students.index` | Search/filter/enroll | School Admin |
| School Admin | Add student | GET `/school/{schoolId}/students/create` + POST `/school/{schoolId}/students` · `school.students.create/store` | Enrol new student | School Admin |
| School Admin | View/edit/delete student | `/school/{schoolId}/students/{student}` (+edit, PATCH, DELETE) · `school.students.*` | Student profile & lifecycle | School Admin |
| School Admin | Student photo upload/remove | POST `/school/{schoolId}/students/{student}/photo` and `/photo/remove` · `school.students.upload-photo/remove-photo` | Portrait management | School Admin |
| School Admin | Student documents | POST `.../students/{student}/documents`; GET `.../documents/{document}/download`; DELETE document · `school.students.documents.*` | Attach/download files | School Admin |
| School Admin | Status actions | POST `.../students/{student}/status`, `/graduate`, `/transfer` · `school.students.status/graduate/transfer` | Active/alumni/transfer flows | School Admin |
| School Admin | Student portal accounts | POST `.../students/{student}/portal-account`, `/portal-account/reset-password`, `/portal-account/toggle` · `school.students.portal-account.*` | Create/reset/toggle student login | School Admin |
| School Admin | Promote students | GET+POST `/school/{schoolId}/students/promote` · `school.students.promote.form/promote` | Bulk year-over-year promotion | School Admin |
| School Admin | Import students | GET+POST `/school/{schoolId}/students/import` · `school.students.import.form/import` | CSV bulk import | School Admin |
| School Admin | Export students | `/school/{schoolId}/students-export` · `school.students.export` | CSV export | School Admin |
| School Admin | Alumni | `/school/{schoolId}/students/alumni` · `school.students.alumni.index` (+POST `.../alumni/{student}/reinstate` · `school.students.reinstate`) | Alumni register | School Admin |
| School Admin | ID cards | `/school/{schoolId}/students/id-cards` · `school.students.id-cards.index`; printable card `/school/{schoolId}/id-cards/{student}` · `school.id-cards.show` | Generate/print ID cards | School Admin |
| School Admin | Parents list/CRUD | `/school/{schoolId}/parents` (+create/store/show/edit/update/destroy) · `school.parents.*` | Guardian records | School Admin |
| School Admin | Parent portal accounts | POST `.../parents/{parent}/portal-account` (+`/reset-password`, `/toggle`) · `school.parents.portal-account.*` | Parent login management | School Admin |
| School Admin | Admissions applications | `/school/{schoolId}/admissions` (+create/store/show/edit/update/destroy) · `school.admissions.*` | Review public applications | School Admin |
| School Admin | Convert application | POST `.../admissions/{application}/convert` · `school.admissions.convert` | Convert applicant to student | School Admin |
| School Admin | Toggle intake | POST `.../admissions/toggle-intake` · `school.admissions.toggle-intake` | Open/close online intake | School Admin |
| School Admin | Enquiries (CRM) | `/school/{schoolId}/enquiries` (+create/store/show/edit/update/destroy) · `school.enquiries.*` | Prospect pipeline | School Admin |
| School Admin | Enquiry status/convert | POST `.../enquiries/{enquiry}/status`; GET+POST `.../enquiries/convert/{enquiry}` · `school.enquiries.status/convert(.store)` | Pipeline actions | School Admin |

### 3.3 Teachers

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Teachers list | `/school/{schoolId}/teachers` · `school.teachers.index` (+create/store/show/edit/update/destroy) | Teacher records | School Admin |
| School Admin | Teacher photo | POST `.../teachers/{teacher}/photo` · `school.teachers.upload-photo` | Upload portrait | School Admin |
| School Admin | Toggle teacher | PATCH `.../teachers/{teacher}/toggle` · `school.teachers.toggle` | Activate/deactivate | School Admin |
| School Admin | Teacher login account | GET+POST `.../teachers/{teacher}/account`; POST `.../account/password`; PATCH `.../account/toggle` · `school.teachers.account/save-account/reset-password/toggle-account` | Staff workspace credentials | School Admin |
| School Admin | Teaching assignments | GET+POST `.../teachers/{teacher}/assignments` · `school.teachers.assignments/save-assignments` | Class-subject allocation | School Admin |
| School Admin | Teacher permissions | GET+POST `.../teachers/{teacher}/permissions` · `school.teachers.permissions/save-permissions` | Granular portal capabilities | School Admin |

| School Admin | Teacher permissions | GET+POST `.../teachers/{teacher}/permissions` · `school.teachers.permissions/save-permissions` | Granular portal capabilities | School Admin |

### 3.3b Staff Management (wraps Teachers; teachers stay linked, no duplicate records)

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Staff Dashboard | `/school/{schoolId}/staff/overview` · `school.staff.overview` | Workforce tiles, today's attendance summary, staff by category, recent hires | School Admin |
| School Admin | All Staff directory | `/school/{schoolId}/staff` · `school.staff.index` (filters: q/category/department/designation/status/type) | Full staff register incl. linked teacher records | School Admin |
| School Admin | Add Staff Member | GET+POST `/school/{schoolId}/staff/create`, `/staff` · `school.staff.create/store` | Non-teaching staff onboarding; STF#### number auto-assigned | School Admin |
| School Admin | Staff profile | `/school/{schoolId}/staff/{staffMember}` · `school.staff.show` | Personal/employment details, 30-day attendance, portal account status | School Admin |
| School Admin | Edit Staff | GET+PATCH `.../staff/{staffMember}/edit` · `school.staff.edit/update` | Names locked when record is linked to a teacher (edit via 3.3 instead) | School Admin |
| School Admin | Activate/Deactivate | PATCH `.../staff/{staffMember}/status` · `school.staff.status` | active ⇄ inactive (history preserved) | School Admin |
| School Admin | Portal account | GET+POST `.../staff/{staffMember}/account`; POST `.../account/password`; PATCH `.../account/toggle` · `school.staff.account/save-account/reset-password/toggle-account` | role=staff workspace credentials via Staff Login | School Admin |
| All school roles | Staff Attendance marking | GET+POST `/school/{schoolId}/staff/attendance` · `school.staff.attendance(.save)` | Per-date present/absent/late/excused + notes — separate from student attendance | School Admin |
| School Admin | Attendance history | `/school/{schoolId}/staff/attendance/history` · `school.staff.attendance.history` | Last 60 days daily rollups | School Admin |
| School Admin | Categories & Designations | GET+POST+DELETE `/school/{schoolId}/staff/settings...` · `school.staff.settings(.store/.destroy)` | Manage categories, departments, designations per school (in-use items undeletable) | School Admin |
| Staff user | Staff Workspace | `/school/{schoolId}/staff/dashboard` · `school.staff.dashboard` | Post-login home for teacher/staff/accountant roles incl. My Staff Record card | auth:school (teacher/staff/accountant) |

### 3.4 Academics

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Classes CRUD | `/school/{schoolId}/classes` (+create/store/show/edit/update/destroy) · `school.classes.*` | Classrooms/levels | School Admin |
| School Admin | Subjects CRUD | `/school/{schoolId}/subjects` (+create/store/show/edit/update/destroy) · `school.subjects.*` | Subject catalogue | School Admin |
| School Admin | Academic years/terms | `/school/{schoolId}/academic` · `school.academic.index`; POST `academic/years` (+terms), DELETE years/terms, PATCH set-current · `school.academic.*` | Sessions management | School Admin |
| School Admin | Timetable | GET+POST `/school/{schoolId}/timetable` · `school.timetable.index/store`; POST `timetable/copy`; GET `timetable/print`; DELETE `timetable/{timetable}` | Period grid builder | School Admin |
| School Admin | Attendance marking | GET+POST `/school/{schoolId}/attendance` · `school.attendance.index/store` | Daily class register | School Admin |
| School Admin | Attendance report | `/school/{schoolId}/attendance/report` · `school.attendance.report` | Summarised attendance | School Admin |

### 3.5 Exams & Results

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Exams CRUD | `/school/{schoolId}/exams` (+create/store/show/edit/update/destroy) · `school.exams.*` | Exam definitions | School Admin |
| School Admin | Legacy exam results entry | GET+POST `.../exams/{exam}/results` · `school.exams.results/save-results` | Per-exam score sheet | School Admin |
| School Admin | Assessment setup | GET+POST `/school/{schoolId}/assessments` · `school.exams.assessment-types/store-assessment-type`; POST `assessments/seed`; DELETE `assessments/{type}` | CA/exam weight configuration | School Admin |
| School Admin | Grading scale | GET+POST `/school/{schoolId}/grading` · `school.exams.grading/store-grade`; POST `grading/seed`; DELETE `grading/{grade}` | Grades & remarks | School Admin |
| School Admin | Score entry (broad sheet) | GET+POST `/school/{schoolId}/results/entry` · `school.results.entry/save-scores` | Multi-student score capture | School Admin |
| School Admin | Result sheets | `/school/{schoolId}/results` · `school.results.index` | Workflow dashboard (draft→published) | School Admin |
| School Admin | Save computed sheets | POST `.../results/save-sheets` · `school.results.save-sheets` | Totals/grades/GPA/positions | School Admin |
| School Admin | Report card preview | `/school/{schoolId}/results/report-card/{student}/{term}` · `school.results.report-card` | A4 printable report card | School Admin |
| School Admin | Edit remarks on card | POST `.../results/{student}/remarks` · `school.results.remarks` | Teacher/principal comments | School Admin |
| School Admin | Submit/review/approve | POST `.../results/submit`, `/review`, `/approve` · `school.results.submit/review/approve` | Approval workflow steps | Approve Results permission / School Admin |
| School Admin | Publish/unpublish | POST `.../results/publish`, `/unpublish` · `school.results.publish/unpublish` | Release to portals; generates verification codes | Publish permission |
| School Admin | Result settings | GET+POST `/school/{schoolId}/results/settings` · `school.results.settings/save-settings` | Report-card display toggles, comment titles, workflow requirement | School Admin |
| School Admin | Result signatures | GET+POST `/school/{schoolId}/results/signatures` · `school.results.signatures(.store)` | Signature strip manager | School Admin |
| School Admin | Update/toggle/delete signature | PATCH `.../results/signatures/{signature}`, PATCH `.../toggle`, DELETE · `school.results.signatures.update/toggle/destroy` | Signature row actions | School Admin |
| School Admin | Behaviour traits & ratings | GET `/school/{schoolId}/behaviour` · `school.behaviour.index`; POST `behaviour/ratings`, `behaviour/traits`; DELETE `behaviour/traits/{trait}` · `school.behaviour.*` | Affective/psychomotor domain | School Admin |

### 3.6 Finance

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin/Accountant | Invoices list/create | `/school/{schoolId}/finance/invoices` (+create, POST store) · `school.finance.invoices/create-invoice/store-invoice` | Billing | Finance access |
| School Admin/Accountant | Invoice detail + payment | `/school/{schoolId}/finance/invoices/{invoice}` · `school.finance.show-invoice`; POST `.../payment` · `school.finance.record-payment` | Record receipts | Finance access |
| School Admin/Accountant | Fee categories | GET+POST `/school/{schoolId}/finance/categories`; DELETE `categories/{category}` · `school.finance.categories*` | Fee heads | Finance access |
| School Admin/Accountant | Fee structures | GET+POST `/school/{schoolId}/finance/structures` · `school.finance.structures*` | Class-level pricing | Finance access |

### 3.7 Communications

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Inbox | GET+POST `/school/{schoolId}/inbox` · `school.communications.inbox/store-message` | Internal messages | School Admin/Staff |
| School Admin | Compose message | `/school/{schoolId}/inbox/compose` · `school.communications.send-message`; view at `inbox/{message}` | Broadcast/recipients | School Admin/Staff |
| School Admin | Announcements CRUD | `/school/{schoolId}/announcements` (+create/store/show/delete) · `school.communications.announcements*` | Notice board | School Admin |
| School Admin | Publish announcement | POST `.../announcements/{announcement}/publish` · `school.communications.publish-announcement` | Push to portals/site | School Admin |
| School Admin | Notifications centre | GET `/school/{schoolId}/notifications` · `school.communications.notifications`; POST `notifications/read-all` and `notifications/{notification}/read` | System notifications | School Admin/Staff |

### 3.8 Website CMS

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | CMS overview | `/school/{schoolId}/cms` · `school.cms.index` | Website content hub | School Admin |
| School Admin | Design & theme | GET+PUT `/school/{schoolId}/website` · `school.website.show/update`; PUT `website/theme`, `/content`, `/sections`, `/carousel`, `/navigation`, `/seo` | Full site customisation | School Admin |
| School Admin | Slides | GET+POST `cms/slides`; PUT/DELETE `cms/slides/{slide}`; PATCH `slides/{slide}/move`, `/toggle` · `school.cms.slides*` | Homepage carousel | School Admin |
| School Admin | Pages | GET+POST `cms/pages`; PUT/DELETE `cms/pages/{page}`; PATCH toggle · `school.cms.pages*` | Static pages | School Admin |
| School Admin | News | GET+POST `cms/news`; edit at `cms/news/{news}/edit`; PUT/DELETE; PATCH toggle · `school.cms.news*` | Site news articles | School Admin |
| School Admin | Events | GET+POST `cms/events`; edit/PUT/DELETE `cms/events/{event}`; PATCH toggle · `school.cms.events*` | Site events | School Admin |
| School Admin | Gallery albums/images | GET `cms/gallery`; POST `gallery/albums`; POST `albums/{album}/images`; DELETE album/image · `school.cms.gallery*` | Photo galleries | School Admin |
| School Admin | Media library | GET+POST `cms/media`; PUT/DELETE `cms/media/{mediaFile}` · `school.cms.media*` | Reusable uploads | School Admin |
| School Admin | Testimonials / FAQs / Downloads | GET+POST `cms/testimonials` (DELETE row); `cms/faqs`; `cms/downloads` (+DELETE) · `school.cms.*` | Content blocks | School Admin |
| School Admin | Site settings | GET+PUT `cms/settings` · `school.cms.settings/update-settings` | Global site config | School Admin |
| School Admin | Contact messages | GET `cms/contacts` · `school.cms.contact-messages`; show `contacts/{contactMessage}`; DELETE row | Inbox from contact form | School Admin |

### 3.9 Reports

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| School Admin | Reports overview | `/school/{schoolId}/reports` · `school.reports.index` | Report launcher | School Admin |
| School Admin | Academic performance | `/school/{schoolId}/reports/academic` · `school.reports.academic-performance` | Class/subject analytics | School Admin |
| School Admin | Student report | `/school/{schoolId}/reports/student` · `school.reports.student-report` | Single-student analysis | School Admin |
| School Admin | Class report | `/school/{schoolId}/reports/class` · `school.reports.class-report` | Class-level summary | School Admin |
| School Admin | Attendance report (alt) | `/school/{schoolId}/reports/attendance` · `school.reports.attendance-report` | Attendance analytics | School Admin |
| School Admin | Finance report | `/school/{schoolId}/reports/finance` · `school.reports.finance-report` | Revenue/outstanding | School Admin |

### 3.10 Settings & account

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| Any school user | My profile | GET+PATCH `/school/{schoolId}/settings/profile` · `school.settings.my-profile/update-profile-me` | Own account details | Authenticated |
| Any school user | Change password | GET+PATCH `/school/{schoolId}/settings/password` · `school.settings.change-password/update-password` | Credential rotation | Authenticated |
| School Admin | School profile | GET+PATCH `/school/{schoolId}/settings/school` · `school.settings.school-profile/update-profile` | Tenant identity | School Admin |
| School Admin | User management | GET+POST `/school/{schoolId}/settings/users`; PATCH `users/{user}/toggle`; DELETE `users/{user}` · `school.settings.users*` | Staff/system accounts | School Admin |
| School Admin | Role permissions | GET `/school/{schoolId}/settings/permissions` · `school.settings.permissions`; PATCH `permissions/{user}` | Per-user capability matrix | School Admin |
| School Admin | Portal access settings | GET+PATCH `/school/{schoolId}/settings/portal-access` · `school.settings.portal-access(.update)` | Which portal sections are visible | School Admin |
| School Admin | Campuses | GET+POST `/school/{schoolId}/settings/campuses`; PATCH/DELETE `campuses/{campus}`; PATCH `campuses/{campus}/toggle` · `school.settings.campuses*` | Multi-campus setup | School Admin |
| Any | Logout | POST `/school/{schoolId}/logout` · `school.logout` | End session | Authenticated |
| Any | Password recovery | GET+POST `/school/{schoolId}/forgot-password`; GET `/reset-password/{token}` + POST `/reset-password` · `school.password.*` | Self-service reset | None/token |

---

## 4. Teacher Portal (tportal)

Guard: `school`, role Teacher (or permitted staff). Base prefix `/school/{schoolId}/portal/teacher`. Sidebar items are gated by **TeacherAccess** permissions.

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| Teacher | Dashboard | `/school/1/portal/teacher/dashboard` · `tportal.dashboard` | Today overview, quick links | Teacher login |
| Teacher | My classes | `/school/{schoolId}/portal/teacher/my-classes` · `tportal.classes`; detail `my-classes/{class}` · `tportal.classes.show` | Assigned class rosters | Teacher login |
| Teacher | My subjects | `/school/{schoolId}/portal/teacher/my-subjects` · `tportal.subjects` | Teaching allocations | Teacher login |
| Teacher | Take attendance | GET `/school/{schoolId}/portal/teacher/attendance/take` + POST `attendance/store` · `tportal.attendance.take/store` | Daily register | Attendance permission |
| Teacher | Attendance history | `/school/{schoolId}/portal/teacher/attendance/history` · `tportal.attendance.history` | Past registers | Attendance permission |
| Teacher | Marks entry | GET `/school/{schoolId}/portal/teacher/marks` + POST `marks/save` · `tportal.marks.entry/save` | CA/exam score capture | Enter Scores permission |
| Teacher | Marks submitted log | `/school/{schoolId}/portal/teacher/marks/submitted` · `tportal.marks.submitted` | Submission history | Enter Scores permission |
| Teacher | Results sheets | `/school/{schoolId}/portal/teacher/results` · `tportal.results` | Class result status (incl. approve if permitted) | Results permission(s) |
| Teacher | Class teacher remarks | GET+POST `/school/{schoolId}/portal/teacher/comments` · `tportal.comments(.save)` | Report-card comments | Class teacher only |
| Teacher | Conduct ratings | GET+POST `/school/{schoolId}/portal/teacher/conduct` · `tportal.conduct(.save)` | Affective/psychomotor entry | Conduct permission |
| Teacher | Timetable | `/school/{schoolId}/portal/teacher/timetable` · `tportal.timetable` | Personal teaching timetable | Teacher login |
| Teacher | Announcements | `/school/{schoolId}/portal/teacher/announcements` · `tportal.announcements` | Read announcements | Announcements permission |
| Teacher | Profile | GET `/school/{schoolId}/portal/teacher/profile` · `tportal.profile`; POST `profile/update`, `profile/photo` | Own details & avatar | Teacher login |
| Teacher | Logout | POST `/school/{schoolId}/portal/teacher/logout` · `tportal.logout` | End session | Teacher login |

---

## 5. Student Portal (portal)

Guard: `portal` (student accounts). Base prefix `/school/{schoolId}/portal`. Optional `{student}` segment applies when a **parent** with multiple children browses (see §6).

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| Student | Login | GET+POST `/school/{schoolId}/portal/login/{role?}` · `portal.login(.submit)` | Role-aware login (`student` default) | None |
| Student | Home | `/school/{schoolId}/portal/dashboard` · `portal.dashboard` | Attendance %, fees, quick tiles | Student login |
| Student | Results list | `/school/{schoolId}/portal/results` · `portal.results` | Terms with published sheets | Student login |
| Student | Report card | `/school/{schoolId}/portal/report-card/{sheet}/{student?}` · `portal.report-card` | Full report card (respects Result Settings) | Student login |
| Student | Attendance | `/school/{schoolId}/portal/attendance` · `portal.attendance` | History & streaks | Student login |
| Student | Timetable | `/school/{schoolId}/portal/timetable` · `portal.timetable` | Weekly schedule | Student login |
| Student | Subjects | `/school/{schoolId}/portal/subjects` · `portal.subjects` | Enrolled subjects & teachers | Student login |
| Student | Fees | `/school/{schoolId}/portal/fees` · `portal.fees` | Invoices & payments | Student login |
| Student | Updates | `/school/{schoolId}/portal/announcements` · `portal.announcements` | Published announcements | Student login |
| Student | Profile | GET `/school/{schoolId}/portal/profile` · `portal.profile`; POST `profile/update`, `profile/photo` | Details & avatar | Student login |
| Student | Logout | POST `/school/{schoolId}/portal/logout` · `portal.logout` | End session | Student login |

---

## 6. Parent Portal (portal, role=parent)

Parents authenticate through the same portal routes with role `parent` (login URL `/school/{schoolId}/portal/login/parent`) and see one extra control: the **child switcher**. Every section URL accepts the optional trailing `/{student}` to select which child is viewed, e.g.:

- `/school/1/portal/dashboard/3`
- `/school/1/portal/results/3`
- `/school/1/portal/report-card/{sheet}/3`

Sections available to parents mirror the Student Portal table above (dashboard, results, attendance, timetable, subjects, fees, updates, profile) and respect **Portal Access** settings configured by the school (`school.settings.portal-access`).

---

## 7. Other Modules & Infrastructure

| Portal/Role | Page or Feature | Actual URL/Route | Description | Access Required |
|---|---|---|---|---|
| System | Root landing | `/` · `home` | App entry point (redirects by context) | None |
| System | Health check | `/up` | Laravel health endpoint | None |
| System | Local storage passthrough | GET/PUT `/storage/{path}` · `storage.local` | Serves uploaded files (public disk) | File-dependent |
| Public | Result verification | `/verify-result/{code}` · `result.verify` | Certificate/report authenticity check | None |
| Public | Application form | `/apply/{slug}` · `public.apply(.submit)` | Standalone admission intake | None |

---

## 8. Demo & Test Accounts (DemoAccountsSeeder)

All accounts are created by `php artisan db:seed` (`DatabaseSeeder` → `PermissionSeeder` → `DemoAccountsSeeder`) and every password is **`password`**. Re-running the seeder is safe — it upserts.

### Greenfield Academy — `{schoolId}` = `1`, slug `greenfield-academy`

| Role | Login URL | Email | Notes |
|---|---|---|---|
| Platform Super Admin | `/platform/login` | `admin@eduschool.ng` | Sees all tenants |
| School Administrator | `/school/1/login` | `admin@greenfield.edu.ng` | Full school console |
| Teacher | `/school/1/portal/login/teacher` (or Staff Login) | `ngozi@greenfield.edu.ng` | Maths; class teacher JSS 1A. Also: `tunde@…` (English), `musa@…` (Basic Science) |
| Student | `/school/1/portal/login/student` | `student@greenfield.edu.ng` | Chinedu Okafor, JSS 1A, published First-Term report card |
| Parent/Guardian (2 children) | `/school/1/portal/login/parent` | `parent@greenfield.edu.ng` | Paula Obi — mother of Ada **and** Emeka Obi (child switcher demo); also `parent2@…` (Grace Okafor) |
| Accountant/Bursar | `/school/1/login/staff` | `accountant@greenfield.edu.ng` | Bursary dept; finance workspace |
| Librarian | `/school/1/login/staff` | `librarian@greenfield.edu.ng` | Library dept |
| Receptionist | `/school/1/login/staff` | `receptionist@greenfield.edu.ng` | Administration dept |
| Hostel Manager | `/school/1/login/staff` | `hostel@greenfield.edu.ng` | Hostel dept |
| School Nurse | `/school/1/login/staff` | `nurse@greenfield.edu.ng` | Health dept |
| HR Officer | `/school/1/login/staff` | `hr@greenfield.edu.ng` | Human Resources dept |
| Transport Manager | `/school/1/login/staff` | `transport@greenfield.edu.ng` | Transport dept |
| Security Officer | `/school/1/login/staff` | `security@greenfield.edu.ng` | Security dept |

Seeded demo data at Greenfield: 2026/2027 session with 3 terms · classes JSS 1A–3A · 3 subjects per class with teachers assigned · weekly timetable (Mon–Fri) · 8 students across 3 classes · tuition invoices per student (one paid in full, one partial, rest pending + payments recorded) · CA + Exam assessment types and an A–F grading scale · **3 published First-Term result sheets for JSS 1A** (verification codes work on `/verify-result/{code}`) · 10 days of attendance records · announcements for all/parents/students audiences · one admissions enquiry + one submitted application.

### Sunrise International School — `{schoolId}` = `2`

Minimal mirror dataset for cross-tenant isolation testing:

| Role | Login URL | Email |
|---|---|---|
| School Administrator | `/school/2/login` | `admin@sunrise.edu.ng` |
| Teacher | `/school/2/portal/login/teacher` | `teacher@sunrise.edu.ng` |
| Parent/Guardian | `/school/2/portal/login/parent` | `parent@sunrise.edu.ng` |

Sunrise IDs never resolve Greenfield records (and vice versa) — authenticated requests to the other tenant's `{schoolId}` return 404.

---

### Notes

1. **Tenant isolation**: every authenticated school-scoped controller resolves models through the `{schoolId}` route parameter and rejects cross-tenant access (404). IDs are never interchangeable between schools. Verified live: a school-1 session requesting school-2 URLs is refused — portal routes bounce to that school's login page (fail-closed via tenant-scoped auth lookup), while admin/staff routes abort with **403** (`EnsureUserHasSchoolAccess`).
2. **Result workflow** (when *Require approval workflow* is ON in Result Settings): draft → submitted → reviewed → approved → published; publish otherwise allowed directly. Unpublishing returns sheets to `approved` (workflow mode) or `draft` (legacy mode).
3. **Verification codes** are generated once per result sheet at first publish and surfaced via `/verify-result/{code}`.
4. Portals share the `portal` guard; the `{role?}` login parameter and middleware determine whether a student or parent session is created.
