Quran_Tech_Server / docs /architecture.md
aboalaa147's picture
Initial deployment
eb6a2f9
|
Raw
History Blame Contribute Delete
38.8 kB
# Quran App β€” Full System Architecture
---
## 1. System Overview
Quran App is a full-stack web platform that connects students with certified Quran teachers (Sheikhs) for live online recitation sessions. It also provides AI-powered solo practice where students record their recitation and receive automated evaluation.
The system has three user roles:
- **Student** β€” finds a sheikh, books sessions, practices solo, tracks progress
- **Sheikh** β€” manages availability, accepts session requests, conducts live sessions, reviews students
- **Admin** β€” approves sheikh applications, manages users, monitors the platform
### High-Level System Diagram
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Browser (Client) β”‚
β”‚ β”‚
β”‚ React 19 + TypeScript + Vite β”‚
β”‚ Tailwind CSS + Radix UI (shadcn) β”‚
β”‚ React Router v7 Β· i18next (AR/EN) Β· Stripe.js β”‚
β”‚ STOMP/SockJS Client Β· WebRTC (RTCPeerConnection) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ HTTPS REST + WebSocket (WS)
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Spring Boot 4 Backend β”‚
β”‚ (Java 21) β”‚
β”‚ β”‚
β”‚ REST API (port 8080) β”‚
β”‚ Spring Security + JWT + Google OAuth2 β”‚
β”‚ Spring Data JPA Β· WebSocket (STOMP broker) β”‚
β”‚ JavaMail Β· Stripe SDK Β· JAVE2 (audio) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PostgreSQL DB β”‚ β”‚ External Services β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ Users, Sessions, β”‚ β”‚ ● AI Service (ngrok) β€” recitation eval β”‚
β”‚ Payments, β”‚ β”‚ ● Stripe β€” payments & payouts β”‚
β”‚ Recitations, β”‚ β”‚ ● Google OAuth2 β€” social login β”‚
β”‚ Reviews, β”‚ β”‚ ● Gmail SMTP β€” email / OTP β”‚
β”‚ Availability, β”‚ β”‚ β”‚
β”‚ Streaks β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
## 2. Technology Stack
### Frontend
| Concern | Technology |
|---|---|
| Framework | React 19 + TypeScript |
| Build tool | Vite 7 |
| Styling | Tailwind CSS + Radix UI (shadcn components) |
| Routing | React Router v7 |
| Internationalization | i18next + react-i18next (Arabic / English) |
| Real-time | STOMP/SockJS (@stomp/stompjs + sockjs-client) |
| Video calls | WebRTC (RTCPeerConnection, browser native) |
| Payments | @stripe/react-stripe-js + @stripe/stripe-js |
| Notifications | Sonner + react-hot-toast |
| Icons | Lucide React |
| Date picker | react-day-picker |
### Backend
| Concern | Technology |
|---|---|
| Framework | Spring Boot 4.0 (Java 21) |
| Security | Spring Security + JWT (jjwt 0.12.5) + OAuth2 Client |
| Database ORM | Spring Data JPA + Hibernate |
| Database | PostgreSQL |
| WebSocket | Spring WebSocket + STOMP (in-memory broker) |
| Email | Spring Mail (Gmail SMTP, STARTTLS) |
| Payments | Stripe Java SDK 25.3 |
| Audio processing | JAVE2 3.5 (ffmpeg wrapper for Linux) |
| Google Auth | Google API Client 2.6 |
| Monitoring | Spring Boot Actuator |
| Boilerplate | Lombok |
---
## 3. User Roles & Capabilities
### Student
- Register/login (email or Google)
- Complete profile (Quran level, language preference, accent)
- Browse and search Sheikhs by rating, price, availability
- Book 1-hour sessions with a Sheikh
- Pay for sessions via Stripe (credit card)
- Join live video sessions (WebRTC)
- Record solo recitations and get AI-powered evaluation
- View evaluation reports (word accuracy, tashkeel, mistakes)
- Track daily streak and practice statistics
- Write reviews after completed sessions
### Sheikh
- Register/login (email or Google)
- Complete profile (bio, specialization, years of experience, hourly rate)
- Submit to admin approval process (including interview scheduling)
- Set weekly availability (recurring time slots per day)
- Receive and manage session requests (accept / reject)
- Conduct live video sessions
- Write session notes for students
- Receive payouts via Stripe Connect after session completion
- View their students and session history
### Admin
- Approve or reject sheikh applications
- Schedule interview sessions with pending sheikhs
- Conduct video interview sessions
- Manage all users (activate / deactivate accounts)
- View full user profiles and session history
- Access admin dashboard with platform statistics
---
## 4. Frontend Architecture
### Application Entry Point
The app boots from `main.tsx` β†’ `App.tsx`. The provider stack wraps the entire app:
```
BrowserRouter
└── LanguageProvider (i18next context)
└── AuthProvider (user state, JWT management)
└── StudentProvider (student-specific data)
└── Routes
```
### Route Structure
Routes are split into three groups:
**Public (no auth required)**
```
/ Landing page
/signin Email login
/register Registration
/forgot-password OTP request
/verify-otp OTP verification
/reset-password New password
/auth/google Google OAuth callback
/complete-profile Role selection after register
/complete-profile/student Student profile wizard
/complete-profile/sheikh Sheikh profile wizard
/sheikh/interview Interview scheduling (pending sheikh)
```
**Protected β€” Student**
```
/student/dashboard Dashboard with stats, streak, recent activity
/student/practice AI-powered recitation practice
/student/find-sheikh Sheikh search/browse
/student/sheikh/:id Sheikh profile + booking
/student/sessions Session list
/student/evaluations/:id AI evaluation reports
/waiting-room/:id Pre-session waiting room
/session/:sessionId Live video session
/session-report/:id Post-session report + review
/session-waiting/:id Post-session waiting (before report)
```
**Protected β€” Sheikh**
```
/sheikh/dashboard Dashboard with stats, pending requests
/sheikh/sessions Session management
/sheikh/students Student list
```
**Protected β€” Admin**
```
/admin/dashboard Platform statistics
/admin/sheikh-approval Sheikh approval queue
/admin/users All users management
/admin/user/:userId User detail view
/admin/interview/:id Live interview session
```
**Common**
```
/profile Edit own profile
```
### Route Guard Logic
`ProtectedRoute` checks three conditions in order:
1. Loading state β†’ show spinner
2. No user β†’ redirect to `/signin`
3. Profile not completed β†’ redirect to `/complete-profile` (except admin, who skips this)
### State Management
No Redux. State lives in three React contexts:
| Context | Responsibility |
|---|---|
| `AuthContext` | User identity, JWT token, login/logout/register, session restore on load |
| `LanguageContext` | Current language (AR/EN), direction (RTL/LTR) |
| `StudentContext` | Student-specific data (streak, stats, etc.) |
Auth token is stored in `localStorage` under key `authToken`. User data is stored under `currentUser`. On app load, `AuthContext` re-validates the token by calling `GET /api/auth/verify-profile`.
### Frontend Module Map
```
src/
β”œβ”€β”€ App.tsx Route definitions + providers
β”œβ”€β”€ main.tsx App entry + Google OAuth provider
β”œβ”€β”€ components/
β”‚ β”œβ”€β”€ auth/ Login, Register, OTP, Profile wizards
β”‚ β”œβ”€β”€ dashboards/ StudentDashboard, SheikhDashboard, AdminDashboard
β”‚ β”œβ”€β”€ sessions/ LiveSession, WaitingRoom, MySessions, SessionReport
β”‚ β”œβ”€β”€ sheikh/ FindSheikh, SheikhProfile, MyStudents, UpdatePricing
β”‚ β”œβ”€β”€ practice/ RecordingPractice, EvaluationReports
β”‚ β”œβ”€β”€ profile/ ProfilePage
β”‚ β”œβ”€β”€ admin/ SheikhApproval, UserManagement, InterviewSession
β”‚ β”œβ”€β”€ ui/ Reusable shadcn/Radix UI components (50+ components)
β”‚ β”œβ”€β”€ Navbar.tsx Top navigation bar
β”‚ └── RoleSwitcher.tsx Dev tool for switching roles
β”œβ”€β”€ hooks/
β”‚ └── useWebRTC.ts WebRTC + STOMP signaling hook
β”œβ”€β”€ lib/
β”‚ β”œβ”€β”€ authContext.tsx Auth state and API calls
β”‚ β”œβ”€β”€ languageContext.tsx i18n context
β”‚ β”œβ”€β”€ StudentContext.tsx Student data context
β”‚ └── api/ All REST API modules (one file per domain)
β”‚ β”œβ”€β”€ aiApi.ts AI analysis service calls
β”‚ β”œβ”€β”€ bookingApi.ts Availability, booking, sessions
β”‚ β”œβ”€β”€ paymentApi.ts Stripe payment flow
β”‚ β”œβ”€β”€ studentApi.ts Student data
β”‚ β”œβ”€β”€ sheikhApi.ts Sheikh data
β”‚ β”œβ”€β”€ adminApi.ts Admin operations
β”‚ └── ...
β”œβ”€β”€ types/
β”‚ β”œβ”€β”€ index.ts Domain types (User, Session, Payment, etc.)
β”‚ └── api.ts API helper types (PaginatedResponse, AppError, etc.)
└── styles/
└── globals.css
```
---
## 5. Backend Architecture
### Package Structure
The backend is organized by domain slice, not by layer. Each domain has its own controller, service, repository, DTO, and mapper.
```
com.yourcompany.quranapp.quran_app_backend/
β”œβ”€β”€ config/
β”‚ β”œβ”€β”€ SecurityConfig.java CORS, JWT filter chain, role rules
β”‚ └── GlobalExceptionHandler.java Centralized error responses
β”œβ”€β”€ security/
β”‚ β”œβ”€β”€ JwtAuthenticationFilter.java Validates Bearer token on every request
β”‚ β”œβ”€β”€ CustomUserDetails.java Wraps User entity, exposes userId + role
β”‚ └── UserDetailsServiceImpl.java Loads user by email from DB
β”œβ”€β”€ entity/ JPA entities (data model)
β”œβ”€β”€ dashboard/
β”‚ β”œβ”€β”€ common/ Auth (login, register, OTP, Google OAuth)
β”‚ β”œβ”€β”€ student/ Student APIs (sessions, recitations, profile)
β”‚ β”œβ”€β”€ sheikh/ Sheikh APIs (sessions, availability, notes)
β”‚ └── admin/ Admin APIs (approvals, user management)
β”œβ”€β”€ payment/ Stripe payment controller + service
β”œβ”€β”€ websocket/ WebSocket config + signaling controller
β”œβ”€β”€ google/ Google token verification
└── setup/
└── DataLoader.java Seed data on startup
```
### Security Configuration
Spring Security is configured as stateless (no HTTP session). Every request goes through:
```
HTTP Request
β†’ JwtAuthenticationFilter
β†’ Extract Bearer token from Authorization header
β†’ Validate token via JwtService
β†’ Load user from DB
β†’ Set SecurityContext
β†’ SecurityFilterChain
β†’ Check role-based access rules
β†’ Controller
```
**Endpoint access rules:**
| Path pattern | Access |
|---|---|
| `/api/auth/**` | Public |
| `/api/public/**` | Public |
| `/ws/**` | Public (WebSocket needs its own auth) |
| `/api/admin/**` | ADMIN only |
| `/api/sheikhs/**` | STUDENT only (browse sheikhs) |
| `/api/sheikh/**` | SHEIKH, ADMIN, STUDENT |
| `/api/student/**` | STUDENT, SHEIKH, ADMIN |
| `/api/reviews/**` | STUDENT, SHEIKH, ADMIN |
| `/api/payments/**` | STUDENT, SHEIKH, ADMIN |
| Everything else | Any authenticated user |
### Domain Controllers
#### Common β€” `/api/auth/**`
| Endpoint | Description |
|---|---|
| `POST /register/student` | Register new student |
| `POST /register/sheikh` | Register new sheikh |
| `POST /login` | Email/password login β†’ returns JWT |
| `POST /google` | Google ID token login/register |
| `POST /forgot-password` | Send OTP email |
| `POST /verify-otp` | Validate OTP |
| `POST /reset-password` | Set new password with OTP |
| `POST /logout` | Invalidate session (stateless β€” client discards token) |
| `GET /verify-profile` | Check profile completion status |
| `POST /complete-google-profile` | Complete profile for Google-registered student |
| `POST /complete-google-profile/sheikh` | Complete profile for Google-registered sheikh |
#### Student β€” `/api/student/**`
| Endpoint | Description |
|---|---|
| `GET /sessions` | Get all student sessions (filterable by status) |
| `GET /sessions/{id}` | Get single session |
| `POST /sessions` | Book a session with a sheikh |
| `POST /sessions/{id}/join` | Record student join timestamp |
| `POST /sessions/{id}/leave` | Record student leave timestamp |
| `GET /recitations` | Get all recitations |
| `GET /recitations/recent` | Get top 5 recent recitations |
| `GET /recitations/stats` | Get recitation statistics |
| `POST /recitations` | Upload audio + surah number β†’ AI eval + save |
| `GET /recitations/{id}` | Get single recitation detail |
| `GET /profile/complete` | (also via auth) Complete student profile |
#### Sheikh β€” `/api/sheikh/**`
| Endpoint | Description |
|---|---|
| `GET /sessions` | Get sheikh sessions (filterable by status) |
| `GET /sessions/{id}` | Get single session |
| `POST /sessions/{id}/accept` | Accept session β†’ status = TOPAY |
| `POST /sessions/{id}/reject` | Reject/cancel session |
| `POST /sessions/{id}/start` | Start session β†’ status = ON_GOING |
| `POST /sessions/{id}/end` | End session + save notes β†’ status = COMPLETED |
| `POST /sessions/{id}/join` | Record sheikh join timestamp |
| `POST /sessions/{id}/leave` | Record sheikh leave timestamp |
| `POST /sessions/{id}/notes` | Update session notes |
| `GET /availability` | Get sheikh's weekly availability slots |
| `PUT /availability` | Set sheikh's weekly availability slots |
| `GET /students` | Get sheikh's student list |
| `GET /dashboard` | Dashboard statistics |
#### Student browsing Sheikhs β€” `/api/sheikhs/**`
| Endpoint | Description |
|---|---|
| `GET /` | Browse sheikhs (filters: country, price, rating, language) |
| `GET /{id}` | Get sheikh public profile |
| `GET /{id}/available-dates` | Get available dates in next N days |
| `GET /{id}/available-slots/day` | Get time slots for a specific date |
| `GET /{id}/available-slots` | Get all slots in a date range |
| `GET /{id}/Top-Reviews` | Get top reviews for a sheikh |
#### Admin β€” `/api/admin/**`
| Endpoint | Description |
|---|---|
| `GET /dashboard` | Platform-wide statistics |
| `GET /sheikh-approvals` | Pending sheikh applications |
| `POST /sheikh-approvals/{id}/approve` | Approve sheikh |
| `POST /sheikh-approvals/{id}/reject` | Reject sheikh with reason |
| `POST /sheikh-approvals/{id}/schedule-interview` | Schedule interview session |
| `GET /users` | All users with filters |
| `GET /users/{id}` | Full user profile |
| `POST /users/{id}/deactivate` | Deactivate user account |
#### Reviews β€” `/api/reviews/**`
| Endpoint | Description |
|---|---|
| `POST /session/{id}` | Student submits review after session |
| `GET /student/session/{id}/details` | Student view of session + review |
| `GET /sheikh/session/{id}/details` | Sheikh view of session + review |
#### Payments β€” `/api/payments/**`
| Endpoint | Description |
|---|---|
| `POST /initiate/card` | Create Stripe PaymentIntent, return clientSecret |
| `POST /confirm-payment/{intentId}` | Confirm payment with backend after Stripe.js success |
| `POST /confirm-session/{sessionId}` | Verify payment is PAID when sheikh accepts |
| `POST /payout/{sessionId}` | Transfer funds to sheikh via Stripe Connect |
| `POST /refund/{sessionId}` | Refund student via Stripe Refunds API |
| `POST /connect/sheikh/{sheikhId}` | Create Stripe Connect account for sheikh |
#### WebSocket β€” `/ws`
| Destination | Description |
|---|---|
| `/app/signal` | Send WebRTC/chat signaling message |
| `/topic/session/{id}` | Subscribe to receive signals for a session |
---
## 6. Data Model
### Entity Relationship Summary
```
User (1) ─────────── (0..1) StudentProfile
User (1) ─────────── (0..1) SheikhProfile
User (1) ─────────── (0..1) Streak
User (1) ─────────── (n) Availability [sheikh side]
User (1) ─────────── (n) Session [as student]
User (1) ─────────── (n) Session [as sheikh]
User (1) ─────────── (n) Recitation [as student]
User (1) ─────────── (n) Payment [as student]
User (1) ─────────── (n) Payment [as sheikh]
User (1) ─────────── (n) Review [as student]
Session (1) ─────── (0..1) Payment
Session (1) ─────── (0..1) Review
```
### Entity Details
#### User
```
id BIGINT PK
email VARCHAR UNIQUE
passwordHash VARCHAR
fullName VARCHAR
phone VARCHAR
gender VARCHAR
country VARCHAR
birthDateTime TIMESTAMP
role ENUM(STUDENT, SHEIKH, ADMIN)
status ENUM(ALIVE, DEAD) [soft delete]
isActive BOOLEAN
authProvider VARCHAR [LOCAL or GOOGLE]
resetPasswordOtp VARCHAR
resetPasswordOtpExpiresAt TIMESTAMP
createdAt TIMESTAMP
Indexes: role, phone, country, is_active, created_at
```
#### StudentProfile
```
id (= user_id) BIGINT PK FK β†’ users.id
quranLevel VARCHAR [beginner / intermediate / advanced]
preferredLanguage VARCHAR
preferredAccent VARCHAR
profilePhotoUrl VARCHAR
```
#### SheikhProfile
```
id (= user_id) BIGINT PK FK β†’ users.id
bio TEXT
specialization VARCHAR
yearsOfExperience INT
hourlyRate DECIMAL(10,2)
ratingAvg DOUBLE
ratingCount INT
certificateUrl VARCHAR
profilePhotoUrl VARCHAR
status ENUM(PENDING, APPROVED, REJECTED, INTERVIEW_SCHEDULED)
rejectionReason VARCHAR
stripeAccountId VARCHAR [Stripe Connect account ID]
interviewDateTime TIMESTAMP
messageToPendingSheikh VARCHAR
Indexes: status, rating_avg, hourly_rate, status+rating_avg
```
#### Session
```
id BIGINT PK
scheduledStart TIMESTAMP
scheduledEnd TIMESTAMP
actualStart TIMESTAMP
actualEnd TIMESTAMP
studentJoinedAt TIMESTAMP
sheikhJoinedAt TIMESTAMP
studentLeftAt TIMESTAMP
sheikhLeftAt TIMESTAMP
status ENUM(REQUESTED, TOPAY, ON_GOING, COMPLETED, CANCELLED, MISSED)
price DECIMAL(10,2)
sessionDescription VARCHAR(255)
sessionNotes TEXT
student_id FK β†’ users.id
sheikh_id FK β†’ users.id
createdAt TIMESTAMP
updatedAt TIMESTAMP
Indexes: student_id, sheikh_id, status, scheduled_start,
sheikh+status+start, student+status, sheikh+student
```
#### Payment
```
id BIGINT PK
amount DECIMAL(10,2)
currency VARCHAR(10) [Always "EGP" currently, Stripe handles conversion]
paymentMethod ENUM(CREDIT_CARD, VODAFONE_CASH)
paymentStatus ENUM(PENDING, PAID, REFUNDED, FAILED)
transactionId VARCHAR UNIQUE [Stripe PaymentIntent ID]
orderId VARCHAR UNIQUE [Stripe Order ID]
transferId VARCHAR UNIQUE [Stripe Transfer/Refund ID]
platformCommission DECIMAL(10,2) [15% of amount]
sheikhPayout DECIMAL(10,2) [85% of amount]
student_id FK β†’ users.id
sheikh_id FK β†’ users.id
session_id FK β†’ sessions.id UNIQUE
paymentDate TIMESTAMP
capturedAt TIMESTAMP
transferredAt TIMESTAMP
refundedAt TIMESTAMP
Indexes: student_id, sheikh_id, payment_status
```
#### Recitation
```
id BIGINT PK
surahName VARCHAR(25)
ayahStart INT
ayahEnd INT
wordScore DECIMAL(4,2)
tashkeelScore DECIMAL(4,2)
totalScore DECIMAL(4,2) [tajweed score from AI]
durationInMinutes DECIMAL(5,2)
mistakesReportJson JSONB [full AI response stored as JSON]
student_id FK β†’ users.id
createdAt TIMESTAMP
Index: student_id
```
#### Review
```
id BIGINT PK
comment TEXT
rate INT (1-5)
session_id FK β†’ sessions.id UNIQUE
student_id FK β†’ users.id
createdAt TIMESTAMP
Index: student_id
```
#### Availability
```
id BIGINT PK
dayOfWeek ENUM(MONDAY..SUNDAY)
startTime TIME
endTime TIME
sheikh_id FK β†’ users.id
Indexes: sheikh_id, day_of_week
```
#### Streak
```
id (= user_id) BIGINT PK FK β†’ users.id
currentStreak INT
longestStreak INT
lastActivityDate DATE
```
---
## 7. Authentication & Authorization Flow
### Email/Password Registration
```
Frontend Backend
───────── ───────
POST /api/auth/register/student
{ fullName, email, password,
phone, gender, country,
birthDate }
───► Validate fields
Hash password (BCrypt)
Save User (role=STUDENT)
Generate JWT
◄─── { token, user }
POST /api/auth/verify-profile
Authorization: Bearer <token>
───► Decode token β†’ userId
Check StudentProfile exists
◄─── { profileCompleted, profileStatus }
β†’ if profileCompleted = false β†’ redirect to /complete-profile/student
POST /api/student/profile/complete
{ quranLevel, language, accent }
───► Save StudentProfile
◄─── 200 OK
β†’ redirect to /student/dashboard
```
### Google OAuth Flow
```
Frontend Backend Google
───────── ─────── ──────
User clicks "Sign in with Google"
β†’ Google Identity Services
returns idToken
◄──────► Verify idToken
POST /api/auth/google
{ idToken, role: "STUDENT" }
───► Verify idToken with
Google API Client
Find/create User
Generate JWT
◄─── { token, user }
(same profile completion flow as above)
```
### JWT Token Lifecycle
- Token expiry: 24 hours (86400000 ms, configurable via `app.jwt.expiration-ms`)
- Token storage: `localStorage` key `authToken`
- Token format: Standard JWT signed with HMAC-SHA key (`app.jwt.secret-key`)
- Every protected API request sends: `Authorization: Bearer <token>`
- `JwtAuthenticationFilter` validates token on every request before it reaches the controller
- On app load, `AuthContext` restores session by re-calling `GET /api/auth/verify-profile`
### Password Reset (OTP flow)
```
POST /api/auth/forgot-password { email }
β†’ Generate 6-digit OTP
β†’ Store OTP + expiry in users table
β†’ Send OTP via Gmail SMTP
POST /api/auth/verify-otp { email, otp }
β†’ Validate OTP matches + not expired
β†’ Return success
POST /api/auth/reset-password { email, otp, newPassword }
β†’ Re-validate OTP
β†’ BCrypt hash new password
β†’ Clear OTP fields
```
---
## 8. Session Lifecycle
### Complete Flow: Booking to Completion
```
1. REQUESTED
Student books a session β†’ POST /api/student/sessions
Session created with status = REQUESTED
2. TOPAY (payment pending)
Sheikh accepts β†’ POST /api/sheikh/sessions/{id}/accept
Status changes to TOPAY
3. Payment
Student sees payment prompt
Frontend creates PaymentIntent β†’ POST /api/payments/initiate/card
Backend returns { clientSecret, publishableKey }
Stripe.js handles card entry on frontend
On Stripe success β†’ POST /api/payments/confirm-payment/{intentId}
Status changes to SCHEDULED (payment confirmed)
4. ON_GOING
At session time, both parties join waiting room
Sheikh starts β†’ POST /api/sheikh/sessions/{id}/start
Status = ON_GOING
Both parties join live WebRTC session
5. COMPLETED
Sheikh ends session + adds notes β†’ POST /api/sheikh/sessions/{id}/end
Status = COMPLETED
Payout triggered β†’ POST /api/payments/payout/{sessionId}
Platform keeps 15%, sheikh receives 85% via Stripe Connect
6. Review
Student writes review β†’ POST /api/reviews/session/{id}
Sheikh rating updated (rolling average)
Exception paths:
β†’ Sheikh rejects β†’ CANCELLED
β†’ Session time passes without start β†’ MISSED β†’ student refunded
```
### Session Statuses
```
REQUESTED β†’ TOPAY β†’ (SCHEDULED) β†’ ON_GOING β†’ COMPLETED
└──► CANCELLED (sheikh rejects)
└──────────────► MISSED (no-show, auto-refund)
```
---
## 9. Real-Time Communication (WebRTC + WebSocket)
### Architecture
The backend acts as a **signaling server** only. It does not relay audio/video. Actual media flows peer-to-peer between browser clients via WebRTC.
```
Student Browser Backend (Signaling) Sheikh Browser
─────────────── ───────────────── ──────────────
Connect SockJS /ws ──────► STOMP broker Connect SockJS /ws
Subscribe /topic/ /topic/session/{id} Subscribe /topic/
session/{id} session/{id}
Send join signal ──────► Broadcast to topic ────────► Receives join
/topic/session/{id}
Creates RTCPeerConnection Creates RTCPeerConnection
Creates Offer ──────► Broadcast ────────► Receives Offer
Creates Answer
Receives Answer ◄────── Broadcast ◄──────── Sends Answer
ICE exchange ◄──────► Broadcast ◄────────► ICE exchange
Direct P2P stream ════════════════════════════════════════► Direct P2P stream
(audio + video, no server relay)
```
### Signaling Message Types
| Type | Direction | Purpose |
|---|---|---|
| `join` | Any β†’ Topic | Notify that a user entered the session room |
| `offer` | Caller β†’ Topic | WebRTC SDP offer |
| `answer` | Callee β†’ Topic | WebRTC SDP answer |
| `ice-candidate` | Any β†’ Topic | ICE connectivity candidates |
| `chat` | Any β†’ Topic | In-session text chat message |
### ICE Servers (STUN)
The frontend uses Google's public STUN servers for NAT traversal:
- `stun:stun.l.google.com:19302`
- `stun:stun1.l.google.com:19302`
- `stun:stun2.l.google.com:19302`
No TURN server is currently configured. This means sessions behind symmetric NAT may fail to connect.
### WebSocket Config (Backend)
- Endpoint: `/ws` with SockJS fallback
- Application destination prefix: `/app` (send to controller)
- Broker topics: `/topic` (broadcast), `/queue` (point-to-point)
- User destination prefix: `/user`
---
## 10. Payment Flow (Stripe)
### Architecture
The system uses **Stripe Payment Intents** for collecting student payments and **Stripe Connect** (Express accounts) for paying out sheikhs.
### Student Payment Flow
```
Frontend Backend Stripe
───────── ─────── ──────
POST /api/payments/initiate/card
{ sessionId, studentId,
sheikhId, amount }
───► Create PaymentIntent
(amount in smallest unit)
◄──── { clientSecret,
publishableKey,
paymentIntentId }
Stripe.js loads card form
User enters card details
stripe.confirmCardPayment(clientSecret)
──────► Charge card
◄────── Payment confirmed
POST /api/payments/confirm-payment/{intentId}
───► Retrieve PaymentIntent from Stripe
Verify status = succeeded
Save Payment record (PAID)
Update Session status β†’ SCHEDULED
◄──── { success: true }
```
### Sheikh Payout Flow (after session completion)
```
Backend Stripe
─────── ──────
POST /api/payments/payout/{sessionId}
Verify session is COMPLETED
Calculate: sheikhPayout = amount Γ— 0.85
commission = amount Γ— 0.15
Create Stripe Transfer to sheikh's
connected account (stripeAccountId) ──────► Transfer funds
Update Payment: transferredAt, transferId ◄────── Transfer confirmed
```
### Refund Flow (missed/cancelled sessions)
```
Backend Stripe
─────── ──────
POST /api/payments/refund/{sessionId}
Verify payment is PAID
Create Stripe Refund for full amount ──────► Refund issued
Update Payment: refundedAt, paymentStatus=REFUNDED
```
### Platform Commission
Commission percentage is configurable: `platform.commission.percentage = 15`
---
## 11. AI Recitation Evaluation Flow
### Flow
```
Frontend Backend AI Service
───────── ─────── ──────────
User records audio in browser
(MediaRecorder API)
POST /api/student/recitations
multipart/form-data
{ surahNumber, audio file }
───► Receive audio file
Convert to WAV (JAVE2)
Forward to AI service:
POST {AI_BASE_URL}/analyze
{ audio, surah_number }
──────► Speech recognition
Text alignment with
Quran reference
Error detection:
- Extra words
- Missed words
- Tashkeel errors
◄────── { surah_info,
overall_stats,
ayahs[] }
Parse AI response
Calculate scores:
- wordScore
- tashkeelScore
- totalScore
Store Recitation
(mistakesReportJson as JSONB)
◄──── RecitationDetailsDto
Display scores + mistake report
```
### AI Response Structure
The AI service returns per-ayah analysis:
- `words_stage`: extra words and missed words per ayah
- `tashkeel_stage`: per-word tashkeel comparison with reasons
- `overall_stats`: word accuracy % and tashkeel accuracy %
Scores are stored as JSONB in `mistakesReportJson` for full replay capability on the frontend.
### Direct AI Call (frontend also calls AI directly)
The frontend `aiApi.ts` can also call the AI service directly (bypassing the backend) for immediate feedback before saving. This is used in the `RecordingPractice` component.
---
## 12. Sheikh Approval Flow
### Steps
```
1. Register
Sheikh registers β†’ role = SHEIKH
Status = PENDING (no SheikhProfile yet)
2. Complete Profile
POST /api/sheikh/profile/complete
{ bio, specialization, yearsOfExperience,
hourlyRate, certificate }
SheikhProfile created β†’ status = PENDING
3. Admin Review
Admin sees sheikh in approval queue
GET /api/admin/sheikh-approvals
4. Interview Scheduling
Admin schedules interview:
POST /api/admin/sheikh-approvals/{id}/schedule-interview
{ dateTime, message }
Status β†’ INTERVIEW_SCHEDULED
Sheikh notified (email or in-app)
5. Interview Session
Admin and sheikh join live video call
(same WebRTC infrastructure as student sessions)
Route: /admin/interview/:sheikhId
Route: /sheikh/interview-session/:sheikhId
6. Decision
Approve: status β†’ APPROVED, sheikh can accept students
Reject: status β†’ REJECTED, rejectionReason saved
7. Post-Approval
Sheikh sets hourly rate: PUT /api/sheikh/update-pricing
Sheikh sets availability: PUT /api/sheikh/availability
Sheikh appears in student search: GET /api/sheikhs/
```
---
## 13. Internationalization (i18n)
The frontend supports Arabic and English using i18next.
- Language detection: browser preference (`i18next-browser-languagedetector`)
- Translations: `src/lib/translations.ts`
- Language context: `src/lib/languageContext.tsx`
- Direction: Automatically switches between LTR (English) and RTL (Arabic)
- Language switcher: `src/components/LanguageSwitcher.tsx`
---
## 14. Database Optimization
### JDBC Batching (Hibernate)
Enabled globally for bulk insert/update performance:
```yaml
hibernate:
jdbc:
batch_size: 20
order_inserts: true
order_updates: true
```
### Indexes
Key composite and single-column indexes defined at entity level:
| Table | Indexes |
|---|---|
| users | role, phone, country, is_active, created_at |
| sessions | student_id, sheikh_id, status, scheduled_start, sheikh+status+start, student+status, sheikh+student |
| sheikh_profile | status, rating_avg, hourly_rate, status+rating_avg |
| payment | student_id, sheikh_id, payment_status |
| recitations | student_id |
| review | student_id |
| availability | sheikh_id, day_of_week |
---
## 15. Configuration & Environment
### Backend Environment Variables
| Variable | Purpose |
|---|---|
| `DB_URL` | PostgreSQL JDBC URL |
| `PGUSER` | Database username |
| `PGPASSWORD` | Database password |
| `JWT_SECRET` | JWT HMAC signing key |
| `MAIL_USERNAME` | Gmail address for OTP emails |
| `MAIL_PASSWORD` | Gmail app password |
| `STRIPE_SECRET_KEY` | Stripe secret key |
| `STRIPE_PUBLISHABLE_KEY` | Stripe publishable key |
| `GOOGLE_CLIENT_ID` | Google OAuth client ID |
### Frontend Environment Variables
| Variable | Purpose |
|---|---|
| `VITE_API_BASE_URL` | Backend base URL (defaults to `http://localhost:8080`) |
### AI Service
External Python service exposed via ngrok:
- Base URL: configured in `app.ai.base-url`
- Connect timeout: 5s
- Read timeout: 600s (10 min, for long audio files)
- Endpoint: `POST /analyze` with `{ audio, surah_number }`
---
## 16. Cross-Cutting Concerns
### Error Handling
- Backend: `GlobalExceptionHandler` catches all exceptions and returns consistent JSON error responses
- Frontend: `AppError` class standardizes error handling across all API modules with `status` + `path` context
- Frontend: `ErrorBoundary` component wraps dashboards to prevent full-page crashes
### CORS
Backend allows requests from `http://localhost:*` with credentials. For production this needs to be restricted to the actual frontend domain.
### Monitoring
Spring Boot Actuator is enabled with all endpoints exposed (`management.endpoints.web.exposure.include: "*"`). For production this should be restricted to health + metrics only.
### Logging
```yaml
org.hibernate.SQL: DEBUG # All SQL statements
org.hibernate.stat: DEBUG # Query counts per session
```
Hibernate statistics are enabled (`generate_statistics: true`) for N+1 query detection during development.
### Schema Management
JPA `ddl-auto: update` β€” Hibernate auto-updates the schema on startup. This is acceptable for development but should be replaced with Flyway or Liquibase for production.
### Audio Processing
JAVE2 wraps ffmpeg. The Linux 64-bit native binary is included as a Maven dependency (`jave-nativebin-linux64`). Audio files uploaded by students are converted to WAV before being sent to the AI service.