Skip to content

Commit 1138985

Browse files
authored
Merge pull request #462 from lenneTech/develop
Release 11.7.0
2 parents 317256b + ee18534 commit 1138985

36 files changed

+4840
-2477
lines changed

.claude/rules/architecture.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Code Architecture
2+
3+
## Framework Stack
4+
5+
- **NestJS** - Server framework
6+
- **GraphQL** - API layer (Apollo Server)
7+
- **MongoDB** - Database (Mongoose ODM)
8+
9+
## Two-Layer Structure
10+
11+
1. **Core Layer** (`src/core/`) - Reusable framework components (exported to consumers)
12+
2. **Server Layer** (`src/server/`) - Internal test/demo implementation (not exported)
13+
14+
## Core Module (`src/core.module.ts`)
15+
16+
- Dynamic module providing base functionality
17+
- Configures GraphQL with Apollo Server, MongoDB with Mongoose
18+
- Provides global services: ConfigService, EmailService, TemplateService
19+
- Sets up security interceptors, validation pipes, complexity plugins
20+
- Handles GraphQL subscriptions with authentication
21+
22+
## Configuration System (`src/config.env.ts`)
23+
24+
Environment-based configuration (development, local, production) with multiple sources:
25+
26+
- Direct environment variables in config file
27+
- `NEST_SERVER_CONFIG` JSON environment variable
28+
- `NSC__*` prefixed single environment variables
29+
30+
Key areas: JWT, MongoDB, GraphQL, email, security, static assets
31+
32+
## Core Common Components (`src/core/common/`)
33+
34+
| Type | Components |
35+
|------|------------|
36+
| **Decorators** | `@Restricted()`, `@Roles()`, `@CurrentUser()`, `@UnifiedField()` |
37+
| **Helpers** | Database, GraphQL, filtering, validation utilities |
38+
| **Security** | Response/security interceptors, input validation pipes |
39+
| **Scalars** | Custom GraphQL scalars (Date, JSON, Any) |
40+
| **Services** | CRUD operations, email (Mailjet/SMTP), template rendering |
41+
42+
## Core Modules (`src/core/modules/`)
43+
44+
| Module | Purpose |
45+
|--------|---------|
46+
| **Auth** | JWT authentication, refresh tokens, role-based access |
47+
| **BetterAuth** | Modern auth integration (2FA, Passkey, Social) |
48+
| **File** | File upload/download with GridFS storage |
49+
| **User** | Core user management functionality |
50+
| **HealthCheck** | Application health monitoring |
51+
52+
## Security Implementation
53+
54+
- `@Restricted()` - Field-level access control
55+
- `@Roles()` - Method-level authorization
56+
- `CheckResponseInterceptor` - Filters restricted fields
57+
- `CheckSecurityInterceptor` - Processes `securityCheck()` methods
58+
59+
## Model Inheritance
60+
61+
- `CorePersistenceModel` - Base for database entities
62+
- `CoreModel` - Base for GraphQL types
63+
- Automatic ID handling with custom Mongoose plugin
64+
65+
## Input Validation
66+
67+
- `MapAndValidatePipe` - Automatic validation
68+
- class-validator decorators on input classes
69+
- Core args classes for filtering/pagination

