# Migration Guide: 11.24.2 → 11.24.3

## Overview

| Category | Details |
|----------|---------|
| **Breaking Changes** | None |
| **New Features** | Simplified enum API, `registerEnums()`, expanded mail transports |
| **Bugfixes** | Optional enum fields no longer rejected as "must be an object" |
| **Deprecations** | `enum: { enum: MyEnum, enumName: ... }` long form (still works) |
| **Migration Effort** | ~5 min setup + find-and-replace per project |

---

## Quick Start (Minimum — No Code Changes Required)

```bash
pnpm install @lenne.tech/nest-server@11.24.3
pnpm run build
pnpm test
```

Everything works as before. You will see **deprecation warnings** for every
`enum: { enum: ... }` usage at startup. These are informational — no behavior
changes, no errors. Follow the steps below to migrate and silence them.

---

## What Changed

### Bugfix: Optional Enum Validation

Fields like `status?: MyEnum` were rejected with `"must be an object"`.
Fixed — `IsEnum()` is now the authoritative validator for enum fields.

### New: Simplified Enum API

The `{ enum: MyEnum }` wrapper is no longer needed:

```typescript
// OLD (deprecated — still works, emits warning)
@UnifiedField({ enum: { enum: StatusEnum, enumName: 'StatusEnum' } })

// NEW (recommended)
@UnifiedField({ enum: StatusEnum })
```

### New: `registerEnums()` Bulk Registration

One-line setup per project — enables enum name auto-detection so you can
drop `enumName` entirely:

```typescript
import * as Enums from './common/enums';
import { registerEnums } from '@lenne.tech/nest-server';
registerEnums(Enums);
```

### New: `isArray` Auto-Propagation

Array enum fields no longer need `options: { each: true }`:

```typescript
// OLD
@UnifiedField({ enum: { enum: X, options: { each: true } }, isArray: true, type: () => X })

// NEW
@UnifiedField({ enum: X, isArray: true, type: () => X })
```

### New: Expanded Mail Transports

`email.smtp` now accepts all nodemailer transports. `{ jsonTransport: true }`
is useful for CI/e2e tests (no SMTP server needed). A runtime guard prevents
accidental use in production/staging.

---

## Migration Steps

### Step 1: Set Up `registerEnums()` (1 minute)

This enables auto-detection of enum names from barrel exports. After this
step, `enumName` is no longer needed.

**Prerequisite:** Your project has a barrel file that re-exports all enums
(e.g. `src/server/common/enums/index.ts`). If not, create one.

```typescript
// src/server/common/enums/index.ts
export { ContactStatusEnum } from './contact-status.enum';
export { IndustryEnum } from './industry.enum';
// ... all your enums
```

Then add one line to your module setup:

```typescript
// src/server/server.module.ts (or main.ts, before NestFactory.create)
import * as Enums from './common/enums';
import { registerEnums } from '@lenne.tech/nest-server';

registerEnums(Enums);
```

**How it works:** `import * as Enums` creates an object where the keys are
the export names (`{ ContactStatusEnum: {...}, IndustryEnum: {...} }`).
`registerEnums()` iterates the entries, filters out non-enums, and registers
each enum for both Swagger and GraphQL under its export name.

**Verify:** Start your server — enum names should appear correctly in
Swagger UI and GraphQL schema. If you see missing enum names, check that
the enum is exported from the barrel file.

### Step 2: Transform Enum Declarations (find-and-replace)

Use these regex patterns to transform all `@UnifiedField` enum usages.
Run them in order.

**Pattern A — Remove `options: { each: true }` from array enums:**

```
Search:  enum: \{ enum: (\w+),\s*enumName: '[^']+',\s*options: \{ each: true \}\s*\}
Replace: enum: $1
```

**Pattern B — Long form with enumName → shortcut:**

```
Search:  enum: \{ enum: (\w+),\s*enumName: '[^']+'\s*\}
Replace: enum: $1
```

**Pattern C — Long form without enumName → shortcut:**

```
Search:  enum: \{ enum: (\w+)\s*\}
Replace: enum: $1
```

**After each pattern:** Build and run tests to verify nothing broke:

