Imported from NaldsonChagas/thera-consulting-challenge (
AGENTS.md). Install upstream withnpx skills add NaldsonChagas/thera-consulting-challenge. Copyright stays with the author.
OVGS - Sales Order Management System
Project Overview
OVGS is a Sales Order Management System REST API built with NestJS, TypeORM, and PostgreSQL. It follows Modular + Hexagonal Architecture to keep domain logic framework-free, testable, and decoupled from infrastructure concerns.
Technology Stack
| Technology | Version | Purpose |
|---|---|---|
| Node.js | 24 LTS | Runtime |
| NestJS | 11.0 | Backend framework |
| TypeScript | 5.5 | Type safety |
| PostgreSQL | 16 | Relational database |
| TypeORM | 0.3 | ORM + migrations |
| Fastify | - | HTTP server (performance) |
| Pino | - | Structured logging |
| class-validator | - | DTO validation |
| class-transformer | - | Data transformation |
| Swagger/OpenAPI | - | API documentation |
| Docker Compose | - | Containerization |
| Jest | 29 | Unit + E2E tests |
| commitlint + husky | - | Conventional commits enforcement |
Modules
| Module | Responsibility |
|---|---|
| TransportType | Extensible transport type catalog (Truck, Semi-truck, etc.) |
| Item | Product/SKU catalog |
| Customer | Customer management and transport type authorization |
| SalesOrder | Sales order lifecycle with state machine |
| Scheduling | Delivery scheduling and rescheduling |
| Audit | Immutable event logging for system audit trail |
Architecture Map
src/
├── config/ # Environment validation, TypeORM datasource, Swagger setup, Logger config
├── shared/
│ ├── domain/ # Framework-free: BaseEntity, DomainError, ValueObject
│ ├── adapters/ # Infrastructure-aware: BaseTypeOrmEntity (TypeORM)
│ └── http/ # Filters, interceptors, pipes (global NestJS infrastructure)
├── modules/
│ └── <module>/
│ ├── domain/ # Framework-free: entities, value-objects, errors
│ ├── use-cases/ # Framework-free: business logic, depends only on port interfaces
│ ├── ports/ # Framework-free: in/out interfaces
│ │ ├── in/ # Inbound port interfaces (e.g., ICreateOrderUseCase)
│ │ └── out/ # Outbound port interfaces (e.g., IOrderRepository)
│ ├── adapters/
│ │ ├── http/ # NestJS controllers, DTOs, mappers (HTTP layer)
│ │ └── persistence/ # TypeORM entities, repositories (database layer)
│ └── <module>.module.ts
├── database/
│ ├── migrations/ # TypeORM migration files (auto-generated, append-only)
│ └── seeds/ # Standalone seed scripts
├── scripts/ # Standalone utility scripts (e.g., OpenAPI export)
├── app.module.ts
├── health.controller.ts
└── main.ts
Where AI Agents Should Operate
AI agents should focus on these directories — they are framework-free and safe to generate/modify without breaking infrastructure:
src/modules/*/domain/— entities, value-objects, domain errorssrc/modules/*/use-cases/— business logic, receives dependencies via constructor injectionsrc/modules/*/ports/— interfaces (inbound use case contracts, outbound repository contracts)src/modules/audit/ports/out/audit-logger.port.ts— add new audit event methodssrc/modules/audit/adapters/audit-logger.ts— implement new audit methodssrc/rules/— create and update business rule documentationsrc/skills/— create new agent instruction files
Agents may also modify:
src/modules/*/adapters/— but must understand the framework (NestJS, TypeORM) to do sosrc/modules/*/<module>.module.ts— to register new providers
Out of Scope for Agents
- Do NOT modify migration files in
src/database/migrations/(auto-generated, append-only) - Do NOT add framework decorators (
@Entity(),@Injectable(),@Controller()) to domain entities - Do NOT import TypeORM, NestJS, or any external framework in domain/use-cases/ports
(Exception:
@Inject()is allowed in use case constructors for DI token injection) - Do NOT modify the DataSource configuration in
src/config/typeorm.config.ts - Do NOT create or modify
src/config/env.config.ts - Do NOT modify
src/database/run-migrations.ts - Do NOT modify
src/config/— infrastructure config is human-maintained - Do NOT modify
.github/workflows/— CI pipeline is human-maintained
Rules for Code Generation
- Domain layer must have ZERO external dependencies
- No imports from
@nestjs/*,typeorm,class-validator, or any framework - Only import from
@shared/*or other domain/use-case/port files
- No imports from
- Use cases receive all dependencies via constructor injection through port interfaces
- Never instantiate repositories directly inside a use case
- Errors must extend
DomainError(from@shared/domain/base.error.ts) - Value objects must extend
ValueObject<T>(from@shared/domain/base.value-object.ts) - Use cases are plain classes — not
@Injectable()— they must NOT use NestJS decorators
Module Structure
Each module follows this internal structure:
src/modules/<module>/
├── domain/
│ ├── entities/ # Pure domain entities (extend BaseEntity, no ORM decorators)
│ ├── value-objects/ # Value objects (extend ValueObject<T>)
│ └── errors/ # Domain errors (extend DomainError)
├── use-cases/ # Business logic classes
├── ports/
│ ├── in/ # Inbound port interfaces (e.g., ICreateOrderUseCase)
│ └── out/ # Outbound port interfaces (e.g., IOrderRepository)
├── adapters/
│ ├── persistence/ # TypeORM entity + repository implementations
│ └── http/ # Controllers, DTOs, request/response mappers
└── <module>.module.ts # NestJS module definition
Layer responsibilities:
| Layer | Responsibility | Imports from |
|---|---|---|
domain/ |
Business rules, entity state, validation | Nothing external, only @shared/domain/* |
use-cases/ |
Orchestration, flow control | Only ports/* and domain/* |
ports/ |
Contracts (interfaces) | Only domain types |
adapters/persistence/ |
Database access (TypeORM) | Implements ports/out/* |
adapters/http/ |
HTTP handling (NestJS controllers) | Implements ports/in/* |
Conventions
- File naming: kebab-case (
create-order.use-case.ts,order.repository.ts) - Class naming: PascalCase (
CreateOrderUseCase,OrderRepository) - Interface prefix:
Iprefix (ICreateOrderUseCase,IOrderRepository) - Use case naming: verb + noun +
UseCase(CreateOrderUseCase,CancelOrderUseCase) - Entity properties: Use
getValue()on value objects, not direct property access in domain layer - Repository methods: CRUD naming (
findById,save,delete,findAll)
Running the Project
Local Development
npm install
cp .env.example .env
npm run migration:run
npm run seed
npm run start:dev
Docker Compose
cp .env.example .env
docker compose up
API available at http://localhost:3000 Swagger docs at http://localhost:3000/docs
Tests
npm run test:unit # Unit tests
npm run test:e2e # End-to-end tests
npm run test:cov # Tests with coverage report
OpenAPI Export
npm run docs:export
Generates docs/openapi.json and docs/openapi.yaml.
Migrations
npm run migration:generate -- --name=DescriptiveName # Generate new migration
npm run migration:run # Apply pending migrations
npm run migration:revert # Revert last migration
Seed
npm run seed # Populate database with initial data
Conventional Commits Guide
Valid Commit Types
feat, fix, chore, docs, style, refactor, test, perf, ci, build, revert
Examples
feat(sales-orders): add item quantity validation
fix(scheduling): prevent past date on reschedule
test(audit): add fault tolerance tests to AuditLogger
docs(rules): update sales-order transport change rules
chore(deps): update nestjs to v11
ci(actions): add caching for npm dependencies
refactor(customers): extract authorization logic to dedicated use case