# Review Subdomain

> Reviews a NestJS bounded context implementation for Hexagonal Architecture + DDD + CQRS compliance. Checks 6 dimensions — domain purity, application patterns, infrastructure isolation, presentation concerns, testing coverage, and module organization. Produces a structured Pass/Warning/Fail report.

- **Type:** Skill
- **Install:** `agentstack add skill-softtor-nestjs-hexagonal-review-subdomain`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Softtor](https://agentstack.voostack.com/s/softtor)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Softtor](https://github.com/Softtor)
- **Source:** https://github.com/Softtor/nestjs-hexagonal/tree/main/skills/review-subdomain
- **Website:** https://github.com/Softtor/nestjs-hexagonal#readme

## Install

```sh
agentstack add skill-softtor-nestjs-hexagonal-review-subdomain
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# review-subdomain

Review a bounded context for architectural compliance. Accept the BC path as the argument (e.g., `src/enterprise/billing/invoices`). Run each dimension in order. Produce a structured report at the end.

The rubric with scoring criteria is in `references/review-rubric.md`.

---

## Setup

Resolve the target directory from the argument. If no argument is given, ask the user for the path.

Verify the directory exists:

```bash
ls 
```

If the directory does not exist, stop and report an error.

Set `BC_PATH` to the resolved absolute path. All grep and glob searches below use `BC_PATH` as the root.

---

## Dimension 1 — Domain Purity

**Purpose:** Confirm the domain layer has zero framework or infrastructure dependencies.

Run the following checks against `/domain/`:

**Check D1 — No NestJS common imports in domain:**
```bash
grep -r "@nestjs/common" /domain/ --include="*.ts" -l
```
FAIL if any files are returned. Exception: `@nestjs/cqrs` is allowed (for `AggregateRoot`, `IEvent`).

**Check D2 — No class-validator in VOs:**
```bash
grep -r "class-validator" /domain/value-objects/ --include="*.ts" -l
```
FAIL if any files are returned. `class-validator` is allowed in `domain/validators/` only.

**Check D3 — No Prisma imports in domain:**
```bash
grep -r "PrismaClient\|PrismaService\|@prisma/client" /domain/ --include="*.ts" -l
```
FAIL if any files are returned.

**Check D4 — Entity uses apply() not addDomainEvent():**
```bash
grep -r "addDomainEvent\|pullDomainEvents" /domain/ --include="*.ts" -l
```
FAIL if any files are returned. Entities must use `this.apply(event)`.

**Check D5 — Entity has create() and restore() factories:**

For each entity file found in `/domain/entities/`:
- Read the file
- Confirm `static create(` is present
- Confirm `static restore(` is present
- Confirm `private constructor` is present

FAIL if any entity is missing one of these.

**Check D6 — Repository interface is a pure interface (no @Injectable):**
```bash
grep -r "@Injectable" /domain/repositories/ --include="*.ts" -l
```
FAIL if any files are returned.

**Check D7 — Data builders exist:**
```bash
ls /domain/testing/helpers/
```
WARNING if the directory is empty or does not exist.

---

## Dimension 2 — Application Patterns

**Purpose:** Confirm the application layer follows the chosen pattern correctly and does not hold framework concerns.

**Check A1 — EventPublisher not in use cases:**
```bash
grep -r "EventPublisher" /application/ --include="*.ts" -l
```
FAIL if `EventPublisher` appears in `application/usecases/` or `application/dtos/`. It is allowed in `application/commands/` (Pattern B/C handlers).

**Check A2 — No class-validator in application DTOs:**
```bash
grep -r "IsString\|IsNotEmpty\|IsEmail\|IsOptional\|IsUUID\|IsEnum\|IsNumber\|IsBoolean\|IsArray\|ValidateNested" /application/ --include="*.ts" -l
```
FAIL if any files are returned. `class-validator` belongs only in presentation request DTOs.

**Check A3 — Pattern A use cases have no @Injectable:**

Find files matching `/application/usecases/*.usecase.ts`:
```bash
grep -r "@Injectable" /application/usecases/ --include="*.ts" -l
```
FAIL if `@Injectable` appears in use case files.

**Check A4 — Write handlers return void or { id: string }:**

Read each command handler in `/application/commands/`:
- Check the return type annotation on `execute()`
- FAIL if return type is an entity class or a full output DTO with many fields
- PASS if return type is `void`, `Promise`, `{ id: string }`, or `Promise`

**Check A5 — commit() called in handlers, not in use cases:**
```bash
grep -r "\.commit()" /application/usecases/ --include="*.ts" -l
```
FAIL if `.commit()` appears in use case files.

**Check A6 — Ports defined in application/ports/ with TOKEN symbol:**

Find files in `/application/ports/`:
- Each port file should export a `Symbol` token
```bash
grep -r "Symbol(" /application/ports/ --include="*.ts" -l
```
WARNING if port files exist without a `Symbol(` token export.

---

## Dimension 3 — Infrastructure Isolation

**Purpose:** Confirm infrastructure wires domain to the outside world without leaking domain logic.

**Check I1 — Module exports only tokens:**

Read `/infrastructure/*.module.ts`:
- Find the `exports:` array
- FAIL if any class name (not a Symbol constant) appears in the exports array
- PASS if exports contains only token constants (e.g., `_REPOSITORY`, `_PORT_TOKEN`)

**Check I2 — Repository has no event dispatch:**
```bash
grep -r "\.commit()\|EventBus\|EventPublisher\|publish(" /infrastructure/database/ --include="*.ts" -l
```
FAIL if any of these appear in repository files.

**Check I3 — Mapper uses restore() not create():**
```bash
grep -r "Entity\.create\|\.create(" /infrastructure/database/prisma/models/ --include="*.ts" -l
```
FAIL if entity `create()` is called inside a mapper. Mappers must call `restore()`.

**Check I4 — In-memory repository exists:**
```bash
ls /infrastructure/database/in-memory/repositories/
```
WARNING if directory is empty or missing.

**Check I5 — Event handlers use @EventsHandler not @OnEvent:**
```bash
grep -r "@OnEvent" /infrastructure/listeners/ --include="*.ts" -l
```
FAIL if `@OnEvent` is used in listeners. All new domain event handlers must use `@EventsHandler`.

**Check I6 — Event handlers have try/catch:**

Read each file in `/infrastructure/listeners/`:
- FAIL if `handle()` method does not contain a `try {` block

**Check I7 — organizationId (or tenant id) in all Prisma queries:**

Read each Prisma repository file in `/infrastructure/database/prisma/repositories/`:
- Check `search()` has `organizationId` (or tenant field) in `whereClause`
- WARNING if `search()` does not scope by tenant

---

## Dimension 4 — Presentation Concerns

**Purpose:** Confirm controllers are thin HTTP adapters and request DTOs hold all input validation.

**Check P1 — class-validator used only in request DTOs:**
```bash
grep -r "IsString\|IsNotEmpty\|IsEmail\|IsOptional\|IsUUID\|IsEnum\|ValidateNested" /infrastructure/controllers/dtos/ --include="*.ts" -l
```
This should return files. If no files returned: WARNING (validation may be missing).
```bash
grep -r "IsString\|IsNotEmpty\|IsEmail\|IsOptional\|IsUUID\|IsEnum\|ValidateNested" /infrastructure/controllers/ --include="*.ts" -l
```
Cross-check: all results should be inside `dtos/`, not in the controller itself.

**Check P2 — organizationId not taken from request body:**
```bash
grep -r "body\.organizationId\|dto\.organizationId\|req\.body.*organizationId" /infrastructure/controllers/ --include="*.ts" -l
```
FAIL if `organizationId` is read from the request body in a controller. Must come from `@CurrentOrganization()`.

**Check P3 — Swagger decorators present:**
```bash
grep -r "@ApiOperation\|@ApiResponse\|@ApiTags" /infrastructure/controllers/ --include="*.ts" -l
```
WARNING if no Swagger decorators found in controller files.

**Check P4 — Guards applied:**
```bash
grep -r "@UseGuards\|@ApiBearerAuth" /infrastructure/controllers/ --include="*.ts" -l
```
WARNING if no guards found on any controller.

**Check P5 — No business logic in controllers:**

Read each controller file. Flag as FAIL if any of these patterns appear directly in a controller method (not in a called service):
- Direct repository calls (`this.repository.findById`)
- Domain entity instantiation (`XxxEntity.create`)
- Business rule conditions beyond simple null checks

---

## Dimension 5 — Testing Coverage

**Purpose:** Confirm test files exist and follow the test-first structure.

**Check T1 — Entity spec files exist:**
```bash
find /domain/entities/__tests__ -name "*.spec.ts" 2>/dev/null
```
WARNING if no spec files found.

**Check T2 — VO spec files exist:**
```bash
find /domain/value-objects/__tests__ -name "*.spec.ts" 2>/dev/null
```
WARNING if VO files exist but no specs.

**Check T3 — Application spec files exist:**
```bash
find /application -name "*.spec.ts" 2>/dev/null
```
WARNING if application layer has no specs.

**Check T4 — Controller spec files exist:**
```bash
find /infrastructure/controllers/__tests__ -name "*.spec.ts" 2>/dev/null
```
WARNING if controllers exist but no specs.

**Check T5 — In-memory repository used in application tests:**
```bash
grep -r "InMemoryRepository" /application --include="*.spec.ts" -l
```
WARNING if application specs exist but none use the in-memory repository.

---

## Dimension 6 — Module Organization

**Purpose:** Confirm the directory structure and naming conventions are correct.

**Check M1 — Standard directories present:**

Verify these paths exist under `BC_PATH`:
- `domain/entities/`
- `domain/repositories/`
- `domain/events/`
- `application/`
- `infrastructure/`

WARNING for each missing standard directory.

**Check M2 — Module file exists:**
```bash
find /infrastructure -maxdepth 1 -name "*.module.ts" 2>/dev/null
```
FAIL if no module file found.

**Check M3 — No cross-layer imports (domain importing infrastructure):**
```bash
grep -r "from.*infrastructure\|require.*infrastructure" /domain/ --include="*.ts" -l
grep -r "from.*infrastructure\|require.*infrastructure" /application/ --include="*.ts" -l
```
FAIL if domain or application imports from infrastructure.

**Check M4 — File naming conventions:**

Spot-check a few files:
- Entity files: `.entity.ts`
- VO files: `.vo.ts`
- Event files: `-ed.event.ts`
- Handler files: `.handler.ts` or `-ed.handler.ts`
- Repository files: `.repository.ts`, `prisma-.repository.ts`

WARNING if files deviate significantly from these naming conventions.

---

## Report Format

Produce a structured markdown report after all checks:

```
# Architecture Review: 

## Summary

| Dimension | Status |
|---|---|
| Domain Purity | PASS / FAIL |
| Application Patterns | PASS / FAIL |
| Infrastructure Isolation | PASS / FAIL |
| Presentation Concerns | PASS / WARNING |
| Testing Coverage | PASS / WARNING |
| Module Organization | PASS / FAIL |

Overall: PASS / NEEDS WORK

---

## Findings

### FAIL Items (must fix before merge)

- **[D1] No NestJS common imports in domain:** Found in `domain/entities/order.entity.ts` (line 3: `import { Injectable }`)
  Fix: Remove `@Injectable` — entities have no framework decorators.

- **[I1] Module exports only tokens:** `PrismaOrderRepository` exported from `orders.module.ts`
  Fix: Change to `exports: [ORDER_REPOSITORY]`.

### WARNING Items (recommended improvements)

- **[T1] Entity spec files:** No spec files found in `domain/entities/__tests__/`
  Recommendation: Add entity unit tests covering `create()`, `restore()`, and each mutating method.

- **[D7] Data builders:** `domain/testing/helpers/` is empty
  Recommendation: Add `OrderDataBuilder` with faker defaults for use in all test files.

### PASS Items

- Domain purity: no framework imports in domain
- Application DTOs: no class-validator found
- Mapper uses restore(): confirmed in `order-model.mapper.ts`
- Module exports: only token Symbols exported
```

---

## After the Report

- FAIL items are blocking — the BC is not ready to merge until all FAILs are resolved.
- WARNING items are advisory — present them to the user and ask whether to address now or log as tech debt.
- If all items are PASS or WARNING: report the BC as architecture-compliant.

Suggest specific fixes for each FAIL item, referencing the relevant layer skill (`nestjs-hexagonal:domain`, `nestjs-hexagonal:application`, etc.) for implementation guidance.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Softtor](https://github.com/Softtor)
- **Source:** [Softtor/nestjs-hexagonal](https://github.com/Softtor/nestjs-hexagonal)
- **License:** MIT
- **Homepage:** https://github.com/Softtor/nestjs-hexagonal#readme

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-softtor-nestjs-hexagonal-review-subdomain
- Seller: https://agentstack.voostack.com/s/softtor
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
