template-saas/apps/backend/src/modules/auth/entities/user.entity.ts
Adrian Flores Cortes 7a43ac1c96
Some checks are pending
CI / Backend CI (push) Waiting to run
CI / Frontend CI (push) Waiting to run
CI / Security Scan (push) Waiting to run
CI / CI Summary (push) Blocked by required conditions
[TASK-007] feat: Complete CAPVED analysis and sync for template-saas
## Entities (DDL↔Backend sync):
- user.entity: 8 missing fields added
- role.entity: 4 missing fields added
- tenant.entity: 5 missing fields added

## Documentation:
- PROXIMA-ACCION.md: Rewritten with 2026-01-27 status
- PROJECT-STATUS.md: Added MLM, Goals, Portfolio phases
- docs/01-modulos/_INDEX.md: Updated module states to Completado

## Inventories:
- DATABASE_INVENTORY.yml: Added mlm/goals schemas (10 tables)
- BACKEND_INVENTORY.yml: Added mlm/goals modules (10 entities)
- MASTER_INVENTORY.yml: MLM/Goals marked as completado
- tareas/_INDEX.yml: Registered TASK-007, SAAS-021, SAAS-022

Metrics: 23 modules, 17 schemas, 48 tables, 260 SP (100%)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 12:30:59 -06:00

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(' ');
}
}