Education & Learning / LMS Scripts / Meridian
Home Documentation Setup Guide Get Meridian

Documentation

Everything about Meridian

This page is the reference manual: how the platform is organised, what each role can do, how every integration works under the hood, and what the API looks like for your future Flutter app. New to Meridian? Start with the Setup Guide instead.

Overview

Meridian is a Laravel 12 learning management system covering four jobs at once: selling courses, running live classes, administering exams, and issuing certificates — with every third-party integration (payments, SMS, WhatsApp, AI) controlled from the Admin Panel rather than hard-coded into the app.

Design principle: nothing calls a third-party API unless an Admin has explicitly switched it on. This is enforced inside the manager classes (PaymentManager, SmsManager, WhatsappManager, AiManager), not just hidden in the UI — so it can't be bypassed by a stray route or a forgotten checkbox.
StackChoice
BackendLaravel 12, PHP 8.2+
AuthSession (web) + Sanctum tokens (API/Flutter)
Rolesspatie/laravel-permission — Admin, Instructor, Student
FrontendBlade + Tailwind (responsive, no build step required)
UploadsWritten directly to public/uploads/...

Architecture & folders

The codebase follows standard Laravel conventions with a few dedicated folders for the integration layer, so you always know where to look:

app/
├── Http/Controllers/
│   ├── Admin/         # Platform management + gateway settings
│   ├── Instructor/    # Course/exam/live-class authoring
│   ├── Student/        # Learning experience
│   └── Api/            # Sanctum-authenticated REST endpoints (Flutter)
├── Services/
│   ├── Payment/Drivers/   # Cash, Stripe, Razorpay, PayPal, Paystack...
│   ├── Sms/Drivers/       # Twilio, Vonage, MSG91, TextLocal...
│   ├── Whatsapp/Drivers/  # Meta Cloud API, Twilio WhatsApp
│   └── Ai/AiManager.php   # Every AI feature, one gated entry point
├── Models/              # One Eloquent model per table, relationships wired
routes/
├── web.php, api.php, admin.php, instructor.php, student.php
public/uploads/          # courses, users, certificates, live-classes, exams, site

User roles

Every account has exactly one primary role, enforced by an role: middleware alias on each route group, and gets its own dashboard layout so nobody sees controls they don't need.

