Skip to content

nafisrahman006/lumina-ed

Repository files navigation

Lumina Learning

Lumina Learning

A full-stack EdTech platform β€” vibe coded for learning, built with real-world architecture.

React Express PostgreSQL Redis Docker Vite Vibe Coded


⚠️ Disclaimer: This is a personal learning & practice project, vibe coded to explore full-stack development. Not affiliated with, endorsed by, or connected to luminalearning.com in any way.


Table of Contents


Overview

Lumina Learning is a vibe-coded, full-stack EdTech platform built purely for learning purposes. The goal was simple β€” take a real-world project idea and build it properly, with production-grade patterns: Redis sessions, Docker containerization, secure auth, and a dynamic React frontend.

No shortcuts. No tutorials copy-pasted. Just vibes, curiosity, and a lot of debugging. πŸš€


App-Overview

Home Page


Tech Stack

Layer Technology
Frontend React 19, Vite (HMR + Asset Bundling)
Backend Node.js, Express
Database PostgreSQL (primary data store)
Cache / Sessions Redis 7
Containerization Docker & Docker Compose
Auth bcryptjs, express-session, Custom Redis Store

Architecture

graph TD
    User((User Browser)) -->|HTTPS / JSON| App[Express + Vite Server]

    subgraph Application_Layer
        App --> Auth[Auth & Session Logic]
        App --> API[Course & Enrollment API]
        Auth -->|Sanitize| Env[Environment Utility]
    end

    subgraph Data_Persistence
        Auth -->|Custom Store| Redis[(Redis 7 - Sessions)]
        API -->|SQL| DB[(PostgreSQL - Data)]
    end

    subgraph Frontend_SPA
        Vite[Vite Dev Server] -->|HMR / Assets| User
        React[React 19 UI] -->|State Management| User
    end
Loading

Key Features

⚑ Custom Redis Session Store

Standard session libraries (e.g., connect-redis) fail to communicate correctly with Redis 7 in Docker environments, producing ERR syntax error at runtime.

Solution: A fully custom Redis Session Store was implemented directly in the backend, using native Redis commands (SET key value EX seconds) rather than library abstractions.

Result:

  • βœ… 100% compatibility with Redis 7
  • βœ… Zero session-save failures
  • βœ… Full control over TTL and serialization

🐳 Docker Environment Hardening

Docker environments can silently introduce bugs when .env files contain literal quote characters in connection strings, causing the app to fail on startup.

Solution: A cleanEnv utility automatically sanitizes all configuration strings β€” DATABASE_URL, REDIS_URL, etc. β€” before the application consumes them.

Result:

  • βœ… Prevents malformed connection strings
  • βœ… Works reliably across all host environments
  • βœ… Zero manual debugging of quote-escaping issues

πŸ”„ Auto-Login on Registration

Instead of leaking a "User already exists" error (which enables account enumeration attacks), the auth layer intelligently detects an existing account and logs the user in silently.

Result:

  • βœ… Improved security posture β€” no account enumeration
  • βœ… Better UX β€” no confusing errors on duplicate registration

Security

Security is baked into the core of the application, not added as an afterthought.

Threat Mitigation
Plaintext passwords bcryptjs hashing with salt factor 10 β€” raw passwords are never stored
XSS cookie theft httpOnly: true on all session cookies
CSRF attacks sameSite: "lax" on all session cookies
Session forgery Sessions signed with a 64-character hex SESSION_SECRET
SQL Injection Parameterized queries (PostgreSQL) & prepared statements (SQLite)
Stale sessions maxAge of 7 days with automatic TTL expiration enforced in Redis
Secret rotation Rotating SESSION_SECRET instantly invalidates all active sessions

Note: Rotating SESSION_SECRET is a hard logout for all users. This is intentional behavior for incident response.


Redis & Session Management

Redis serves as the short-term memory of the application β€” purpose-built for fast session lookups and stateless horizontal scaling.

Authentication Flow

1.  User submits credentials  β†’  POST /api/auth/login
2.  Server validates password against PostgreSQL (bcrypt compare)
3.  Server generates a unique Session ID (sid)
4.  Server stores { userId: 1 } in Redis  β†’  key: sess:<sid>
5.  Server sends sid to browser in a signed, HttpOnly cookie
6.  On every subsequent request:
        Browser sends cookie
          β†’ Server reads sid
          β†’ Server fetches userId from Redis  (sub-millisecond)
          β†’ Request is authenticated βœ“

