Feature 1 - How-To Intro Tour (react-joyride): - 8-step guided walkthrough highlighting Dashboard, Accounts, Assessments, Transactions, Budgets, Reports, and AI Investment Planning - Runs automatically on first login, tracked via has_seen_intro flag on user - Centralized step config in config/tourSteps.ts for easy text editing - data-tour attributes on Sidebar nav items and Dashboard for targeting Feature 2 - Tenant Onboarding Wizard: - 3-step modal wizard: create operating account, assessment group + units, import budget CSV - Runs after tour completes, tracked via onboardingComplete in org settings JSONB - Reuses existing API endpoints (POST /accounts, /assessment-groups, /units, /budgets/:year/import) Backend changes: - Add has_seen_intro column to shared.users + migration - Add PATCH /auth/intro-seen endpoint to mark tour complete - Add PATCH /organizations/settings endpoint for org settings updates - Include hasSeenIntro in login response, settings in switch-org response Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
67 lines
1.6 KiB
TypeScript
67 lines
1.6 KiB
TypeScript
import {
|
|
Entity,
|
|
PrimaryGeneratedColumn,
|
|
Column,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
OneToMany,
|
|
} from 'typeorm';
|
|
import { UserOrganization } from '../../organizations/entities/user-organization.entity';
|
|
|
|
@Entity({ schema: 'shared', name: 'users' })
|
|
export class User {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Column({ unique: true })
|
|
email: string;
|
|
|
|
@Column({ name: 'password_hash', nullable: true })
|
|
passwordHash: string;
|
|
|
|
@Column({ name: 'first_name', nullable: true })
|
|
firstName: string;
|
|
|
|
@Column({ name: 'last_name', nullable: true })
|
|
lastName: string;
|
|
|
|
@Column({ nullable: true })
|
|
phone: string;
|
|
|
|
@Column({ name: 'is_email_verified', default: false })
|
|
isEmailVerified: boolean;
|
|
|
|
@Column({ name: 'mfa_enabled', default: false })
|
|
mfaEnabled: boolean;
|
|
|
|
@Column({ name: 'mfa_secret', nullable: true })
|
|
mfaSecret: string;
|
|
|
|
@Column({ name: 'oauth_provider', nullable: true })
|
|
oauthProvider: string;
|
|
|
|
@Column({ name: 'oauth_provider_id', nullable: true })
|
|
oauthProviderId: string;
|
|
|
|
@Column({ name: 'is_superadmin', default: false })
|
|
isSuperadmin: boolean;
|
|
|
|
@Column({ name: 'is_platform_owner', default: false })
|
|
isPlatformOwner: boolean;
|
|
|
|
@Column({ name: 'has_seen_intro', default: false })
|
|
hasSeenIntro: boolean;
|
|
|
|
@Column({ name: 'last_login_at', type: 'timestamptz', nullable: true })
|
|
lastLoginAt: Date;
|
|
|
|
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
|
|
createdAt: Date;
|
|
|
|
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
|
|
updatedAt: Date;
|
|
|
|
@OneToMany(() => UserOrganization, (uo) => uo.user)
|
|
userOrganizations: UserOrganization[];
|
|
}
|