Sharaf ul Quran

Sharaf ul Quran

Sharaf ul Quran

Full-stack Islamic education platform connecting students with Quran teachers (Qaris): one-time and monthly booking, course enrollment with Stripe, Google Meet, Fireflies.ai recording, and admin oversight.

Role:Full-Stack Developer / System Architect
Year:
React 18Vite 5React Router 7Tailwind CSSFramer MotionRedux Toolkit (Admin)TanStack React QueryEChartsNode.jsExpress 4PostgreSQLStripeGoogle OAuth2 / Calendar APIFacebook OAuthFireflies.aiSocket.ioNodemailerWhatsApp Cloud APIDockerNginx

Executive Summary

Case Study Overview

Sharaf ul Quran is a full-stack Islamic education platform connecting students with Quran teachers (Qaris). This case study covers the architecture for one-time and monthly booking, course enrollment with Stripe, Google Meet integration, Fireflies.ai recording, and comprehensive admin oversight.

The Challenge

The platform needed to coordinate students, Qaris, and admins across registration, payment handling, session scheduling with meeting links, and access control to learning resources. Students needed to find Qaris, book sessions, and pay; Qaris needed onboarding, availability setup, and earnings tracking; admins needed approval workflows and enrollment management.

The Approach

Dual backends (main + admin) with shared PostgreSQL and role-separated auth. Webhook-driven Stripe payment confirmation, idempotent course payment handling, and an enrollment state machine (pending_approval → approved_unpaid → active → completed). Session notification cron, in-memory admin stats cache with TTL, and resource gating based on paid bookings.

Key Deliverables

Student/Qari registration with admin approval, one-time and monthly booking with Google Meet, course enrollment with slot assignment, Fireflies.ai meeting recordings, and a comprehensive admin panel for oversight and analytics.

Want to dive deeper? Explore the full technical case study with architecture diagrams, implementation details, and outcomes.

Problem

The Challenge

Context

Platform for Quran education requiring coordination between students, Qaris, and admins; payment handling; session scheduling with meeting links; and access control to learning resources.

User Pain Points

1

Students need to find Qaris, book sessions, pay, and access resources

2

Qaris need onboarding approval, availability setup, earnings tracking, resource uploads

3

Admins need to approve onboarding, manage enrollments, assign slots, view stats

Why Existing Solutions Failed

Existing solutions did not provide the combined workflow of onboarding, booking, course enrollment, and resource gating in one platform.

Goals & Metrics

What We Set Out to Achieve

Objectives

  • 01Student/Qari registration and role-based onboarding with admin approval
  • 02One-time and monthly session booking with Stripe and Google Meet
  • 03Course enrollment with admin slot assignment and monthly payments
  • 04Resource sharing gated by paid bookings; meeting recordings via Fireflies
  • 05Admin panel for oversight, stats, and management

Success Metrics

  • 01Dual backends (main + admin) with shared PostgreSQL and role-separated auth
  • 02Webhook-driven payment confirmation and idempotent course payment handling
  • 03Enrollment state machine (pending_approval → approved_unpaid → active → completed)
  • 04Session notification cron; in-memory admin stats cache with TTL

User Flow

User Journey

Landing → Register (student/Qari) → Onboarding → Admin review → Booking (one-time/monthly) or Course enrollment → Portal access; Qari uploads resources; Student accesses resources for Qaris with paid bookings.

start
Landing
action
Register
action
Onboarding
decision
Admin review
action
Booking / Course enroll
action
Portal / Resources
end
Session / Meet

Architecture

System Design

Two frontends (main: Student + Qari; admin: dashboard) and two Express backends sharing one PostgreSQL (Neon). Main backend: auth, calendar, payment, resources, courses, monthly booking, Socket.io, cron. Admin backend: admin auth, Qari/student management, stats. External: Stripe, Google Calendar, Fireflies, SMTP, WhatsApp.

Loading interactive diagram...

What This Diagram Represents

