rockets-crud-generator
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRockets SDK CRUD Generator
Rockets SDK CRUD 生成器
Generate complete CRUD modules following Rockets SDK patterns with TypeORM, NestJS, and proper DTOs/interfaces.
遵循Rockets SDK规范,使用TypeORM、NestJS及标准DTO/接口生成完整的CRUD模块。
Quick Start
快速开始
bash
undefinedbash
undefinedGenerate files (outputs JSON)
生成文件(输出JSON格式)
node skills/rockets-crud-generator/scripts/generate.js '{ "entityName": "Product", "fields": [...] }'
node skills/rockets-crud-generator/scripts/generate.js '{ "entityName": "Product", "fields": [...] }'
Generate + integrate into project
生成并集成到项目中
node skills/rockets-crud-generator/scripts/generate.js '{ ... }' | node skills/rockets-crud-generator/scripts/integrate.js --project ./apps/api
node skills/rockets-crud-generator/scripts/generate.js '{ ... }' | node skills/rockets-crud-generator/scripts/integrate.js --project ./apps/api
Validate after generation
生成后验证
node skills/rockets-crud-generator/scripts/validate.js --project ./apps/api --build
undefinednode skills/rockets-crud-generator/scripts/validate.js --project ./apps/api --build
undefinedScripts
脚本说明
| Script | Purpose | Tokens |
|---|---|---|
| Generate all files as JSON output | 0 |
| Write files + wire into project (entities, modules, ACL, queryServices) | 0 |
| Post-generation checks (structure, build, ACL) | 0 |
| 脚本 | 用途 | 令牌 |
|---|---|---|
| 以JSON格式输出所有生成的文件 | 0 |
| 写入文件并集成到项目中(实体、模块、ACL、查询服务) | 0 |
| 生成后检查(结构、构建、ACL) | 0 |
Configuration
配置项
typescript
interface Config {
// Required
entityName: string; // PascalCase entity name
// Optional naming
pluralName?: string; // API path plural (auto-pluralized)
tableName?: string; // Database table (snake_case)
// Output paths (configurable per project)
paths?: {
entity?: string; // Default: "src/entities"
module?: string; // Default: "src/modules"
shared?: string; // Default: "src/shared" (set to null to skip)
};
// Shared package import path for generated code
sharedPackage?: string; // e.g., "@my-org/shared" (default: relative import)
// Fields & Relations
fields: FieldConfig[];
relations?: RelationConfig[];
// Operations (default: all)
operations?: ('readMany' | 'readOne' | 'createOne' | 'updateOne' | 'deleteOne' | 'recoverOne')[];
// ACL (access control)
acl?: Record<string, { possession: 'own' | 'any'; operations: ('create'|'read'|'update'|'delete')[] }>;
ownerField?: string; // Field for ownership check (default: "userId")
// Options
generateModelService?: boolean;
isJunction?: boolean;
}typescript
interface Config {
// 必填项
entityName: string; // 大驼峰式实体名称
// 可选命名配置
pluralName?: string; // API路径复数形式(自动生成复数)
tableName?: string; // 数据库表名(蛇形命名)
// 输出路径(可按项目配置)
paths?: {
entity?: string; // 默认值:"src/entities"
module?: string; // 默认值:"src/modules"
shared?: string; // 默认值:"src/shared"(设为null则跳过)
};
// 生成代码的共享包导入路径
sharedPackage?: string; // 示例:"@my-org/shared"(默认:相对导入)
// 字段与关联关系
fields: FieldConfig[];
relations?: RelationConfig[];
// 操作选项(默认:全部支持)
operations?: ('readMany' | 'readOne' | 'createOne' | 'updateOne' | 'deleteOne' | 'recoverOne')[];
// ACL(访问控制)
acl?: Record<string, { possession: 'own' | 'any'; operations: ('create'|'read'|'update'|'delete')[] }>;
ownerField?: string; // 所有权检查字段(默认值:"userId")
// 其他选项
generateModelService?: boolean;
isJunction?: boolean;
}Field Configuration
字段配置
typescript
interface FieldConfig {
name: string;
type: 'string' | 'text' | 'number' | 'float' | 'boolean' | 'date' | 'uuid' | 'json' | 'enum';
required?: boolean; // Default: true
unique?: boolean;
maxLength?: number;
minLength?: number;
min?: number;
max?: number;
precision?: number; // For float
scale?: number; // For float
default?: any;
enumValues?: string[]; // Required for enum type
apiDescription?: string;
apiExample?: any;
creatable?: boolean; // Include in CreateDto (default: true)
updatable?: boolean; // Include in UpdateDto (default: true)
}typescript
interface FieldConfig {
name: string;
type: 'string' | 'text' | 'number' | 'float' | 'boolean' | 'date' | 'uuid' | 'json' | 'enum';
required?: boolean; // 默认值:true
unique?: boolean;
maxLength?: number;
minLength?: number;
min?: number;
max?: number;
precision?: number; // 针对float类型
scale?: number; // 针对float类型
default?: any;
enumValues?: string[]; // enum类型必填
apiDescription?: string;
apiExample?: any;
creatable?: boolean; // 是否包含在CreateDto中(默认:true)
updatable?: boolean; // 是否包含在UpdateDto中(默认:true)
}Relation Configuration
关联关系配置
typescript
interface RelationConfig {
name: string;
type: 'manyToOne' | 'oneToMany' | 'oneToOne';
targetEntity: string; // Base name WITHOUT "Entity" suffix (e.g., "User" not "UserEntity")
foreignKey?: string; // Default: targetCamelId
joinType?: 'LEFT' | 'INNER';
onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT';
nullable?: boolean;
}Important:must be the base entity name (e.g.,targetEntity,"User"). The generator appends"Category"automatically. If you passEntity, the suffix is stripped to prevent double-suffixing ("UserEntity").UserEntityEntity
typescript
interface RelationConfig {
name: string;
type: 'manyToOne' | 'oneToMany' | 'oneToOne';
targetEntity: string; // 基础实体名称,不带"Entity"后缀(例如:"User"而非"UserEntity")
foreignKey?: string; // 默认值:targetCamelId
joinType?: 'LEFT' | 'INNER';
onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT';
nullable?: boolean;
}重要提示:必须是基础实体名称(例如:targetEntity、"User")。 生成器会自动追加"Category"后缀。如果传入Entity,后缀会被去除,避免重复添加导致"UserEntity"的错误。UserEntityEntity
ACL Configuration
ACL配置示例
json
{
"entityName": "Task",
"ownerField": "userId",
"acl": {
"admin": { "possession": "any", "operations": ["create","read","update","delete"] },
"user": { "possession": "own", "operations": ["create","read","update","delete"] }
}
}When is provided:
acl- Access query service uses for ownership checks
@InjectDynamicRepository - Generator outputs wiring snippets for (resource enum + grants)
app.acl.ts - Generator outputs wiring for in AccessControlModule
queryServices
json
{
"entityName": "Task",
"ownerField": "userId",
"acl": {
"admin": { "possession": "any", "operations": ["create","read","update","delete"] },
"user": { "possession": "own", "operations": ["create","read","update","delete"] }
}
}当配置了时:
acl- 访问查询服务使用进行所有权检查
@InjectDynamicRepository - 生成器会输出的配置代码片段(资源枚举 + 权限规则)
app.acl.ts - 生成器会输出AccessControlModule中的配置代码
queryServices
Examples
示例
Basic Entity
基础实体示例
json
{
"entityName": "Tag",
"fields": [
{ "name": "name", "type": "string", "required": true, "maxLength": 50, "unique": true },
{ "name": "color", "type": "string", "maxLength": 7, "apiExample": "#FF5733" }
]
}json
{
"entityName": "Tag",
"fields": [
{ "name": "name", "type": "string", "required": true, "maxLength": 50, "unique": true },
{ "name": "color", "type": "string", "maxLength": 7, "apiExample": "#FF5733" }
]
}With ACL + Custom Paths (monorepo)
带ACL和自定义路径的示例(单体仓库)
json
{
"entityName": "Product",
"paths": {
"entity": "apps/api/src/entities",
"module": "apps/api/src/modules",
"shared": "packages/shared/src"
},
"ownerField": "createdById",
"acl": {
"admin": { "possession": "any", "operations": ["create","read","update","delete"] },
"user": { "possession": "own", "operations": ["create","read","update","delete"] }
},
"fields": [
{ "name": "name", "type": "string", "required": true },
{ "name": "price", "type": "float", "precision": 10, "scale": 2 }
]
}json
{
"entityName": "Product",
"paths": {
"entity": "apps/api/src/entities",
"module": "apps/api/src/modules",
"shared": "packages/shared/src"
},
"ownerField": "createdById",
"acl": {
"admin": { "possession": "any", "operations": ["create","read","update","delete"] },
"user": { "possession": "own", "operations": ["create","read","update","delete"] }
},
"fields": [
{ "name": "name", "type": "string", "required": true },
{ "name": "price", "type": "float", "precision": 10, "scale": 2 }
]
}Junction Table
关联表示例
json
{
"entityName": "ProductTag",
"tableName": "product_tag",
"isJunction": true,
"fields": [],
"relations": [
{ "name": "product", "type": "manyToOne", "targetEntity": "Product", "onDelete": "CASCADE" },
{ "name": "tag", "type": "manyToOne", "targetEntity": "Tag", "onDelete": "CASCADE" }
],
"operations": ["readMany", "readOne", "createOne", "deleteOne"]
}json
{
"entityName": "ProductTag",
"tableName": "product_tag",
"isJunction": true,
"fields": [],
"relations": [
{ "name": "product", "type": "manyToOne", "targetEntity": "Product", "onDelete": "CASCADE" },
{ "name": "tag", "type": "manyToOne", "targetEntity": "Tag", "onDelete": "CASCADE" }
],
"operations": ["readMany", "readOne", "createOne", "deleteOne"]
}Generated Files
生成的文件结构
For a given entity (e.g. ) with default paths:
Productsrc/
├── entities/
│ └── {entity}.entity.ts
├── modules/{entity}/
│ ├── constants/{entity}.constants.ts
│ ├── {entity}.module.ts
│ ├── {entity}.crud.controller.ts
│ ├── {entity}.crud.service.ts
│ ├── {entity}-typeorm-crud.adapter.ts
│ └── {entity}-access-query.service.ts
└── shared/{entity}/ (if paths.shared is set)
├── dtos/
│ ├── {entity}.dto.ts
│ ├── {entity}-create.dto.ts
│ ├── {entity}-update.dto.ts
│ └── {entity}-paginated.dto.ts
├── interfaces/
│ ├── {entity}.interface.ts
│ ├── {entity}-creatable.interface.ts
│ └── {entity}-updatable.interface.ts
└── index.ts以实体为例,使用默认路径时的文件结构:
Productsrc/
├── entities/
│ └── {entity}.entity.ts
├── modules/{entity}/
│ ├── constants/{entity}.constants.ts
│ ├── {entity}.module.ts
│ ├── {entity}.crud.controller.ts
│ ├── {entity}.crud.service.ts
│ ├── {entity}-typeorm-crud.adapter.ts
│ └── {entity}-access-query.service.ts
└── shared/{entity}/ (若设置了paths.shared)
├── dtos/
│ ├── {entity}.dto.ts
│ ├── {entity}-create.dto.ts
│ ├── {entity}-update.dto.ts
│ └── {entity}-paginated.dto.ts
├── interfaces/
│ ├── {entity}.interface.ts
│ ├── {entity}-creatable.interface.ts
│ └── {entity}-updatable.interface.ts
└── index.tsAccessControl Integration (queryServices pattern)
AccessControl集成(查询服务模式)
The generator produces controllers with full ACL decorators (, , , etc.). These work correctly when the access query service is registered via in .
@UseGuards(AccessControlGuard)@AccessControlQuery@AccessControlReadManyqueryServicesAccessControlModule.forRoot()生成器会生成带有完整ACL装饰器的控制器(、、等)。当访问查询服务通过AccessControlModule.forRoot()的注册后,这些装饰器即可正常工作。
@UseGuards(AccessControlGuard)@AccessControlQuery@AccessControlReadManyqueryServicesHow it works
工作原理
- Generator creates the access query service with (database-agnostic)
@InjectDynamicRepository - integrate.js registers the service in of the AccessControlModule config
queryServices - The resolves the service from its own scope (no hack needed)
AccessControlGuard
- 生成器创建带有的访问查询服务(数据库无关)
@InjectDynamicRepository - integrate.js在AccessControlModule配置的中注册该服务
queryServices - 从自身作用域中解析服务(无需额外技巧)
AccessControlGuard
Access Query Service pattern
访问查询服务模式示例
typescript
@Injectable()
export class TaskAccessQueryService implements CanAccess {
constructor(
@InjectDynamicRepository(TASK_MODULE_TASK_ENTITY_KEY)
private taskRepo: RepositoryInterface<TaskEntity>,
) {}
async canAccess(context: AccessControlContextInterface): Promise<boolean> {
const query = context.getQuery();
if (query.possession === 'any') return true;
if (query.possession === 'own') {
// Ownership check via dynamic repository (database-agnostic)
const entity = await this.taskRepo.findOne({ where: { id: entityId } });
return entity?.userId === user.id;
}
return false;
}
}typescript
@Injectable()
export class TaskAccessQueryService implements CanAccess {
constructor(
@InjectDynamicRepository(TASK_MODULE_TASK_ENTITY_KEY)
private taskRepo: RepositoryInterface<TaskEntity>,
) {}
async canAccess(context: AccessControlContextInterface): Promise<boolean> {
const query = context.getQuery();
if (query.possession === 'any') return true;
if (query.possession === 'own') {
// 通过动态仓库进行所有权检查(数据库无关)
const entity = await this.taskRepo.findOne({ where: { id: entityId } });
return entity?.userId === user.id;
}
return false;
}
}Required wiring in app.module.ts
app.module.ts中所需的配置
typescript
// AccessControlModule config (or via RocketsAuthModule):
accessControl: {
settings: { rules: acRules },
queryServices: [TaskAccessQueryService, CategoryAccessQueryService],
}The script handles this automatically.
integrate.jstypescript
// AccessControlModule配置(或通过RocketsAuthModule):
accessControl: {
settings: { rules: acRules },
queryServices: [TaskAccessQueryService, CategoryAccessQueryService],
}integrate.jsintegrate.js — Auto-wiring
integrate.js — 自动配置
Takes the JSON output from and wires everything:
generate.jsbash
node generate.js '{ ... }' | node integrate.js --project ./apps/apiWhat it does:
- Writes all generated files to disk
- Adds entity export to
entities/index.ts - Adds entity to entities array
typeorm.settings.ts - Adds module import to
app.module.ts - Adds resource + grants to (if
app.acl.tsconfig present)acl - Adds access query service to in AccessControlModule config
queryServices
接收输出的JSON内容并完成所有集成操作:
generate.jsbash
node generate.js '{ ... }' | node integrate.js --project ./apps/api具体操作包括:
- 将所有生成的文件写入磁盘
- 在中添加实体导出
entities/index.ts - 在的entities数组中添加该实体
typeorm.settings.ts - 在中添加模块导入
app.module.ts - 在中添加资源和权限规则(若配置了acl)
app.acl.ts - 在AccessControlModule配置的中添加访问查询服务
queryServices
validate.js — Post-generation Checks
validate.js — 生成后检查
Validates project structure and patterns after generation:
bash
node validate.js --project ./apps/api # Static checks only
node validate.js --project ./apps/api --build # Static checks + TypeScript build生成完成后验证项目结构和规范:
bash
node validate.js --project ./apps/api # 仅静态检查
node validate.js --project ./apps/api --build # 静态检查 + TypeScript构建Generated Code Checks
生成代码检查项
- only in
@InjectRepository*-typeorm-crud.adapter.ts - All entities exported in
entities/index.ts - All modules imported in
app.module.ts - ACL resources defined in
app.acl.ts - Access query services registered in feature module providers
- No ACL workaround providers in feature modules
- ACL own-scope entities have matching column in entity
ownerField - present when
CrudModule.forRoot({})is usedCrudModule.forFeature()
- 仅出现在
@InjectRepository中*-typeorm-crud.adapter.ts - 所有实体都在中导出
entities/index.ts - 所有模块都在中导入
app.module.ts - ACL资源在中定义
app.acl.ts - 访问查询服务在功能模块的providers中注册
- 功能模块中无ACL兼容的providers
- ACL自有作用域实体在实体中存在对应的列
ownerField - 当使用时,必须存在
CrudModule.forFeature()CrudModule.forRoot({})
Template Integrity Checks (safety nets — should never fire on a correct template)
模板完整性检查(安全机制 — 正确模板下不会触发)
- No imports from internal paths
dist/ - No stale template placeholder strings (Music Management, PetAccessQueryService, etc.)
- All entity tables have corresponding migrations (severity: error)
- No SQLite base classes () in a Postgres project
*SqliteEntity
Output:
{ passed: boolean, issues: [{ severity, rule, message, file, line }] }- 无来自内部路径的导入
dist/ - 无过期的模板占位符字符串(如Music Management、PetAccessQueryService等)
- 所有实体表都有对应的迁移文件(严重级别:错误)
- Postgres项目中无SQLite基类()
*SqliteEntity
输出格式:
{ passed: boolean, issues: [{ severity, rule, message, file, line }] }Known Limitations — Relations
已知限制 — 关联关系
The generator produces decorators and providers for modules with relations. These reference the related module's CRUD service (e.g., ), which must exist as an importable module. If the related entity is managed by the SDK (e.g., User from ) rather than by a standalone module you wrote, the generated relation wiring will fail.
CrudRelationsCrudRelationRegistryUserCrudServiceRocketsAuthModuleWorkaround for SDK-managed entities: Remove the decorator, the provider, and all references to non-existent related modules/services. Instead, rely on TypeORM / decorators on the entity and include the FK column (, ) directly in the DTO. The CRUD endpoints will accept and persist the FK; TypeORM handles the join at query time.
CrudRelationsCrudRelationRegistry@ManyToOne@JoinColumnuserIdcategoryId生成器会为带有关联关系的模块生成装饰器和提供者,这些会引用关联模块的CRUD服务(例如),而该服务必须是可导入的模块。如果关联实体由SDK管理(例如中的User)而非你编写的独立模块,则生成的关联配置会失效。
CrudRelationsCrudRelationRegistryUserCrudServiceRocketsAuthModuleSDK管理实体的解决方法:移除装饰器、提供者以及所有对不存在的关联模块/服务的引用。转而依赖实体上的TypeORM /装饰器,并在DTO中直接包含外键列(、)。CRUD端点会接收并持久化外键;TypeORM会在查询时处理关联。
CrudRelationsCrudRelationRegistry@ManyToOne@JoinColumnuserIdcategoryIdPost-Generation (manual steps if not using integrate.js)
生成后手动步骤(未使用integrate.js时)
- Export entity from entities index
- Import module in app.module.ts
- Add entity to typeorm.settings.ts
- Register access query service in of AccessControlModule config
queryServices - Add resource + grants to app.acl.ts (if using ACL)
- Remove CrudRelations if related entity is SDK-managed (see above)
- Export from shared index (if using shared package)
- 在实体索引文件中导出该实体
- 在app.module.ts中导入模块
- 在typeorm.settings.ts中添加实体
- 在AccessControlModule配置的中注册访问查询服务
queryServices - 在app.acl.ts中添加资源和权限规则(若使用ACL)
- 若关联实体由SDK管理,移除CrudRelations(见上文)
- 在共享包索引中导出(若使用共享包)