Instruction file imported from artem8746/cinemora-api (
.cursor/rules/architecture.mdc). Copyright stays with the author.
Architecture
Structure
- Root:
src/app.module.ts,src/main.ts,src/instrument.ts - Config:
src/config/— configuration, env validation - Database:
src/database/— TypeORM data-source, migrations - Feature modules:
auth/,users/,tokens/,email/,files/,resume/,vacancies/,settings/,notifications/,openai/,redis/ - Shared:
src/common/,src/filters/,src/utils/,src/validators/,src/transformers/
Layered (DDD) modules
Where used (e.g. files/, resume/):
- presentation/ — controllers, DTOs, pipes, interceptors
- application/ — commands, queries, handlers, events; depends only on domain ports
- domain/ — interfaces (ports), types, enums; no framework, no I/O
- infrastructure/ — adapters implementing domain ports (DB, R2, etc.)
Controllers → Application (handlers/services) → Domain ports; Infrastructure implements ports.
CQRS
- Commands:
commands/{action-name}/{action-name}.command.ts,{action-name}.handler.ts - Queries:
queries/{action-name}/same pattern - Handlers orchestrate; business logic lives in application services. Publish domain events after success.
- See existing
users/commands/create-user,auth/commands/register,files/application/commands.
Cross-module communication
- Never import services from other modules directly into handlers or services. Use
QueryBus/CommandBusinstead. - Each module exposes its functionality via CQRS queries and commands. Other modules interact exclusively through the bus.
- Only same-module services may be injected directly into handlers.
- This keeps modules decoupled and avoids importing foreign modules just for a single service call.
Module registration
Feature modules in app.module.ts. Use NestJS DI; inject ports via @Inject(SYMBOL) where DDD layers exist.