The full topology of Sharaf ul Quran: main and admin frontends, main and admin backends, PostgreSQL, and external systems (Stripe, Google Calendar, Fireflies, SMTP, WhatsApp, Socket.io). It shows which components exist and how they are grouped (frontend, backend, db, external).

How to Read the Flow

Nodes are systems or services; edges indicate primary communication (e.g. Frontend → Backend, Backend → PostgreSQL, Backend → Stripe). Follow edges to see request direction (e.g. user → main frontend → main backend) and integration points (webhooks from Stripe/Fireflies to main backend). The split between main and admin is visible in the two frontend and two backend nodes.

Key Engineering Decisions

Dual frontend/backend split for role isolation; single database shared by both backends; webhooks as inbound edges from Stripe and Fireflies; Socket.io as a service used by the main backend to push to the main frontend.

Layer Breakdown

Frontend

Main Frontend (React, Vite) — Student and Qari portalsAdmin Frontend (React, Vite, Redux, React Query, ECharts)

Backend

Main Backend (Node/Express) — Auth, calendar, payment, resources, courses, monthly booking, Socket.ioAdmin Backend (Node/Express) — Admin auth, Qari/student management, stats

Data

PostgreSQL (Neon in production)uploads/certificates, uploads/resources

External

Stripe (payments, webhooks)Google Calendar API (Meet links)Fireflies.ai (recording, transcription)Gmail SMTP, WhatsApp Cloud API

Security

Authentication & Authorization Flow

JWT in httpOnly cookie with role-based backend separation; main backend rejects admin tokens. Email/password and OAuth (Google, Facebook); profile endpoint for cookie clients.

Loading interactive diagram...

What This Diagram Represents

The path from user action (register, login, OAuth callback) through backend verification and token issuance to role-based redirect and subsequent authenticated requests. Includes branches for email/password vs OAuth and for student/Qari vs admin.

How to Read the Flow

Start at "User" or "Frontend"; follow edges through "Backend" (auth routes, token generation, cookie set) and back to "Frontend" (profile fetch, redirect). Admin flow goes to Admin Backend and Admin Frontend. Edges are labeled with the main data or action (e.g. "JWT cookie", "Profile", "403 if admin on main").

Key Engineering Decisions

Single user store with role; main backend rejecting admin tokens; cookie-based JWT; profile endpoint for cookie clients; OAuth callback cleanup and profile fetch.

Core Feature

One-Time Booking Lifecycle

From slot selection to PaymentIntent, webhook confirmation, Google Meet link creation, and email/WhatsApp notifications.

Loading interactive diagram...

What This Diagram Represents

One-time booking flow: student → slot selection → payment → webhook → Meet + notifications. Nodes are steps or systems; edges are "next step" or "sends to".

How to Read the Flow

Follow from the first user action ("Select Qari & slot") through backend steps (create PaymentIntent, create booking record) to external events (Stripe webhook) and back to backend (update status, create Meet, send email/WhatsApp).

Key Engineering Decisions

Webhook as source of truth for payment; separation of "create intent" vs "confirm and fulfill"; notifications as best-effort after confirmation.

Core Feature

Course Enrollment Lifecycle

Submit → admin approval → slot assignment → payment → idempotent webhook → state machine → course_sessions.

Loading interactive diagram...

What This Diagram Represents

Course enrollment flow: enroll → admin approval → payment → webhook → state machine → sessions. Shows state transitions and idempotent webhook handling.

How to Read the Flow

Follow state transitions (pending_approval → approved_unpaid → active) and webhook idempotency (webhook_events, claimForProcessing). Admin approves and assigns slot; Stripe webhook triggers state machine; course_sessions generated on active.

Key Engineering Decisions

State machine for course enrollment; idempotent webhook processing to handle Stripe retries and concurrency; course webhook returns 200 on processing error to avoid retry storms.

Data Flow

How Data Moves

Frontend → Backend (auth, booking, enrollment); Backend → Stripe (PaymentIntent); Stripe/Fireflies → Backend (webhooks); Backend → PostgreSQL, Google Calendar, SMTP, WhatsApp; Backend → Frontend via Socket.io.

