import { EmailAddress } from '@core/identity/domain/value-objects/EmailAddress'; import { UserId } from '@core/identity/domain/value-objects/UserId'; import { User } from '@core/identity/domain/entities/User'; import { IAuthRepository } from '@core/identity/domain/repositories/IAuthRepository'; import { IPasswordHashingService } from '@core/identity/domain/services/PasswordHashingService'; import { Result } from '@core/shared/application/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { UseCaseOutputPort, Logger, UseCase } from '@core/shared/application'; export type DemoLoginInput = { role: 'driver' | 'sponsor' | 'league-owner' | 'league-steward' | 'league-admin' | 'system-owner' | 'super-admin'; }; export type DemoLoginResult = { user: User; }; export type DemoLoginErrorCode = 'DEMO_NOT_ALLOWED' | 'REPOSITORY_ERROR'; export type DemoLoginApplicationError = ApplicationErrorCode; /** * Application Use Case: DemoLoginUseCase * * Provides demo login functionality for development environments. * Creates demo users with predefined credentials. * * ⚠️ DEVELOPMENT ONLY - Should be disabled in production */ export class DemoLoginUseCase implements UseCase { constructor( private readonly authRepo: IAuthRepository, private readonly passwordService: IPasswordHashingService, private readonly logger: Logger, private readonly output: UseCaseOutputPort, ) {} async execute(input: DemoLoginInput): Promise> { // Security check: Only allow in development if (process.env.NODE_ENV !== 'development' && process.env.ALLOW_DEMO_LOGIN !== 'true') { return Result.err({ code: 'DEMO_NOT_ALLOWED', details: { message: 'Demo login is only available in development environment' }, }); } try { // Generate demo user email and display name based on role const roleConfig = { 'driver': { email: 'demo.driver@example.com', name: 'John Demo', primaryDriverId: true }, 'sponsor': { email: 'demo.sponsor@example.com', name: 'Jane Sponsor', primaryDriverId: false }, 'league-owner': { email: 'demo.owner@example.com', name: 'Alex Owner', primaryDriverId: true }, 'league-steward': { email: 'demo.steward@example.com', name: 'Sam Steward', primaryDriverId: true }, 'league-admin': { email: 'demo.admin@example.com', name: 'Taylor Admin', primaryDriverId: true }, 'system-owner': { email: 'demo.systemowner@example.com', name: 'System Owner', primaryDriverId: true }, 'super-admin': { email: 'demo.superadmin@example.com', name: 'Super Admin', primaryDriverId: true }, }; const config = roleConfig[input.role]; const emailVO = EmailAddress.create(config.email); // Check if demo user already exists let user = await this.authRepo.findByEmail(emailVO); if (!user) { // Create new demo user this.logger.info('[DemoLoginUseCase] Creating new demo user', { role: input.role }); const userId = UserId.create(); // Use a fixed demo password and hash it const demoPassword = 'Demo1234!'; const hashedPassword = await this.passwordService.hash(demoPassword); // Import PasswordHash and create proper object const passwordHashModule = await import('@core/identity/domain/value-objects/PasswordHash'); const passwordHash = passwordHashModule.PasswordHash.fromHash(hashedPassword); // eslint-disable-next-line @typescript-eslint/no-explicit-any const userProps: any = { id: userId, displayName: config.name, email: config.email, passwordHash, }; if (config.primaryDriverId) { userProps.primaryDriverId = `demo-${input.role}-${userId.value}`; // Add avatar URL for demo users with primary driver // Use the same format as seeded drivers: /media/default/neutral-default-avatar userProps.avatarUrl = '/media/default/neutral-default-avatar'; } user = User.create(userProps); await this.authRepo.save(user); } else { this.logger.info('[DemoLoginUseCase] Using existing demo user', { role: input.role, userId: user.getId().value }); } this.output.present({ user }); return Result.ok(undefined); } catch (error) { const message = error instanceof Error && error.message ? error.message : 'Failed to execute DemoLoginUseCase'; this.logger.error('DemoLoginUseCase.execute failed', error instanceof Error ? error : undefined, { input, }); return Result.err({ code: 'REPOSITORY_ERROR', details: { message }, }); } } }