feat: Add roles, permissions, and company entities to auth
Entities added from erp-construccion: - role.entity.ts - permission.entity.ts - user-role.entity.ts - session.entity.ts - api-key.entity.ts - password-reset.entity.ts - company.entity.ts - group.entity.ts - index.ts (new) Build: Clean (0 TypeScript errors) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8c010221fb
commit
497307ed04
84
src/modules/auth/entities/api-key.entity.ts
Normal file
84
src/modules/auth/entities/api-key.entity.ts
Normal file
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* ApiKey Entity
|
||||
* Gestión de API Keys para integraciones headless/CI/CD
|
||||
* Compatible con erp-core api-key.entity
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Index,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../core/entities/user.entity';
|
||||
import { Tenant } from '../../core/entities/tenant.entity';
|
||||
|
||||
@Entity({ schema: 'auth', name: 'api_keys' })
|
||||
@Index('idx_api_keys_lookup', ['keyIndex', 'isActive'], {
|
||||
where: 'is_active = TRUE',
|
||||
})
|
||||
@Index('idx_api_keys_expiration', ['expirationDate'], {
|
||||
where: 'expiration_date IS NOT NULL',
|
||||
})
|
||||
@Index('idx_api_keys_user', ['userId'])
|
||||
@Index('idx_api_keys_tenant', ['tenantId'])
|
||||
export class ApiKey {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid', nullable: false, name: 'user_id' })
|
||||
userId: string;
|
||||
|
||||
@Column({ type: 'uuid', nullable: false, name: 'tenant_id' })
|
||||
tenantId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 16, nullable: false, name: 'key_index' })
|
||||
keyIndex: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false, name: 'key_hash' })
|
||||
keyHash: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 100, nullable: true })
|
||||
scope: string | null;
|
||||
|
||||
@Column({ type: 'inet', array: true, nullable: true, name: 'allowed_ips' })
|
||||
allowedIps: string[] | null;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true, name: 'expiration_date' })
|
||||
expirationDate: Date | null;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true, name: 'last_used_at' })
|
||||
lastUsedAt: Date | null;
|
||||
|
||||
@Column({ type: 'boolean', default: true, nullable: false, name: 'is_active' })
|
||||
isActive: boolean;
|
||||
|
||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user: User;
|
||||
|
||||
@ManyToOne(() => Tenant, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'tenant_id' })
|
||||
tenant: Tenant;
|
||||
|
||||
@ManyToOne(() => User, { nullable: true })
|
||||
@JoinColumn({ name: 'revoked_by' })
|
||||
revokedByUser: User | null;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true, name: 'revoked_at' })
|
||||
revokedAt: Date | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'revoked_by' })
|
||||
revokedBy: string | null;
|
||||
}
|
||||
79
src/modules/auth/entities/company.entity.ts
Normal file
79
src/modules/auth/entities/company.entity.ts
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Company Entity
|
||||
* Soporte multi-empresa dentro de un tenant
|
||||
* Compatible con erp-core company.entity
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
Index,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { Tenant } from '../../core/entities/tenant.entity';
|
||||
|
||||
@Entity({ schema: 'auth', name: 'companies' })
|
||||
@Index('idx_companies_tenant_id', ['tenantId'])
|
||||
@Index('idx_companies_parent_company_id', ['parentCompanyId'])
|
||||
@Index('idx_companies_active', ['tenantId'], { where: 'deleted_at IS NULL' })
|
||||
@Index('idx_companies_tax_id', ['taxId'])
|
||||
export class Company {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid', nullable: false, name: 'tenant_id' })
|
||||
tenantId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: true, name: 'legal_name' })
|
||||
legalName: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 50, nullable: true, name: 'tax_id' })
|
||||
taxId: string | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'currency_id' })
|
||||
currencyId: string | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'parent_company_id' })
|
||||
parentCompanyId: string | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'partner_id' })
|
||||
partnerId: string | null;
|
||||
|
||||
@Column({ type: 'jsonb', default: {} })
|
||||
settings: Record<string, any>;
|
||||
|
||||
@ManyToOne(() => Tenant, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'tenant_id' })
|
||||
tenant: Tenant;
|
||||
|
||||
@ManyToOne(() => Company, { nullable: true })
|
||||
@JoinColumn({ name: 'parent_company_id' })
|
||||
parentCompany: Company | null;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
|
||||
createdAt: Date;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'created_by' })
|
||||
createdBy: string | null;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at', type: 'timestamp', nullable: true })
|
||||
updatedAt: Date | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'updated_by' })
|
||||
updatedBy: string | null;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true, name: 'deleted_at' })
|
||||
deletedAt: Date | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'deleted_by' })
|
||||
deletedBy: string | null;
|
||||
}
|
||||
75
src/modules/auth/entities/group.entity.ts
Normal file
75
src/modules/auth/entities/group.entity.ts
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Group Entity
|
||||
* Agrupación de usuarios para gestión de permisos
|
||||
* Compatible con erp-core group.entity
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
Index,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { Tenant } from '../../core/entities/tenant.entity';
|
||||
|
||||
@Entity({ schema: 'auth', name: 'groups' })
|
||||
@Index('idx_groups_tenant_id', ['tenantId'])
|
||||
@Index('idx_groups_code', ['code'])
|
||||
@Index('idx_groups_category', ['category'])
|
||||
@Index('idx_groups_is_system', ['isSystem'])
|
||||
export class Group {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid', nullable: false, name: 'tenant_id' })
|
||||
tenantId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 100, nullable: false })
|
||||
code: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string | null;
|
||||
|
||||
@Column({ type: 'boolean', default: false, nullable: false, name: 'is_system' })
|
||||
isSystem: boolean;
|
||||
|
||||
@Column({ type: 'varchar', length: 100, nullable: true })
|
||||
category: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 20, nullable: true })
|
||||
color: string | null;
|
||||
|
||||
@Column({ type: 'integer', default: 30, nullable: true, name: 'api_key_max_duration_days' })
|
||||
apiKeyMaxDurationDays: number | null;
|
||||
|
||||
@ManyToOne(() => Tenant, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'tenant_id' })
|
||||
tenant: Tenant;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
|
||||
createdAt: Date;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'created_by' })
|
||||
createdBy: string | null;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at', type: 'timestamp', nullable: true })
|
||||
updatedAt: Date | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'updated_by' })
|
||||
updatedBy: string | null;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true, name: 'deleted_at' })
|
||||
deletedAt: Date | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'deleted_by' })
|
||||
deletedBy: string | null;
|
||||
}
|
||||
15
src/modules/auth/entities/index.ts
Normal file
15
src/modules/auth/entities/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Auth Entities - Export
|
||||
*/
|
||||
|
||||
export { RefreshToken } from './refresh-token.entity';
|
||||
export { User } from './user.entity';
|
||||
export { Workshop } from './workshop.entity';
|
||||
export { Role } from './role.entity';
|
||||
export { Permission } from './permission.entity';
|
||||
export { UserRole } from './user-role.entity';
|
||||
export { Session, SessionStatus } from './session.entity';
|
||||
export { ApiKey } from './api-key.entity';
|
||||
export { PasswordReset } from './password-reset.entity';
|
||||
export { Company } from './company.entity';
|
||||
export { Group } from './group.entity';
|
||||
49
src/modules/auth/entities/password-reset.entity.ts
Normal file
49
src/modules/auth/entities/password-reset.entity.ts
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* PasswordReset Entity
|
||||
* Flujo seguro de recuperación de contraseña con token temporal
|
||||
* Compatible con erp-core password-reset.entity
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Index,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../core/entities/user.entity';
|
||||
|
||||
@Entity({ schema: 'auth', name: 'password_resets' })
|
||||
@Index('idx_password_resets_user_id', ['userId'])
|
||||
@Index('idx_password_resets_token', ['token'])
|
||||
@Index('idx_password_resets_expires_at', ['expiresAt'])
|
||||
export class PasswordReset {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid', nullable: false, name: 'user_id' })
|
||||
userId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 500, unique: true, nullable: false })
|
||||
token: string;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: false, name: 'expires_at' })
|
||||
expiresAt: Date;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true, name: 'used_at' })
|
||||
usedAt: Date | null;
|
||||
|
||||
@Column({ type: 'inet', nullable: true, name: 'ip_address' })
|
||||
ipAddress: string | null;
|
||||
|
||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user: User;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
|
||||
createdAt: Date;
|
||||
}
|
||||
34
src/modules/auth/entities/permission.entity.ts
Normal file
34
src/modules/auth/entities/permission.entity.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Permission Entity
|
||||
* Permisos granulares del sistema
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity({ schema: 'auth', name: 'permissions' })
|
||||
export class Permission {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 100, unique: true })
|
||||
code: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 200 })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 50 })
|
||||
module: string;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
}
|
||||
90
src/modules/auth/entities/role.entity.ts
Normal file
90
src/modules/auth/entities/role.entity.ts
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Role Entity
|
||||
* Roles del sistema para RBAC
|
||||
* Compatible con erp-core role.entity
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
Index,
|
||||
} from 'typeorm';
|
||||
import { Permission } from './permission.entity';
|
||||
import { UserRole } from './user-role.entity';
|
||||
import { Tenant } from '../../core/entities/tenant.entity';
|
||||
|
||||
@Entity({ schema: 'auth', name: 'roles' })
|
||||
@Index('idx_roles_tenant_id', ['tenantId'])
|
||||
@Index('idx_roles_code', ['code'])
|
||||
@Index('idx_roles_is_system', ['isSystem'])
|
||||
export class Role {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'tenant_id' })
|
||||
tenantId: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 50, unique: true })
|
||||
code: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 100 })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string | null;
|
||||
|
||||
@Column({ name: 'is_system', type: 'boolean', default: false })
|
||||
isSystem: boolean;
|
||||
|
||||
@Column({ name: 'is_active', type: 'boolean', default: true })
|
||||
isActive: boolean;
|
||||
|
||||
@Column({ type: 'varchar', length: 20, nullable: true })
|
||||
color: string | null;
|
||||
|
||||
// Relations
|
||||
@ManyToOne(() => Tenant, { onDelete: 'CASCADE', nullable: true })
|
||||
@JoinColumn({ name: 'tenant_id' })
|
||||
tenant: Tenant | null;
|
||||
|
||||
@ManyToMany(() => Permission)
|
||||
@JoinTable({
|
||||
name: 'role_permissions',
|
||||
schema: 'auth',
|
||||
joinColumn: { name: 'role_id', referencedColumnName: 'id' },
|
||||
inverseJoinColumn: { name: 'permission_id', referencedColumnName: 'id' },
|
||||
})
|
||||
permissions: Permission[];
|
||||
|
||||
@OneToMany(() => UserRole, (userRole) => userRole.role)
|
||||
userRoles: UserRole[];
|
||||
|
||||
// Audit trail
|
||||
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'created_by' })
|
||||
createdBy: string | null;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
|
||||
updatedAt: Date;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'updated_by' })
|
||||
updatedBy: string | null;
|
||||
|
||||
@Column({ name: 'deleted_at', type: 'timestamptz', nullable: true })
|
||||
deletedAt: Date | null;
|
||||
|
||||
@Column({ type: 'uuid', nullable: true, name: 'deleted_by' })
|
||||
deletedBy: string | null;
|
||||
}
|
||||
85
src/modules/auth/entities/session.entity.ts
Normal file
85
src/modules/auth/entities/session.entity.ts
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Session Entity
|
||||
* Gestión de sesiones de usuario (reemplaza refresh tokens simples)
|
||||
* Compatible con erp-core session.entity
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Index,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../core/entities/user.entity';
|
||||
|
||||
export enum SessionStatus {
|
||||
ACTIVE = 'active',
|
||||
EXPIRED = 'expired',
|
||||
REVOKED = 'revoked',
|
||||
}
|
||||
|
||||
@Entity({ schema: 'auth', name: 'sessions' })
|
||||
@Index('idx_sessions_user_id', ['userId'])
|
||||
@Index('idx_sessions_token', ['token'])
|
||||
@Index('idx_sessions_status', ['status'])
|
||||
@Index('idx_sessions_expires_at', ['expiresAt'])
|
||||
export class Session {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid', nullable: false, name: 'user_id' })
|
||||
userId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 500, unique: true, nullable: false })
|
||||
token: string;
|
||||
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
length: 500,
|
||||
unique: true,
|
||||
nullable: true,
|
||||
name: 'refresh_token',
|
||||
})
|
||||
refreshToken: string | null;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: SessionStatus,
|
||||
default: SessionStatus.ACTIVE,
|
||||
nullable: false,
|
||||
})
|
||||
status: SessionStatus;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: false, name: 'expires_at' })
|
||||
expiresAt: Date;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true, name: 'refresh_expires_at' })
|
||||
refreshExpiresAt: Date | null;
|
||||
|
||||
@Column({ type: 'inet', nullable: true, name: 'ip_address' })
|
||||
ipAddress: string | null;
|
||||
|
||||
@Column({ type: 'text', nullable: true, name: 'user_agent' })
|
||||
userAgent: string | null;
|
||||
|
||||
@Column({ type: 'jsonb', nullable: true, name: 'device_info' })
|
||||
deviceInfo: Record<string, any> | null;
|
||||
|
||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user: User;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
|
||||
createdAt: Date;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true, name: 'revoked_at' })
|
||||
revokedAt: Date | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 100, nullable: true, name: 'revoked_reason' })
|
||||
revokedReason: string | null;
|
||||
}
|
||||
54
src/modules/auth/entities/user-role.entity.ts
Normal file
54
src/modules/auth/entities/user-role.entity.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* UserRole Entity
|
||||
* Relación usuarios-roles con soporte multi-tenant
|
||||
*
|
||||
* @module Auth
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
Index,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../core/entities/user.entity';
|
||||
import { Role } from './role.entity';
|
||||
import { Tenant } from '../../core/entities/tenant.entity';
|
||||
|
||||
@Entity({ schema: 'auth', name: 'user_roles' })
|
||||
@Index(['userId', 'roleId', 'tenantId'], { unique: true })
|
||||
export class UserRole {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ name: 'user_id', type: 'uuid' })
|
||||
userId: string;
|
||||
|
||||
@Column({ name: 'role_id', type: 'uuid' })
|
||||
roleId: string;
|
||||
|
||||
@Column({ name: 'tenant_id', type: 'uuid', nullable: true })
|
||||
tenantId: string;
|
||||
|
||||
@Column({ name: 'assigned_by', type: 'uuid', nullable: true })
|
||||
assignedBy: string;
|
||||
|
||||
@CreateDateColumn({ name: 'assigned_at', type: 'timestamptz' })
|
||||
assignedAt: Date;
|
||||
|
||||
// Relations
|
||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user: User;
|
||||
|
||||
@ManyToOne(() => Role, (role) => role.userRoles, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'role_id' })
|
||||
role: Role;
|
||||
|
||||
@ManyToOne(() => Tenant, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'tenant_id' })
|
||||
tenant: Tenant;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user