Skip to content

MoonFuji/eazzy-backend-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Eazzy Backend API

Laravel 12 API-only backend for a content/learning platform, showcasing device-scoped authentication, secure offline delivery (DRM-lite), and a queue-driven media pipeline running on Docker, PostgreSQL, Redis, and MinIO.

This repository is intentionally structured to read like a production-grade backend sample for technical screeners (mid/senior Laravel).

Project Overview

At a high level, this service:

  • Exposes a JSON HTTP API for students, professors, and admins (no coupled frontend).
  • Uses Sanctum + per-device sessions to control access to high-value media.
  • Offloads heavy work (FFmpeg transcoding, manifest rewriting) to background jobs on a dedicated media queue.
  • Delivers lessons as encrypted HLS streams and offline bundles, using JWT “licenses” and encrypted keys.
  • Runs in Docker with PostgreSQL, Redis, MinIO, a queue worker, and Laravel Octane for high-concurrency traffic.

Architecture & Tech Stack

  • Framework: Laravel 12 (PHP 8.2), API-only with Laravel Octane
  • Auth: Laravel Sanctum, device-bound sessions, email verification, password reset
  • Database: PostgreSQL
  • Caching & Queues: Redis (verification codes, queues), long-running media queue for transcoding
  • Storage: MinIO/S3 via Flysystem for private lesson assets and HLS segments
  • Media Pipeline: FFmpeg via queued jobs for encrypted HLS generation
  • Security: JWT-based licenses (firebase/php-jwt), encrypted media keys (libsodium / Laravel Crypt)
  • Runtime: Dockerized dev & prod, separate queue worker, Octane for high concurrency

High-level architecture:

  • HTTP API layer: Auth, catalog, quizzes, admin authoring, media/DRM endpoints.
  • Domain layer: Eloquent models and services for modules, lessons, offers, payments, device sessions, downloads, quizzes.
  • Async layer: Laravel queues (Redis/database) for TranscodeLesson and queued notifications.
  • Storage layer: PostgreSQL for relational data, MinIO/S3 for media, Redis for cache/queues.
  • Ops tooling: Docker Compose, environment-specific .env presets, deploy docs, and GitHub Actions workflow for deployment.

Authentication, Authorization & Device Sessions

  • Per-device auth: Each login associates a Sanctum token with a DeviceSession record (device info, IP, UA, rooted/emulator flags).
  • Middleware enforcement: EnsureDeviceSessionIsValid ensures every authenticated request has a valid device session, revoking tokens and logging security events when sessions are invalid.
  • Role model: Roles (student, professor, admin) are enforced in middleware and controllers, backing separate catalog, professor, and admin experiences.
  • Security logging: Auth and device events are funneled through LoggingService and persisted to ActivityLog for auditability.

Media Pipeline, DRM-Lite & Offline Downloads

  • Transcoding job: TranscodeLesson is a long-running queued job that:
    • Downloads source video from MinIO/S3.
    • Invokes FFmpeg to produce encrypted HLS segments and a playlist.
    • Rewrites HLS manifests so all segments are served through API routes, not directly from storage.
    • Uploads segments and manifests back to object storage and updates LessonAsset metadata.
  • Key management: LessonAsset stores AES keys encrypted with a master key (libsodium / Laravel Crypt), never in plaintext at rest.
  • License service: LessonDownloadService issues and validates JWT “license” tokens bound to (user, device, lesson) with TTL and revocation, and tracks StudentDownload records per device.
  • API-level DRM: Manifest and segment endpoints validate both device session and license before proxying media from MinIO, so raw objects remain private.

Async Processing, Queues & Performance

  • Queues: Heavy work (FFmpeg) is moved to a dedicated media queue; notifications and other async tasks can use the default queue.
  • Workers: A separate queue worker service runs php artisan queue:work --queue=media,default in Docker.
  • Timeouts & failure handling: Jobs declare explicit timeouts and bubble failures to Laravel’s failed-jobs table, while logging performance metrics via LoggingService.
  • Octane: The API runs under Laravel Octane to improve throughput and latency for concurrent clients.

