# Migration Guide: 11.13.x → 11.14.0

## Overview

| Category | Details |
|----------|---------|
| **Breaking Changes** | None |
| **New Features** | CoreSystemSetupModule (11.13.5), `disableSignUp` (11.13.4), BetterAuth performance optimizations (11.13.3), BetterAuthRolesGuard DI fix (11.13.2), API middleware 404 fallback (11.14.0) |
| **Internal Changes** | Switch from ESLint/Prettier to oxlint/oxfmt, remove legacy Jest references, tsconfig target es2020 → es2022 |
| **Dependency Updates** | `nodemailer` 7→8, `ejs` 3→4, `mongoose` 9.1.5→9.1.6, `better-auth` 1.4.17→1.4.18, NestJS 11.1.12→11.1.13 |
| **Migration Effort** | Minimal (~2 minutes) - update package and verify build |

---

## Quick Migration

```bash
# Update package
npm install @lenne.tech/nest-server@11.14.0

# If package.json dependencies changed
npm run update

# Verify build
npm run build

# Run tests
npm test
```

---

## What's New in 11.13.1 – 11.14.0

### 1. CoreSystemSetupModule – Initial Admin Creation (11.13.5)

New module for creating the first admin user on fresh deployments, especially useful when `disableSignUp` is enabled.

**Enabled by default** when BetterAuth is active. No configuration needed.

**REST Endpoints:**

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/system-setup/status` | Check if system needs setup |
| POST | `/api/system-setup/init` | Create initial admin user |

**Auto-creation for Docker/CI deployments:**

```bash
# .env or Docker environment
NSC__systemSetup__initialAdmin__email=admin@example.com
NSC__systemSetup__initialAdmin__password=YourSecurePassword123!
NSC__systemSetup__initialAdmin__name=Admin  # optional
```

Or in `config.env.ts`:

```typescript
systemSetup: {
  initialAdmin: {
    email: process.env.INITIAL_ADMIN_EMAIL,
    password: process.env.INITIAL_ADMIN_PASSWORD,
  },
},
```

**Security:** Init only works when zero users exist. Once any user is created, the endpoint is permanently locked (403).

**To disable:**
```typescript
systemSetup: { enabled: false },
```

**Documentation:** [SystemSetup README](../src/core/modules/system-setup/README.md) | [Integration Checklist](../src/core/modules/system-setup/INTEGRATION-CHECKLIST.md)

### 2. Disable Sign-Up for Invite-Only Apps (11.13.4)

New configuration option to disable email/password sign-up while keeping sign-in for existing users:

```typescript
// config.env.ts
betterAuth: {
  emailAndPassword: {
    disableSignUp: true,
  },
},
```

When enabled:
- REST `POST /iam/sign-up/email` returns error `LTNS_0026`
- GraphQL `betterAuthSignUp` mutation returns error `LTNS_0026`
- Sign-in for existing users continues to work normally
- System Setup endpoints bypass this restriction (for initial admin creation)

**Defense in Depth:** Custom `ensureSignUpEnabled()` check fires before BetterAuth API calls (structured error), native `disableSignUp` flag acts as safety net for direct API access.

### 3. BetterAuth Sign-In Performance Optimization (11.13.3)

- **Native scrypt** implementation replaces JS-based hashing for faster password verification
- **Migration fast-path** skips unnecessary operations for already-migrated users
- **Bounded in-memory stores** prevent unbounded memory growth in rate limiters and caches

No configuration changes needed. Performance improvements are automatic.

### 4. BetterAuthRolesGuard – DI Fix for autoRegister:false (11.13.2)

Fixes dependency injection issues when using `betterAuth: { autoRegister: false }` (Pattern 3). The new `BetterAuthRolesGuard` has no constructor dependencies, avoiding the mixin DI conflict with `AuthGuard(JWT)`.

**Impact:** If you use Pattern 3 (`autoRegister: false`) and experienced `Reflector not available` errors, this is now fixed automatically.

### 5. Middleware Token Priority Fix (11.13.1)

Fixes a bug where an invalid Authorization header could prevent cookie-based authentication fallback. The middleware now correctly falls back to session cookies when the Authorization header token is invalid.

### 6. API Middleware 404 Fallback (11.14.0)

The BetterAuth API middleware now calls `next()` when BetterAuth returns a 404 response, allowing NestJS controllers to handle custom `/iam/*` endpoints. Previously, custom controller endpoints under the `/iam/` path would get intercepted and return 404.

**Impact:** Projects with custom BetterAuth controller endpoints that previously returned 404 should now work correctly.

### 7. Internal Tooling: Switch to oxlint and oxfmt (11.14.0)

nest-server internally switched from ESLint/Prettier to [oxlint](https://oxc.rs/docs/guide/usage/linter) and [oxfmt](https://oxc.rs/docs/guide/usage/formatter) for linting and formatting.

**Impact on consuming projects:** None. This is an internal tooling change. Consuming projects can continue using ESLint/Prettier or any other linting setup.

**What was removed from nest-server:**
- `eslint`, `eslint-config-prettier`, `eslint-plugin-unused-imports`, `@typescript-eslint/*`
- `prettier`, `pretty-quick`
- `ts-jest`, `@lenne.tech/eslint-config-ts`
- `jest-e2e.json`, Jest config in `package.json`
- `eslint.config.mjs`, `.prettierrc`, `.prettierignore`

**What was added:**
- `oxlint` (linter)
- `oxfmt` (formatter)
- `.oxlintrc.json`, `.oxfmtrc.jsonc`, `.oxlintignore`

### 8. Dependency Updates (11.14.0)

| Package | From | To | Notes |
|---------|------|----|-------|
| `nodemailer` | 7.0.13 | 8.0.1 | Major version bump (internal dependency) |
| `ejs` | 3.1.10 | 4.0.1 | Major version bump (internal dependency) |
| `mongoose` | 9.1.5 | 9.1.6 | Patch update |
| `better-auth` | 1.4.17 | 1.4.18 | Patch update |
| `@better-auth/passkey` | 1.4.17 | 1.4.18 | Patch update |
| `@nestjs/common` | 11.1.12 | 11.1.13 | Patch update |
| `@nestjs/core` | 11.1.12 | 11.1.13 | Patch update |
| `@nestjs/apollo` | 13.2.3 | 13.2.4 | Patch update |
| `@nestjs/graphql` | 13.2.3 | 13.2.4 | Patch update |
| `@nestjs/swagger` | 11.2.5 | 11.2.6 | Patch update |
| `dotenv` | 17.2.3 | 17.2.4 | Patch update |

These are **nest-server's own dependencies**, not peer dependencies. Consuming projects are not directly affected unless they also depend on these packages at conflicting versions.

---

## Breaking Changes

None. This release is fully backward compatible.

**Note:** The email verification URL `console.log` is now restricted to `local`, `development`, and `test` environments (`NODE_ENV`). In production, the URL is no longer logged to the console. This is a security improvement — verification URLs should never appear in production logs.

---

## Detailed Migration Steps

### Step 1: Update Package

```bash
npm install @lenne.tech/nest-server@11.14.0
```

### Step 2: Adopt New Features (Optional)

#### Enable disableSignUp (Invite-Only)

```typescript
// config.env.ts
betterAuth: {
  emailAndPassword: {
    disableSignUp: true,
  },
},
```

#### Configure System Setup Auto-Creation

```bash
# .env
NSC__systemSetup__initialAdmin__email=admin@example.com
NSC__systemSetup__initialAdmin__password=YourSecurePassword123!
```

### Step 4: Build and Test

```bash
npm run build
npm test
```

---

## Compatibility Notes

### Consuming Project Tooling

nest-server's switch to oxlint/oxfmt does **not** affect consuming projects. Your project can continue using ESLint, Prettier, or any other tooling independently.

### TypeScript Target

nest-server's internal `tsconfig.json` target changed from `es2020` to `es2022`. This only affects nest-server's own compilation output. Consuming projects are not affected since they use the compiled `dist/` output.

### nodemailer and ejs Major Bumps

`nodemailer` (7→8) and `ejs` (3→4) are nest-server's internal dependencies. They are not exposed as peer dependencies. If your project independently depends on these packages at different major versions, npm should resolve them separately.

### Existing Custom BetterAuth Endpoints

If you have custom controller endpoints under the `/iam/` path that previously returned 404, they should now work correctly thanks to the API middleware 404 fallback fix.

### Projects Without BetterAuth

If your project does not use BetterAuth, the SystemSetup module and disableSignUp feature have no impact. The tooling switch and dependency updates apply universally but require no action.

---

## Bugfixes Included (11.13.1 – 11.14.0)

### Promise Constructor Antipattern Fix (11.14.0)

`CrudService.updateMany()` previously wrapped async operations in unnecessary `new Promise()` constructors. This has been cleaned up to use direct promise returns, which is both simpler and avoids the async executor antipattern.

No action needed — this is a purely internal cleanup.

### Code Formatting Normalization (11.14.0)

oxfmt applies slightly different formatting than Prettier:
- Arrow function parameters always have parentheses: `key =>` → `(key) =>`
- Operators at end of line instead of start: `&&\n` instead of `\n&&`
- Redundant spread removal: `...(obj ?? {})` → `...obj`
- Double negation removal: `!!parameter` → `parameter`

These are code style changes only and do not affect behavior.

### Regex Escape Fix in isEmail() (11.14.0)

The `isEmail()` helper function had unnecessary escape characters in a character class (`[\.-]` → `[.-]`). This was a linting warning fix with no behavioral change.

---

## Troubleshooting

### Tests Fail Capturing Email Verification URL

**Cause:** The `console.log` for verification URLs now only runs when `NODE_ENV` is `local`, `development`, or `test`. If your test environment uses a different `NODE_ENV`, the log won't appear.

**Solution:** Ensure your test environment sets `NODE_ENV=local` or `NODE_ENV=test`.

### Custom `/iam/*` Controller Endpoints Now Return Different Responses

**Cause:** The API middleware 404 fallback now passes unhandled paths to NestJS controllers.

**Solution:** This is the intended fix. If you had workarounds for the previous 404 behavior, you may need to remove them.

### `Reflector not available` Error with autoRegister:false

**Cause:** Fixed in 11.13.2 with BetterAuthRolesGuard.

**Solution:** Update to 11.14.0. No code changes needed.

### Sign-Up Suddenly Fails with LTNS_0026

**Cause:** `disableSignUp` may be set to `true` in config.

**Solution:** Check `betterAuth.emailAndPassword.disableSignUp` in `config.env.ts`. Set to `false` or remove to re-enable sign-up.

### System Setup Endpoint Returns 403

**Cause:** Users already exist in the database, OR BetterAuth is not enabled.

**Solution:** System setup init only works on an empty database. Check `GET /api/system-setup/status` for diagnostics.

---

## New Exports

The following are newly exported from `@lenne.tech/nest-server` (since 11.13.0):

```typescript
// System Setup Module (11.13.5)
export { CoreSystemSetupController, SystemSetupInitDto } from './core/modules/system-setup/core-system-setup.controller';
export { CoreSystemSetupModule } from './core/modules/system-setup/core-system-setup.module';
export { CoreSystemSetupService, SystemSetupInitInput, SystemSetupInitResult, SystemSetupStatus } from './core/modules/system-setup/core-system-setup.service';

// Configuration Interfaces (11.13.5)
export { ISystemSetup, ISystemSetupInitialAdmin } from './core/common/interfaces/server-options.interface';
```

---

## Module Documentation

### System Setup Module (New)

- **README:** [src/core/modules/system-setup/README.md](../src/core/modules/system-setup/README.md)
- **Integration Checklist:** [src/core/modules/system-setup/INTEGRATION-CHECKLIST.md](../src/core/modules/system-setup/INTEGRATION-CHECKLIST.md)
- **Key Files:**
  - `core-system-setup.controller.ts` – REST endpoints (status + init)
  - `core-system-setup.service.ts` – Admin creation logic with zero-user guard
  - `core-system-setup.module.ts` – Conditionally imported in CoreModule

### Better-Auth Module (Updated)

- **README:** [src/core/modules/better-auth/README.md](../src/core/modules/better-auth/README.md)
- **Integration Checklist:** [src/core/modules/better-auth/INTEGRATION-CHECKLIST.md](../src/core/modules/better-auth/INTEGRATION-CHECKLIST.md)
- **Customization Guide:** [src/core/modules/better-auth/CUSTOMIZATION.md](../src/core/modules/better-auth/CUSTOMIZATION.md)
- **Key Changes:**
  - `emailAndPassword.disableSignUp` configuration option (11.13.4)
  - BetterAuthRolesGuard for DI fix in Pattern 3 (11.13.2)
  - API middleware 404 fallback for custom endpoints (11.14.0)
  - Native scrypt performance optimization (11.13.3)

---

## Version History (11.13.0 → 11.14.0)

| Version | Type | Summary |
|---------|------|---------|
| 11.13.1 | Bugfix | BetterAuth middleware token priority fix, RolesGuard REST support |
| 11.13.2 | Bugfix | BetterAuthRolesGuard for DI issues with autoRegister:false |
| 11.13.3 | Performance | Native scrypt, migration fast-path, bounded in-memory stores |
| 11.13.4 | Feature | `emailAndPassword.disableSignUp` for invite-only apps |
| 11.13.5 | Feature | CoreSystemSetupModule for initial admin creation |
| 11.14.0 | Breaking | Switch to oxlint/oxfmt, remove ESLint/Prettier/Jest legacy, dependency updates |

---

## References

- [SystemSetup Module](../src/core/modules/system-setup/) – New module for initial admin creation
- [Better-Auth Module](../src/core/modules/better-auth/) – Core auth module
- [nest-server-starter](https://github.com/lenneTech/nest-server-starter) – Reference implementation
- [oxlint Documentation](https://oxc.rs/docs/guide/usage/linter) – New linter
- [oxfmt Documentation](https://oxc.rs/docs/guide/usage/formatter) – New formatter
- [Configurable Features Pattern](../.claude/rules/configurable-features.md) – Configuration patterns used
