Spaces:
Sleeping
Furqan β Full System & Component Architecture Blueprint
This document provides a comprehensive blueprint of the system and component-level architecture for Furqan, an interactive Quran learning and reciting platform. It details the multi-tier topology, component definitions, communication channels, state management, database schema, and core design patterns.
1. System Topology & Multi-Tier Architecture
Furqan is built on a modern multi-tier architecture designed for scalability, low-latency real-time video streaming, and automated AI processing.
graph TB
subgraph ClientTier["Client Tier (Browser SPA)"]
ReactSPA["React 19 SPA (Vite + TS)"]
WebRTCClient["Browser WebRTC (RTCPeerConnection)"]
SockJSClient["SockJS + STOMP Client"]
StripeJS["Stripe.js Element SDK"]
end
subgraph ApplicationTier["Application Server Tier"]
subgraph SpringBoot["Spring Boot 4.0 Backend (Java 21)"]
SecurityFilterChain["Spring Security & JWT Filter"]
RestController["REST Controllers (Auth, Booking, Profile, Admin)"]
WSController["WebSocket Signaling Controller"]
DomainService["Domain Services (Session, Availability, AI mapping)"]
PaymentService["Stripe Connect Integration Service"]
JAVE2["JAVE2 Audio Transcoder (FFmpeg wrapper)"]
end
end
subgraph DatabaseTier["Database Tier"]
PostgresDB[("PostgreSQL Database (Neon Cloud / Local)")]
end
subgraph ExternalTier["External Services Tier"]
AIService["Quran AI Service (FastAPI / ngrok)"]
StripeAPI["Stripe Connect & Payments API"]
GoogleOAuth["Google Identity Provider"]
GmailSMTP["Gmail SMTP (OTP delivery)"]
end
%% Client Connections
ReactSPA -->|HTTPS REST| SecurityFilterChain
SockJSClient -->|WS / SockJS| WSController
WebRTCClient <-->|Peer-to-Peer Media Streams| PeerWebRTCClient["Peer Browser WebRTC - RTCPeerConnection"]
StripeJS -->|Secure Card Tokenization| StripeAPI
%% Backend Routing
SecurityFilterChain --> RestController
WSController --> DomainService
RestController --> DomainService
DomainService --> PaymentService
DomainService --> JAVE2
DomainService -->|Spring Data JPA| PostgresDB
%% External API Integrations
PaymentService -->|Stripe SDK| StripeAPI
DomainService -->|RestTemplate Multipart| AIService
RestController -->|Google OAuth2 Client| GoogleOAuth
DomainService -->|JavaMailSender| GmailSMTP
1.1 Communication & Protocol Specifications
- REST HTTP API (State Mutators & Querying): The React SPA interacts with the Spring Boot backend via JSON-based REST APIs. All protected endpoints require a JWT token in the
Authorization: Bearer <JWT>header. - WebRTC Peer-to-Peer (Audio/Video Media): Media streams (audio and video) for live recitation classes run directly peer-to-peer between client browsers. No media passes through the application server, saving bandwidth and lowering latency.
- WebSocket / STOMP (Signaling Channel): Handshaking (SDP offers, answers, and ICE candidates) is facilitated by the backend via a SockJS endpoint (
/ws) utilizing the STOMP messaging protocol. Messages published to/app/signalare multiplexed to the appropriate sub-channel under/topic/session/{sessionId}. - External AI Payload (Multipart HTTP): Transcoded audio files (WAV) are pushed from the backend to the external Python AI Service via
multipart/form-datarequests.
2. Technology Stack & Environment
| Layer | Concern | Technology / Dependency | Specifications |
|---|---|---|---|
| Frontend | Framework & Language | React 19 + TypeScript | Strict typing, functional components |
| Build System | Vite 7 | Hot Module Replacement (HMR) | |
| Styling | Vanilla CSS + Radix UI (shadcn) | Curated CSS Custom Properties | |
| Router | React Router v7 | Nested routing, role guards | |
| Localization | i18next & react-i18next | Multi-language (AR/EN), RTL support | |
| Real-Time | @stomp/stompjs + sockjs-client |
STOMP signaling over WebSockets | |
| Payment Gateway | @stripe/react-stripe-js |
Secure hosted payment elements | |
| Backend | Framework & Language | Spring Boot 4.0 (Java 21) | MVC, Security, WebSocket, Mail |
| Security | Spring Security 6 + JJWT | Stateless JWT auth, OAuth2 client | |
| Persistence | Spring Data JPA + Hibernate 6 | PostgreSQL dialect, connection pool | |
| Database | PostgreSQL | Hosted (Neon Cloud) or local instances | |
| Transcoding | JAVE2 (Java Audio Video Encoder) | FFmpeg wrapping for audio conversion | |
| External APIs | Stripe Java SDK (v25.3), Google Client API | Connection to Stripe Connect & Google OAuth |
3. Component Architecture
3.1 Frontend Component Tree (React SPA)
src/
βββ main.tsx # Client boots with GoogleOAuthProvider
βββ App.tsx # Base Router configurations & context nesting
βββ lib/
β βββ authContext.tsx # Holds current user state, triggers token restore
β βββ StudentContext.tsx # Manages and caches student session lists/history
β βββ languageContext.tsx # Toggles directionality (LTR/RTL), triggers i18n
β βββ api/ # Domain-specific fetch clients
β βββ aiApi.ts # Talks to the ngrok-tunneled Python Quran Model
β βββ bookingApi.ts # Availability slots, reservations, reviews
β βββ paymentApi.ts # Stripe payment initiation
β βββ studentApi.ts / sheikhApi.ts / adminApi.ts
βββ hooks/
β βββ useWebRTC.ts # Manages RTCPeerConnection, STOMP signaling,
β # and RTT quality metric reporting
βββ components/
βββ Navbar.tsx # Top navigation with responsive menus and language switcher
βββ LandingPage.tsx # Introduction & guest landing page
βββ auth/ # SignIn, Register, OTP verification, Profile wizard
βββ dashboards/
β βββ StudentDashboard.tsx # Student home page showing streak, history, and goals
β βββ SheikhDashboard.tsx # Teacher dashboard displaying class requests and stats
β βββ AdminDashboard.tsx # Platform dashboard (user activation, sheikh approval queue)
βββ sheikh/
β βββ FindSheikh.tsx # Search engine to filter sheikhs by country, rate, rating
β βββ SheikhProfile.tsx # Teacher profile with availability picker and booking flow
β βββ MyStudents.tsx # Student management & history view
βββ sessions/
β βββ WaitingRoom.tsx # 5-minute pre-session countdown & connection check
β βββ LiveSession.tsx # Real-time dashboard containing WebRTC video & notes
β βββ SessionReport.tsx # Student feedback form after classes
β βββ SessionEndWaiting.tsx # Polling component waiting for sheikh to finalize report
βββ practice/
β βββ RecordingPractice.tsx # Recording interface for solo Quran reciting
β βββ EvaluationReports.tsx # AI report display (word error markup, tashkeel issues)
βββ admin/ # Approve Sheikhs, Manage Users, Conduct Interviews
βββ ui/ # Reusable shadcn primitive elements (Dialog, Accordion)
Key React Contexts:
- AuthContext: Stores
authTokenandcurrentUserobject in memory and local storage. On boot, it verifies profile status againstGET /api/auth/verify-profile. - LanguageContext: Evaluates language configuration (AR/EN). Modifies the root document's body direction element (
dir="rtl"ordir="ltr") dynamically. - StudentContext: Holds listing and filter state for searching teachers, reducing component re-renders during queries.
3.2 Backend Packages & Layers (Spring Boot)
The Spring Boot backend is structured as a vertical domain slice pattern. Components are grouped by functional slice (Common/Auth, Student, Sheikh, Admin, WebSocket, Payment) rather than simple controller/service/repository folders.
com.yourcompany.quranapp.quran_app_backend/
βββ config/
β βββ SecurityConfig.java # JWT filter chains, CORS configurations, RBAC
β βββ GlobalExceptionHandler.java # Catches all exceptions, rendering standardized JSON responses
βββ security/
β βββ JwtAuthenticationFilter.java # OncePerRequestFilter extracting and verifying tokens
β βββ CustomUserDetails.java # UserDetails implementation mapping roles and statuses
β βββ UserDetailsServiceImpl.java # Resolves queries checking user status
βββ entity/ # Contains JPA entities (User, Session, Recitation, etc.)
βββ dashboard/
β βββ common/ # Auth Controllers, Services, JwtService, EmailService
β βββ student/ # Student Profile, Recitation, and Booking controllers
β βββ sheikh/ # Session, Availability, and Review endpoints
β βββ admin/ # User management, approval systems, and Interview scheduling
βββ payment/ # Stripe API controllers and processing services
βββ websocket/ # WS STOMP configuration and WebRTC signaling controllers
βββ google/ # Google ID Token verification utility
βββ setup/ # DataLoader for system bootstrapping
4. Database Schema & Data Architecture
The PostgreSQL database relies on Flyway migrations to evolve schemas. Soft delete mechanisms, checks, and cascade triggers ensure database integrity.
erDiagram
users ||--|| student_profile : "1:1 profile"
users ||--|| sheikh_profile : "1:1 profile"
users ||--o{ availability : "sets availability"
users ||--o{ recitations : "records recitation"
users ||--o| wallet : "owns wallet"
users ||--o{ session : "books as student"
users ||--o{ session : "conducts as sheikh"
users ||--o{ payment : "pays / receives"
users ||--o{ review : "submits"
users ||--|| streak : "tracks streak"
session ||--o| payment : "1:1 payment"
session ||--o| review : "1:1 review"
wallet ||--o{ wallet_transaction : "has transactions"
payment ||--o| wallet_transaction : "triggers transaction"
session ||--o| wallet_transaction : "triggers transaction"
users {
bigint userId PK
varchar email UK
varchar passHash
varchar fullName
boolean isActive
varchar phone UK
role_enum role
timestamp createdAt
}
student_profile {
bigint studentId PK, FK
gender_enum gender
date birthdate
quraan_level_enum quraan_level
}
sheikh_profile {
bigint sheikhId PK, FK
text bio
specialization_enum specialization
int yearsOfExperience
varchar certificatesURL
decimal hourlyRate
decimal ratingAVG
live_status_enum liveStatus
timestamp lastActiveAt
}
availability {
bigint availabilityId PK
day_of_week_enum dayOfWeek
time startTime
time endTime
bigint sheikhId FK
}
recitations {
bigint recitationId PK
varchar surahName
int ayahStart
int ayahEnd
decimal wordScore
decimal tashkeelScore
jsonb mistakesReportJson
bigint studentId FK
timestamp createdAt
}
session {
bigint sessionId PK
timestamp scheduledStart
timestamp scheduledEnd
timestamp actualStart
timestamp actualEnd
timestamp studentJoinedAt
timestamp sheikhJoinedAt
timestamp studentLeftAt
timestamp sheikhLeftAt
session_status_enum status
decimal price
text sessionNotes
bigint studentId FK
bigint sheikhId FK
}
payment {
bigint paymentId PK
decimal amount
varchar currency
payment_method_enum paymentMethod
payment_status_enum paymentStatus
varchar transaction_id UK
bigint sessionId FK, UK
bigint studentId FK
bigint sheikhId FK
}
review {
bigint reviewId PK
int rate
text comment
bigint sessionId FK, UK
bigint studentId FK
}
wallet {
bigint walletId PK
decimal balance
bigint userId FK, UK
}
wallet_transaction {
bigint transactionId PK
decimal amount
transaction_type_enum transactionType
bigint walletId FK
bigint paymentId FK
bigint sessionId FK
}
4.1 Schema Optimization & Indexes
- Foreign Keys: Mappings are managed via cascading constraints (
ON DELETE CASCADE) for profile data, while critical records (Sessions, Payments) useON DELETE RESTRICTto protect audit trails. - Indexing Strategy:
- Composite index on
sessions (sheikh_id, status, scheduled_start)for dashboard rendering. - Composite index on
sheikh_profile (status, ratingAVG)for search rankings. - Indexes on search filters (
users.role,availability.dayOfWeek,payments.paymentStatus).
- Composite index on
5. Architectural Workflows & Sequences
5.1 Real-Time WebRTC Peer-to-Peer Calling Flow
This flow enables media streams to bypass backend servers. Handshaking is done over the WebSocket STOMP broker.
sequenceDiagram
participant Student as Student Browser
participant WS as Backend STOMP Broker
participant Sheikh as Sheikh Browser
Note over Student, Sheikh: Pre-conditions: Both join session room
Student->>WS: Connects & Subscribes to /topic/session/{id}
Sheikh->>WS: Connects & Subscribes to /topic/session/{id}
Student->>WS: Send Signal {type: 'join', sender: StudentId}
WS-->>Sheikh: Forward 'join' payload
Note over Sheikh: Received Join -> Initialize Handshake
Sheikh->>Sheikh: Fetch camera/mic streams via getUserMedia()
Sheikh->>Sheikh: Create RTCPeerConnection & Add local media tracks
Sheikh->>Sheikh: Create SDP Offer
Sheikh->>WS: Send Signal {type: 'offer', data: SDP_Offer}
WS-->>Student: Forward 'offer' payload
Note over Student: Received Offer -> Formulate Answer
Student->>Student: Fetch camera/mic streams via getUserMedia()
Student->>Student: Create RTCPeerConnection & Add local media tracks
Student->>Student: Set Remote Description (SDP_Offer)
Student->>Student: Create SDP Answer
Student->>WS: Send Signal {type: 'answer', data: SDP_Answer}
WS-->>Sheikh: Forward 'answer' payload
Note over Sheikh: Set Remote Description (SDP_Answer)
Note over Student, Sheikh: ICE Candidate Exchange (Parallel)
Student->>WS: Send Signal {type: 'ice-candidate', data: Candidate}
WS-->>Sheikh: Forward candidate
Sheikh->>WS: Send Signal {type: 'ice-candidate', data: Candidate}
WS-->>Student: Forward candidate
Note over Student, Sheikh: Handshake Complete. P2P Direct Media Pipeline Established.
5.2 AI Recitation Evaluation Lifecycle
Automated speech recognition and Tajweed/Tashkeel correction processing pipeline.
sequenceDiagram
participant Student as Student Browser
participant Spring as Spring Boot Backend
participant FFmpeg as FFmpeg / JAVE2
participant AI as AI Model Service (FastAPI)
Student->>Student: Records voice using MediaRecorder (WebM/AAC)
Student->>Spring: POST /api/student/recitations (Multipart: File + Surah)
Note over Spring: Upload received -> Audio transcoding
Spring->>FFmpeg: Transcode input file -> WAV (PCM 16kHz, mono)
FFmpeg-->>Spring: WAV Stream / File
Spring->>AI: POST /analyze (Multipart: WAV File + Surah Number)
Note over AI: 1. ASR (Automatic Speech Recognition)<br/>2. Text Alignment with Surah Text<br/>3. Tashkeel & word-accuracy comparison
AI-->>Spring: JSON Report {surah_info, overall_stats, ayahs[]}
Spring->>Spring: Map details, compute scores & generate mistakes list
Spring->>Spring: Save Recitation entity (mistakesReportJson column = JSONB)
Spring-->>Student: Return RecitationDetailsDto
5.3 Stripe Payments & Payout Split Routing
Stripe Payment Intents for student collection, combined with Stripe Connect Express accounts to route money to teachers.
sequenceDiagram
participant Student as Student Browser
participant Backend as Spring Boot Backend
participant Stripe as Stripe API
participant Sheikh as Sheikh Wallet (Stripe Connect)
Student->>Backend: POST /api/payments/initiate/card (Session Details)
Backend->>Stripe: Create PaymentIntent (Amount, metadata)
Stripe-->>Backend: Return PaymentIntent Details (clientSecret)
Backend-->>Student: Return { clientSecret, publishableKey }
Note over Student: Render Stripe Credit Card element
Student->>Stripe: Submit card details + Confirm Payment (clientSecret)
Stripe-->>Student: Return Success
Student->>Backend: POST /api/payments/confirm-payment/{intentId}
Backend->>Stripe: Query status of PaymentIntent
Stripe-->>Backend: Return status (Succeeded)
Backend->>Backend: Update Payment status -> PAID, Session -> SCHEDULED
Backend-->>Student: Confirm success (200 OK)
Note over Student, Backend: Time passes -> Session completes
Backend->>Backend: Trigger Payout routing
Backend->>Backend: Calculate Split: Sheikh (85%), Commission (15%)
Backend->>Stripe: Create Transfer (Amount = 85%, Destination = sheikhAccountId)
Stripe->>Sheikh: Route payout to bank account
Stripe-->>Backend: Return transfer confirmation
Backend->>Backend: Update Payment record -> PAYOUT_DONE
6. Key Design Patterns & Engineering Best Practices
6.1 Eliminating JPA N+1 Query Bottlenecks
To prevent excessive queries during operations like mapping collections, the backend follows optimized loading rules:
- Strict Lazy Loading by Default: All
@ManyToOneand@OneToOnedatabase mappings are annotated withFetchType.LAZY. - JOIN FETCH Queries for Collection Mapping: When resolving lists of objects, custom JPQL queries use
JOIN FETCHto retrieve relations in a single query:@Query("SELECT s FROM Session s JOIN FETCH s.student JOIN FETCH s.sheikh LEFT JOIN FETCH s.payment WHERE s.student.id = :studentId") List<Session> findByStudentIdWithUsers(@Param("studentId") Long studentId); - Projections for Performance Statistics: For aggregate metrics, queries map directly to flat DTO projections using constructors instead of reading full entity trees:
@Query("SELECT new com.yourcompany.quranapp.quran_app_backend.dashboard.sheikh.dto.MyStudentsStats(COUNT(DISTINCT s.student.id), COALESCE(SUM(s.price), 0)) FROM Session s WHERE s.sheikh.id = :sheikhId") MyStudentsStats getMyStudentsStats(@Param("sheikhId") Long sheikhId);
6.2 Event-Driven Lifecycle Check Schedulers
To handle session outcomes (e.g. no-shows or unpaid requests), the backend sets up scheduled checks when sessions are created or on server boot:
- Unpaid Cancellations: Runs 5 minutes before
scheduledStart. If payment status is pending, session changes toCANCELLED. - Student No-Show Checks: Runs 1 minute after
scheduledStart. If neither party joins, session is marked asMISSEDand student receives a refund. - Sheikh No-Show Checks: Runs 10 minutes after
scheduledStart. If sheikh fails to join, session is marked asMISSEDand student receives a refund.
Startup scheduling listeners reconstruct these checks on server launch:
@EventListener(ApplicationReadyEvent.class)
public void rescheduleExistingSessionsOnStartup() {
List<Session> scheduled = sessionStatusRepository.findByStatus(SessionStatus.SCHEDULED);
for (Session session : scheduled) {
scheduleMissedCheck(session.getId(), session.getScheduledStart());
scheduleSheikhNoShowCheck(session.getId(), session.getScheduledStart());
}
}
6.3 Optimistic UI Updates & Error Boundaries
- Optimistic Dashboards: Frontend state changes (e.g., accepting/declining classes) update user state immediately, then send requests to the backend. The UI reverts state only if a network error occurs.
- Component Isolation: Layouts utilize
ErrorBoundaryelements, isolating widget failures so that an error in a single component (e.g., a stats chart) does not break the entire dashboard.