Skip to content

Backend Technical Details

Architecture Overview

The BidScript backend is built using NestJS, a progressive Node.js framework that employs modern design patterns and best practices. It follows a modular architecture with dependency injection for maintainable and testable code.

Design Patterns

  • Dependency Injection: Core pattern for managing dependencies
  • Repository Pattern: Abstracts data access layer
  • Module Pattern: Organises code into cohesive modules
  • Service Layer: Encapsulates business logic
  • Controller-Service-Repository: Layered architecture
  • Event-Driven Architecture: Using event emitters for loose coupling
  • Middleware Pipeline: For request processing
  • Gateway Pattern: For WebSocket communication

Directory Structure

bidssappserver-nestjs/
├── src/
│   ├── main.ts                    # Application entry point
│   ├── app.module.ts              # Root application module
│   ├── app.controller.ts          # Root controller
│   ├── app.service.ts             # Root service
│   ├── auth/                      # Authentication module
│   │   ├── auth.module.ts
│   │   ├── auth.service.ts
│   │   ├── auth.controller.ts
│   │   ├── strategies/            # Passport strategies
│   │   └── guards/                # Auth guards
│   ├── azure/                     # Azure services integration
│   │   ├── azure.module.ts
│   │   ├── azure.service.ts       # Core Azure service
│   │   ├── blob.service.ts        # Azure Storage management
│   │   ├── document-parse.service.ts # Document parsing
│   │   └── azure-sql.service.ts   # Azure SQL database
│   ├── chat/                      # Chat functionality
│   │   ├── chat.module.ts
│   │   ├── chat.controller.ts
│   │   ├── chat.service.ts
│   │   ├── chat-context.service.ts # Chat context management
│   │   └── chat.dto.ts            # Data transfer objects
│   ├── rag/                       # Retrieval Augmented Generation
│   │   ├── rag.module.ts
│   │   ├── rag.service.ts         # RAG implementation
│   │   └── dto/                   # RAG DTOs
│   ├── editor/                    # Document editor module
│   │   ├── editor.module.ts
│   │   ├── editor.controller.ts
│   │   ├── editor.service.ts
│   │   ├── editor.gateway.ts      # WebSocket gateway
│   │   └── dto/                   # Editor DTOs
│   ├── llama/                     # Llama integration
│   │   ├── llama.module.ts
│   │   └── llama.service.ts       # Llama document parsing
│   ├── langchain/                 # LangChain module
│   │   ├── langchain.module.ts
│   │   ├── langchain.service.ts
│   │   └── chains/                # Custom LangChain chains
│   ├── vectorstore/               # Vector database
│   │   ├── vectorstore.module.ts
│   │   └── vectorstore.service.ts # Vector DB operations
│   ├── redis/                     # Redis module
│   │   ├── redis.module.ts
│   │   └── redis.service.ts       # Redis operations
│   ├── conversation/              # Conversation history
│   │   ├── conversation.module.ts
│   │   └── conversation.service.ts # Conversation management
│   ├── theme/                     # Theming functionality
│   │   ├── theme.module.ts
│   │   └── theme.service.ts       # Theme management
│   ├── grafana/                   # Monitoring
│   │   ├── grafana.module.ts
│   │   └── grafana.service.ts     # Metrics collection
│   └── types/                     # TypeScript type definitions
│       ├── dto/                   # Common DTOs
│       └── interfaces/            # TypeScript interfaces
├── test/                          # Tests
│   ├── app.e2e-spec.ts            # E2E tests
│   └── jest-e2e.json              # Jest E2E config
├── dist/                          # Compiled output
├── node_modules/                  # Dependencies
├── .env                           # Environment variables
├── package.json                   # Dependencies and scripts
├── tsconfig.json                  # TypeScript configuration
├── nest-cli.json                  # NestJS CLI configuration
├── docker-compose.yml             # Docker Compose config
└── Dockerfile                     # Docker config

Module Architecture

NestJS Module System

Each feature in the application is organised into a NestJS module that exports services and controllers:

@Module({
  imports: [
    // Imported modules
    DependentModule,
  ],
  controllers: [FeatureController],
  providers: [FeatureService],
  exports: [FeatureService],
})
export class FeatureModule {}

Application Bootstrap

The application bootstrap process is defined in main.ts:

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Configure body parser, CORS, validation pipe, etc.

  await app.listen(process.env.PORT || 3000);
}
bootstrap();

Authentication System

JWT Authentication

The backend uses JWT (JSON Web Tokens) for stateless authentication:

  1. Authentication Flow:

  2. User submits credentials

  3. Server validates and issues JWT token
  4. Token is included in subsequent requests
  5. JWT Guard validates token on protected routes

  6. JWT Configuration:

