Quran_Tech_Server / docs /full_project_architecture.md
aboalaa147's picture
Initial deployment
eb6a2f9
|
Raw
History Blame Contribute Delete
21.1 kB

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/signal are 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-data requests.

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:

  1. AuthContext: Stores authToken and currentUser object in memory and local storage. On boot, it verifies profile status against GET /api/auth/verify-profile.
  2. LanguageContext: Evaluates language configuration (AR/EN). Modifies the root document's body direction element (dir="rtl" or dir="ltr") dynamically.
  3. 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) use ON DELETE RESTRICT to 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).

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:

  1. Strict Lazy Loading by Default: All @ManyToOne and @OneToOne database mappings are annotated with FetchType.LAZY.
  2. JOIN FETCH Queries for Collection Mapping: When resolving lists of objects, custom JPQL queries use JOIN FETCH to 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);
    
  3. 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 to CANCELLED.
  • Student No-Show Checks: Runs 1 minute after scheduledStart. If neither party joins, session is marked as MISSED and student receives a refund.
  • Sheikh No-Show Checks: Runs 10 minutes after scheduledStart. If sheikh fails to join, session is marked as MISSED and 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 ErrorBoundary elements, isolating widget failures so that an error in a single component (e.g., a stats chart) does not break the entire dashboard.