Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Zapiony/PUCE_UZDI_2026/llms.txt

Use this file to discover all available pages before exploring further.

The UZDI backend is a standard NestJS application where each business domain is encapsulated in its own feature module. Every module follows the same internal structure, shares a common set of globally registered pipes, and maps TypeORM entities to named PostgreSQL schemas defined by DDL_UZDI_FINAL.sql. This page describes the architecture, the global bootstrap configuration, and the patterns every module must follow.

Module Anatomy

Each domain module in UZDI_BACK/src contains the following files:
FileRole
*.module.tsNestJS module definition — declares and exports controller, service, and TypeORM feature
*.controller.tsRoute handlers — maps HTTP verbs and paths to service methods
*.service.tsBusiness logic — interacts with the TypeORM repository
entities/*.entity.tsTypeORM entity — maps a TypeScript class to a PostgreSQL table in the correct schema
dto/create-*.dto.tsDTO for POST requests — decorated with class-validator constraints
dto/update-*.dto.tsDTO for PATCH requests — extends PartialType(CreateDto) making all fields optional

Registered Domain Modules

All feature modules are imported in AppModule:
// app.module.ts (imports array)
AuthModule,
UsersModule,
EstructuraInstitucionalModule,
SeguridadModule,
AdolescentesModule,
ContextoFamiliarModule,
TalleresActividadesModule,
GestionDocumentalModule,
Each domain module is responsible for sub-resources within its bounded context. For example, AdolescentesModule contains controllers and services for adolescents, expedients, socio-educational measures, infractions, GDO, ethnicity, civil status, and nationality.

Global Bootstrap Configuration (main.ts)

The application bootstrap in src/main.ts applies the following global configuration before the server starts listening:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { SanitizationPipe } from './common/pipes/sanitization.pipe';

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

  app.enableCors({
    origin: 'http://localhost:5174',
    methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true,
  });

  // Global API version prefix
  app.setGlobalPrefix('api/v1');

  // Sanitization runs first — strips dangerous HTML from all string inputs
  app.useGlobalPipes(new SanitizationPipe());

  // Validation runs second — enforces DTO constraints
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,
    forbidNonWhitelisted: true,
    transform: true,
  }));

  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
ConfigurationValue / Behavior
Global prefixapi/v1 — all routes are prefixed (e.g., POST /api/v1/auth/login)
SanitizationPipeRuns before ValidationPipe; trims whitespace, strips <script> tags via regex, and escapes </> from all string inputs in body, query, and params
ValidationPipewhitelist: trueStrips any properties not declared in the DTO
ValidationPipeforbidNonWhitelisted: trueThrows 400 Bad Request if unknown properties are present
ValidationPipetransform: trueAuto-converts plain objects to DTO class instances and coerces primitive types
CORS originhttp://localhost:5174 (Vite dev server)
Portprocess.env.PORT or 3000

Adding a New Module

1

Generate the module, controller, and service

Use the NestJS CLI from the UZDI_BACK directory. Replace my-resource with the snake-case domain name:
nest generate module my-resource
nest generate controller my-resource
nest generate service my-resource
This scaffolds src/my-resource/my-resource.module.ts, my-resource.controller.ts, and my-resource.service.ts with proper decorators and wiring.
2

Create the TypeORM entity

Create src/my-resource/entities/my-resource.entity.ts. Map the entity to the correct PostgreSQL schema using the @Entity options object:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { BooleanVF } from '../../common/transformers/boolean-vf.transformer';

@Entity({ schema: 'seguridad', name: 'my_table' })
export class MyResource {
  @PrimaryGeneratedColumn()
  myrs_id: number;

  @Column({ type: 'varchar', length: 100 })
  nombre: string;

  // CHAR(1) boolean — use BooleanVF transformer
  @Column({ type: 'char', length: 1, transformer: BooleanVF })
  activo: boolean;
}
3

Create the Create DTO

Create src/my-resource/dto/create-my-resource.dto.ts with class-validator decorators:
import { IsString, IsNotEmpty, MaxLength, IsBoolean, IsOptional } from 'class-validator';

export class CreateMyResourceDto {
  @IsString()
  @IsNotEmpty()
  @MaxLength(100)
  nombre: string;

  @IsBoolean()
  @IsOptional()
  activo?: boolean;
}
4

Create the Update DTO

Create src/my-resource/dto/update-my-resource.dto.ts extending PartialType:
import { PartialType } from '@nestjs/mapped-types';
import { CreateMyResourceDto } from './create-my-resource.dto';

export class UpdateMyResourceDto extends PartialType(CreateMyResourceDto) {}
PartialType makes all fields from CreateMyResourceDto optional, which is the correct behavior for PATCH endpoints.
5

Register the entity in the feature module

Import TypeOrmModule.forFeature([MyResource]) in your module so the repository is available for injection:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MyResource } from './entities/my-resource.entity';
import { MyResourceController } from './my-resource.controller';
import { MyResourceService } from './my-resource.service';

@Module({
  imports: [TypeOrmModule.forFeature([MyResource])],
  controllers: [MyResourceController],
  providers: [MyResourceService],
})
export class MyResourceModule {}
6

Register the module in AppModule

Add the new module to the imports array in src/app.module.ts:
import { MyResourceModule } from './my-resource/my-resource.module';

@Module({
  imports: [
    // ... existing modules
    MyResourceModule,
  ],
})
export class AppModule implements NestModule { ... }
Because autoLoadEntities: true is set in TypeOrmModule.forRoot(), registering the module here is sufficient — no manual entity list is needed.

BooleanVF Value Transformer

All CHAR(1) boolean columns in the DDL are mapped in TypeORM entities using the BooleanVF transformer defined in src/common/transformers/boolean-vf.transformer.ts:
import { ValueTransformer } from 'typeorm';

/**
 * Converts boolean values to the CHAR(1) 'V'/'F' representation
 * required by the DDL CHECK constraints.
 * The API exposes/receives booleans; the database stores 'V' or 'F'.
 */
