Building FocusHub: My Deep Dive Into Real-Time Django, WebSockets & Productivity Design

A breakdown of the journey building FocusHub—a real-time virtual study room platform with live chat, Pomodoro sessions, lo-fi music, and gamified study tracking—powered by Django, PostgreSQL, Channels, and Render.

Published on: July 1, 2025

FocusHub Preview

Building FocusHub wasn’t a weekend hack project—it was an end-to-end crash course in designing production-ready web apps with real-time components. From setting up Django Channels to deploying WebSocket-enabled apps on Render, I hit every wall, fought every 403, and learned more in 3 weeks than most textbooks could teach in a semester.

This post walks through what I built, how it works, and what it taught me.

🎯 What is FocusHub?

FocusHub is a virtual productivity space where users can:

  • Join real-time study rooms and chat with others via WebSockets
  • Use a Pomodoro timer to track sessions
  • Listen to lo-fi music embedded from curated static tracks
  • Rate their productivity via session-end prompts & visual dashboards
  • View session history, notes, and time breakdowns
  • Track weekly study progress and heatmaps

🔧 Major Features and How They Work

💬 Real-Time Study Rooms (Django Channels + ASGI)

This was my first dive into ASGI with Django for WebSockets. Traditional WSGI just wouldn’t cut it.

  • Used Daphne instead of Gunicorn
  • Set up rooms.routing for WebSocket logic
  • Chat functionality via channel layers and async consumers

Lesson: ASGI needs a whole different setup—`asgi.py`, middleware, routing—debugging async stack traces was brutal but worth it.

⏲️ Pomodoro Timer & Session Logs

Each session is logged with a model tracking start and end time, auto-calculating duration. The timer frontend syncs with backend logs.

Lesson: I nearly cried over “False min” showing up in the dashboard—fixed it with a clean `@property` decorator and proper `total_seconds()` handling.

🎵 Lo-fi Music Integration

  • Static MP3 tracks served from assets
  • Used WhiteNoise for static file serving on Render
  • Fixed a bunch of 404s from incorrect paths

Lesson: Never forget to configure `STATICFILES_DIRS`, `STATIC_ROOT`, and run `collectstatic`. Ever.

🧠 Gamified Productivity Ratings

  • Streak tracking and session streaks
  • Leaderboards for most productive rooms and users
  • Study consistency visualized via heatmaps
  • Weekly stats: hours, session counts, and durations

Lesson: Little visual nudges (like streak counters) go a long way in engagement and habit-building.

📊 Recent Sessions Timeline

The dashboard shows your most recent sessions including room title, duration, and notes—great for accountability.

🏗️ The Deployment Journey (aka The Struggles)

  • ModuleNotFoundError: app – from Render’s default `gunicorn app:app`
  • 404s from missing collectstatic
  • web: command not found – due to `web:` in `startCommand`
  • 403 CSRF – fixed with `CSRF_TRUSTED_ORIGINS`
  • auth_user does not exist – forgot `migrate` 🤦‍♂️
  • No predeploy scripts – so I hacked migrate into `asgi.py`

Lesson: Render’s free tier is amazing but has limitations. You learn dirty deployment hacks fast—and that’s a superpower in itself.

🧠 Tech Stack

  • Frontend: HTML, TailwindCSS, JS
  • Backend: Django, Channels, PostgreSQL
  • Real-Time: ASGI, Daphne, WebSockets
  • Hosting: Render (free tier)
  • Static Files: WhiteNoise

💡 Final Thoughts

This project made me appreciate how much goes into building even a “simple” platform. From backend logic to UI to deployment and devops—everything matters.

You can try the live site 👉 FocusHub

Or check out the code on GitHub (or DM me on LinkedIn).

— Rohit