RoleCan doRoute prefix
AdminApprove courses, manage users/categories/curricula, configure every integration, confirm cash orders, view reports/admin/*
InstructorBuild courses, schedule live classes, author exams, use AI authoring tools, request payouts/instructor/*
StudentBrowse, enroll, track progress, sit exams, join live classes, chat with the AI tutor, download certificates/student/*

Course & sale lifecycle

  1. Instructor creates a course (draft) with sections, lessons, pricing and curriculum/grade-level tags.
  2. Instructor submits it for review → status becomes pending_review.
  3. Admin approves → status becomes published and it appears in the public catalog.
  4. Student adds it to cart, applies a coupon if any, and checks out through any Admin-enabled gateway.
  5. On payment confirmation (or immediately, for cash/free), an Enrollment row is created.
  6. Progress is tracked per lesson; once 100% complete, a certificate PDF is generated automatically.

Payment gateways

Admin can enable any number of gateways at the same time from /admin/settings/payment-gateways; the student chooses one at checkout. Cash is always enabled as the guaranteed fallback and can't be switched off.

GatewayDriver classCredentials needed
Cash / OfflineCashGatewayNone — always on
Bank TransferBankTransferGatewayBank details text block
StripeStripeGatewayKey, Secret, Webhook secret
RazorpayRazorpayGatewayKey, Secret
PayPalPaypalGatewayClient ID, Client secret, Mode
PaystackPaystackGatewayPublic key, Secret key
FlutterwaveFlutterwaveGatewayPublic key, Secret key
SSLCommerzSslCommerzGatewayStore ID, Store password, Mode

Every driver implements the same three methods, so adding a ninth gateway later is a matter of writing one class:

interface PaymentGatewayInterface {
    public function boot(array $credentials, string $mode = 'sandbox'): void;
    public function initiate(Order $order, array $options = []): array;
    public function verify(Order $order, array $payload = []): bool;
    public function refund(Order $order, ?float $amount = null): bool;
}

SMS gateways

Admin can store credentials for as many SMS providers as they like, but exactly one is ever is_active — activating one automatically deactivates the rest, so there's never ambiguity about which provider actually sends a message.

ProviderBest for
TwilioGlobal coverage, reliable delivery
Vonage (Nexmo)Global coverage, competitive pricing
MSG91India / South Asia
TextLocalUK / India
Generic HTTPAny local/regional gateway with a simple HTTP API

WhatsApp integration

Built on the official Meta WhatsApp Cloud API by default (Twilio WhatsApp also included). A master switch turns the whole integration on or off, and six event-level toggles control exactly which system events actually send a message — all of which are genuinely wired into the checkout, exam grading, and certificate-issuing flows, not just present in Settings:

AI features

One master switch (Admin → Settings → AI) plus fifteen independent feature toggles, all read from the database so they can change instantly without a redeploy. Every single one below has a real, working implementation behind it — not just a checkbox:

FeatureUsed by
Course description generatorInstructor authoring
Lesson summary generatorInstructor authoring
Quiz question generatorInstructor authoring
Exam auto-grading (essay/short-answer)Assessment
AI essay feedbackAssessment
AI tutor chatbotStudent learning
Course recommendation engineStudent discovery
Student performance insightsAnalytics
Auto-translate contentLocalization
Video transcript generatorAccessibility (real Whisper API call)
Plagiarism / similarity checkAssessment integrity
Smart certificate notesCertificates
AI proctoring flaggingExam integrity (tab-switch/blur detection)
Chat & review moderationSafety
SEO meta generatorMarketing
Nothing is called unless enabled. Every feature method in AiManager calls assertFeature() first and throws if that specific toggle is off — even if the master switch is on.

REST API (Flutter-ready)

Every learner-facing action already exists as a versioned, Sanctum-authenticated JSON endpoint under /api/v1/... — the Flutter app is a client of this API, not a reason to change the backend.

# Auth
POST  /api/v1/auth/register
POST  /api/v1/auth/login
POST  /api/v1/auth/otp/request
POST  /api/v1/auth/otp/verify
POST  /api/v1/auth/social

# Catalog (public)
GET   /api/v1/courses
GET   /api/v1/courses/{slug}

# Authenticated
POST  /api/v1/checkout
GET   /api/v1/my-courses
POST  /api/v1/my-courses/{slug}/lessons/{lesson}/progress
GET   /api/v1/exams/{exam}
POST  /api/v1/exam-attempts/{attempt}/submit
GET   /api/v1/live-classes
GET   /api/v1/certificates

Uploads & storage

Every upload — course videos and thumbnails, avatars, certificates, exam images, site branding — is written directly to public/uploads/<type>. There's no storage:link symlink dependency for the media the app actually serves, which keeps things simple on shared hosting.

FolderContains
public/uploads/coursesThumbnails, lesson videos, attachments
public/uploads/usersAvatars
public/uploads/certificatesGenerated PDF certificates
public/uploads/live-classesRecordings/thumbnails
public/uploads/examsQuestion images
public/uploads/siteLogo, favicon, branding assets
Demo/seed data can also store a full external image URL directly in these same fields (course thumbnails, avatars, category images) — the model accessors detect a URL and pass it through untouched instead of mangling it into a local path.

FAQ

Can I add a payment gateway that isn't listed?

Yes — implement PaymentGatewayInterface, register it in config/payment.php, and it appears in the Admin settings screen automatically.

Does disabling AI remove the database columns?

No. Disabling AI just stops the feature methods from running — nothing is deleted, so you can re-enable it later with no data loss.

Is the API versioned for future breaking changes?

Yes — everything lives under /api/v1, so a future /api/v2 can be introduced without breaking an already-shipped mobile app.

Ready to install it?

The Setup Guide walks through every step, start to first login.

Open Setup Guide →