Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

220 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

CodeLearning Platform πŸš€

Live Demo

An enterprise-grade Full-Stack E-learning & Online Judge platform featuring automated multi-language code evaluation, real-time contest execution, and integrated financial transactions.

🌐 Visit the Live Demo Website at: www.codelearning.io.vn


React TypeScript Vite Tailwind CSS

Spring Boot Java 21 PostgreSQL Redis RabbitMQ Docker PayOS

An advanced Full-Stack E-learning & Online Judge (OJ) platform engineered with Spring Boot 3.5.7, Java 21, and React 19. It integrates automated code execution sandboxes, real-time status updates via WebSockets, event-driven contest scheduling, and secure payment processing.

Designed with enterprise-grade architectures (Layered Monolith, Monorepo, Event-Driven, Asynchronous execution), this project demonstrates practical solutions to high concurrency, resource management, performance optimization, and web application security.


🌟 Key Features

⚑ 1. Online Judge (Automated Code Evaluation System)

  • Monaco Code Editor: Integrated feature-rich code editor (VS Code-like interface) supporting code completion, syntax highlighting, and custom themes across multiple programming languages (C++, Java, Python, JavaScript, etc.).
  • Asynchronous Sandbox Evaluation (Judge0): Submits source code to the evaluation sandbox asynchronously via Spring WebFlux & Webhooks, providing exact testcase verdicts (Accepted, Wrong Answer, TLE, MLE, Compile Error).
  • Real-time Status Updates (WebSocket STOMP): Pushes real-time evaluation progress and final submission results directly from backend to frontend clients via WebSockets without requiring page refreshes.
  • Short-Circuit Evaluation Logic: Automatically halts judgment and returns immediate failure upon encountering the first failed testcase, conserving sandbox computing resources during live contests.

πŸ’³ 2. Cart & Payment Gateway (Cart & PayOS Integration)

  • Cart & Order Management: Allows users to add multiple courses to cart, apply promotional vouchers/discount codes, and create seamless checkout orders.
  • PayOS Payment Gateway Integration: Automatically generates dynamic banking QR codes for instant, hassle-free bank transfers.
  • Transaction Safety (Idempotency & Pessimistic Locking): Processes PayOS webhook callbacks reliably using Postgres pessimistic locking (SELECT FOR UPDATE via findByUserIdWithLock) to credit wallets and activate courses securely, preventing race conditions.

πŸ›‘οΈ 3. Authentication & Security (Authentication & Authorization)

  • Multi-Factor / Multi-Provider Auth: Supports standard Email/Password authentication as well as Google OAuth2 Single Sign-On (SSO).
  • Secure Token Management (JWT + RTR): Resolves JWT tokens dynamically from either standard Authorization headers or secure HttpOnly, SameSite cookies (mitigating XSS/CSRF attacks). Enforces Refresh Token Rotation (RTR) to issue fresh token pairs while blacklisting revoked tokens (invalidated_tokens).
  • Dynamic Authorization (Dynamic RBAC & Contextual SpEL): Role-based access control (STUDENT, INSTRUCTOR, ADMIN) with fine-grained method-level security (@PreAuthorize) evaluating SpEL expressions to verify resource ownership and course enrollment before granting access.

βœ‰οΈ 4. Enterprise Async Email Pipeline (RabbitMQ & SendGrid Integration)

  • Batch Processing & Message Queue: Chunks recipient lists into batches (500 users/batch) and dispatches them asynchronously through RabbitMQ (email.exchange & bulk.email.queue).
  • SendGrid Dynamic Templates: Integrates SendGrid API v3 with dynamic template data binding for personalized bulk email delivery.
  • DLQ Recovery & Webhook Telemetry: Stores failed delivery attempts in a DLQ database table (FailedEmailQueueEntity) for retries, and verifies SendGrid Webhook signatures (X-Twilio-Email-Event-Webhook-Signature) to record real-time delivery telemetry (delivered, open, click, bounce).

πŸ—ΊοΈ System Architecture

1. Asynchronous Webhook-Driven Online Judge (OJ) Flow

