Module Structure

Last Updated: May 19, 2025

This document describes the module structure and patterns used in the Typus Development Framework backend.

Overview

The backend of the Typus Development Framework is organized into modules, each responsible for a specific domain or feature. This modular architecture promotes separation of concerns, code reusability, and maintainability.

Modules are self-contained units that encapsulate related functionality, including API endpoints, business logic, data access, and validation. Each module follows a consistent structure and pattern, making it easy to understand and extend.

Automatic Module Registration

One of the key features of the Typus Development Framework is the automatic registration of modules. Modules are discovered and loaded dynamically at application startup, eliminating the need for manual registration. This is achieved through:

  1. Decorator-based registration: Modules, controllers, services, and repositories are annotated with decorators that register them with the dependency injection container.
  2. Dynamic module loading: The application scans the modules directory and loads modules based on the configuration in config/modules.config.ts.
  3. Dependency resolution: Dependencies between modules are automatically resolved by the dependency injection container.

This automatic registration system simplifies the development process and reduces boilerplate code, allowing developers to focus on implementing business logic rather than configuring the application.

Module Architecture

The module architecture follows a layered approach, with clear separation between different responsibilities:

Module

Controller Layer

Service Layer

Repository Layer

Validation Layer

Routes

Middleware

Business Logic

Error Handling

Data Access

Data Transformation

Validation Schemas

Data Transfer Objects

Directory Structure

Each module follows a standardized directory structure:

modules/feature/
├── FeatureModule.ts       # Module definition
├── index.ts               # Module exports
├── controllers/           # API controllers
│   └── FeatureController.ts
├── services/              # Business logic
│   └── FeatureService.ts
├── repositories/          # Data access (optional)
│   └── FeatureRepository.ts
├── validation/            # Request validation (optional)
│   └── featureSchemas.ts
├── dto/                   # Data transfer objects (optional)
│   └── FeatureDto.ts
└── dsl/                   # DSL models (optional)
    └── feature.model.ts

Module Components

Module Class

The module class is the entry point for the module. It extends BaseModule and is responsible for:

  • Defining the module's base path
  • Initializing controllers and services
  • Setting up routes
  • Configuring middleware
  • Implementing module-specific initialization logic

Controller

Controllers handle HTTP requests and responses. They extend BaseController and are responsible for:

  • Defining API endpoints
  • Validating request data
  • Calling service methods
  • Formatting responses

Service

Services implement business logic. They extend BaseService and are responsible for:

  • Implementing domain logic
  • Handling data operations
  • Managing transactions
  • Throwing typed errors for exceptional conditions

Repository (Optional)

Repositories handle data access. They extend BaseRepository and are responsible for:

  • Implementing CRUD operations
  • Handling data transformation
  • Managing database-specific logic

Validation Schemas

Validation schemas define the structure and constraints for request data. They use Zod for schema validation.

Custom Logic Implementation

All custom business logic in the Typus Development Framework is implemented through modules. This approach ensures that:

  1. Separation of concerns: Each module is responsible for a specific domain or feature.
  2. Encapsulation: Module internals are hidden from other modules, promoting loose coupling.
  3. Testability: Modules can be tested in isolation.
  4. Reusability: Common functionality can be extracted into shared modules.
  5. Maintainability: Changes to one module do not affect other modules.

By implementing custom logic through modules, the framework provides a consistent and scalable approach to application development. Developers can focus on implementing business requirements without worrying about the underlying infrastructure.

Decorator-Based Architecture

The framework uses decorators to simplify component registration and configuration:

Module Decorator

@Module({ path: 'feature' })
export class FeatureModule extends BaseModule {
  // Module implementation
}

Controller Decorator

@Controller({ path: 'features' })
export class FeatureController extends BaseController {
  // Controller implementation
}

Service Decorator

@Service()
export class FeatureService extends BaseService {
  // Service implementation
}

Repository Decorator

@Repository()
export class FeatureRepository extends BaseRepository<Feature> {
  // Repository implementation
}

These decorators automatically register components with the dependency injection container, eliminating the need for manual registration.

Route Definition

Routes are defined in the module's initializeRoutes method, which sets up the API endpoints for the module. The framework provides built-in support for:

  • HTTP method handlers (GET, POST, PUT, DELETE, etc.)
  • Middleware integration (authentication, validation, etc.)
  • Parameter validation
  • Response formatting

Authentication and Authorization

Authentication and authorization are handled through middleware provided by the BaseModule class:

  • Authentication middleware ensures that requests are authenticated
  • Role-based authorization middleware restricts access based on user roles
  • Permission-based authorization middleware restricts access based on user permissions

Validation

Request validation is handled through middleware provided by the BaseController class, which uses Zod schemas to validate request data.

Error Handling

The framework uses a centralized error handling approach with typed errors, which are automatically converted to appropriate HTTP responses.

Dependency Injection

The framework uses the tsyringe container for dependency injection, which automatically resolves dependencies between components.

Module Communication

Modules can communicate with each other through dependency injection, allowing for loose coupling between modules.

Module Extension

Modules can be extended by adding new components or modifying existing ones, providing a flexible approach to application development.

Best Practices

Module Design

  1. Single Responsibility: Each module should focus on a specific domain or feature
  2. Clear Boundaries: Define clear boundaries between modules
  3. Minimal Dependencies: Minimize dependencies between modules
  4. Consistent Structure: Follow the standard module structure
  5. Descriptive Naming: Use descriptive names for modules, controllers, services, etc.

Controllers

  1. Thin Controllers: Keep controllers thin, focusing on request/response handling
  2. Validation: Always validate request data
  3. Error Handling: Let the framework handle errors
  4. Response Formatting: Use the standard response methods

Services

  1. Business Logic: Put all business logic in services
  2. Typed Errors: Use typed errors for exceptional conditions
  3. Transactions: Use transactions for operations that modify multiple records
  4. Logging: Log important operations and errors

Repositories

  1. Data Access: Put all data access logic in repositories
  2. Reusable Queries: Create reusable query methods
  3. Data Transformation: Handle data transformation in repositories
  4. Logging: Log database operations

Validation

  1. Comprehensive Schemas: Define comprehensive validation schemas
  2. Reusable Schemas: Create reusable schema components
  3. Clear Error Messages: Provide clear error messages
  4. Type Inference: Use type inference for DTOs

Conclusion

The module structure and patterns used in the Typus Development Framework provide a solid foundation for building scalable, maintainable, and extensible applications. By following these patterns, developers can create consistent modules that integrate seamlessly with the framework.

The automatic registration system, combined with the decorator-based architecture, reduces boilerplate code and allows developers to focus on implementing business logic. The clear separation of concerns between controllers, services, and repositories promotes code reusability and maintainability.

WARNING

Failed to fetch dynamically imported module: https://typus.dev/assets/RecursiveNavItem-Cep7andh.js

{ "stack": "AppError: Failed to fetch dynamically imported module: https://typus.dev/assets/RecursiveNavItem-Cep7andh.js\n at https://typus.dev/assets/index-DS79FI73.js:315:420\n at dn (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:13:1385)\n at We (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:13:1455)\n at Ws.t.__weh.t.__weh (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:14:7364)\n at jt (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:13:1866)\n at v (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:14:4019)\n at https://typus.dev/assets/vue-vendor-Ct83yDeK.js:14:4097" }