ADR-006: Dual Portal Architecture
Status: Accepted | Date: 2026-03-12
Context
SA3 serves two distinct user populations:
- System administrators (ADMIN role) who configure academic systems, manage staff/students, and access all data.
- Operational staff (teachers, principals, vice-principals) who enter scores, view class lists, and generate reports.
A single UI would require complex conditional rendering and risk exposing administrative controls to non-admin staff.
Decision
Build a single Next.js app with two independent route segments:
| Portal | URL prefix | Roles | Layout file |
|---|---|---|---|
| System Admin | /admin/** | ADMIN only | src/app/admin/layout.tsx |
| Staff Portal | /app/** | All authenticated staff | src/app/app/layout.tsx |
Two independent layout files provide completely separate chrome:
- Admin layout: dark slate sidebar, full-width configuration panels.
- Staff layout: white sidebar, card-based operational views.
Portal Boundary
| Concern | Portal |
|---|---|
| Academic system config | /admin |
| User & role management | /admin |
| School-year / term setup | /admin |
| Score entry | /app |
| Class lists | /app |
| Report card preview | /app |
API Routes
All /api/admin/** routes serve both portals. The /api/admin/ prefix is a naming artifact -- not a permission gate. All handlers enforce access via resolvePermissionsForResource.
Consequences
Positive: Clean separation of concerns, independent layouts, straightforward middleware guards.
Negative: src/app/app/ double-nesting can cause confusion (valid Next.js App Router behaviour but requires awareness).
Alternatives Rejected
- Separate Next.js apps -- over-engineered for single-school; doubles deployment surface
- Single layout with role-conditional chrome -- deeply nested conditionals; harder to maintain