To prevent blocking main application threads during long-running code evaluation in the sandbox, the evaluation process is decoupled into a non-blocking asynchronous flow using Spring WebFlux (WebClient), Redis Atomic Counter, and WebSocket (STOMP).

sequenceDiagram
    autonumber
    actor Student as Student (Web Client)
    participant API as Spring Boot Backend
    participant Redis as Redis Cache
    participant Sandbox as Judge0 Sandbox
    participant DB as PostgreSQL DB

    Student->>API: Submit Code (Problem ID, Language, Source Code)
    activate API
    API->>DB: Save Submission & Details (Status: PENDING)
    API->>Sandbox: Batch Submission Request (Async WebClient)
    activate Sandbox
    Sandbox-->>API: Return Batch Tokens (UUIDs)
    deactivate Sandbox
    API->>Student: Return Submission ID (Immediate HTTP 200)
    deactivate API
    
    Note over Student: Shows Progress Bar (WebSocket listener active)

    loop Webhook Callbacks per Testcase
        Sandbox->>API: PUT /online-judge/webhooks (Token, Verdict, CPU/Memory)
        activate API
        API->>DB: Update Testcase Status (AC, WA, TLE, etc.)
        API->>Redis: Increment Atomic Progress Counter (opsForValue().increment)
        
        alt Contest Mode: Short-Circuit Logic (First Failure)
            API->>Redis: Lock result using setIfAbsent("oj_failed:submissionId")
            Note over API, Redis: If locking succeeds, mark final verdict (e.g. WA) & skip waiting for remaining testcases
            API->>DB: Mark Submission as COMPLETED (Verdict: WA)
            API->>Student: Push Final Result via WebSocket STOMP
        else Normal Mode: All Testcases Completed
            Redis-->>API: Counter reaches N (Total Testcases)
            API->>DB: Calculate Final Verdict & Save
            API->>Student: Push Final Result via WebSocket STOMP
            API->>Redis: Clear Redis keys (Deregister counter & lock)
        end
        deactivate API
    end
Loading

2. PayOS Payment & Checkout Flow (Idempotent Webhook, Late Payment & Cron Reconciliation)

To process financial transactions reliably without money loss, race conditions, or duplicate payments, the checkout workflow combines PayOS Dynamic Banking QR Codes, HMAC-SHA256 Signature Verification, PostgreSQL Pessimistic Locking (SELECT FOR UPDATE), Late Payment Handling (LATE_SUCCESS), and Active CronJob Reconciliation.

sequenceDiagram
    autonumber
    actor Customer as User / Student
    participant API as Spring Boot Backend
    participant Cron as Payment CronJob (Every 5 mins)
    participant PayOS as PayOS Gateway API
    participant DB as PostgreSQL DB (Pessimistic Lock)

    Customer->>API: POST /payments/deposit (Create Deposit Request)
    activate API
    API->>DB: Save PaymentTransaction (Status: PENDING)
    API->>PayOS: Request Payment Link (v2/payment-requests)
    activate PayOS
    PayOS-->>API: Return Checkout Payload (Payment Link, Dynamic QR Code)
    deactivate PayOS
    API-->>Customer: Return Checkout QR Code & Redirect URL
    deactivate API

    alt Path A: Standard Asynchronous Webhook Delivery
        PayOS->>API: POST /payment/payos-webhook (Webhook Payload & Signature Header)
        activate API
        API->>API: Verify Webhook Signature (HMAC-SHA256 Checksum)
        
        alt Idempotency Guard: Already SUCCESS or LATE_SUCCESS
            API-->>PayOS: Return HTTP 200 OK (Ignore duplicate webhook)
        else Transaction PENDING or CANCELLED
            API->>DB: Acquire Lock via findByUserIdWithLock (SELECT FOR UPDATE)
            activate DB
            alt Transaction Status was CANCELLED or EXPIRED (Late Payment)
                API->>DB: Mark Status -> LATE_SUCCESS (Prevent Customer Money Loss)
            else Transaction Status was PENDING
                API->>DB: Mark Status -> SUCCESS
            end
            API->>DB: Credit Wallet Balance & Write Wallet Transaction Ledger
            DB-->>API: Commit Transaction & Release Lock
            deactivate DB
            API-->>PayOS: Return HTTP 200 OK (Webhook Processed)
        end
        deactivate API

    else Path B: Active CronJob Reconciliation (Missed Webhooks & Auto Expiry)
        Cron->>DB: Scan Pending Transactions (Status == PENDING)
        activate Cron
        loop For each Pending Transaction (> 5 mins)
            Cron->>PayOS: GET /v2/payment-requests/{orderCode}
            activate PayOS
            PayOS-->>Cron: Return Transaction Status (PAID / CANCELLED / PENDING)
            deactivate PayOS
            
            alt PayOS Status == PAID (Missed Webhook Recovery)
                Cron->>API: Trigger Fallback Processing (Lock Wallet & Credit Balance)
                API->>DB: Mark Status -> SUCCESS / LATE_SUCCESS & Update Wallet
            else PayOS Status == CANCELLED / EXPIRED or PENDING > 30 mins
                Cron->>DB: Force Update Status -> CANCELLED (Release Stale Tx)
            end
        end
        deactivate Cron
    end
