Engineering
🏗️ System Architecture
From request to response — how the multi-client iSpeaker Live platform is wired together.
On this page
High-Level Overview
iSpeaker Live is a headless API + multi-client architecture. A single Laravel API serves a Next.js web app, a Flutter mobile app, and a Filament admin panel. Real-time communication is delivered via Laravel Reverb (WebSockets), and live video uses Jitsi Meet.
Technology Stack
🎨 Frontend Web
- Next.js 15 (App Router)
- React 19
- TypeScript
- Tailwind CSS + shadcn/ui
- SWR / fetch for data
- Laravel Echo + Pusher-JS for WebSocket
📱 Mobile
- Flutter (latest stable)
- Clean Architecture (data / domain / presentation)
- Provider / Riverpod for state
- Dio for HTTP, FlutterSecureStorage
- jitsi_meet_flutter_sdk
- firebase_messaging
⚙️ Backend API
- Laravel 11 on PHP 8.3
- Laravel Sanctum (auth)
- Spatie laravel-permission (roles)
- Filament v3 (admin panel)
- Laravel Reverb (WebSocket server)
- Laravel Queues + Scheduler
🗄️ Data & Infra
- MySQL 8.0
- Redis (cache + queues)
- Object storage for media
- DigitalOcean droplets
- Nginx + PHP-FPM
- Self-hosted Jitsi for streaming
System Diagram
flowchart TB
subgraph Clients
W[Next.js Web App]
M[Flutter Mobile App]
AD[Filament Admin]
end
subgraph EdgeLayer ["Edge / Web Tier"]
NGINX[Nginx
Reverse Proxy + TLS] end subgraph App ["Application Tier"] API[Laravel 11 API
PHP-FPM] REVERB[Reverb
WebSocket Server] QUEUE[Queue Workers] SCHED[Scheduler] end subgraph Data ["Data Tier"] MYSQL[(MySQL 8)] REDIS[(Redis
cache + queue)] STORAGE[Object Storage
media / PDFs / videos] end subgraph External ["External Services"] JITSI[Jitsi Meet
self-hosted] PAYPAL[PayPal] FCM[Firebase
Cloud Messaging] SMTP[Email SMTP] end W --> NGINX M --> NGINX AD --> NGINX NGINX --> API NGINX --> REVERB API --> MYSQL API --> REDIS API --> STORAGE API --> QUEUE API --> SCHED QUEUE --> MYSQL QUEUE --> FCM QUEUE --> SMTP API <--> REVERB REVERB --> REDIS M --> JITSI W --> JITSI API --> PAYPAL
Reverse Proxy + TLS] end subgraph App ["Application Tier"] API[Laravel 11 API
PHP-FPM] REVERB[Reverb
WebSocket Server] QUEUE[Queue Workers] SCHED[Scheduler] end subgraph Data ["Data Tier"] MYSQL[(MySQL 8)] REDIS[(Redis
cache + queue)] STORAGE[Object Storage
media / PDFs / videos] end subgraph External ["External Services"] JITSI[Jitsi Meet
self-hosted] PAYPAL[PayPal] FCM[Firebase
Cloud Messaging] SMTP[Email SMTP] end W --> NGINX M --> NGINX AD --> NGINX NGINX --> API NGINX --> REVERB API --> MYSQL API --> REDIS API --> STORAGE API --> QUEUE API --> SCHED QUEUE --> MYSQL QUEUE --> FCM QUEUE --> SMTP API <--> REVERB REVERB --> REDIS M --> JITSI W --> JITSI API --> PAYPAL
Backend (Laravel)
Folder structure
app/Http/Controllers/Api/— 26 REST controllers (Auth, Cart, Course, Book, LiveRoom, Wallet, …).app/Models/— 40+ Eloquent models with relationships.app/Filament/— Filament resources for the admin panel.app/Events/— broadcast events for real-time (new messages, room updates).app/Services/— business logic (PaypalService, NotificationService, etc.).app/Traits/— reusable model traits (e.g.HasMediaUrls).app/Helpers/— global helper functions.routes/api.php— 180+ endpoints grouped by feature.
Middleware stack on API routes
throttle:api— rate limiting.localization— sets app locale.auth:sanctum— token auth (where required).role:speaker/role:student— Spatie role gates.
Background jobs
- Notification fan-out (FCM + in-app).
- Email delivery (welcome, password reset, invoice).
- Media processing (thumbnails, transcoding hooks).
- Scheduled tasks: room reminders, abandoned cart hints, daily aggregates.
Web (Next.js)
App Router layout — student and speaker have separate dashboards.
app/dashboard/student/*— feed, learn, books, rooms, marketplace, profile, wallet, chat, notifications, collections, speakers, follow-requests, cart.app/dashboard/speaker/*— same surfaces plus authoring tools (courses, books, rooms, consultations, statistics, my-creations).app/(public)/*— landing, login, register, privacy, terms.app/courses/[courseId]— public course preview pages.app/profile/[username],app/users/[id],app/posts/[id].components/— organized by feature (feed, course, reader, chat, wallet, rooms, …) plus shared UI primitives.app/sitemap.ts,app/robots.ts— search-engine metadata served by Next's native routes at/sitemap.xmland/robots.txt. The sitemap lists the pages a signed-out visitor can genuinely read, plus current posts and hashtags pulled hourly from the public API; dashboards and auth screens are excluded from it and disallowed in robots.
Mobile (Flutter)
Clean Architecture with feature-based folders.
lib/core/— helpers, networking, providers, routing, error, theme, storage, localization.lib/features/<feature>/data— repositories & remote data sources.lib/features/<feature>/domain— entities & use cases.lib/features/<feature>/presentation— screens, widgets, state.
18 feature modules:
auth · feed · profile · home · marketplace · speakers · book_consultation · speaker_consultations · rooms · speaker_rooms · my_creations · speaker_courses · speaker_books · collections · wallet · statistics · chat · notifications
Real-time (Laravel Reverb)
- WebSocket server runs alongside the API.
- Frontend authenticates against
/api/broadcasting/authusing its Sanctum token. - Channels by feature:
conversation.{id}for chat,room.{id}for live rooms,user.{id}for personal events. - Events:
MessageSent,RoomMessageSent,NotificationCreated,RoomStatusChanged, etc.
sequenceDiagram
participant C as Client
participant A as Laravel API
participant R as Reverb
participant D as DB
C->>A: POST /chat/messages
A->>D: Insert message
A->>R: broadcast(MessageSent)
R-->>C: message event (other party)
C-->>C: Live update UI
Live Streaming (Jitsi Meet)
- Self-hosted Jitsi server on a dedicated droplet (separate from web tier).
- Room IDs are server-generated and stored in
live_rooms.current_jitsi_room_id. - JWT-based authentication on Jitsi where required (paid rooms).
- Web uses
iframeembed; mobile usesjitsi_meet_flutter_sdk. - Served from
meet.ispeakerlive.comwith the iSpeaker logo as an in-room watermark (set in the Jitsi server'sinterface_config.js). - A wait-for-host gate keeps participants in the lobby until the room owner joins.
- All room scheduling and countdown times are displayed in Asia/Riyadh (UTC+3) across web, mobile and the API.
- Recordings (where enabled) saved to object storage and listed on the room.
Storage & Media
- User-uploaded media (avatars, covers, post images / videos / audio) live in object storage.
- Course videos, book PDFs, and lesson attachments use private buckets.
- Access to protected media via signed short-lived URLs generated by the API.
HasMediaUrlstrait normalizes media field URLs on model serialization.
Security
- Auth: Sanctum bearer tokens with last-used / expires-at indexes.
- Authorization: Spatie roles + per-route middleware. Speaker-only endpoints explicitly gated.
- Transport: HTTPS everywhere; HSTS at the edge.
- Passwords: bcrypt hashing via Laravel.
- Encryption at rest: stored bank details — IBAN and account-holder name — are encrypted with AES-256-CBC through Laravel's
encryptedcast, keyed byAPP_KEY. Both storage sites are covered: the speaker's profile record, and the payout snapshot held inside each withdrawal transaction. Each row gets its own random IV, so two accounts holding the same IBAN do not produce matching ciphertext. - Rate limiting: per-IP and per-user on auth and high-cost endpoints.
- CSRF: not applicable to stateless API; web forms use Laravel's built-in protection.
- File uploads: validated MIME & size; stored outside web root.
- SQL injection / XSS: Eloquent + Laravel escaping by default.
- Reverb auth: presence and private channels go through Sanctum.
Scalability
- Stateless API horizontally scalable behind load balancer.
- Reverb can scale via Redis broadcaster across nodes.
- Queue workers scale per workload (notifications high-throughput).
- MySQL read-replica path planned for Phase 2 (heavy listing endpoints).
- CDN in front of object storage for media delivery.
- Jitsi instance scales by adding video bridges (JVBs).