import { VersionedAggregateRoot } from '@task-stream/api/shared/domain'; import { UserDeactivatedEvent } from './events/user-deactivated.event'; export interface UserSnapshot { /** Pireon user id (string to stay provider-agnostic). */ id: string; name: string; email: string; isActive: boolean; /** Global roles in the identity server. */ roles: string[]; /** Roles granted inside this OAuth client (task-stream). */ appRoles: string[]; } /** * A person managed by the Pireon identity server. Not event-sourced here * (Pireon owns users): UserFactory rebuilds it from Pireon or the local cache. */ export class User extends VersionedAggregateRoot implements UserSnapshot { public name!: string; public email!: string; public isActive = true; public roles: string[] = []; public appRoles: string[] = []; constructor(id: string) { super(); this.id = id; } /** Global Pireon admins implicitly hold every app role. */ hasAppRole(role: string): boolean { return this.appRoles.includes(role) || this.roles.includes('admin'); } deactivate(): void { if (!this.isActive) return; this.apply(new UserDeactivatedEvent(this.id)); } onUserDeactivatedEvent(): void { this.isActive = false; } toSnapshot(): UserSnapshot { return { id: this.id, name: this.name, email: this.email, isActive: this.isActive, roles: [...this.roles], appRoles: [...this.appRoles], }; } }