Loading

3. Security Architecture & Dynamic Authorization

The security subsystem is built around Spring Security configured as an OAuth2 Resource Server with token verification against a token blacklist.

graph TD
    A[Client Request] --> B[SecurityFilterChain]
    B --> C[CorsFilter / CsrfFilter]
    C --> D[BearerTokenResolver]
    D -->|Extract JWT from Authorization Header OR HttpOnly Cookie| E[BearerTokenAuthenticationFilter]
    E --> F[OAuth2AuthenticationProvider]
    F --> G[CustomJwtDecoder]
    G -->|Introspect: Check JTI Blacklist| H(AuthenticationService)
    H -->|Query DB invalidated_tokens| I[(PostgreSQL)]
    I -->|Return validity status| G
    G -->|Decode & Verify Signature| J[NimbusJwtDecoder]
    J --> K[JwtAuthenticationConverter]
    K -->|Map scopes to GrantedAuthorities| L[SecurityContextHolder]
    L --> M[Method Security Filter: @PreAuthorize]
    M -->|Evaluate SpEL invoking @courseSecurity| N[CourseSecurity Bean]
    N -->|Perform Contextual DB Checks| I
    N -->|Allow Access| O[Controller Endpoint]
Loading

4. Asynchronous Bulk Email Pipeline (RabbitMQ & SendGrid Integration)

To handle mass email distribution efficiently without HTTP request timeouts or API rate-limit violations, the system utilizes RabbitMQ Message Queues, SendGrid Dynamic Templates, Database DLQ, and Webhook Signature Telemetry.

sequenceDiagram
    autonumber
    actor Admin as Admin / System Event
    participant Producer as EmailProducerService
    participant Rabbit as RabbitMQ (email.exchange)
    participant Consumer as EmailConsumerService (@RabbitListener)
    participant SendGrid as SendGrid API v3
    participant DB as PostgreSQL DB
    participant Webhook as SendGrid Webhook Controller

    Admin->>Producer: POST /api/admin/email/send-campaign (Target & Template ID)
    activate Producer
    Producer->>DB: Fetch Valid Target Users (isEmailValid == true)
    Producer->>Producer: Chunk Recipients into Batches (500 users/batch with Batch ID)
    Producer->>Rabbit: Publish BulkEmailMessage to email.exchange (Routing: email.bulk)
    Producer-->>Admin: Return HTTP 200 OK (Batch Dispatched Asynchronously)
    deactivate Producer

    activate Consumer
    Rabbit->>Consumer: Consume BulkEmailMessage from bulk.email.queue
    Consumer->>Consumer: Map Batch Data into SendGrid Personalizations
    
    alt Successful SendGrid API Call
        Consumer->>SendGrid: POST /v3/mail/send (Template ID & Personalizations)
        activate SendGrid
        SendGrid-->>Consumer: Return HTTP 202 Accepted
        deactivate SendGrid
    else API Error / Delivery Failure
        Consumer->>DB: Save Payload to FailedEmailQueueEntity (Status: PENDING_RETRY)
    end
    deactivate Consumer

    note over SendGrid, Webhook: Asynchronous Delivery Tracking via SendGrid Webhook Callback
    SendGrid->>Webhook: POST /api/webhooks/sendgrid (Events & Signature Header)
    activate Webhook
    Webhook->>Webhook: Verify Signature (X-Twilio-Email-Event-Webhook-Signature)
    Webhook->>DB: Save Telemetry Log to EmailDeliveryLogEntity (Delivered / Open / Bounce)
    Webhook-->>SendGrid: Return HTTP 200 OK
    deactivate Webhook
