๐จโ๐ซ Week 1 of Building Edly: Schemas, Structure, and Smart Choices

Every big product starts with a small step โ this week, I took mine.
Welcome to Week 1 of building Edly, a full-stack online course platform focused on giving educators their own branded subdomains (like anmol.edly.com
) and complete autonomy over their content.
๐ Introduction
As a passionate developer focused on solving real problems, I started building a full-stack scalable learning platform where educators can create their own branded subdomains, manage courses, and monetize their knowledge. The goal was simple:
Let any educator/creator launch their own mini version of Udemy โ fully controlled, fully branded, and scalable โ without the need to build a platform from scratch.
This series of blogs will be a full documentation of my technical journey: every decision I made, why I made it, what alternatives I considered, where I struggled, and what I learned.
๐ง The Problem I Wanted to Solve
Many educators want to build branded learning platforms with:
Subdomains (e.g.,
anmol.edly.com
)Control over content
Built-in monetization
Certificate issuing
Analytics
But existing solutions like Udemy, etc., don't offer true autonomy. So I envisioned a centralized platform (like Shopify for learning) that gives individual educators their own admin control and learning environment under subdomains.
๐ง Phase 1: Architecting the System
I decided to start with the MERN stack:
MongoDB: Flexible schema โ perfect for course/content hierarchy.
Express.js + Node.js: Lightweight and scalable backend.
React.js (Coming soon): Dynamic UI for student and educator interfaces.
Subdomains architecture: Each educator has a unique space like
anmol.edly.com
.
๐งฉ Why MongoDB?
Schema flexibility: Each course has modules โ modules have lessons/pdfs/quizzes.
Easy to embed related structures or reference them for performance.
Designed for read-heavy platforms with document-based content.
๐ Deciding Between Monolith vs. Microservices
Although microservices seem attractive for scalability, I stuck with a monolithic architecture for Phase 1 due to:
Faster iteration
Easier debugging
No infrastructure overhead
In the future, once I hit scale, I can break services like auth
, content
, and analytics
into microservices.
๐ Phase 2: Setting Up Educator Onboarding & Authentication
I started with the educator flow first:
/register
: Register an educator with a subdomain and basic profile./login
: Log in to access the dashboard./onboarding
: A simple form to collect organization details, bio, etc.
๐งฑ Educator Schema
const educatorSchema = new mongoose.Schema({
firstName: String,
lastName: String,
emailId: { type: String, unique: true },
password: String,
subdomain: { type: String, unique: true },
bio: String,
organization: String,
});
I chose to assign a unique
subdomain
per educator. Later, this will help me configure dynamic routing or proxy setups for subdomains likeanmol.edly.com
.
๐ Auth Controller
JWT-based auth
Middleware to attach
req.user
Only logged-in users can create courses, modules, content
๐ฆ Phase 3: Designing Course โ Module โ Content Hierarchy
This was a major design decision. I explored multiple options and faced a few challenges:
Option 1: Nest Everything (Embed modules & lessons inside course)
โ
Simple, easy access
โ Hard to update independently
โ Inflexible for future analytics
Option 2: Normalize Everything (Separate models + references)
โ
Scalable
โ
Easily update lessons, modules
โ
Trackable analytics
โ
Works well with subdomain filtering
๐ง I chose Option 2. Hereโs the architecture:
Course
: created by educatorModule
: belongs to a courseContent
: contains either a video lesson, PDF, or quizContent items are referenced with a flexible field
๐ Models I Created
๐ Course
title, description, thumbnail, price,
aboutCourse (6 paragraphs),
highlights (5 one-liners),
educatorId (ref)
๐ Module
title,
courseId (ref),
content: [ { type: 'lesson' | 'pdf' | 'quiz', refId } ],
๐ Content Models (Separate for clarity)
Lesson:
- title, videoUrl, moduleId
PDF:
- title, pdfUrl, moduleId
Quiz:
- title, questions[], moduleId
๐ Controllers Created
courseController.js
moduleController.js
lessonController.js
pdfController.js
quizController.js
Each one has:
create
delete
For modules, an
updateModuleContent
to add new lessons/pdfs/quizzes in sequence
โ Lesson of the Day: Maintain Sequence
I struggled a bit with how to store content in a proper order.
Solution: A
content[]
array inside Module withtype + refId
pattern. This lets me maintain the order as they were added by the educator.
๐ Problem I Encountered
โ โHow will students know which courses they can access?โ
โ
Solution: On course creation, I store educatorId
โ then during API calls, filter based on the logged-in educator.
โ โHow do I maintain modularity for updates?โ
โ Solution: Normalize everything. Independent models make it easy to update/delete without touching the parent document.
โ โShould I use MongoDBโs default _id
or custom IDs?โ
โ
Used MongoDBโs _id
โ theyโre unique, indexed, and scalable.
๐ Future Scope ( Coming Soon)
Student flows: registration, enroll in course, access content
Doubt engine: raise questions, educators reply
Live class integration (e.g., Jitsi/Zoom APIs)
Subdomain handling with reverse proxy (e.g., Nginx/Express middleware)
Payment system: Stripe integration
Certificate issuing engine
Dashboards for educators: analytics, earnings, student behavior
๐ What I Learned
Donโt over-engineer early โ monolith was the right choice.
MongoDB gives you enough flexibility but use references smartly.
Auth flow is key to controlling access and visibility.
Always think about "who can see/edit what?" while building APIs.
Document your journey โ helps you reflect, debug, and share.
โจ Final Thoughts
This journey is not just about building a project โ itโs about design thinking, problem-solving, and developing a mindset for scale. By carefully choosing the right architecture and anticipating future needs, Iโve laid the foundation for a powerful learning platform.
Iโll be uploading a new blog every Wednesday as I continue building this platform, until the project is complete. Each post will dive deeper into key features, tech decisions, and lessons learned along the way.
If you're an aspiring full-stack developer โ remember:
Start simple. Validate. Iterate. Scale.
๐ Connect with Me
If you found this helpful or have feedback, connect with me on GitHub or Linkedin.
Stay tuned for the next blog โ where Iโll build out the student-side APIs and begin rendering content dynamically via React. ๐
Subscribe to my newsletter
Read articles from Anmol Khatri directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