Session Lifecycle

Property Value
Storage backend Redis 7 (persists across server restarts)
TTL 7 days, calculated manually by CustomRedisStore
Key format sess:<sessionId>
Scaling model Stateless β€” supports horizontal scaling behind a load balancer
Lookup latency Sub-millisecond

Search & Discovery

The platform features a dynamic, real-time course search built entirely on the client β€” no page reloads, no server round-trips.

How It Works

User types in search box
        ↓
Client-side filter executes on `courses` state (zero API calls)
        ↓
Algorithm scans: Title Β· Description Β· Category
        ↓
Results update instantly on every keystroke

Capabilities

  • Real-time filtering β€” results appear as you type
  • Multi-field matching β€” searches title, description, and category simultaneously
  • Case-insensitive β€” React matches react, REACT, and ReAcT
  • Zero-state handling β€” a dedicated "No results found" view renders when the query returns nothing

Getting Started

Prerequisites

  • Docker & Docker Compose
  • Node.js v18+ (for local development without Docker)

1. Clone the Repository

git clone https://github.com/nafisrahman006/lumina-ed.git
cd lumina-ed

2. Configure Environment Variables

cp .env.example .env

Open .env and fill in your values: Generate a Secure Session Secret

3.πŸ” Never skip this step. A weak secret = broken session security.

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Copy the output

⚠️ Do not wrap values in quotes inside .env files. The cleanEnv utility handles sanitization, but bare values are always preferred.

4. Start the Application

docker compose up --build

The platform will be available at http://localhost:3000


Diagnostics & Inspection

Use these commands to inspect the live state of the application at runtime.

πŸ‘€ View All Registered Users

docker exec -it edtech-platform-db psql -U edtech_user -d edtech_db \
  -c "SELECT id, email, name FROM users;"

πŸ”‘ View All Active Sessions (Redis)

docker exec -it edtech-platform-redis redis-cli keys "*"

πŸ” Inspect a Specific Session

docker exec -it edtech-platform-redis redis-cli get "sess:YOUR_SESSION_ID"

πŸ“š View All Enrollments

docker exec -it edtech-platform-db psql -U edtech_user -d edtech_db -c "
SELECT
    u.name    AS student_name,
    u.email,
    c.title   AS course_name,
    e.enrolled_at
FROM enrollments e
JOIN users u ON e.user_id = u.id
JOIN courses c ON e.course_id = c.id
ORDER BY e.enrolled_at DESC;"

πŸ—‘οΈ Full Reset (Wipe All Data)

# Wipe PostgreSQL
docker exec -it edtech-platform-db psql -U edtech_user -d edtech_db \
  -c "TRUNCATE users, courses, lessons, enrollments RESTART IDENTITY CASCADE;"

# Wipe Redis
docker exec -it edtech-platform-redis redis-cli FLUSHALL

⚠️ Irreversible. Use only in development or staging environments.


CI/CD Pipeline

Built with GitHub Actions, Docker, and Trivy security scanning.

auto-pr-merge.yml β€” push to dev

flowchart LR
    A[Push to dev] --> B[πŸ” Lint]
    B --> C[πŸ§ͺ Test]
    C --> D[πŸ”€ Auto PR]
    D --> E[βœ… Merge to main]
Loading

docker.yml β€” push to docker

flowchart LR
    A[Push to docker] --> B[🐳 Docker Build]
    B --> C[πŸ›‘οΈ Trivy Scan]
    C --> D[πŸ”€ Auto PR]
    D --> E[βœ… Merge to main]
Loading

release.yml β€” git tag v1.0.0

flowchart LR
    A[git tag v1.0.0] --> B[🐳 Docker Build]
    B --> C[πŸ“¦ Push to Docker Hub]
    C --> D[βœ… lumina-learning:v1.0.0]
Loading

Observability

The platform includes a comprehensive observability stack built with Prometheus, Grafana, and industry-standard exporters to monitor system health, metrics, and performance in real-time.

What's Included

Component Purpose Port
Prometheus Metrics scraping and time-series database 9090
Grafana Visualization & dashboard creation 3001
cAdvisor Container metrics (CPU, memory, network) 8080
Redis Exporter Redis performance and key statistics 9121
Node Exporter Host-level system metrics (disk, CPU, memory) 9100

Architecture