.claude/rules/core-modules.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
paths: src/core/modules/**
3+
---
4+
5+
# Core Module Development Rules
6+
7+
These rules apply when working in `src/core/modules/`.
8+
9+
## Naming Conventions
10+
11+
- Base classes: `Core` prefix (e.g., `CoreAuthService`, `CoreBetterAuthResolver`)
12+
- Interfaces: `I` prefix (e.g., `IBetterAuth`, `IServerOptions`)
13+
- Models: `*Model` suffix for GraphQL types
14+
- Inputs: `*Input` suffix for input types
15+
- Args: `*Args` suffix for query arguments
16+
17+
## Method Visibility
18+
19+
- Use `protected` for methods that should be overridable
20+
- Use `public` for API methods
21+
- Avoid `private` for methods that projects might need to customize
22+
23+
## Module Registration
24+
25+
Always support both registration modes:
26+
27+
```typescript
28+
// In module class
29+
static forRoot(options: ModuleOptions): DynamicModule {
30+
// Check autoRegister option
31+
if (options.config?.autoRegister === true) {
32+
// Auto-registration logic
33+
}
34+
// Manual registration is default
35+
}
36+
```
37+
38+
## Export Requirements
39+
40+
All public classes must be exported in `src/index.ts`:
41+
42+
```typescript
43+
// src/index.ts
44+
export { CoreAuthService } from './core/modules/auth/services/core-auth.service';
45+
export { CoreBetterAuthResolver } from './core/modules/better-auth/core-better-auth.resolver';
46+
```
47+
48+
## Documentation
49+
50+
Each core module should have:
51+
52+
1. README.md in module directory
53+
2. JSDoc comments on public methods
54+
3. Interface documentation in `server-options.interface.ts`
55+
56+
## Logging
57+
58+
Use NestJS Logger with module name:
59+
60+
```typescript
61+
private readonly logger = new Logger(ModuleName.name);
62+
63+
// Use appropriate log levels
64+
this.logger.log('Important info'); // Normal operations
65+
this.logger.warn('Warning message'); // Potential issues
66+
this.logger.error('Error occurred'); // Errors
67+
this.logger.debug('Debug info'); // Development only (sparingly)
68+
```
69+
70+
## Testing
71+
72+
- Create story tests in `tests/stories/`
73+
- Test through API (REST/GraphQL), not direct service calls
74+
- Include security tests for authentication/authorization
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Module Inheritance Pattern
2+
3+
**This is a fundamental architectural pattern that MUST be followed for all new modules in `src/core/modules/`.**
4+
5+
## Why Inheritance Over Hooks/Events
6+
7+
Core modules (like `AuthModule`, `BetterAuthModule`, `FileModule`) are designed to be **extended through inheritance** in consuming projects, not manipulated through hooks, events, or other workarounds. This provides:
8+
9+
1. **Full Control**: Projects can override methods and precisely define what happens before/after `super()` calls
10+
2. **Flexibility**: Parts of the parent implementation can be skipped entirely for custom logic
11+
3. **Type Safety**: TypeScript inheritance ensures proper typing and IDE support
12+
4. **Robustness**: No runtime event systems or hooks that can fail silently
13+
14+
## Pattern Structure
15+
16+
```typescript
17+
// src/core/modules/example/core-example.resolver.ts (in nest-server)
18+
@Resolver()
19+
export class CoreExampleResolver {
20+
async someMethod() { /* base implementation */ }
21+
}
22+
23+
// src/server/modules/example/example.resolver.ts (in consuming project)
24+
@Resolver()
25+
export class ExampleResolver extends CoreExampleResolver {
26+
override async someMethod() {
27+
// Custom pre-processing
28+
const result = await super.someMethod(); // Or skip for full override
29+
// Custom post-processing
30+
return result;
31+
}
32+
}
33+
```
34+
35+
## Module Registration Options
36+
37+
Core modules should support both:
38+
39+
1. **Auto-registration** (`autoRegister: true`) - For simple projects without customization
40+
2. **Manual registration** (`autoRegister: false`, default) - Projects integrate via extended module
41+
42+
```typescript
43+
// config.env.ts - auto-registration for simple projects
44+
betterAuth: { autoRegister: true }
45+
46+
// server.module.ts - manual registration with custom resolver (recommended)
47+
BetterAuthModule.forRoot({ config, resolver: CustomResolver })
48+
```
49+
50+
## Examples in Codebase
51+
52+
- `CoreAuthService` → extended by project's `AuthService`
53+
- `CoreBetterAuthResolver` → extended by project's `BetterAuthResolver`
54+
- `CoreUserService` → extended by project's `UserService`
55+
56+
## Checklist for New Core Modules
57+
58+
When adding new core modules, ensure:
59+
60+
- [ ] Base classes in `src/core/modules/` with `Core` prefix
61+
- [ ] Methods are `protected` or `public` (not `private`) to allow override
62+
- [ ] `autoRegister` option defaults to `false`
63+
- [ ] Clear documentation for extension points
64+
- [ ] Export base classes via `src/index.ts`

.claude/rules/role-system.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Role System (RoleEnum)
2+
3+
The role system distinguishes between **real roles** and **system roles**.
4+
5+
## Real Roles
6+
7+
Actual roles stored in `user.roles` array in the database:
8+
9+
- `RoleEnum.ADMIN` - Administrator role
10+
11+
## System Roles (S_ Prefix)
12+
13+
System roles are used for **runtime checks only** and must **NEVER** be stored in `user.roles`:
14+
15+
| Role | Purpose | Check Logic |
16+
|------|---------|-------------|
17+
| `S_USER` | User is logged in | `currentUser` exists |
18+
| `S_VERIFIED` | User is verified | `user.verified \|\| user.verifiedAt \|\| user.emailVerified` |
19+
| `S_CREATOR` | User created the object | `object.createdBy === user.id` |
20+
| `S_SELF` | User is accessing own data | `object.id === user.id` |
21+
| `S_EVERYONE` | Public access | Always true |
22+
| `S_NO_ONE` | Locked access | Always false |
23+
24+
## Critical Rule
25+
26+
```typescript
27+
// CORRECT: Using S_ roles in decorators (runtime checks)
28+
@Roles(RoleEnum.S_USER)
29+
@Restricted(RoleEnum.S_VERIFIED)
30+
31+
// WRONG: Storing S_ roles in user.roles array
32+
roles: [RoleEnum.S_USER] // NEVER do this!
33+
34+
// CORRECT: Empty roles or real roles only
35+
roles: [] // Empty array
36+
roles: [RoleEnum.ADMIN] // Real role
37+
```
38+
39+
The `S_` prefix indicates a **system check**, not an actual role. These are evaluated dynamically at runtime based on context (current user, request, object being accessed).
40+
41+
## Role Decorators
42+
43+
- `@Roles(RoleEnum.ADMIN)` - Method-level authorization
44+
- `@Restricted(RoleEnum.S_VERIFIED)` - Field-level access control
45+
46+
## Role Check Implementation
47+
48+
The role system is evaluated in:
49+
- `RolesGuard` - Checks method-level `@Roles()` decorators
50+
- `CheckResponseInterceptor` - Filters fields based on `@Restricted()` decorators
51+
- `CheckSecurityInterceptor` - Processes `securityCheck()` methods

.claude/rules/testing.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Testing Configuration
2+
3+
## Test Framework
4+
5+
- **Vitest** - Primary test framework (migrated from Jest)
6+
- Configuration: `vitest.config.ts`
7+
- Test files: `tests/` directory with `.e2e-spec.ts` suffix
8+
9+
## Running Tests
10+
11+
```bash
12+
# Run all E2E tests (default)
13+
npm test
14+
15+
# Run with coverage
16+
npm run test:cov
17+
18+
# Run in CI mode
19+
npm run test:ci
20+
21+
# Debug open handles
22+
npm run test:e2e-doh
23+
```
24+
25+
## Test Environment
26+
27+
- Environment: `NODE_ENV=local`
28+
- Database: Local MongoDB instance (`mongodb://127.0.0.1/nest-server-local`)
29+
- Test helper: `src/test/test.helper.ts`
30+
- Coverage: Collected from `src/**/*.{ts,js}`
31+
32+
## Test Best Practices
33+
34+
1. **Always run tests before completing changes**: `npm test`
35+
2. **Production-ready = all tests pass** without errors
36+
3. **Use TestHelper** for GraphQL and REST API testing
37+
4. **Clean up test data** in `afterAll` hooks
38+
5. **Unique test data** - Use timestamps/random strings to avoid conflicts
39+
40+
## Test File Structure
41+
42+
```typescript
43+
import { Test, TestingModule } from '@nestjs/testing';
44+
import { TestHelper } from '../../src';
45+
46+
describe('Feature Name', () => {
47+
let testHelper: TestHelper;
48+
49+
beforeAll(async () => {
50+
const moduleFixture = await Test.createTestingModule({
51+
imports: [ServerModule],
52+
}).compile();
53+
54+
const app = moduleFixture.createNestApplication();
55+
await app.init();
56+
testHelper = new TestHelper(app);
57+
});
58+
59+
afterAll(async () => {
60+
// Cleanup test data
61+
await app.close();
62+
});
63+
64+
it('should do something', async () => {
65+
const result = await testHelper.graphQl({
66+
name: 'someQuery',
67+
type: TestGraphQLType.QUERY,
68+
fields: ['id', 'name'],
69+
});
70+
expect(result.data.someQuery).toBeDefined();
71+
});
72+
});
73+
```
74+
75+
## Common Test Issues
76+
77+
- **Tests timeout**: Ensure MongoDB is running
78+
- **Open handles**: Use `npm run test:e2e-doh` to debug
79+
- **Data conflicts**: Use unique identifiers per test