```bash
pnpm run build && pnpm test
```

### Step 3: Verify (1 minute)

```bash
# Check no long-form patterns remain
grep -rn "enum: { enum:" src/ --include="*.ts"

# Start server — should have zero deprecation warnings
pnpm start
```

---

## Cheat Sheet

| Before (deprecated) | After |
|---------------------|-------|
| `enum: { enum: X }` | `enum: X` |
| `enum: { enum: X, enumName: 'X' }` | `enum: X` |
| `enum: { enum: X, options: { each: true } }, isArray: true` | `enum: X, isArray: true` |
| `enum: { enum: X, enumName: 'X', options: { each: true } }, isArray: true` | `enum: X, isArray: true` |

For cases where you need explicit control:

| Need | Solution |
|------|----------|
| Custom enum name in schema | `enum: X, enumName: 'CustomName'` |
| Disable auto-detection | `enum: X, enumName: null` |
| Skip all validation | `enum: X, isAny: true` |
| Custom validator | `enum: X, validator: (opts) => [...]` |

---

## Compatibility Notes

### Deprecation Warnings

After updating, every `enum: { enum: ... }` usage emits a `console.warn`
at class definition time (server startup). This is intentional — it helps
you find all places that need migration. The warnings disappear once you
complete Steps 1–3.

If you need to update the package but cannot migrate immediately, the
warnings are purely informational — no behavior changes.

### Existing `options: { each: true }`

Explicit `options: { each: true }` continues to work. The auto-propagation
from `isArray` only applies when `each` is not already set. You can remove
the explicit option at your own pace.

### Custom `isAny` / `validator` Workarounds

If you added `isAny: true` or a custom `validator` to work around the
optional-enum bug, both continue to work. You can safely remove them.

### SMTP Configuration

All existing `email.smtp` configurations continue to work unchanged. The
type is a strict superset of the previous type.

---

## Troubleshooting

### "JSONTransport is not permitted in production/staging environments"

This new runtime guard triggers when `email.smtp` is `{ jsonTransport: true }`
in `NODE_ENV=production` or `NODE_ENV=staging`. JSONTransport silently
discards all mail — use a real transport in production.

### Enum name missing in Swagger/GraphQL after migration

Ensure the enum is exported from your barrel file and `registerEnums()` is
called before NestJS bootstraps. Check with:

```typescript
import { enumNameRegistry } from '@lenne.tech/nest-server';
console.log(enumNameRegistry.get(MyEnum)); // Should print the enum name
```

### Optional enum fields still rejected

Verify: (1) `enum:` is set on the field, (2) the field type is the enum
type, (3) you're running 11.24.3+ (`pnpm list @lenne.tech/nest-server`).

---

## Module Documentation

| Module / File | Documentation |
|---------------|---------------|
| `@UnifiedField` decorator | [`src/core/common/decorators/unified-field.decorator.ts`](../src/core/common/decorators/unified-field.decorator.ts) — JSDoc on `UnifiedFieldOptions.enum` and `enumName` |
| `registerEnum` / `registerEnums` | [`src/core/common/helpers/register-enum.helper.ts`](../src/core/common/helpers/register-enum.helper.ts) — JSDoc with `@example` blocks |
| `MailTransportOptions` type | [`src/core/common/interfaces/server-options.interface.ts`](../src/core/common/interfaces/server-options.interface.ts) — all nodemailer transport types |
| `FRAMEWORK-API.md` | [`FRAMEWORK-API.md`](../FRAMEWORK-API.md) — auto-generated API reference (v11.24.3) |

### New Public Exports (via `src/index.ts`)

- `registerEnums(namespace, options?)` — bulk-register all enums from a barrel-export namespace
- `graphqlEnumRegistry` — WeakSet tracking GraphQL-registered enums (advanced use only)
- `MailTransportOptions` — union type of all nodemailer transport configurations
- `RegisterEnumsOptions` — options interface for `registerEnums()`

---

## References

- [nest-server-starter](https://github.com/lenneTech/nest-server-starter)
- [nodemailer transports](https://nodemailer.com/transports/)