Exporters (cAdvisor, Redis, Node) 
        ↓
  Prometheus (Scrapes every 15s)
        ↓
  Grafana (Visualizes & Alerts)
        ↓
   Dashboards & Analytics

Grafana Dashboards

The platform comes pre-configured with Grafana dashboards for:

  • System Health β€” CPU, memory, disk usage
  • Container Metrics β€” Application container performance
  • Redis Monitoring β€” Key counts, memory usage, command latency
  • Application Uptime β€” Service availability and response times

πŸ“Š Grafana Dashboard

Grafana Monitoring

Real-time monitoring dashboards showing system metrics, container performance, and application health powered by Prometheus.

πŸ’Ύ Redis Metrics

Redis Exporter Metrics

Redis exporter providing detailed metrics including key counts, memory consumption, command latency, and eviction statistics.

Accessing the Dashboards

  1. Prometheus (raw metrics): http://localhost:9090
  2. Grafana (dashboards): http://localhost:3001
    • Default credentials: admin / admin
    • Pre-configured datasource: Prometheus (http://prometheus:9090)

Prometheus Configuration

Prometheus scrapes metrics every 15 seconds from the following targets:

# Prometheus β†’ Targets
- localhost:9090        # Prometheus itself
- edtech-cadvisor:8080  # Container metrics
- edtech-redis-exporter:9121   # Redis stats
- edtech-node-exporter:9100    # Host metrics

Configuration file: observability/prometheus.yml

AI Log Analyzer

The platform includes an AI-powered sidecar container that watches Docker logs in real time, detects errors, and sends an instant analysis to Slack β€” with zero changes to the application source code.

How It Works

flowchart TD
    A[edtech-platform-app] -->|stdout/stderr| B[Docker Log Stream]
    B -->|watched by| C[ai-analyzer sidecar]
    C --> D{Is it an ERROR?}
    D -->|No| E[Ignored]
    D -->|Yes| F[🧹 Sanitize Log]
    F -->|remove emails, passwords, IPs, tokens| G[Clean Log]
    G -->|send to| H[Google Gemini 2.0 Flash]
    H -->|analysis| I[πŸ”΄ Root Cause + πŸ”§ Fix + πŸ’‘ Code]
    I --> J[πŸ“¨ Slack Alert]
    I --> K[Docker Logs]
Loading

Sidecar Container Architecture

Docker Compose Stack
β”œβ”€β”€ edtech-platform-app     ← app
β”œβ”€β”€ edtech-platform-db      ← PostgreSQL
β”œβ”€β”€ edtech-platform-redis   ← Redis
└── edtech-ai-analyzer      ← sidecar (reads app logs via docker.sock)
        β”‚
        β”œβ”€β”€ Mounts: /var/run/docker.sock  (read-only access to Docker logs)
        β”œβ”€β”€ No ports exposed
        └── No changes to app container needed

Privacy β€” Log Sanitization

Before any log is sent to Gemini, all sensitive data is automatically stripped:

Data Before After
Emails [email protected] [EMAIL]
DB URLs postgresql://user:pass@host postgresql://[REDACTED]
Redis URLs redis://:secret@host redis://[REDACTED]
Session IDs sess:abc123xyz sess:[REDACTED]
JWT tokens eyJhbGci... [JWT]
IP addresses 192.168.1.105 [IP]
API keys AIzaSyD8x... [SECRET]

Gemini only ever sees the error type and stack trace β€” never real credentials or user data.

Slack Alert

Slcak Alert

Setup

Add to .env:

GEMINI_API_KEY=your_key_here        
SLACK_WEBHOOK_URL=your_webhook_here 

View analyzer logs:

docker logs edtech-ai-analyzer

Contributing

This is a personal learning project, but PRs and suggestions are always welcome!

  1. Fork the repository
  2. Create your feature branch: git checkout -b feature/your-feature-name
  3. Commit your changes: git commit -m 'feat: describe your change'
  4. Push to the branch: git push origin feature/your-feature-name
  5. Open a Pull Request

Please follow Conventional Commits for all commit messages.


Vibe coded with curiosity. Built with real-world patterns. Broken many times. Fixed every time. πŸ’œ

Lumina Learning Β· Report a Bug Β· Request a Feature

⚠️ This is a learning/practice project. Not affiliated with luminalearning.com

About

πŸŽ“ A vibe-coded full-stack EdTech platform built with React 19, Express, PostgreSQL & Redis. Features custom Redis session store, Docker hardening & real-time search. Learning project only.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors