Phase 1 & 2: Authentication and Children Management

Completed Features:
- Full JWT authentication system with refresh tokens
- User registration and login with device fingerprinting
- Child profile CRUD operations with permission-based access
- Family management with roles and permissions
- Database migrations for core auth and family structure
- Comprehensive test coverage (37 unit + E2E tests)

Tech Stack:
- NestJS backend with TypeORM
- PostgreSQL database
- JWT authentication with Passport
- bcrypt password hashing
- Docker Compose for infrastructure

🤖 Generated with Claude Code
This commit is contained in:
andupetcu
2025-09-30 18:40:10 +03:00
commit 98e01ebe80
35 changed files with 9683 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
import {
Entity,
Column,
PrimaryColumn,
CreateDateColumn,
UpdateDateColumn,
OneToMany,
BeforeInsert,
} from 'typeorm';
import { DeviceRegistry } from './device-registry.entity';
import { FamilyMember } from './family-member.entity';
@Entity('users')
export class User {
@PrimaryColumn({ length: 20 })
id: string;
@Column({ length: 255, unique: true })
email: string;
@Column({ length: 20, nullable: true })
phone?: string;
@Column({ name: 'password_hash', length: 255 })
passwordHash: string;
@Column({ length: 100 })
name: string;
@Column({ length: 10, default: 'en-US' })
locale: string;
@Column({ length: 50, default: 'UTC' })
timezone: string;
@Column({ name: 'email_verified', default: false })
emailVerified: boolean;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
@OneToMany(() => DeviceRegistry, (device) => device.user)
devices: DeviceRegistry[];
@OneToMany(() => FamilyMember, (familyMember) => familyMember.user)
familyMemberships: FamilyMember[];
@BeforeInsert()
generateId() {
if (!this.id) {
this.id = `usr_${this.generateNanoId()}`;
}
}
private generateNanoId(): string {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < 12; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
}