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:

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

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.