Studyland is a full-stack, real-time social study platform designed to help users track their study hours, analyze their performance, and study alongside friends in virtual rooms.
Built with a focus on Clean Architecture utilizing Vertical Slices and Domain-Driven Design (DDD) principles, it leverages the power of .NET 9 for a robust backend and React 19 for a high-performance, responsive frontend.
Live URL: studyland.rufususmle.com
To immediately explore the real-time features and architecture of the platform, use the dedicated demo account:
- Email:
demo@example.com - Password:
demouser
The solution follows a strict Clean Architecture approach, further organized by Vertical Slices within the Application layer. This ensures that all logic related to a specific feature (e.g., "Sessions") is cohesive and easy to maintain.
Domain: The core of the application. Contains enterprise logic and entities (User,Session,Topic) with zero external dependencies.Application: Implements business logic using CQRS (Command Query Responsibility Segregation) via MediatR.- Vertical Slices: Features are organized by domain area, keeping related logic together.
- Behaviors: Cross-cutting concerns like Validation are handled via MediatR Pipeline Behaviors.
Persistence: Implements database access using Entity Framework Core with SQL Server.API: The entry point, containing minimal controllers that delegate execution immediately to MediatR.
- Real-time Presence: Users can instantly track the status of friends (Studying, On Break) via a high-performance, in-memory SignalR Presence System.
- Advanced Analytics: Tracks study sessions by topic and time, generating robust analytics for personalized dashboard insights.
- Full-Stack Type Safety: Utilizes auto-generated API clients and type-safe SignalR wrappers to ensure zero-tolerance for contract drift between C# and TypeScript/React.
One of the project's core philosophies is eliminating "magic strings" and runtime errors through rigorous type safety across the full stack.
The API endpoints return DTOs with precise annotations. We utilize the OpenAPI specification generated by the backend to automatically build the frontend client.
- Tooling:
openapi-typescript-codegenscans the live Swagger/OpenAPI JSON. - Benefit: This generates a fully typed Axios client for React. If a DTO property changes in C#, the frontend build will fail immediately, guaranteeing perfect synchronization between backend and frontend.
Standard SignalR calls like hub.invoke("MethodName") are error-prone. I implemented a generic TypeScript wrapper to enforce type safety on real-time events.
- Implementation: By defining interfaces for
ServerToClientEventsandClientToServerEvents, the wrapper ensures that you can only invoke methods that actually exist on the Hub, with the correct payload types.
One of the most complex parts of Studyland is managing the real-time state of users (Online, Studying, On Break) without overloading the database. This is achieved through a sophisticated in-memory state machine supported by background workers.
This service acts as the source of truth for all active WebSocket connections.
- Connection Mapping: It maintains concurrent dictionaries to map
ConnectionId↔UserId↔ChannelId. - State Management: When a user joins, their profile is fetched from the DB once and cached. Subsequent updates mutate this in-memory state, ensuring O(1) performance.
On the frontend, complex real-time logic is abstracted into custom hooks like usePressence.
- Role: Manages the subscription to SignalR events and synchronizes local React state with the server's in-memory presence list, keeping UI components declarative.
To maintain data integrity and automate state transitions, two IHostedService jobs run in the background:
ZombieSessionsKiller: This job runs periodically to identify "orphaned" connections (users with no active SignalR socket) and cleanly removes them or stops their study session, ensuring accurate room listings.StudyTimerMonitor: This job scans the in-memory state for expired timers. It automatically transitions users from "Studying" to "On Break" and broadcasts the update to the room, ensuring synchronized timer states for all peers.
The frontend is designed to be beautiful, responsive, and app-like.
- Stack: Built with Shadcn UI and Tailwind CSS for a modern, accessible, and clean aesthetic.
- Animations: Utilizes Framer Motion for smooth transitions and interactive feedback.
- PWA (Progressive Web App): The application is fully optimized to run on all devices. It is installable and responsive, providing a native mobile app experience directly from the browser.
To keep validation logic readable and expressive, custom extension methods were built for FluentValidation.
.Required(): A shorthand that combines.NotEmpty()with a standardized error message format..MustExistInDb<T>: A powerful generic extension that validates foreign keys. It takes a genericDbSet<T>and automatically performs an asynchronousAnyAsynccheck against the database.
Example Usage:
// Inside CreateSession.Validator
RuleFor(x => x.UserId)
.Required()
.MustExistInDb(context.Users); // Automatically checks DB and returns 404-style error if missingCurrent Status: Manual Testing Only
While the architecture (Clean Architecture + CQRS) is specifically designed to support rigorous Unit and Integration testing (by decoupling logic from infrastructure), no automated tests are currently implemented in this repository.
- Context: As a solo developer optimizing for speed and feature delivery, I adopted a pragmatic approach, relying on manual testing to verify features.
- My Stance: I deeply believe in the value of TDD and automated testing for long-term project health. In my commercial SaaS product (Rufus USMLE), I employed extensive unit testing (Jest) to ensure the reliability of critical exam engines.
- Future Work: In a professional team setting, adding a test project to cover the MediatR handlers and Domain logic would be my first priority.
To run this project locally, start by cloning the repository:
git clone https://github.com/WaseemAldemeri/Studyland.git
cd StudylandYou can then run the application using either method below.
This method only requires Docker to be installed and handles the database, backend, and frontend containers automatically.
Run the entire stack with one command from the project root (/Studyland):
# Run via Docker Compose
docker compose -f docker-compose.prod.yml up --build -dOnce the containers are running, navigate to the frontend: http://localhost:3000
You can immediately log in to the application using the seeded demo user:
- Email:
demo@example.com - Password:
demouser
This method requires Node.js and the .NET 9 SDK to be installed on your machine.
1. Database Install Sql server locally or run the database only using Docker:
docker compose up -d2. Backend Setup & Run Navigate to the backend folder, restore dependencies, and run the API. The app will automatically apply migrations and seed data on startup.
cd backend/API
dotnet restore
dotnet watch run3. Frontend Setup & Run Open a new terminal window, navigate to the frontend folder, install dependencies, and start the development server.
cd frontend
npm install
npm run devThis project is released under the MIT License.

