Imported from HoaiPhuongcoder/nestjs-starter-kit (
AGENTS.md). Install upstream withnpx skills add HoaiPhuongcoder/nestjs-starter-kit. Copyright stays with the author.
Codex Project Guide
Project
- Project name:
be-tntt-manage - Runtime: NestJS 11, TypeScript, pnpm
- Package manager command on this Windows workspace: use
pnpm.cmd - Main source folder:
src - Test folder:
test
Architecture
This backend is being shaped toward a clean architecture style.
Use these top-level folders consistently:
src/bootstrap: application bootstrap setup such as CORS, versioning, pipes, filters, interceptors, and docs.src/common: shared NestJS-facing utilities such as filters, interceptors, guards, decorators, DTOs, pipes, constants, types, and utils.src/config: app config and environment validation.src/database: database module, migrations, seeds, and persistence setup.src/modules: business modules. Each business module should separate domain, application, infrastructure, and presentation concerns.src/shared: framework-agnostic shared helpers when needed.
For business modules, prefer this shape:
src/modules/<module-name>/
domain/
entities/
repositories/
value-objects/
enums/
errors/
application/
dto/
use-cases/
infrastructure/
persistence/
repositories/
presentation/
<module-name>.controller.ts
<module-name>.module.ts
Domain code must stay framework-agnostic: do not import @nestjs/*, ORM clients, or database-specific code inside domain.
Imports
Use path alias imports for internal project files:
import { AppModule } from '@/app.module';
Alias config:
@/*maps tosrc/*- Build uses
tsc-aliasafternest buildso compiled output can run.
Avoid long relative imports for source files unless there is a local reason.
Bootstrap
Keep src/main.ts thin. Runtime setup belongs in src/bootstrap.
Current bootstrap responsibilities:
- global prefix:
api - URI versioning:
v1 - CORS
- global exception filter:
GlobalHttpExceptionFilter - global response interceptor:
TransformInterceptor - global validation pipe with custom validation exception factory
- Swagger docs via
setupDocs(app, configService)
Current base health endpoint is:
GET /api/v1
Swagger is configured through src/bootstrap/docs.bootstrap.ts and src/config/app.config.ts.
Default docs path:
GET /api/docs
GET /api/docs-json
Swagger environment variables:
SWAGGER_ENABLEDSWAGGER_PATHSWAGGER_TITLESWAGGER_DESCRIPTIONSWAGGER_VERSION
API Shape
Successful responses are wrapped by TransformInterceptor:
{
success: true,
statusCode: number,
message: string,
timestamp: string,
path: string,
data: unknown,
meta?: PaginatedMeta
}
Use these decorators from src/common/decorators for response behavior:
@ResponseMessage(message): sets the success message.@SkipTransform(): bypasses the global response wrapper, useful for raw/file responses.@Paginated(): marks paginated endpoints for metadata and future docs/behavior.
Errors are formatted by GlobalHttpExceptionFilter:
{
success: false,
statusCode: number,
code: ApiResponseErrorCode,
message: string | string[],
error: string,
path: string,
timestamp: string,
details?: ValidationErrorDetails
}
Standard API error codes:
VALIDATION_ERRORRESOURCE_NOT_FOUNDDATABASE_QUERY_ERRORHTTP_ERRORINTERNAL_SERVER_ERROR
Keep legacy imports working when needed:
HttpExceptionFilterre-exportsGlobalHttpExceptionFilter.ResponseInterceptorre-exportsTransformInterceptor.
Validation And Config
- Use
@nestjs/configfor app configuration. - Keep config in
src/config. - Update
.env.examplewhenever introducing new environment variables. - Global
ValidationPipealready enablestransform,whitelist, andforbidNonWhitelisted. - Validation errors should flow through
ValidationExceptionso the global filter can producedetails.fieldsanddetails.fieldErrors. SWAGGER_ENABLEDacceptstrue,false,1,0,yes,no,on, oroff.
Pagination
Shared pagination utilities live in:
src/common/dto/offset-pagination.dto.tssrc/common/dto/cursor-pagination.dto.tssrc/common/pagination/prisma-pagination.helper.ts
Use OffsetPaginationDto for page/limit pagination and CursorPaginationDto for cursor pagination. The Prisma-style helper exposes:
paginate()for offset pagination.paginateCursor()for cursor pagination.encodeCursor()anddecodeCursor()for opaque base64url cursors.
Paginated application results should return:
{
data: T[],
meta: PaginatedMeta
}
The global transform interceptor will move meta to the top-level API response.
Database
Prisma is the database client.
Prisma files:
prisma/schema.prisma: datasource and data models.prisma.config.ts: Prisma CLI config, migrations path, andDATABASE_URLloading.src/database/database.module.ts: global Nest database module.src/database/prisma.service.ts: injectable Prisma client service.
Current Prisma setup:
- datasource provider:
postgresql - local PostgreSQL is defined in
docker-compose.yml - app container is built from
Dockerfile - generated client output:
src/generated/prisma - generated client is ignored by Git and regenerated before build
PrismaServiceimportsPrismaClientfrom@/generated/prisma/clientPrismaServiceuses@prisma/adapter-pgandDATABASE_URL- Prisma connects lazily; it does not call
$connect()during module init
Useful commands:
pnpm.cmd run db:up
pnpm.cmd run db:down
pnpm.cmd run db:logs
pnpm.cmd run db:reset
pnpm.cmd run docker:up
pnpm.cmd run docker:down
pnpm.cmd run docker:logs
pnpm.cmd run prisma:generate
pnpm.cmd run prisma:migrate
pnpm.cmd run prisma:deploy
pnpm.cmd run prisma:studio
pnpm.cmd exec prisma validate
When changing Prisma schema or database setup, run:
pnpm.cmd run prisma:generate
pnpm.cmd exec prisma validate
pnpm.cmd run build
Examples
src/modules/items/presentation/items.example.controller.ts is a mock/example controller showing:
- offset pagination
- cursor pagination
- custom response messages
- skipped transform for CSV export
- validation flowing through the global error shape
Treat it as a usage example, not a database-backed production module.
Verification Rules
For every implementation task, run the project build before giving the final response:
pnpm.cmd run build
If the build fails, fix the issue and run it again until it passes.
When changing tests, routing, aliases, or bootstrap behavior, also run the relevant tests, usually:
pnpm.cmd exec jest --config .\test\jest-e2e.json --runInBand
Mention the build result in the final response.