.claude/rules/versioning.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Versioning Strategy
2+
3+
## Version Schema: `MAJOR.MINOR.PATCH`
4+
5+
| Part | Meaning |
6+
|---------|--------------------------------------------------------------------|
7+
| `MAJOR` | Mirrors the NestJS major version (e.g., `11.x.x` = NestJS 11) |
8+
| `MINOR` | Breaking changes or significant restructuring |
9+
| `PATCH` | Improvements (bugfixes) or additions (new features) - non-breaking |
10+
11+
## Examples
12+
13+
- `11.0.0` → Initial release for NestJS 11
14+
- `11.1.0` → Breaking change or major restructuring within NestJS 11
15+
- `11.1.5` → Bugfix or new feature (backward compatible)
16+
17+
## Important Rules
18+
19+
1. **Document breaking changes** clearly in commit messages when incrementing MINOR version
20+
2. **Update nest-server-starter** with migration instructions for breaking changes
21+
3. **Consider downstream impact** - this package is used by multiple projects
22+
23+
## Release Process
24+
25+
1. Make changes and ensure all tests pass (`npm test`)
26+
2. Update version in `package.json`
27+
3. Build the package (`npm run build`)
28+
4. Publish to npm
29+
5. Update and test in [nest-server-starter](https://github.com/lenneTech/nest-server-starter)
30+
6. Commit changes to starter with migration notes
31+
32+
## Package Distribution
33+
34+
- **NPM Package**: `@lenne.tech/nest-server`
35+
- **Main entry**: `dist/index.js`
36+
- **Types**: `dist/index.d.ts`
37+
- **Public APIs**: Exported from `src/index.ts`
38+
39+
## Package Development Commands
40+
41+
```bash
42+
# Build and push to yalc for local testing
43+
npm run build:dev
44+
45+
# Create tarball for integration testing
46+
npm run build:pack
47+
48+
# Clean reinstall with tests and build
49+
npm run reinit
50+
51+
# Watch for changes
52+
npm run watch
53+
```

0 commit comments

Comments
 (0)