apps/recallassess/recallassess-api/src/api/client/account/dto/account.dto.ts
Payload for public signup (POST /api/client/account/create-from-signup).
Creates company + admin participant after Stripe payment / trial setup.
Properties |
|
| Optional admin_address |
Type : string
|
Decorators :
@Expose()
|
| Optional admin_city |
Type : string
|
Decorators :
@Expose()
|
| Optional admin_country |
Type : string
|
Decorators :
@Expose()
|
| admin_email |
Type : string
|
Decorators :
@Expose()
|
| admin_first_name |
Type : string
|
Decorators :
@Expose()
|
| admin_last_name |
Type : string
|
Decorators :
@Expose()
|
| Optional admin_password |
Type : string
|
Decorators :
@Expose()
|
| Optional admin_phone |
Type : string
|
Decorators :
@Expose()
|
| Optional billing_cycle |
Type : string
|
Decorators :
@Expose()
|
| company_email |
Type : string
|
Decorators :
@Expose()
|
| company_name |
Type : string
|
Decorators :
@Expose()
|
| Optional company_phone |
Type : string
|
Decorators :
@Expose()
|
| license_count |
Type : number
|
Decorators :
@Expose()
|
| package_id |
Type : number
|
Decorators :
@Expose()
|
| Optional payment_intent_id |
Type : string
|
Decorators :
@Expose()
|
| Optional promo_code |
Type : string
|
Decorators :
@Expose()
|
| Optional setup_intent_id |
Type : string
|
Decorators :
@Expose()
|
| Optional stripe_customer_id |
Type : string
|
Decorators :
@Expose()
|
| Optional team_size |
Type : number
|
Decorators :
@Expose()
|
|
Expected number of people who will need training (organisation team size at signup).
Stored on |
| total_amount |
Type : number
|
Decorators :
@Expose()
|
| unit_price |
Type : number
|
Decorators :
@Expose()
|
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
}