Skip to main content

Core Architectural Layers

3.1 Controllers (Express + routing-controllers)

  • What: Expose REST endpoints and map incoming requests to service calls.
  • Where: src/modules/<module>/controllers/*.ts
  • Key Roles:
    • Parse and validate input via class-validator.
    • Delegate to Services.
    • Format and send HTTP responses (standard codes and payloads).

Why? Decorator-driven routing (e.g. @Get, @Post) keeps routing definitions close to handler logic, improving readability and reducing boilerplate.

3.2 Services (Business Logic)

  • What: Encapsulate all business rules, orchestration, and cross-repository workflows.
  • Where: src/modules/<module>/services/*.ts
  • Key Roles:
    • Transactional operations spanning multiple repositories.
    • Input sanitization and domain validation.
    • Integration with third-party systems (e.g., Firebase, Sentry, GenAI SDK).

Why? Centralizing logic in Services prevents Controllers from becoming fat and simplifies unit testing by isolating business behaviors.

3.3 Repositories (Data Access)

  • What: Abstract MongoDB CRUD operations behind domain-specific methods.
  • Where: src/modules/<module>/repositories/*.ts
  • Key Roles:
    • Define entity schemas and indexes.
    • Provide methods like findById, create, update, delete, and advanced queries.
    • Manage sessions for transactional writes.

Why? The repository pattern decouples database concerns from business logic, making it easier to swap implementations or mock data stores in tests.

3.4 Dependency Injection (InversifyJS)

  • What: Automatically wire Controllers, Services, and Repositories together using injectable symbols.
  • Where: src/container.ts, plus types.ts for symbol definitions.
  • Why? DI promotes loose coupling, enables easy mocking for tests, and enforces clear contract boundaries between layers.