Skip to content

1.4 Server

Martin Stierlen edited this page Mar 10, 2026 · 19 revisions

What you will find on this page πŸ¦‰


The server is a NestJS 11 application written in TypeScript.

Folder Structure

server/src/
β”œβ”€β”€ main.ts                     # Bootstrap
β”œβ”€β”€ app.module.ts               # Root module
β”‚
β”œβ”€β”€ common/                     # Cross-cutting concerns: logging decorators/interceptors/utils, health check
β”œβ”€β”€ config/                     # App config, logging config, env var validation (Joi)
β”‚
β”œβ”€β”€ domain/                     # Framework-agnostic domain knowledge and shared type definitions
β”‚   β”œβ”€β”€ didactical-frameworks/   # Bloom's, SOLO and AVIVA definitions
β”‚   └── schemas/                 # Zod schemas - single source of truth for types
β”‚       β”œβ”€β”€ base/                  # Defines base schemas (learning-goal, session, all block types, ...)
β”‚       β”œβ”€β”€ dto/                   # Defines 2 DTOs for every API endpoint (1 request DTO + 1 response DTO)
β”‚       └── llm-parser/            # Defines schemas for structured LLM output parsing
β”‚
└── modules/                    # Feature modules: each owns its routes, controllers, services
    β”œβ”€β”€ learning-goals/          # Generate learning goals + easier alternatives
    β”œβ”€β”€ sessions/                # Handles session lifecycle: create, get, update, delete, continue, feedback
    β”œβ”€β”€ blocks/                  # Handles block generation (sequences, summary), chat, answer submission
    └── shared/
        β”œβ”€β”€ database/              # Prisma repositories (sessions, blocks)
        └── llm/                   # LLM integration
            β”œβ”€β”€ llm.service.ts        # Anthropic SDK wrapper - callClaude()
            β”œβ”€β”€ llm.parser.ts         # Zod-based structured output parser with retry
            β”œβ”€β”€ chains/               # One chain per use case (prompt + llm.service call + parse)
            └── prompts/              # One prompt per chain

Module Overview

Module Responsibility
LearningGoalsModule Handles generation of learning goals for new / easier session
SessionsModule Handles session lifecycle: create, navigate, continue logic, feedback
BlocksModule Handles block generation (sequences, summary), chat responses, answer evaluation
LlmModule Handles LLM integration
DatabaseModule Handles database interaction via repository pattern - all Prisma access is encapsulated in repositories so services never call Prisma directly, keeping DB logic in one place

Basic Request Flow

From HTTP request to HTTP response - here is what happens:

HTTP Request
    β†’ Controller         (validates request DTO, calls service)
        β†’ Service            (handles business logic, interacts with DB via repositories)
            β†’ Chain             (builds LLM call: selects prompt, calls LLM via service, parses output)
                β†’ Prompt            (constructs the final prompt string)
                β†’ LlmService        (calls Anthropic SDK)
                β†’ LlmParser         (validates structured JSON response against Zod schema, retries on failure)
        β†’ Service            (again handles business logic, interacts with DB via repositories, maps result to Response DTO)
    β†’ Controller         (validates response DTO)
β†’ HTTP Response

Zod Schemas

server/src/domain/schemas/ is the single source of truth for all types used in ExplAIner across server and client. If you want to add a new schema or adjust an existing one, do it there! :) nestjs-zod converts the Zod schemas into NestJS DTOs and OpenAPI decorators, which @nestjs/swagger exposes as an OpenAPI spec. The client then uses openapi-typescript to generate api.types.ts from that spec.

Sounds complex? It's not, Owlbert promises! πŸ¦‰ Here's how to add or change a schema:


Case 1: Server-Side Only

Use this when the schema change does not affect the API (e.g. changing a base schema or LLM parser schema that is not exposed to the client).

1. Add or change the Zod schema in server/src/domain/schemas/

2. Fix any TypeScript errors on the server


Case 2: Schema Exposed via API (affects client)

Use this when the change affects data sent to/from the client - i.e. a DTO in schemas/dto/ changes.

1. Add or change the Zod schema in server/src/domain/schemas/

  • Update the corresponding DTOs in schemas/dto/ - one request DTO and one response DTO per endpoint

2. Start the server, then regenerate client types:

cd client
npm run generate:api-types

β†’ writes client/src/types/generated/api.types.ts (do not edit by hand)

3. (Optional) Add a re-export from client/src/types/domain/ for simpler usage

4. TypeScript will surface errors wherever the changed type is used - fix all of them:

// TypeScript error: Property 'newField' is missing
const session: Session = { ... };

Owlbert

ExplAIner Wiki

Simply click here to checkout ExplAIner yourself! πŸ¦‰

Welcome

System Architecture

Contributor Guide

Clone this wiki locally