export const BooleanVF: ValueTransformer = {
  to: (value?: boolean | null): string => (value ? 'V' : 'F'),
  from: (value?: string | null): boolean => value === 'V',
};
Apply it on any CHAR(1) boolean column:
@Column({ type: 'char', length: 1, transformer: BooleanVF })
reincide: boolean;
With this transformer in place:
  • Reading from the database: 'V'true, 'F'false
  • Writing to the database: true'V', false / null / undefined'F'
API consumers and DTOs work entirely with JavaScript boolean values and never need to know about the 'V'/'F' encoding.

TypeORM Entity Schema Mapping

Every entity must target its named PostgreSQL schema explicitly. The schema name matches the domain schema defined in DDL_UZDI_FINAL.sql:
// Targeting the 'seguridad' schema, table 'prsn'
@Entity({ schema: 'seguridad', name: 'prsn' })
export class Persona { ... }

// Targeting the 'adolescente' schema, table 'expediente'
@Entity({ schema: 'adolescente', name: 'expediente' })
export class Expediente { ... }

// Targeting the 'estructura_institucional' schema, table 'uzdi'
@Entity({ schema: 'estructura_institucional', name: 'uzdi' })
export class Uzdi { ... }
Omitting the schema option causes TypeORM to default to the public schema, where none of the UZDI tables reside.

PartialType for Update DTOs

PartialType from @nestjs/mapped-types is used in every Update DTO. It copies all fields and their validation decorators from the Create DTO but marks them all as optional, which is the correct shape for PATCH semantics (partial updates):
// create-expediente.dto.ts
export class CreateExpedienteDto {
  @IsInt() adlc_id: number;
  @IsInt() uzdi_id: number;
  @IsString() estado: string;
  // ...
}

// update-expediente.dto.ts
export class UpdateExpedienteDto extends PartialType(CreateExpedienteDto) {}
// All fields are now optional — a PATCH can update just `estado`
// without needing to re-supply adlc_id or uzdi_id
PartialType from @nestjs/mapped-types is not the same as TypeScript’s built-in Partial<T>. It also carries the class-validator metadata forward, so validation still runs on any field that is provided in the request body.

Build docs developers (and LLMs) love