- user.entity: Add display_name, phone_verified, is_owner, password_changed_at, failed_login_attempts, locked_until, preferences, last_activity_at - role.entity: Add slug, permissions, parent_role_id, level for hierarchy - tenant.entity: Add subscription_status, stripe_customer_id, stripe_subscription_id, subscription_ends_at, deleted_at Closes DDL↔Backend coherence gaps identified in TASK-007 analysis. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
110 lines
2.7 KiB
TypeScript
110 lines
2.7 KiB
TypeScript
import {
|
|
Entity,
|
|
Column,
|
|
PrimaryGeneratedColumn,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
Index,
|
|
ManyToOne,
|
|
JoinColumn,
|
|
} from 'typeorm';
|
|
|
|
@Entity({ schema: 'users', name: 'users' })
|
|
export class User {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Column({ type: 'uuid' })
|
|
@Index()
|
|
tenant_id: string;
|
|
|
|
@Column({ type: 'varchar', length: 255 })
|
|
@Index()
|
|
email: string;
|
|
|
|
@Column({ type: 'varchar', length: 255 })
|
|
password_hash: string;
|
|
|
|
@Column({ type: 'varchar', length: 100, nullable: true })
|
|
first_name: string | null;
|
|
|
|
@Column({ type: 'varchar', length: 100, nullable: true })
|
|
last_name: string | null;
|
|
|
|
@Column({ type: 'varchar', length: 200, nullable: true })
|
|
display_name: string | null;
|
|
|
|
@Column({ type: 'varchar', length: 255, nullable: true })
|
|
avatar_url: string | null;
|
|
|
|
@Column({ type: 'varchar', length: 20, nullable: true })
|
|
phone: string | null;
|
|
|
|
@Column({ type: 'boolean', default: false })
|
|
phone_verified: boolean;
|
|
|
|
@Column({
|
|
type: 'enum',
|
|
enum: ['active', 'inactive', 'suspended', 'pending_verification'],
|
|
enumName: 'users.user_status',
|
|
default: 'pending_verification',
|
|
})
|
|
status: string;
|
|
|
|
@Column({ type: 'boolean', default: false })
|
|
is_owner: boolean;
|
|
|
|
@Column({ type: 'boolean', default: false })
|
|
email_verified: boolean;
|
|
|
|
@Column({ type: 'timestamp with time zone', nullable: true })
|
|
email_verified_at: Date | null;
|
|
|
|
@Column({ type: 'boolean', default: false })
|
|
mfa_enabled: boolean;
|
|
|
|
@Column({ type: 'varchar', length: 255, nullable: true })
|
|
mfa_secret: string | null;
|
|
|
|
@Column({ type: 'text', array: true, nullable: true })
|
|
mfa_backup_codes: string[] | null;
|
|
|
|
@Column({ type: 'timestamp with time zone', nullable: true })
|
|
mfa_enabled_at: Date | null;
|
|
|
|
@Column({ type: 'timestamp with time zone', nullable: true })
|
|
password_changed_at: Date | null;
|
|
|
|
@Column({ type: 'int', default: 0 })
|
|
failed_login_attempts: number;
|
|
|
|
@Column({ type: 'timestamp with time zone', nullable: true })
|
|
locked_until: Date | null;
|
|
|
|
@Column({ type: 'timestamp with time zone', nullable: true })
|
|
last_login_at: Date | null;
|
|
|
|
@Column({ type: 'varchar', length: 45, nullable: true })
|
|
last_login_ip: string | null;
|
|
|
|
@Column({ type: 'jsonb', nullable: true })
|
|
metadata: Record<string, any> | null;
|
|
|
|
@Column({ type: 'jsonb', nullable: true })
|
|
preferences: Record<string, any> | null;
|
|
|
|
@Column({ type: 'timestamp with time zone', nullable: true })
|
|
last_activity_at: Date | null;
|
|
|
|
@CreateDateColumn({ type: 'timestamp with time zone' })
|
|
created_at: Date;
|
|
|
|
@UpdateDateColumn({ type: 'timestamp with time zone' })
|
|
updated_at: Date;
|
|
|
|
// Computed property
|
|
get fullName(): string {
|
|
return [this.first_name, this.last_name].filter(Boolean).join(' ');
|
|
}
|
|
}
|