High-Level Features

  • Authentication: Registration, login, logout with Laravel Sanctum
  • Email Verification: 6-digit codes (4-digit in development with bypass)
  • Password Reset: Secure code-based password reset
  • Redis Caching: Fast verification code storage
  • Docker: Containerized development and production environments
  • Catalog Management: Modules → lessons → resources with admin authoring tooling
  • Student Catalog: Published module browsing, enrollments, recent progress, and offer discovery
  • Quiz System: Admin quiz creation with questions/options, student attempts with automatic scoring
  • Offers & Seeding: Semester/annual bundles generated per level with strong seed data for testing
  • Offline DRM Pipeline: Admin uploads → FFmpeg transcode job → encrypted HLS stored in MinIO with manifest rewriting and secure segment proxy
  • API Documentation: Complete API documentation for Flutter integration and admin workflows

Quick Start

Development

# Start development environment with bind mounts
./dev.sh start

# View logs
./dev.sh logs

# Stop environment
./dev.sh stop

Development Features

  • Bind Mounts: File changes are instantly reflected in the container
  • No Rebuilds: Edit PHP files directly without rebuilding Docker images
  • Hot Reload: Laravel Octane automatically reloads on file changes
  • Development Bypass: Use verification code 1234 for any user

Available Commands

./dev.sh start      # Start development environment
./dev.sh stop       # Stop development environment
./dev.sh restart    # Restart development environment
./dev.sh logs       # Show application logs
./dev.sh exec bash  # Access container shell
./dev.sh install    # Install dependencies
./dev.sh migrate    # Run database migrations
./dev.sh clear      # Clear all caches
./dev.sh test       # Run tests
./dev.sh status     # Show container status

API Surface & Documentation