Loading

πŸ› οΈ Tech Stack & Dependencies

Layer Technology / Library
Frontend Framework React 19, TypeScript 5, Vite 6
UI & Styling Tailwind CSS v4, Framer Motion, Lucide Icons
Code Editor & Tools @monaco-editor/react, Axios, i18next
Realtime Communication SockJS-client, STOMPjs (WebSockets)
Backend Framework Java 21, Spring Boot 3.5.7 (WebFlux, OAuth2 Resource Server, Data JPA)
Database & Caching PostgreSQL 15, Redis 7
Message Broker RabbitMQ 3 (with rabbitmq_delayed_message_exchange plugin)
Sandbox Engine Judge0 API v1.13.1 Sandbox
Integrations PayOS SDK (Payment Gateway), Cloudinary (Media Hosting)
DevOps & Containers Docker, Docker Compose (Dev/Prod Profiles), NGINX

πŸ“‚ Monorepo Project Structure

codelearning-platform/
β”œβ”€β”€ backend/                      # Spring Boot 3.5.7 Backend Application
β”‚   β”œβ”€β”€ src/main/java/com/thanhmila/codelearning/
β”‚   β”‚   β”œβ”€β”€ configuration/        # Bean configs (Redis, RabbitMQ, WebClient, PayOS, etc.)
β”‚   β”‚   β”œβ”€β”€ controller/           # REST Controllers (Auth, Course, Contest, OJ, Payment, User)
β”‚   β”‚   β”œβ”€β”€ dto/                  # Data Transfer Objects
β”‚   β”‚   β”œβ”€β”€ entity/               # JPA Entities mapped to PostgreSQL
β”‚   β”‚   β”œβ”€β”€ exception/            # Global Exception Handlers
β”‚   β”‚   β”œβ”€β”€ listener/             # RabbitMQ Queue Consumers
β”‚   β”‚   β”œβ”€β”€ repository/           # Spring Data JPA Repositories (Projections, Specifications)
β”‚   β”‚   β”œβ”€β”€ security/             # Security configs, Custom JWT Decoder & SpEL Evaluators
β”‚   β”‚   └── service/              # Core Business Logic Services
β”‚   β”œβ”€β”€ Dockerfile                # Multi-stage Dockerfile for Backend
β”‚   β”œβ”€β”€ Dockerfile.rabbitmq       # RabbitMQ Dockerfile with Delayed Exchange plugin
β”‚   └── pom.xml                   # Maven dependencies
β”œβ”€β”€ frontend/                     # React 19 + TypeScript + Vite Frontend Application
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ api/                  # Axios API Clients & Endpoints
β”‚   β”‚   β”œβ”€β”€ components/           # Reusable UI Components (Monaco Editor, Modals, Navbar)
β”‚   β”‚   β”œβ”€β”€ pages/                # Page Components (Home, OJ, Courses, Contest, Cart, Admin)
β”‚   β”‚   β”œβ”€β”€ context/              # React Context (Auth, Theme, Cart)
β”‚   β”‚   └── layouts/              # Main App & Dashboard Layouts
β”‚   β”œβ”€β”€ Dockerfile                # NGINX Container Dockerfile
β”‚   └── package.json              # Node.js dependencies
β”œβ”€β”€ database/                     # Database Initialization Scripts
β”‚   └── init.sql                  # PostgreSQL Schema & Seed Data
β”œβ”€β”€ docs/                         # Detailed System Architecture & Workflow Specs
β”‚   β”œβ”€β”€ project_analysis_report.md
β”‚   β”œβ”€β”€ workflow_judge0.md
β”‚   β”œβ”€β”€ generation_testcase_automation.md
β”‚   β”œβ”€β”€ rabbitmq_contest_status_workflow.md
β”‚   └── workflow_cart_payment.md
β”œβ”€β”€ docker-compose.dev.yml        # Orchestration for Development Environment
β”œβ”€β”€ docker-compose.prod.yml       # Orchestration for Production Environment
β”œβ”€β”€ judge0.conf                   # Judge0 Sandbox Configuration
└── README.md                     # Monorepo Documentation

