222 lines
6.2 KiB
Markdown
222 lines
6.2 KiB
Markdown
# Navigation and RBAC
|
|
|
|
## Overview
|
|
|
|
This repository uses an Auth.js-based access model with server-side authorization as the real security boundary.
|
|
|
|
Navigation filtering exists for usability only. It helps show the right menus to the right users, but it is not the thing that protects data. Real protection is enforced in:
|
|
|
|
- `src/proxy.ts`
|
|
- page guards under `src/lib/auth/page-guards.ts`
|
|
- session helpers under `src/lib/auth/session.ts`
|
|
- route handlers under `src/app/api/**`
|
|
|
|
## Core Concepts
|
|
|
|
### User
|
|
|
|
Authenticated person from Auth.js session.
|
|
|
|
### Organization
|
|
|
|
The active tenant/workspace from `session.user.activeOrganizationId`.
|
|
|
|
### Membership
|
|
|
|
The user's relation to the active organization. This is loaded server-side and includes:
|
|
|
|
- `role`
|
|
- `permissions`
|
|
|
|
### Business Role
|
|
|
|
The UI and feature model mainly uses:
|
|
|
|
- `HRD`
|
|
- `EMPLOYEE`
|
|
|
|
Business role is derived from session and membership state through `getBusinessRole()` in [src/lib/auth/roles.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/roles.ts).
|
|
|
|
## Security Boundaries
|
|
|
|
### 1. Proxy route protection
|
|
|
|
[src/proxy.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/proxy.ts) blocks unauthenticated access to:
|
|
|
|
- `/dashboard/**`
|
|
- protected API namespaces such as:
|
|
- `/api/training-records/**`
|
|
- `/api/notifications/**`
|
|
- `/api/announcements/**`
|
|
- `/api/audit-logs/**`
|
|
- other protected modules
|
|
|
|
This ensures unauthenticated users cannot directly browse protected pages or call protected APIs.
|
|
|
|
### 2. Server-side session helpers
|
|
|
|
[src/lib/auth/session.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/session.ts) is the main authorization entry point.
|
|
|
|
Important helpers:
|
|
|
|
- `requireSession()`
|
|
- `requireOrganizationAccess()`
|
|
- `requireHRD()`
|
|
- `requireEmployee()`
|
|
|
|
These helpers:
|
|
|
|
- validate authentication
|
|
- validate active organization context
|
|
- verify membership
|
|
- derive role-based access
|
|
- return organization-scoped access data for downstream queries
|
|
|
|
### 3. Page-level guards
|
|
|
|
[src/lib/auth/page-guards.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/page-guards.ts) handles protected dashboard navigation and redirect behavior.
|
|
|
|
Important guards:
|
|
|
|
- `requireEmployeeDashboardAccess()`
|
|
- `requireHRDDashboardAccess()`
|
|
|
|
These are used by dashboard pages so direct URL access is also protected, not only sidebar visibility.
|
|
|
|
### 4. Route handler authorization
|
|
|
|
Every sensitive route handler must still verify organization and role server-side.
|
|
|
|
Examples:
|
|
|
|
- employee-owned training data is scoped by `organizationId` and `userId`
|
|
- HRD-only actions use `requireHRD()`
|
|
- review and audit routes validate higher privilege before returning data
|
|
|
|
## Navigation Filtering
|
|
|
|
Sidebar and kbar filtering are driven by:
|
|
|
|
- [src/config/nav-config.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/config/nav-config.ts)
|
|
- [src/hooks/use-nav.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/hooks/use-nav.ts)
|
|
|
|
Supported visibility checks in nav items include:
|
|
|
|
- `requireOrg`
|
|
- `systemRole`
|
|
- `role`
|
|
- `permission`
|
|
- `businessRole`
|
|
|
|
This filtering is based on the current Auth.js session in the client.
|
|
|
|
Important: hiding a menu item does not grant or remove backend access. It only controls what the user sees in the UI.
|
|
|
|
## Role-Based Menu Behavior
|
|
|
|
Current practical behavior:
|
|
|
|
### Employee
|
|
|
|
Employee users can see employee-facing areas such as:
|
|
|
|
- Dashboard
|
|
- Training Records
|
|
- Announcements
|
|
- Notifications
|
|
|
|
Employee access is still server-scoped to their own allowed data.
|
|
|
|
### HRD
|
|
|
|
HRD users can access broader organization operations such as:
|
|
|
|
- Pending Review
|
|
- Employees
|
|
- Courses
|
|
- Training Policy
|
|
- Import Employees
|
|
- Reports
|
|
- Audit Logs
|
|
- Master Review
|
|
|
|
These pages also require server-side HRD validation, not only visible nav items.
|
|
|
|
### Super Admin
|
|
|
|
Super admin users can access system-level organizer management and can be elevated into organization context when required by server-side helpers.
|
|
|
|
## Direct URL Protection
|
|
|
|
The system explicitly protects direct navigation to pages even if a user manually enters a URL.
|
|
|
|
Examples:
|
|
|
|
- unauthenticated users are redirected at the proxy layer
|
|
- authenticated but unauthorized users are redirected by page guards
|
|
- API routes return `401` or `403` from server-side helpers when access is invalid
|
|
|
|
This prevents bypass through copied links or bookmarked URLs.
|
|
|
|
## API Protection
|
|
|
|
API protection follows these rules:
|
|
|
|
1. Authentication is required through Auth.js session
|
|
2. Organization membership is verified server-side
|
|
3. Role-specific actions require additional server checks
|
|
4. Data queries are scoped by organization and, when needed, by the current user
|
|
|
|
This is the main security boundary for all business data.
|
|
|
|
## File Download Protection
|
|
|
|
Protected files must not be served only by direct public URLs.
|
|
|
|
Current protected examples:
|
|
|
|
- training certificates:
|
|
- `/api/training-records/[id]/certificates/[certificateId]/download`
|
|
- announcement attachments:
|
|
- `/api/announcements/[id]/attachment`
|
|
|
|
These endpoints verify:
|
|
|
|
- authentication
|
|
- organization scope
|
|
- record-level access
|
|
- HRD/employee visibility rules
|
|
|
|
This prevents unauthorized users from opening files just because they know or guess the storage path.
|
|
|
|
## Recommended Maintenance Rules
|
|
|
|
When adding or changing protected features:
|
|
|
|
1. Add navigation visibility only after server-side access rules are defined
|
|
2. Use `requireOrganizationAccess()` for organization-scoped routes
|
|
3. Use `requireHRD()` for HRD-only operations
|
|
4. Use page guards for dashboard routes
|
|
5. Protect file downloads through route handlers when files are sensitive
|
|
6. Treat `use-nav.ts` as UX logic, not as a security mechanism
|
|
|
|
## What To Avoid
|
|
|
|
Do not reintroduce:
|
|
|
|
- Clerk-specific authorization assumptions
|
|
- client-side-only protection for sensitive features
|
|
- public file URLs for protected business documents
|
|
- page access that depends only on hidden sidebar items
|
|
|
|
## Summary
|
|
|
|
The current model is:
|
|
|
|
- Auth.js for authentication
|
|
- proxy-based route gating for unauthenticated requests
|
|
- server-side authorization helpers for real access control
|
|
- client-side nav filtering for usability
|
|
|
|
That combination keeps the UI predictable while ensuring that direct URLs, APIs, and file downloads are protected at the server boundary.
|