The API is grouped into clear areas: authentication/profile, student catalog, quizzes, and admin authoring/operations. Full details live in docs/*.md and Postman collections under docs/*.json; below is a quick index of major endpoints.

API Endpoints

Authentication & Profile

  • POST /api/auth/login
  • POST /api/auth/basic-info
  • POST /api/auth/email-password
  • POST /api/auth/learning-objectives
  • POST /api/auth/resend-verification-code
  • POST /api/auth/verify-email
  • GET /api/user

Catalog (Students)

  • GET /api/catalog/modules
  • GET /api/catalog/modules/{module}
  • GET /api/catalog/modules/{module}/offers
  • GET /api/catalog/my-modules
  • GET /api/catalog/modules/recent
  • GET /api/catalog/lessons/{lesson}

Quiz System (Students)

  • POST /api/quizzes/{quiz}/attempts
  • POST /api/quizzes/{quiz}/attempts/{attempt}/answers
  • POST /api/quizzes/{quiz}/attempts/{attempt}/complete
  • GET /api/quizzes/{quiz}/attempts/history

Admin Authoring

  • GET /api/admin/modules
  • POST /api/admin/modules
  • PATCH /api/admin/modules/{module}
  • DELETE /api/admin/modules/{module}
  • Nested lesson/resource endpoints under /api/admin/modules/{module}/lessons
  • Quiz management: /api/admin/quizzes* endpoints

Local Development (Docker)

Services

  • App: Laravel API on port 8002 (includes Octane and queue listeners)
  • Queue Worker: Dedicated worker consuming the media,default queues for transcoding
  • Database: PostgreSQL on port 5432
  • Redis: Redis cache + queue on port 6379
  • MinIO: S3-compatible storage on ports 9000/9001 (lesson assets stay private)

Environment Variables (local example)

APP_ENV=local
APP_DEBUG=true
DB_CONNECTION=pgsql
DB_HOST=db
DB_DATABASE=eazzy_backend
DB_USERNAME=postgres
DB_PASSWORD=password
CACHE_DRIVER=redis
REDIS_HOST=redis
REDIS_PORT=6379
LESSON_MASTER_KEY=base64:...
LICENSE_JWT_SECRET=base64:...
LESSON_ASSET_DISK=lesson_assets
LESSON_LICENSE_TTL_DAYS=7
LESSON_OFFLINE_GRACE_DAYS=7
APP_URL=http://localhost:8002

Bind Mounts

  • ./:/var/www/html - Project files (instant changes)
  • vendor:/var/www/html/vendor - Composer dependencies
  • composer_cache:/var/www/html/.composer - Composer cache

Seed Data

  • Run docker exec eazzy_backend-app-1 php artisan migrate:fresh --seed for a curated dataset.
  • Creates first_year semester catalogue (10 modules, priced offers), plus additional demo modules across other levels.
  • Demo accounts: admin@example.com, professor@example.com, student@example.com (password password).

Testing & Quality

API Testing

Use the included test.rest file with REST client:

  • VS Code REST Client extension
  • Postman
  • Insomnia

Development Bypass

In local/development environment:

  • Use verification code 1234 for any user
  • 4-digit codes instead of 6-digit
  • Instant verification without email

Production Deployment (Docker)

This project includes a full CI/CD pipeline and production-ready Docker setup designed for a single VPS behind Traefik.

Docker Compose

# Production build
docker-compose build --no-cache
docker-compose up -d

Environment Setup

APP_ENV=production
APP_DEBUG=false
MAIL_MAILER=smtp
MAIL_HOST=your-smtp-host
MAIL_USERNAME=your-email
MAIL_PASSWORD=your-password

Infrastructure & DevOps

  • Runtime topology: A single VPS runs Docker Compose services for app (Laravel Octane), queue (workers), db (PostgreSQL), redis, minio, and traefik (reverse proxy + TLS).
  • Reverse proxy & TLS: Traefik terminates HTTPS for eazzyedu.xyz, manages Let’s Encrypt certificates, and routes traffic to the app container on port 8002.
  • Stateful services: PostgreSQL, Redis, MinIO, and Traefik certificates use named Docker volumes for persistence (db_data, redis_data, minio_data, traefik_letsencrypt).
  • Environment separation: .env.production.example and DEPLOYMENT.md describe production-only settings (strong credentials, MinIO bucket, manifests TTL, etc.), kept out of version control as real secrets.

CI/CD Pipeline (GitHub Actions → GHCR → VPS)

Deployment is fully automated via GitHub Actions (.github/workflows/deploy.yml):

  • Trigger: Any push to main starts the “Deploy Backend” workflow.
  • Build & test stage:
    • Builds two Docker images (app, queue) with docker/build-push-action.
    • Pushes images to GitHub Container Registry (GHCR), tagged as latest and with the commit SHA.
    • Runs Laravel tests in CI: installs Composer dependencies, generates APP_KEY, runs migrations (test DB), and executes PHPUnit; deployment stops if tests fail.
  • Deploy stage:
    • Uses an SSH key (VPS_SSH_KEY) and host (VPS_HOST) from GitHub Actions secrets to connect to your VPS.
    • rsyncs only deployment configs (docker-compose.yml, traefik.yml, traefik-dynamic.yml, .env) to /root/eazzy_backend on the VPS (source code stays in the container images).
    • Logs into GHCR on the VPS, runs docker compose pull and docker compose up -d to roll forward to the new images.
    • Performs a health check against https://eazzyedu.xyz/api/health; if it fails, a rollback step tears down the new containers and restarts the previous state.

Supporting docs:

  • DEPLOYMENT.md: end-to-end explanation of the CI/CD pipeline (images, GHCR, Traefik, health checks, rollback).
  • VPS_SETUP.md: one-time VPS bootstrap (Docker, Compose, firewall, .env, GHCR auth, log rotation, backups).
  • DEPLOYMENT_CHECKLIST.md: detailed pre-flight checklist (tests, secrets, infra, health checks, monitoring).
  • QUICK_REFERENCE.md: operational cheat sheet for common maintenance and debugging commands on the VPS.

API Documentation

Complete API documentation is available in docs/api.md with:

  • Request/response formats
  • Authentication flows
  • Error handling
  • Security features
  • Module/offer reference and up-to-date Postman collections (see docs/catalog-module-endpoints.md and docs/catalog-postman-collection.json).
  • Quiz system documentation (see docs/quiz-api-endpoints.md and docs/quiz-postman-collection.json).
  • DRM + offline download integration (docs/offline-video-drm-plan.md, docs/flutter-drm-integration.md).

Media & DRM Quick Start

  1. Configure Secrets
    • Set LESSON_MASTER_KEY (32-byte base64) and LICENSE_JWT_SECRET in .env.
    • Point APP_URL to the externally reachable host so manifests embed the correct segment proxy URL.
  2. Start Services
    docker compose up -d db redis minio
    docker compose up -d app queue
    The queue service runs php artisan queue:work --queue=media,default so upload-triggered jobs transcode automatically.
  3. Admin Upload Flow
    • Admin dashboard calls POST /api/admin/lessons/{lesson}/video with multipart form data (video file input).
    • Backend stores the raw source video on the lesson_assets disk, creates/updates the lesson_assets row, and enqueues a TranscodeLesson job.
    • Job runs FFmpeg to generate encrypted HLS, rewrites manifests to the /api/lessons/{lesson}/segments/{file} proxy, and updates metadata (duration_seconds, segment_count, file_size_mb).
  4. Student Download Flow
    • GET /api/catalog/lessons/{lesson} returns a download bundle with signed manifest URL + license token once the asset is ready.
    • GET /api/lessons/{lesson}/manifest?format=hls rewrites the playlist so every segment is fetched through the Laravel proxy instead of MinIO.
    • POST /api/lessons/{lesson}/license issues the AES key/IV for offline playback.
    • Manifest + segments always flow through authenticated endpoints to keep MinIO objects private.

Testing The DRM Flow With Postman

You do not need the Flutter app to validate the backend. Every hop in the DRM-lite pipeline is exposed via HTTP, so Postman (or curl) can exercise the entire workflow:

  1. Authenticate via /api/auth/login with device_id in the body. Save the returned token and the same device_id as Postman variables.
  2. Unlock the lesson (use seeded data or POST /api/payments/mock-success).
  3. Fetch /api/catalog/lessons/{lesson} to copy the license_token, manifest URL, and byte counts.
  4. Request /api/lessons/{lesson}/manifest?format=hls with headers Authorization: Bearer {{token}} and X-Device-Id: {{device_id}} to inspect the rewritten playlist.
  5. POST /api/lessons/{lesson}/license with { "license_token": "..." } to retrieve the AES key/IV; optionally store them in Postman environment variables for local decrypt tests.
  6. Iterate /api/lessons/{lesson}/segments/segment_000.ts (etc.) to fetch encrypted chunks. Postman can save them to disk for spot checks.
  7. POST /api/lessons/{lesson}/downloads/complete with the observed byte totals to close out the flow.

The updated Postman collection under docs/postman_collection.json already includes these requests and example headers so you can import and run them directly.

See docs/offline-video-drm-plan.md for architecture diagrams and docs/testing-guide.md for local verification steps.

Security Features

  • Single Token Policy: Only one active token per user
  • Email Verification: Required before login
  • Password Reset: 6-digit codes with 10-minute expiry
  • Rate Limiting: Throttling on sensitive endpoints
  • Token Revocation: All tokens revoked on password reset
  • Email Enumeration Protection: Password reset always returns success

What This Repo Demonstrates

  • Asynchronous & distributed processing: Clear separation between request/response APIs and heavy FFmpeg/HLS work via Laravel queues and dedicated workers.
  • Applied security & access control: Device-scoped Sanctum auth, JWT-based licenses, encrypted media keys, and per-device session enforcement around high-value content.
  • Media pipeline & DRM design: Practical implementation of a DRM-lite system with HLS transcoding, manifest rewriting, key management, and offline download workflows.
  • Production-ready backend architecture: API-only Laravel 12 service using Octane, Redis, PostgreSQL, MinIO, and queues, wired together for realistic deployment and scaling.
  • API design & documentation discipline: Well-structured endpoints, Markdown docs, and Postman collections that make the API approachable for both humans and tools.
  • Containerized local and prod parity: Dockerized environments with supporting services (DB, cache, object storage, workers) for reproducible setups and easy onboarding.

License

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors