File

apps/recallassess/recallassess-api/src/api/client/account/dto/account.dto.ts

Description

Payload for public signup (POST /api/client/account/create-from-signup). Creates company + admin participant after Stripe payment / trial setup.

Index

Properties

Properties

Optional admin_address
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Admin address'})
@IsOptional()
@IsString()
Optional admin_city
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Admin city'})
@IsOptional()
@IsString()
Optional admin_country
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Admin country (ISO / display name; used for VAT)', example: 'AE'})
@IsOptional()
@IsString()
admin_email
Type : string
Decorators :
@Expose()
@ApiProperty({description: 'Admin email (login)', example: 'jane@acme.com'})
@IsEmail()
admin_first_name
Type : string
Decorators :
@Expose()
@ApiProperty({description: 'Admin first name', example: 'Jane'})
@IsString()
admin_last_name
Type : string
Decorators :
@Expose()
@ApiProperty({description: 'Admin last name', example: 'Doe'})
@IsString()
Optional admin_password
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Admin password (min 8 chars, complexity rules apply)'})
@IsOptional()
@IsString()
@MinLength(8, {message: 'Password must be at least 8 characters long'})
@Matches(/[A-Z]/, {message: 'Password must contain at least one uppercase letter'})
@Matches(/\d/, {message: 'Password must contain at least one number'})
@Matches(/[\W_]/, {message: 'Password must contain at least one special character'})
Optional admin_phone
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Admin phone'})
@IsOptional()
@IsString()
@Matches(/^\+?[\d\s]+$/, {message: 'Phone number can only contain digits, spaces, and an optional plus (+) symbol for country code'})
Optional billing_cycle
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Billing cycle', example: 'QUARTERLY', enum: undefined})
@IsOptional()
@IsString()
company_email
Type : string
Decorators :
@Expose()
@ApiProperty({description: 'Company email (unique tenant identifier)', example: 'admin@acme.com'})
@IsEmail()
company_name
Type : string
Decorators :
@Expose()
@ApiProperty({description: 'Company / organisation name', example: 'Acme Corp'})
@IsString()
Optional company_phone
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Company phone', example: '+971 50 123 4567'})
@IsOptional()
@IsString()
@Matches(/^\+?[\d\s]+$/, {message: 'Phone number can only contain digits, spaces, and an optional plus (+) symbol for country code'})
license_count
Type : number
Decorators :
@Expose()
@ApiProperty({description: 'Number of licenses / seats purchased', example: 5, minimum: 1})
@IsNumber()
@Min(1)
package_id
Type : number
Decorators :
@Expose()
@ApiProperty({description: 'Selected package ID', example: 1})
@IsNumber()
Optional payment_intent_id
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Stripe PaymentIntent id (paid signup)'})
@IsOptional()
@IsString()
Optional promo_code
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Promo / discount code'})
@IsOptional()
@IsString()
Optional setup_intent_id
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Stripe SetupIntent id (trial / $0 signup)'})
@IsOptional()
@IsString()
Optional stripe_customer_id
Type : string
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Existing Stripe customer id, if already created'})
@IsOptional()
@IsString()
Optional team_size
Type : number
Decorators :
@Expose()
@ApiPropertyOptional({description: 'Organisation team size at signup (people who need training). Stored on company.team_size; not the same as license_count.', example: 25, minimum: 1})
@IsOptional()
@Type(undefined)
@IsNumber()
@Min(1)

Expected number of people who will need training (organisation team size at signup). Stored on company.team_size; shown in admin Company list/detail. Distinct from license_count.

total_amount
Type : number
Decorators :
@Expose()
@ApiProperty({description: 'Total amount charged / recorded', example: 149.95})
@Type(undefined)
@IsNumber()
unit_price
Type : number
Decorators :
@Expose()
@ApiProperty({description: 'Unit price used for the signup total', example: 29.99})
@Type(undefined)
@IsNumber()
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import { Exclude, Expose, Type } from "class-transformer";
import { IsEmail, IsNumber, IsOptional, IsString, Matches, Min, MinLength } from "class-validator";

/**
 * Payload for public signup (`POST /api/client/account/create-from-signup`).
 * Creates company + admin participant after Stripe payment / trial setup.
 */
@Exclude()
export class CreateAccountFromSignupDto {
  // Company infos
  @Expose()
  @ApiProperty({ description: "Company / organisation name", example: "Acme Corp" })
  @IsString()
  company_name!: string;

  @Expose()
  @ApiProperty({ description: "Company email (unique tenant identifier)", example: "admin@acme.com" })
  @IsEmail()
  company_email!: string;

  @Expose()
  @ApiPropertyOptional({ description: "Company phone", example: "+971 50 123 4567" })
  @IsOptional()
  @IsString()
  @Matches(/^\+?[\d\s]+$/, {
    message: "Phone number can only contain digits, spaces, and an optional plus (+) symbol for country code",
  })
  company_phone?: string;

  // Admin user info
  @Expose()
  @ApiProperty({ description: "Admin first name", example: "Jane" })
  @IsString()
  admin_first_name!: string;

  @Expose()
  @ApiProperty({ description: "Admin last name", example: "Doe" })
  @IsString()
  admin_last_name!: string;

  @Expose()
  @ApiProperty({ description: "Admin email (login)", example: "jane@acme.com" })
  @IsEmail()
  admin_email!: string;

  @Expose()
  @ApiPropertyOptional({ description: "Admin phone" })
  @IsOptional()
  @IsString()
  @Matches(/^\+?[\d\s]+$/, {
    message: "Phone number can only contain digits, spaces, and an optional plus (+) symbol for country code",
  })
  admin_phone?: string;

  @Expose()
  @ApiPropertyOptional({ description: "Admin address" })
  @IsOptional()
  @IsString()
  admin_address?: string;

  @Expose()
  @ApiPropertyOptional({ description: "Admin city" })
  @IsOptional()
  @IsString()
  admin_city?: string;

  @Expose()
  @ApiPropertyOptional({ description: "Admin country (ISO / display name; used for VAT)", example: "AE" })
  @IsOptional()
  @IsString()
  admin_country?: string;

  @Expose()
  @ApiPropertyOptional({ description: "Admin password (min 8 chars, complexity rules apply)" })
  @IsOptional()
  @IsString()
  @MinLength(8, { message: "Password must be at least 8 characters long" })
  @Matches(/[A-Z]/, {
    message: "Password must contain at least one uppercase letter",
  })
  @Matches(/\d/, { message: "Password must contain at least one number" })
  @Matches(/[\W_]/, {
    message: "Password must contain at least one special character",
  })
  admin_password?: string;

  // Package info
  @Expose()
  @ApiProperty({ description: "Selected package ID", example: 1 })
  @IsNumber()
  package_id!: number;

  @Expose()
  @ApiProperty({ description: "Number of licenses / seats purchased", example: 5, minimum: 1 })
  @IsNumber()
  @Min(1)
  license_count!: number;

  @Expose()
  @ApiProperty({ description: "Unit price used for the signup total", example: 29.99 })
  @Type(() => Number)
  @IsNumber()
  unit_price!: number;

  @Expose()
  @ApiProperty({ description: "Total amount charged / recorded", example: 149.95 })
  @Type(() => Number)
  @IsNumber()
  total_amount!: number;

  // VAT (for regions like UAE)
  // Note: Currently calculated server-side based on admin_country (e.g. 5% for AE)

  // Billing cycle
  @Expose()
  @ApiPropertyOptional({
    description: "Billing cycle",
    example: "QUARTERLY",
    enum: ["QUARTERLY", "HALF_YEARLY", "ANNUAL"],
  })
  @IsOptional()
  @IsString()
  billing_cycle?: string; // QUARTERLY, HALF_YEARLY, ANNUAL

  // Promo code
  @Expose()
  @ApiPropertyOptional({ description: "Promo / discount code" })
  @IsOptional()
  @IsString()
  promo_code?: string;

  // Payment info (for paid plans)
  @Expose()
  @ApiPropertyOptional({ description: "Stripe PaymentIntent id (paid signup)" })
  @IsOptional()
  @IsString()
  payment_intent_id?: string;

  // Setup info (for trial packages - $0 amounts)
  @Expose()
  @ApiPropertyOptional({ description: "Stripe SetupIntent id (trial / $0 signup)" })
  @IsOptional()
  @IsString()
  setup_intent_id?: string;

  @Expose()
  @ApiPropertyOptional({ description: "Existing Stripe customer id, if already created" })
  @IsOptional()
  @IsString()
  stripe_customer_id?: string;

  /**
   * Expected number of people who will need training (organisation team size at signup).
   * Stored on `company.team_size`; shown in admin Company list/detail. Distinct from `license_count`.
   */
  @Expose()
  @ApiPropertyOptional({
    description:
      "Organisation team size at signup (people who need training). Stored on company.team_size; not the same as license_count.",
    example: 25,
    minimum: 1,
  })
  @IsOptional()
  @Type(() => Number)
  @IsNumber()
  @Min(1)
  team_size?: number;
}

/**
 * Response after successful signup account creation.
 */
@Exclude()
export class AccountCreationResponseDto {
  @Expose()
  @ApiProperty({ description: "Whether account creation succeeded", example: true })
  success!: boolean;

  @Expose()
  @ApiPropertyOptional({ description: "Created company id", example: 10 })
  company_id?: number;

  @Expose()
  @ApiPropertyOptional({ description: "Created admin participant id", example: 42 })
  participant_id?: number;

  @Expose()
  @ApiProperty({ description: "Human-readable result message" })
  message!: string;

  // Send temporary credentials via email, don't return in response
  // temporary_password will be sent via email
}

results matching ""

    No results matching ""