πŸš€ Getting Started & Local Setup

πŸ“‹ Prerequisites

Ensure you have the following installed on your machine:


1. Environment Variables Setup

Backend Environment (backend/.env):

Create a .env file in the backend/ directory:

# SERVER CONFIG
PORT=8080
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173

# POSTGRES DB
DB_HOST=localhost
DB_PORT=5432
DB_NAME=codelearning
DB_USERNAME=postgres
DB_PASSWORD=your_secure_password

# REDIS
REDIS_HOST=localhost
REDIS_PORT=6379

# RABBITMQ
RABBITMQ_HOST=localhost
RABBITMQ_PORT=5672
RABBITMQ_USERNAME=guest
RABBITMQ_PASSWORD=guest

# SECURITY (JWT)
JWT_SIGNER_KEY=your_super_secret_32_characters_key_here
JWT_ACCESS_COOKIE_NAME=access_token
JWT_REFRESH_COOKIE_NAME=refresh_token

# THIRD-PARTY INTEGRATIONS
CLOUDINARY_CLOUD_NAME=your_cloudinary_name
CLOUDINARY_API_KEY=your_cloudinary_key
CLOUDINARY_API_SECRET=your_cloudinary_secret

PAYOS_CLIENT_ID=your_payos_client_id
PAYOS_API_KEY=your_payos_api_key
PAYOS_CHECKSUM_KEY=your_payos_checksum_key

# JUDGE0 (OJ SANDBOX)
JUDGE0_API_URL=http://localhost:2358
JUDGE0_WEBHOOK_URL=http://your-public-ip-or-ngrok/online-judge/webhooks/submissions

Frontend Environment (frontend/.env):

Create a .env file in the frontend/ directory:

VITE_API_BASE_URL=http://localhost:8080
VITE_GOOGLE_CLIENT_ID=your_google_oauth_client_id

2. Run via Docker Compose (Recommended)

Run all services (Database, Redis, RabbitMQ, Judge0 Sandbox, Backend, and Frontend) using Docker Compose profiles:

Development Environment:

docker compose -f docker-compose.dev.yml --profile backend --profile frontend --profile judge0 up -d

Production Environment:

docker compose -f docker-compose.prod.yml --profile backend --profile frontend --profile judge0 up -d

Note

Docker Compose is configured with healthchecks. Services will start in order, waiting for PostgreSQL, Redis, and RabbitMQ to become healthy before launching the Spring Boot Backend and React Frontend.


3. Manual Local Execution (Alternative)

A. Run Infrastructure Dependencies Only:

docker compose -f docker-compose.dev.yml up -d db redis rabbitmq judge0-server judge0-workers judge0-db judge0-redis

B. Start Backend (Spring Boot):

cd backend
mvn clean package -DskipTests
mvn spring-boot:run

Backend will start at http://localhost:8080.

C. Start Frontend (Vite + React):

cd frontend
npm install
npm run dev

Frontend will be available at http://localhost:5173.


πŸ“š Detailed System Documentation & Design Specs

For in-depth analysis and workflow specifications of individual subsystems, refer to the documents in the /docs directory:


πŸ‘©β€πŸ’» Author

  • VΓ΅ Ngọc Thanh (Thanh_MiLa) - GitHub Profile
  • Role: Full-Stack & System Engineer

About

Advanced Spring Boot 3 & Java 21 backend for an E-learning & Competitve Programing platform.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages