Skip to content

Codergrounds is a real-time collaborative coding playground featuring a live Monaco editor, peer programming capabilities, and a self-hosted code execution pipeline. Built with React, Express, Socket.io, PostgreSQL, and Docker

Notifications You must be signed in to change notification settings

devnadeemashraf/codergrounds-backend

Repository files navigation

@codergrounds/backend

The backend API and WebSocket server for Codergrounds. Built with Express.js and TypeScript, following a Simplified Layered Architecture with Dependency Injection.

🏗️ Architecture

This project follows a Simplified Layered Architecture that balances structure with pragmatism. Unlike traditional MVC or over-engineered Clean Architecture, this approach provides clear boundaries while remaining maintainable and scalable.

Architecture Overview

The architecture is organized into three main layers:

  1. core/ - Framework-agnostic business logic (use cases, interfaces)
  2. infra/ - Framework-specific implementations (Express, database, cache)
  3. shared/ - Pure utilities (no business logic, no framework dependencies)

Folder Structure

src/
├── core/                           # Framework-agnostic business logic
│   ├── interfaces/                 # Contracts (interfaces for dependencies)
│   │   ├── repositories/           # Repository interfaces
│   │   ├── services/               # Service interfaces (if needed)
│   │   └── cache/                  # Cache interfaces
│   └── useCases/                   # Business logic (one use case per action)
│       ├── auth/                   # Authentication use cases
│       ├── user/                   # User management use cases
│       └── playground/             # Playground use cases
│
├── infra/                          # Framework-specific implementations
│   ├── database/                   # Database connection & repositories
│   ├── cache/                      # Cache implementations (Redis)
│   ├── http/                       # Express-specific code
│   │   ├── controllers/            # Thin controllers (HTTP handling only)
│   │   ├── routes/                 # Route definitions
│   │   └── middlewares/            # Express middlewares
│   ├── mappers/                    # Data transformation (DB → Domain)
│   └── realtime/                   # WebSocket/Socket.io setup
│
├── shared/                         # Pure utilities
│   ├── types/                      # TypeScript types and interfaces
│   ├── errors/                     # Custom error classes
│   ├── utils/                      # Pure utility functions
│   ├── decorators/                 # TypeScript decorators
│   ├── hofs/                       # Higher-order functions
│   └── logger/                     # Logger instance
│
├── config/                         # Configuration files
├── container.ts                    # Dependency injection setup
├── app.ts                          # Express app setup
├── routes.ts                       # Route aggregator
└── index.ts                        # Server entry point

Key Principles

  1. Separation of Concerns: Each layer has a clear responsibility
  2. Dependency Inversion: Core depends on abstractions (interfaces), not implementations
  3. Framework Independence: Core layer can be tested without Express or database
  4. Single Responsibility: One use case = one business action
  5. DRY: No duplicate implementations

Dependency Flow

index.ts → app.ts → routes.ts
    ↓
infra/http/ (routes → controllers → useCases)
    ↓
core/useCases/ (business logic, uses interfaces)
    ↓
infra/database/repositories/ (implements interfaces)

Dependency Rules:

  • core/ → Can import shared/
  • infra/ → Can import core/ and shared/
  • shared/ → Can only import from shared/ or external packages ✅
  • NEVER create circular dependencies

🔌 Dependency Injection

This project uses tsyringe for Dependency Injection, providing:

  • Testability: Easy to mock dependencies
  • Flexibility: Swap implementations without changing code
  • Maintainability: Clear dependency relationships

How It Works

  1. Interfaces define contracts in core/interfaces/
  2. Implementations live in infra/
  3. Registration happens in container.ts
  4. Resolution uses tokens from shared/utils/container.utils.ts

Example

// 1. Define interface
interface UserRepositoryInterface {
  findById(id: string): Promise<User>;
}

// 2. Implement interface
class UserRepository implements UserRepositoryInterface { ... }

// 3. Register in container.ts
container.register<UserRepositoryInterface>(
  ContainerTokens.userRepository,
  { useClass: UserRepository }
);

// 4. Use in use case
@injectable()
class LoginUseCase {
  constructor(
    @inject(ContainerTokens.userRepository)
    private userRepo: UserRepositoryInterface
  ) {}
}

⚡ Key Technologies

  • Express.js: REST API framework
  • Socket.io: Real-time collaboration and chat
  • Zod: Runtime validation (schemas shared with frontend)
  • PostgreSQL: Primary data store
  • Redis: Session store, caching, and BullMQ job queues
  • tsyringe: Dependency Injection container
  • TypeScript: Type-safe development

📜 Scripts

  • pnpm dev: Start development server with watch mode
  • pnpm build: Compile TypeScript to dist/
  • pnpm test: Run unit and integration tests via Vitest
  • pnpm lint: Lint code with ESLint
  • pnpm migrate:create <name>: Create a new migration file (e.g., pnpm migrate:create add-user-avatar)
  • pnpm migrate:up: Run database migrations
  • pnpm migrate:down: Rollback database migrations
  • pnpm seed: Seed database with development data

🚀 Getting Started

  1. Install dependencies: pnpm install
  2. Set up environment variables: Copy .env.example to .env and configure
  3. Run migrations: pnpm migrate:up
  4. Seed database (optional): pnpm seed
  5. Start development server: pnpm dev

📝 API Versioning

All API routes are versioned under /api/v1/

About

Codergrounds is a real-time collaborative coding playground featuring a live Monaco editor, peer programming capabilities, and a self-hosted code execution pipeline. Built with React, Express, Socket.io, PostgreSQL, and Docker

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published