1
Frontend → Backend
Auth credentials, booking payload, enrollment payload
2
Backend → Stripe
PaymentIntent creation, customer creation
3
Stripe → Backend
Webhook (payment_intent.succeeded, etc.)
4
Backend → PostgreSQL
User, booking, enrollment, payment records
5
Backend → Frontend
Socket event (booking update)

Data Flow

Data Processing Flow

Frontend ↔ Backend ↔ PostgreSQL; Backend ↔ Stripe, Google, SMTP, WhatsApp; Fireflies → Backend; Backend → Frontend via Socket.io.

Loading interactive diagram...

What This Diagram Represents

Movement of data between Frontend, Backend, PostgreSQL, Stripe, Google Calendar, SMTP, WhatsApp, and Fireflies. Emphasizes who sends what and on what trigger.

How to Read the Flow

Each edge is a data flow; labels describe the data (e.g. "Auth credentials", "PaymentIntent creation", "Webhook event"). Triggers are implied or in edge labels (e.g. "Payment completion"). Bidirectional flows (e.g. Backend ↔ PostgreSQL) show read/write.

Key Engineering Decisions

Webhook-driven payment updates; backend as the only writer to PostgreSQL; backend as orchestrator for Stripe, Google, SMTP, WhatsApp; Fireflies pushing to backend; Socket.io pushing from backend to frontend.

Core Features

Key Functionality

01

Authentication

What it does

Email/password and OAuth (Google, Facebook); JWT in httpOnly cookie; role-based access.

Why it matters

Single user store; main backend rejects admin tokens for API separation.

Implementation

authController, authMiddleware, useAuth; bcrypt, cookie + Bearer fallback, profile endpoint.

02

Qari & Student Onboarding

What it does

Qaris/students submit details; admin approves or rejects.

Why it matters

Gates platform use and ensures verified teachers and student info.

Implementation

qari_onboarding, student_onboarding; availability JSONB; CNIC validation; admin routes.

03

One-Time Booking

What it does

Students book single sessions; Stripe payment; Google Meet; email/WhatsApp.

Why it matters

Core revenue and session delivery path.

Implementation

calendar_bookings; Stripe webhook as source of truth; googleMeet, emailService, whatsappService.

04

Monthly & Course Enrollment

What it does

Monthly plans (5/6 days) and multi-month courses; admin approval and slot assignment; Stripe.

Why it matters

Recurring engagement and subscription revenue.

Implementation

monthly_sessions, course_sessions; enrollment state machine; idempotent course webhook (webhook_events).

05

Resource Management

What it does

Qaris upload lessons/PDFs/videos; students access only with paid booking for that Qari.

Why it matters

Content gating and fair access.

Implementation

qari_resources; resourceAccessMiddleware checks calendar_bookings before serve.

06

Meeting Recordings (Fireflies)

What it does

Fireflies.ai records/transcribes; webhook and polling update meeting_recordings.

Why it matters

Post-session review and accountability.

Implementation

firefliesRoutes, firefliesService, firefliesWebhookHandlers, firefliesPolling job.

07

Admin Panel & Session Notifications

What it does

Admin dashboard (stats, management); cron sends email ~1h before sessions, creates Meet if missing.

Why it matters

Oversight and reduced no-shows.

Implementation

Admin-frontend/backend; adminStatsService (30s cache); monthlySessionNotificationJob (node-cron).

Performance

Performance & Decision Flow

Admin stats cache (hit/miss, TTL), rate limiting, resource access middleware, file streaming, and cron-driven session notifications.

Loading interactive diagram...

What This Diagram Represents

Where performance and caching decisions are made: admin stats (cache hit vs miss, TTL 30s/2min), rate limiting (request → allow/block), resource serve (middleware check → allow/deny), and cron schedule (every 5 min → session notification job).

How to Read the Flow

