Backend Architecture
The Ever Gauzy backend is built on NestJS, a progressive Node.js framework for building efficient, scalable server-side applications using TypeScript.
NestJS Foundationโ
NestJS provides the architectural backbone with:
- Dependency Injection (DI) โ module-based inversion of control container
- Decorators โ declarative metadata for routes, guards, pipes, and more
- Middleware Pipeline โ composable request/response processing
- Platform Agnostic โ runs on Express or Fastify (Gauzy uses Express)
Module Organizationโ
The backend is organized into well-defined NestJS modules within packages/core/src/lib/:
Core Modulesโ
packages/core/src/lib/
โโโ auth/ # Authentication (login, register, social OAuth)
โโโ user/ # User management
โโโ tenant/ # Tenant management and onboarding
โโโ role/ # Role definitions (SUPER_ADMIN, ADMIN, EMPLOYEE, etc.)
โโโ role-permission/ # Role-permission mappings
โโโ organization/ # Organization CRUD and settings
โโโ employee/ # Employee profiles, statistics, awards
โโโ shared/ # Shared utilities, validators, base entities
โโโ core/ # Core module registration
โโโ bootstrap/ # Application bootstrapping
Feature Modulesโ
packages/core/src/lib/
โโโ time-tracking/ # Time logs, timesheets, activity tracking, screenshots
โโโ tasks/ # Task management with statuses, priorities, sizes
โโโ organization-project/ # Project management
โโโ organization-sprint/ # Sprint management
โโโ organization-project-module/ # Project modules
โโโ invoice/ # Invoice generation and management
โโโ expense/ # Expense tracking
โโโ payment/ # Payment processing
โโโ income/ # Income records
โโโ candidate/ # Applicant tracking
โโโ pipeline/ # Sales pipelines
โโโ contact/ # Contact/lead management
โโโ goal/ # Goals and objectives
โโโ goal-kpi/ # Key Performance Indicators
โโโ reports/ # Reporting and analytics
โโโ ... (148 modules total)
Infrastructure Modulesโ
packages/core/src/lib/
โโโ database/ # Database connection and configuration
โโโ graphql/ # GraphQL schema and resolvers
โโโ health/ # Health check endpoints
โโโ logger/ # Logging configuration
โโโ i18n/ # Internationalization
โโโ email-send/ # Email dispatch
โโโ email-template/ # Email templates (Handlebars)
โโโ export-import/ # Data export/import
โโโ image-asset/ # Image/file management
โโโ throttler/ # Rate limiting
โโโ event-bus/ # Event bus integration
โโโ integration/ # Third-party integration base
CQRS Patternโ
The backend extensively uses Command Query Responsibility Segregation (CQRS):
Commands (Write Operations)โ
// Command definition
export class CreateEmployeeCommand {
constructor(public readonly input: IEmployeeCreateInput) {}
}
// Command handler
@CommandHandler(CreateEmployeeCommand)
export class CreateEmployeeHandler
implements ICommandHandler<CreateEmployeeCommand>
{
constructor(private readonly employeeService: EmployeeService) {}
async execute(command: CreateEmployeeCommand): Promise<IEmployee> {
const { input } = command;
return this.employeeService.create(input);
}
}
Queries (Read Operations)โ
// Query definition
export class FindEmployeesQuery {
constructor(public readonly options: FindManyOptions<Employee>) {}
}
// Query handler
@QueryHandler(FindEmployeesQuery)
export class FindEmployeesHandler implements IQueryHandler<FindEmployeesQuery> {
constructor(private readonly employeeService: EmployeeService) {}
async execute(query: FindEmployeesQuery): Promise<IPagination<IEmployee>> {
return this.employeeService.findAll(query.options);
}
}
Controller Integrationโ
@Controller("employee")
@UseGuards(TenantPermissionGuard)
export class EmployeeController {
constructor(
private readonly commandBus: CommandBus,
private readonly queryBus: QueryBus,
) {}
@Post()
@Permissions(PermissionsEnum.EMPLOYEES_EDIT)
async create(@Body() entity: CreateEmployeeDTO): Promise<IEmployee> {
return this.commandBus.execute(new CreateEmployeeCommand(entity));
}
@Get()
@Permissions(PermissionsEnum.EMPLOYEES_VIEW)
async findAll(
@Query() options: PaginationParams,
): Promise<IPagination<IEmployee>> {
return this.queryBus.execute(new FindEmployeesQuery(options));
}
}
Guard Architectureโ
Guards enforce security at the controller level. They execute in order:
1. Authentication Guard (AuthGuard)โ
Validates the JWT token and attaches the authenticated user to the request:
@UseGuards(AuthGuard('jwt'))
The @Public() decorator bypasses authentication for specific endpoints (e.g., registration, login).
2. Tenant Permission Guard (TenantPermissionGuard)โ
Combines tenant resolution with permission checking:
- Resolves the tenant from the authenticated user
- Sets
RequestContext.currentTenantId() - Validates the user has the required permissions
@UseGuards(TenantPermissionGuard)
3. Role Guard (RoleGuard)โ
Restricts access based on user roles:
@Roles(RolesEnum.SUPER_ADMIN, RolesEnum.ADMIN)
@UseGuards(RoleGuard)
4. Permission Guard (PermissionGuard)โ
Fine-grained permission checking:
@Permissions(PermissionsEnum.EMPLOYEES_EDIT)
@UseGuards(PermissionGuard)
Guard Hierarchyโ
SUPER_ADMIN
โโโ ADMIN
โโโ DATA_ENTRY
โโโ EMPLOYEE
โโโ CANDIDATE
โโโ VIEWER
Service Layerโ
Services contain the core business logic and data access patterns:
Base Serviceโ
Most services extend CrudService<T>:
@Injectable()
export class EmployeeService extends CrudService<Employee> {
constructor(
@InjectRepository(Employee)
private readonly employeeRepository: Repository<Employee>,
) {
super(employeeRepository);
}
// CrudService provides: findAll, findOneByIdString, create, update, delete
// Custom methods add domain-specific logic
}
Tenant-Aware Servicesโ
Services extending TenantAwareCrudService automatically scope all queries by tenantId:
@Injectable()
export class ProjectService extends TenantAwareCrudService<OrganizationProject> {
// All findAll/findOne/create/update/delete operations
// are automatically filtered by the current tenant
}
Request Contextโ
The RequestContext provides a thread-safe way to access request-scoped data anywhere in the application:
// Get current tenant
const tenantId = RequestContext.currentTenantId();
// Get current user
const userId = RequestContext.currentUserId();
const user = RequestContext.currentUser();
// Get current organization
const orgId = RequestContext.currentOrganizationId();
// Get current role
const roleId = RequestContext.currentRoleId();
API Documentationโ
Swagger (OpenAPI)โ
The API automatically generates Swagger documentation:
- URL:
http://localhost:3000/swg - JSON Spec:
http://localhost:3000/swg-json - API Docs (Compodoc):
http://localhost:3000/docs
API Versioningโ
The API uses URL-based versioning:
- Current:
/api/(v1 implicit) - All endpoints are prefixed with
/api/
Error Handlingโ
The platform uses NestJS exception filters with standard HTTP exceptions:
throw new NotFoundException("Employee not found");
throw new BadRequestException("Invalid input");
throw new ForbiddenException("Insufficient permissions");
throw new UnauthorizedException("Token expired");
Custom exceptions extend HttpException with structured error responses.
Middleware Pipelineโ
Request โ Logger Middleware โ Auth Guard โ Tenant Guard โ Permission Guard
โ Validation Pipe โ Controller โ Command/Query Handler โ Service
โ Response Interceptor โ Response
Related Pagesโ
- Architecture Overview โ high-level system design
- Multi-ORM Architecture โ database abstraction layer
- Plugin System โ extending backend functionality
- Event Bus โ inter-module communication