JwtModule.register({
  secret: process.env.JWT_SECRET,
  signOptions: { expiresIn: process.env.JWT_EXPIRATION || "8h" },
});
  1. Global Guard:
    {
      provide: APP_GUARD,
      useClass: JwtAuthGuard,
    }
    

AI Integration Architecture

RAG (Retrieval Augmented Generation)

The RAG system enhances AI responses with relevant information from indexed documents:

  1. Document Processing Pipeline:

  2. Document upload and storage

  3. Text extraction
  4. Chunking and preprocessing
  5. Embedding generation
  6. Vector database indexing

  7. Query Pipeline:

  8. Query embedding generation
  9. Semantic search in vector database
  10. Context retrieval
  11. Context augmentation
  12. LLM generation with augmented context

Azure OpenAI Integration

The application integrates with Azure OpenAI services:

const openAIClient = new OpenAIClient(
  process.env.AZURE_OPENAI_ENDPOINT,
  new AzureKeyCredential(process.env.AZURE_OPENAI_API_KEY)
);

WebSocket Implementation

Socket.IO Integration

Real-time communication is implemented using Socket.IO with NestJS WebSocket gateways:

@WebSocketGateway({
  cors: {
    origin: true,
    credentials: true,
  },
  namespace: "chat",
})
export class ChatGateway implements OnGatewayInit, OnGatewayConnection {
  // WebSocket event handlers
}

YJS for Collaborative Editing

The editor uses YJS for conflict-free collaborative editing:

@WebSocketGateway({
  namespace: "editor/yjs",
})
export class EditorGateway {
  // YJS document handling
}

Database and Storage

Azure Blob Storage

Document storage is managed through Azure Blob Storage:

const containerClient = blobServiceClient.getContainerClient(
  process.env.AZURE_STORAGE_CONTAINER
);

Vector Database (Pinecone)

Embeddings are stored in Pinecone vector database:

const pinecone = new Pinecone({
  apiKey: process.env.PINECONE_API_KEY,
  environment: process.env.PINECONE_ENVIRONMENT,
});
const index = pinecone.Index(process.env.PINECONE_INDEX);

Redis

Redis is used for caching and job queues:

// Redis module registration
RedisModule.forRootAsync({
  useFactory: () => ({
    config: {
      host: process.env.REDIS_HOST,
      port: parseInt(process.env.REDIS_PORT, 10),
      password: process.env.REDIS_PASSWORD,
    },
  }),
});

Background Processing

Bull Queue

Background jobs are processed using Bull queue with Redis:

BullModule.registerQueue({
  name: "document-processing",
});
@Process('parse-document')
async processDocument(job: Job<DocumentProcessingData>) {
  // Process document in background
}

Error Handling

Global Exception Filter

The application uses a global exception filter for consistent error responses:

app.useGlobalFilters(new HttpExceptionFilter());
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: any, host: ArgumentsHost) {
    // Format and return error response
  }
}

Validation and Security

Request Validation

Data validation is implemented using class-validator and pipes:

app.useGlobalPipes(
  new ValidationPipe({
    transform: true,
    whitelist: true,
    forbidNonWhitelisted: true,
  })
);

DTO Example

export class CreateChatSessionDto {
  @IsString()
  @IsNotEmpty()
  title: string;

  @IsArray()
  @IsOptional()
  documentIds?: string[];

  @IsString()
  @IsOptional()
  contextType?: string;
}

API Documentation

API documentation is generated using Swagger/OpenAPI:

const config = new DocumentBuilder()
  .setTitle("BidScript API")
  .setDescription("BidScript Backend API")
  .setVersion("1.0")
  .addBearerAuth()
  .build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup("api-docs", app, document);

Testing Strategy

Unit Testing

Services and controllers are unit tested with Jest:

describe("ChatService", () => {
  let service: ChatService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        ChatService,
        // Mock dependencies
      ],
    }).compile();

    service = module.get<ChatService>(ChatService);
  });

  it("should be defined", () => {
    expect(service).toBeDefined();
  });
});

E2E Testing

End-to-end tests use SuperTest with NestJS testing utilities:

describe("AppController (e2e)", () => {
  let app: INestApplication;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it("/health (GET)", () => {
    return request(app.getHttpServer()).get("/health").expect(200);
  });
});

CI/CD Pipeline

GitHub Actions

Continuous integration and deployment are managed through GitHub Actions:

name: CI/CD Pipeline

on:
  push:
    branches: [main, staging]
  pull_request:
    branches: [main]

jobs:
  build-and-test:
    # CI steps for building and testing

  deploy:
    # CD steps for deployment

Monitoring and Logging

Logging

The application uses NestJS Logger for structured logging:

const logger = new Logger("ModuleName");
logger.log("Info message");
logger.error("Error message", trace);

Metrics

Prometheus metrics are exposed for monitoring:

// Register Prometheus metrics
const register = new Registry();
register.setDefaultLabels({
  app: "bidscript-backend",
});