Architecture Overview
System Architecture
Diagram source
graph TB
subgraph Client["Client Layer"]
A1["Angular UI<br/>(Web SPA, Port: 4200)"]
A2["Desktop App<br/>(Electron, Embedded)"]
A3["Desktop Timer<br/>(Electron, Standalone)"]
A4["Ever Teams<br/>(React/RN)"]
end
subgraph Server["Server Layer β NestJS API Server (Port: 3000)"]
B1["Auth Guards"]
B2["CQRS Commands"]
B3["REST API / Swagger"]
B4["GraphQL (WIP)"]
B5["MCP Server (AI Tools)"]
B6["Modules (Core)"]
B7["Plugin System"]
B8["Event Bus (CQRS)"]
B9["Job Scheduler (Bull/Redis)"]
end
subgraph Data["Data Layer"]
C1["TypeORM"]
C2["MikroORM"]
C3["Knex"]
C4["Redis"]
C5["OpenSearch"]
D1["PostgreSQL / MySQL / SQLite"]
D2["Cache"]
D3["Search"]
end
A1 & A2 & A3 & A4 -- "HTTP / WebSocket" --> Server
C1 & C2 & C3 --> D1
C4 --> D2
C5 --> D3Architectural Layers
1. Client Layer
The client layer consists of multiple application types, all consuming the same API:
| Application | Technology | Package Location | Purpose |
|---|---|---|---|
| Web UI | Angular 19+, Nebular/ngx-admin | apps/gauzy | Primary web interface |
| Desktop App | Electron + Angular | apps/desktop | All-in-one desktop application |
| Desktop Timer | Electron + Angular | apps/desktop-timer | Time tracking & activity monitoring |
| Desktop Server | Electron + NestJS | apps/server | Self-hosted API server |
| API Server Desktop | Electron + NestJS | apps/api-server | API-only server deployment |
| Ever Teams | React/Next.js + React Native | External repo | Modern PM/Task interface |
2. API Layer (NestJS)
The backend is a NestJS application following CQRS (Command Query Responsibility Segregation) patterns:
- Controllers β handle HTTP requests, validate inputs, route to handlers
- Commands/Queries β encapsulate business logic via the CQRS pattern
- Services β core business logic and data access
- Guards β authentication and authorization (JWT, Roles, Permissions, Tenant)
- Interceptors β request/response transformation, logging
- Pipes β input validation and transformation (class-validator)
- Modules β NestJS dependency injection containers
3. Data Layer
The platform uses a Multi-ORM architecture supporting:
- TypeORM β primary ORM with extensive entity definitions, repositories, and migrations
- MikroORM β alternative ORM with its own repositories and entity metadata
- Knex β raw SQL query builder for complex queries and migrations
All three ORMs connect to the same database and share entity definitions through a shared Multi-ORM decorator system.
4. Infrastructure Layer
- PostgreSQL β primary production database
- SQLite β lightweight development/demo database
- Redis β caching, session store, and job queue
- OpenSearch β full-text search indexing
- MinIO/S3 β file and image storage
- Cube β analytics and BI semantic layer
- Zipkin/OTEL β distributed tracing
Key Architecture Patterns
Multi-Tenant Architecture
Every entity in the system is scoped to a tenant. The TenantBaseEntity base class provides:
- Automatic
tenantIdinjection on create/update - Automatic
tenantIdfiltering on read queries - Cross-tenant access prevention at the ORM level
See Multi-Tenancy for details.
Plugin Architecture
The platform supports dynamic plugins for extending functionality:
@Module({})
export class PluginModule {
static forRoot(plugins: Type<any>[]): DynamicModule {
return {
module: PluginModule,
imports: plugins,
};
}
}Plugins can add: entities, controllers, services, commands, and event handlers. See Plugin System.
CQRS Pattern
Business logic is organized into Commands (write) and Queries (read):
Controller β CommandBus/QueryBus β Handler β Service β RepositoryThis pattern enables:
- Clear separation of read and write operations
- Event-driven side effects
- Easier testing through handler isolation
Event Bus
The platform uses NestJS @nestjs/cqrs events for inter-module communication:
// Publishing an event
this.eventBus.publish(new EmployeeCreatedEvent(employee));
// Handling an event in another module
@EventHandler(EmployeeCreatedEvent)
export class EmployeeCreatedHandler {
handle(event: EmployeeCreatedEvent) {
/* ... */
}
}Request Context
A RequestContext utility provides access to the current request context throughout the application:
// Access current user, tenant, and organization
const tenantId = RequestContext.currentTenantId();
const userId = RequestContext.currentUserId();
const orgId = RequestContext.currentOrganizationId();Data Flow
Typical API Request Flow
Diagram source
graph LR
A["Client Request"] --> B["Guard (Auth)"]
B --> C["Pipe (Validation)"]
C --> D["Handler (CQRS)"]
D --> E["Service"]
E --> F["Repository (ORM)"]
F --> G["Database"]- Guard: Validates JWT token, checks roles/permissions, resolves tenant
- Pipe: Validates request body against DTO (Data Transfer Object) classes
- Handler: Executes business logic via CQRS command/query handler
- Service: Performs data access, integrations, and business rules
- Repository: Issues database queries through the active ORM
Guard Chain
Diagram source
graph LR
A["JWT Auth Guard"] --> B["Tenant Resolve"]
B --> C["Role Guard"]
C --> D["Permission Guard"]Deployment Models
| Model | Components | Best For |
|---|---|---|
| SaaS | Cloud-hosted API + UI | Multi-tenant production |
| Self-Hosted | Docker or bare metal | Private infrastructure |
| Desktop Server | Electron app hosting API | Small teams, individuals |
| Desktop All-in-One | Full platform in single app | Personal use |
| Client-Server | Separate API server + clients | Teams with centralized server |
Related Pages
- Monorepo Structure β NX workspace organization
- Technology Stack β all technologies used
- Backend Architecture β NestJS internals
- Frontend Architecture β Angular UI
- Multi-ORM Architecture β TypeORM, MikroORM, Knex
- Plugin System β extending the platform
- Multi-Tenancy β tenant isolation
- Design Principles β core philosophy