← Back to Portfolio
Senior Backend Engineer / Lead Backend Developer

Designing Modular Backend Services for a B2B Learning Platform

NestJS TypeScript PostgreSQL MongoDB RabbitMQ Docker AWS GitHub Actions Grafana Loki Jest Swagger

Overview

I worked on the backend of a B2B learning platform that evolved into a multi-tenant and whitelabel SaaS system. As the platform grew, the backend needed to support more product areas, including learning workflows, user management, access control, reporting, assessments, subscriptions, integrations, and internal tools.

My responsibility was to help design, build, and maintain modular backend services that could support product growth while keeping the system understandable and maintainable for the engineering team.

Problem

As more features were added, the main challenge was avoiding a backend structure where too many responsibilities were mixed together.

Without clear service boundaries, several risks could appear:

  • Business logic becoming harder to locate, change, and review.
  • API behavior becoming inconsistent across product areas.
  • New developers needing too much full-system context before making changes.
  • Product requirements creating unclear ownership between backend services.
  • Future changes becoming slower because of tightly coupled implementation.

The goal was not simply to use microservices, but to make the backend modular in a practical way without adding unnecessary distributed-system complexity.

My Role

I worked as a Senior Backend Engineer / Lead Backend Developer with a hands-on role in backend design, implementation, and team delivery.

I helped define service responsibilities, database structures, API contracts, inter-service communication patterns, and implementation plans. I also supported PRD review, technical task breakdown, code reviews, technical discussions, and backend coding standards.

Part of my role was helping developers understand not only what needed to be built, but also where the logic should belong within the backend architecture.

Approach

The backend was organized around business capabilities rather than only technical layers. Services were separated based on functional ownership, such as user and organization management, learning workflows, access control, reporting, assessments, subscription-related processes, integrations, and internal operational tools.

For new features, I usually started by reviewing the product requirement and identifying which service should own the main logic. From there, I helped define the database model, API contract, implementation scope, and expected integration points with other services.

The approach was intentionally pragmatic. We avoided creating too many small services too early because that could increase operational overhead, deployment coordination, and debugging complexity. Service boundaries were introduced where separation made the system easier to maintain, reason about, or extend.

Swagger/OpenAPI documentation was used to make request and response behavior clearer for frontend and backend collaboration. This helped reduce ambiguity before implementation and made API behavior easier to review during development.

Where synchronous API calls were sufficient, the implementation stayed simple. For workflows that did not need to complete within a single request-response cycle, RabbitMQ was used to decouple processing and avoid forcing all work into synchronous flows.

Shared logic was handled carefully. Common patterns and standards were kept clear, but each service still owned its core business logic to avoid unnecessary coupling.

Impact

This work helped make backend service ownership clearer during feature planning and implementation.

Clearer service boundaries and API contracts made it easier for developers to understand where new logic should belong, how modules should interact, and what behavior frontend teams could expect from backend APIs.

The modular approach helped reduce unnecessary coupling between product areas, making future backend changes easier to reason about and review.

Code reviews, technical discussions, task breakdowns, and shared backend standards helped keep implementation more consistent across services.

Overall, the work contributed to a backend structure that could support continued product growth while remaining maintainable for the engineering team.