Start at "Request" or "Cron tick"; follow through "Rate limiter", "Cache lookup", "DB query", "Middleware check". Decision nodes (e.g. "Cache hit?") branch to "Use cached stats" vs "Query DB & set cache". Edges can be labeled with "30s TTL", "Deny if no paid booking", etc.

Key Engineering Decisions

In-memory cache for admin stats with fixed TTLs; rate limiting at the gateway; resource access as an explicit check before serve; file streaming; no Redis (single-process cache).

Technical Challenges

Problems We Solved

Why This Was Hard

express.json() parses body and breaks signature verification

Our Solution

Stripe and Fireflies webhook routes registered before express.json(); use express.raw() for those routes.

Why This Was Hard

Stripe can retry; multiple workers could process same event

Our Solution

webhook_events table; claimForProcessing atomic lock; mark processed/failed with retry count.

Why This Was Hard

Students should only access resources for Qaris they have paid bookings with

Our Solution

resourceAccessMiddleware extracts qariId from path; queries calendar_bookings; denies if no paid booking.

Why This Was Hard

Admin and student/qari share auth tables but different backends

Our Solution

Main backend explicitly rejects admin tokens; returns 403 and clears cookie.

Why This Was Hard

Meet creation uses OAuth; access token expires

Our Solution

GOOGLE_REFRESH_TOKEN in env; setCredentials with refresh_token; token refresh on use.

Engineering Excellence

Performance, Security & Resilience

Performance

  • Admin stats in-memory cache with 30s–2min TTL
  • PostgreSQL indexes on bookings, enrollments, payments, sessions, availability
  • Connection pooling (pg); file streaming for certificates and resources
  • Rate limiting (express-rate-limit)
🛡️

Error Handling

  • PostgreSQL 23505 (unique), 23503 (FK) in errorHandler
  • Stripe/Fireflies webhook signature verification
  • 401/403 for auth; course webhook returns 200 on processing error to avoid Stripe retry storms
🔒

Security

  • JWT in httpOnly cookie; bcrypt; express-validator
  • Resource access middleware for file serving; CORS; parameterized SQL (pg)
  • Helmet in admin backend

Design Decisions

Visual & UX Choices

Auth and navigation

Rationale

Consistent experience across student and Qari portals

Details

Modal-based login/register; sidebar navigation; skeleton loaders during auth check; role-based redirects (Qari → /qari/overview, Student → /portal).

OAuth and onboarding

Rationale

Clear state and redirects

Details

OAuth callback cleans URL and fetches profile; onboarding status determines redirect (submitted → under-review, approved → dashboard). Legacy routes /wari → /qari, /qari/quran-resources → /qari/resources.

Impact

The Result

What We Achieved

Modular full-stack platform: two Express backends and two React frontends sharing one PostgreSQL and shared file store. Cookie-based JWT with role-based backend separation; webhook-driven Stripe payments with idempotent course handling and enrollment state machine; one-time and monthly booking plus course enrollment; Google Meet, Fireflies, email, WhatsApp; resource access gated by paid booking.

👥

Who It Helped

Single team; implementation-accurate documentation from PROJECT_ANALYSIS and caseStudyData.

Why It Matters

Production-oriented system with clear boundaries, documented limitations (no tests, in-memory cache, Helmet off on main backend), and a path for improvements.

Reflections

Key Learnings

Technical Learnings

  • Webhook raw body and express.raw(); idempotency via claimForProcessing; state machines for enrollment.

Architectural Insights

  • Dual backend split for role isolation; single DB and shared uploads simplify operations.

What I'd Improve

  • Enable Helmet on main backend; add tests; replace in-memory cache with Redis; retries/circuit breakers for external APIs.

Roadmap

Future Enhancements

01

Enable Helmet on main backend once CORS stable

02

Introduce automated tests (unit + integration)

03

Replace in-memory admin stats cache with Redis

04

Move credentials to secrets manager

05

Use dedicated STRIPE_WEBHOOK_SECRET_COURSES

06

Add structured retries and circuit breakers for external APIs

07

Clarify or complete Calendly integration