Build these pages in order. Each page depends on the previous one.
APIs to use (from API_PUBLIC.md):
| Action | Method | Endpoint | Purpose |
|---|---|---|---|
| Login | POST | /accounts/login/ |
Authenticate user, returns JWT cookies + {role, name, is_active} |
| Forgot Password | POST | /accounts/forgot-password/ |
Send OTP to email (always returns 200) |
| Verify OTP | POST | /accounts/verify-otp/ |
Verify 6-digit code, get reset_token |
| Reset Password | POST | /accounts/reset-password/ |
Set new password with OTP + reset_token |
Flow:
POST /accounts/login/{role, name} in React state, redirect to Teachers Page (if role=siteowner)Required: Login form, Forgot Password modal/flow.
APIs to use (from API_PUBLIC.md):
| Action | Method | Endpoint | Purpose |
|---|---|---|---|
| Register | POST | /accounts/student/register/ |
Create student account (pending approval) |
Required fields in form:
username (unique)password + password_confirmname_ar (Arabic name)name_en (English name)phone_number (Egyptian format: 010/011/012/015 + 8 digits)father_number, mother_number (parent phones)father_jobeducational_state → always "school" (hidden, hardcoded)school_type (select from dropdown)grade (select from dropdown)division (select from dropdown, filters by school_type + grade)school_name (text input)national_id (14 digits)birth_date (date picker)gender (male/female)gmail (unique across all users)facebook_link (optional)governorate (select from dropdown)area (select from dropdown, filters by governorate)Dropdown data: Fetch from Settings endpoints (see Page 6).
Business rules:
password_confirm must match passwordThis is the main landing page after login. Shows all teachers as cards.
APIs to use (from API_SITEOWNER.md):
| Action | Method | Endpoint | Purpose |
|---|---|---|---|
| List teachers | GET | /accounts/teachers/ |
Paginated list with search, filter |
| Create teacher | POST | /accounts/teachers/ |
Create new teacher account |
Teacher Card shows:
subject_detail.name)grades_detail[].name)Teacher List Filters:
?all=true for all)Teacher Create Form fields:
username, passwordname, phone, secondary_phone, gmailgender (male/female — required)subject (ID from subjects list)grades (array of grade IDs)is_active (checkbox, default true)biography, facebook (optional)Success response: Returns full teacher profile with ID. Use this to navigate to the new teacher's detail.
Clicking on a teacher card or the edit button from the Teachers Page.
APIs to use:
| Action | Method | Endpoint | Purpose |
|---|---|---|---|
| Get teacher | GET | /accounts/teachers/<id>/ |
Full teacher detail with subject/grades |
| Update teacher | PATCH | /accounts/teachers/<id>/ |
Update teacher fields |
| List assistants | GET | /accounts/teacher/assistants/?teacher=<id> |
View assistants for this teacher |
Teacher Detail sections:
Course Create Form (inline):
name (text — will be validated as unique per teacher+grade)grade (select from dropdown — teacher must teach this grade)description (textarea, optional)is_active (checkbox, default true)Note: Subject is auto-derived from teacher.subject — NOT sent in request.
Success: After creating a course, the page should show a success message and optionally navigate to the Teacher Courses Page.
List all courses for a specific teacher. Accessed via "View Courses" button on teacher card.
APIs to use:
| Action | Method | Endpoint | Purpose |
|---|---|---|---|
| List courses | GET | /courses/?teacher=<id> |
Paginated list of courses for this teacher |
| Get course | GET | /courses/<id>/ |
Full course detail |
| Update course | PATCH | /courses/<id>/ |
Update course name/description/active |
| Delete course | DELETE | /courses/<id>/ |
Delete empty course (no enrollments/topics/lectures) |
Course Card shows:
topic_count in response)total_lectures in response)Course Edit Form:
name, description, is_activeteacher, grade (these are locked after creation)Course Delete rules:
Manage all student registrations. Approve/decline pending students.
APIs to use:
| Action | Method | Endpoint | Purpose |
|---|---|---|---|
| List students | GET | /accounts/students/ |
Paginated list with search, sort, filters |
| Get student | GET | /accounts/students/<id>/ |
Full student detail |
| Change status | PATCH | /accounts/students/<id>/status/ |
Update status + is_active |
Student List Filters:
status (verified/pending/declined/suspended)grade, school_typeStudent Table columns:
Student Detail view:
PATCH {status: "verified", is_active: true}PATCH {status: "declined", is_active: false}PATCH {status: "suspended_temporary", is_active: false}PATCH {status: "suspended_permanent", is_active: false}Default view: Show pending students first (sort by most recent).
Display all reference data for preview. No CRUD operations.
APIs to use (from API_PUBLIC.md):
| Action | Endpoint | Purpose |
|---|---|---|
| List grades | GET | /accounts/grades/ |
| List school types | GET | /accounts/school-types/ |
| List divisions | GET | /accounts/divisions/ |
| List subjects | GET | /accounts/subjects/ |
| List governorates | GET | /accounts/governorates/ |
| List areas | GET | /accounts/areas/ |
| List video security | GET | /accounts/video-security/ |
| List chapters | GET | /curriculum/chapters/ |
| List lessons | GET | /curriculum/lessons/ |
Note: All these endpoints support ?all=true to bypass pagination and get complete lists for dropdowns.
No static files are served by the backend. The frontend should handle all assets (images, icons, logos) on its own.
1. POST /accounts/login/ with {username, password}
2. Server sets httpOnly cookies: access_token (30min), refresh_token (7d)
3. Server returns JSON: {role: "siteowner", name: "Admin", is_active: true}
4. Frontend stores {role, name} in React context/state
5. All subsequent requests automatically send cookies (browser handles this)
6. When access_token expires → POST /accounts/token/refresh/ (reads refresh cookie)
7. POST /accounts/logout/ to clear cookies
Note: Since cookies are httpOnly, the frontend CANNOT read the JWT. Session restoration works via GET /accounts/me/ which reads the cookie and returns {role, name, is_active}.
All API errors follow this pattern:
{"error": "Human-readable error message"}
HTTP Status codes:
200 — Success201 — Created400 — Bad request (validation error)401 — Not authenticated or invalid credentials403 — Not authorized (wrong role)404 — Not found500 — Server error