Skip to Content
🚀 APSO is now in public beta. Get started →
ArchitectureGenerated Code

Generated Code

APSO generates clean, production-ready code following established patterns and best practices.

Layer Architecture

Generated Components

Entities

TypeORM entities with decorators:

// src/entities/project.entity.ts import { Entity, Column, PrimaryGeneratedColumn, OneToMany, Index } from 'typeorm'; import { Task } from './task.entity'; @Entity('projects') export class Project { @PrimaryGeneratedColumn('uuid') id: string; @Column({ length: 200 }) name: string; @Column({ nullable: true, type: 'text' }) description: string | null; @Index() @Column() organizationId: string; @OneToMany(() => Task, task => task.project) tasks: Task[]; @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) createdAt: Date; @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' }) updatedAt: Date; }

Controllers

RESTful API controllers:

// src/modules/projects/projects.controller.ts import { Controller, Get, Post, Patch, Delete, Body, Param, Query, UseGuards } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; import { ProjectsService } from './projects.service'; import { CreateProjectDto, UpdateProjectDto, FindAllQuery } from './dto'; import { AuthGuard } from '../../common/guards/auth.guard'; import { CurrentUser } from '../../common/decorators/current-user.decorator'; @ApiTags('projects') @ApiBearerAuth() @Controller('projects') @UseGuards(AuthGuard) export class ProjectsController { constructor(private readonly projectsService: ProjectsService) {} @Get() @ApiOperation({ summary: 'List all projects' }) findAll(@Query() query: FindAllQuery, @CurrentUser() user: User) { return this.projectsService.findAll(query, user); } @Get(':id') @ApiOperation({ summary: 'Get a project by ID' }) findOne(@Param('id') id: string, @CurrentUser() user: User) { return this.projectsService.findOne(id, user); } @Post() @ApiOperation({ summary: 'Create a project' }) create(@Body() dto: CreateProjectDto, @CurrentUser() user: User) { return this.projectsService.create(dto, user); } @Patch(':id') @ApiOperation({ summary: 'Update a project' }) update(@Param('id') id: string, @Body() dto: UpdateProjectDto, @CurrentUser() user: User) { return this.projectsService.update(id, dto, user); } @Delete(':id') @ApiOperation({ summary: 'Delete a project' }) remove(@Param('id') id: string, @CurrentUser() user: User) { return this.projectsService.remove(id, user); } }

Services

Business logic with repository pattern:

// src/modules/projects/projects.service.ts import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Project } from '../../entities/project.entity'; import { CreateProjectDto, UpdateProjectDto, FindAllQuery } from './dto'; @Injectable() export class ProjectsService { constructor( @InjectRepository(Project) private readonly repository: Repository<Project>, ) {} async findAll(query: FindAllQuery, user: User): Promise<Project[]> { const { limit = 20, offset = 0, sort, include } = query; const qb = this.repository .createQueryBuilder('project') .where('project.organizationId = :orgId', { orgId: user.organizationId }); if (sort) { const [field, order] = sort.split(':'); qb.orderBy(`project.${field}`, order?.toUpperCase() as 'ASC' | 'DESC'); } if (include?.includes('tasks')) { qb.leftJoinAndSelect('project.tasks', 'tasks'); } return qb.skip(offset).take(limit).getMany(); } async findOne(id: string, user: User): Promise<Project> { const project = await this.repository.findOne({ where: { id, organizationId: user.organizationId }, }); if (!project) { throw new NotFoundException(`Project with ID ${id} not found`); } return project; } async create(dto: CreateProjectDto, user: User): Promise<Project> { const project = this.repository.create({ ...dto, organizationId: user.organizationId, }); return this.repository.save(project); } async update(id: string, dto: UpdateProjectDto, user: User): Promise<Project> { const project = await this.findOne(id, user); Object.assign(project, dto); return this.repository.save(project); } async remove(id: string, user: User): Promise<void> { const project = await this.findOne(id, user); await this.repository.remove(project); } }

DTOs

Request validation with class-validator:

// src/modules/projects/dto/create-project.dto.ts import { IsString, IsNotEmpty, MaxLength, IsOptional } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class CreateProjectDto { @ApiProperty({ maxLength: 200 }) @IsString() @IsNotEmpty() @MaxLength(200) name: string; @ApiPropertyOptional() @IsOptional() @IsString() description?: string; } // src/modules/projects/dto/update-project.dto.ts import { PartialType } from '@nestjs/swagger'; import { CreateProjectDto } from './create-project.dto'; export class UpdateProjectDto extends PartialType(CreateProjectDto) {} // src/modules/projects/dto/find-all-query.dto.ts import { IsOptional, IsInt, Min, Max, IsString } from 'class-validator'; import { Type } from 'class-transformer'; import { ApiPropertyOptional } from '@nestjs/swagger'; export class FindAllQuery { @ApiPropertyOptional({ default: 20 }) @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(100) limit?: number = 20; @ApiPropertyOptional({ default: 0 }) @IsOptional() @Type(() => Number) @IsInt() @Min(0) offset?: number = 0; @ApiPropertyOptional({ example: 'createdAt:desc' }) @IsOptional() @IsString() sort?: string; @ApiPropertyOptional({ example: 'tasks' }) @IsOptional() @IsString() include?: string; }

Modules

NestJS module wiring:

// src/modules/projects/projects.module.ts import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Project } from '../../entities/project.entity'; import { ProjectsController } from './projects.controller'; import { ProjectsService } from './projects.service'; @Module({ imports: [TypeOrmModule.forFeature([Project])], controllers: [ProjectsController], providers: [ProjectsService], exports: [ProjectsService], }) export class ProjectsModule {}

Common Utilities

Guards

// src/common/guards/auth.guard.ts @Injectable() export class AuthGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise<boolean> { // JWT verification logic } }

Decorators

// src/common/decorators/current-user.decorator.ts export const CurrentUser = createParamDecorator( (data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return request.user; }, );

Filters

// src/common/filters/http-exception.filter.ts @Catch() export class HttpExceptionFilter implements ExceptionFilter { catch(exception: unknown, host: ArgumentsHost) { // Standardized error response } }

Generated vs Custom Code

LocationGeneratedCustom
src/entities/✅❌
src/modules/{entity}/✅❌
src/common/✅❌
src/extensions/❌✅
src/config/PartialPartial

Regeneration Safety

Generated files include a header:

/** * @generated by APSO * Do not edit this file directly. * Modifications will be overwritten. */

Custom code in extensions/ is never overwritten.

Last updated on