From 7566a061e01caf4971b05cf674a184a6d0bd7a83 Mon Sep 17 00:00:00 2001 From: Mahyargdz Date: Thu, 22 May 2025 10:42:56 +0330 Subject: [PATCH] chore: add domain logic --- package.json | 12 +- src/common/enums/message.enum.ts | 32 +++ .../businesses/businesses.controller.ts | 72 +---- .../services/domain-verification.service.ts | 267 +++++------------- 4 files changed, 118 insertions(+), 265 deletions(-) diff --git a/package.json b/package.json index b00c04d..24ed2d3 100644 --- a/package.json +++ b/package.json @@ -20,12 +20,12 @@ "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json", "prepare": "husky || true", - "orm:create": "mikro-orm migration:create --config=database/mikro-orm.config.ts", - "orm:up": "mikro-orm migration:up --config=database/mikro-orm.config.ts", - "orm:down": "mikro-orm migration:down --config=database/mikro-orm.config.ts", - "orm:generate": "mikro-orm migration:create --blank --config=database/mikro-orm.config.ts", - "orm:update": "mikro-orm schema:update --run --config=database/mikro-orm.config.ts", - "orm:drop": "mikro-orm schema:drop --run --config=database/mikro-orm.config.ts", + "orm:create": "mikro-orm migration:create --config=database/mikro-orm.config.ts", + "orm:up": "mikro-orm migration:up --config=database/mikro-orm.config.ts", + "orm:down": "mikro-orm migration:down --config=database/mikro-orm.config.ts", + "orm:generate": "mikro-orm migration:create --blank --config=database/mikro-orm.config.ts", + "orm:update": "mikro-orm schema:update --run --config=database/mikro-orm.config.ts", + "orm:drop": "mikro-orm schema:drop --run --drop-migrations-table --drop-db --config=database/mikro-orm.config.ts", "orm:seed": "mikro-orm seeder:create --config=database/mikro-orm.config.ts", "seed:run": "mikro-orm seeder:run --config=database/mikro-orm.config.ts" }, diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index 47689ca..80f4260 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -612,4 +612,36 @@ export const enum BusinessMessage { BUSINESS_SETTINGS_UPDATED = "تنظیمات کسب و کار با موفقیت به روز رسانی شد", NAME_REQUIRED = "نام کسب و کار مورد نیاز است", NAME_STRING = "نام کسب و کار باید یک رشته باشد", + DOMAIN_CONNECTED = "دامنه با موفقیت متصل شد", + DOMAIN_NOT_CONNECTED = "دامنه به سرور ما متصل نشد", + DOMAIN_NOT_FOUND = "دامنه یافت نشد", + DOMAIN_VERIFICATION_TOKEN_REQUIRED = "توکن تایید دامنه مورد نیاز است", + + // Domain Connection Instructions in Farsi + DOMAIN_CONNECTION_TITLE = "دامنه خود را به سرور‌های ما متصل کنید", + DOMAIN_CONNECTION_DESCRIPTION = "یکی از این گزینه‌ها را برای اتصال دامنه خود انتخاب کنید:", + DOMAIN_CONNECTION_OPTION_A_TITLE = "گزینه A: استفاده از رکورد A (IP مستقیم)", + DOMAIN_CONNECTION_OPTION_A_STEP1 = "۱. یک رکورد A در تنظیمات DNS خود اضافه کنید", + DOMAIN_CONNECTION_OPTION_A_STEP2 = "۲. میزبان را روی @ یا زیردامنه خود (مثلاً www) تنظیم کنید - رکورد A", + DOMAIN_CONNECTION_OPTION_A_STEP3 = "۳. مقدار را به IP سرور ما تنظیم کنید: ", + DOMAIN_CONNECTION_OPTION_A_STEP4 = "۴. TTL را روی ۳۶۰۰ (۱ ساعت) یا کمترین مقدار موجود تنظیم کنید - رکورد A", + DOMAIN_CONNECTION_OPTION_B_TITLE = "گزینه B: استفاده از رکورد CNAME (توصیه شده)", + DOMAIN_CONNECTION_OPTION_B_STEP1 = "۱. یک رکورد CNAME در تنظیمات DNS خود اضافه کنید", + DOMAIN_CONNECTION_OPTION_B_STEP2 = "۲. میزبان را روی @ یا زیردامنه خود (مثلاً www) تنظیم کنید - رکورد CNAME", + DOMAIN_CONNECTION_OPTION_B_STEP3 = "۳. مقدار را تنظیم کنید به: ", + DOMAIN_CONNECTION_OPTION_B_STEP4 = "۴. TTL را روی ۳۶۰۰ (۱ ساعت) یا کمترین مقدار موجود تنظیم کنید - رکورد CNAME", + DOMAIN_CONNECTION_OPTION_B_NOTE = "توجه: برخی از ارائه‌دهندگان DNS اجازه CNAME برای دامنه‌های اصلی (@) را نمی‌دهند", + DOMAIN_CONNECTION_TROUBLESHOOTING_1 = "- مطمئن شوید که رکوردها را به دامنه صحیح اضافه کرده‌اید", + DOMAIN_CONNECTION_TROUBLESHOOTING_2 = "- برخی از ارائه‌دهندگان DNS برای دامنه‌های اصلی به نماد @ نیاز دارند", + DOMAIN_CONNECTION_TROUBLESHOOTING_3 = "- بررسی کنید که مقادیر را دقیقاً همانطور که نشان داده شده کپی کرده‌اید", + DOMAIN_CONNECTION_TROUBLESHOOTING_4 = "- تغییرات DNS می‌تواند برای انتشار زمان ببرد (معمولاً ۱۵ دقیقه تا ۴۸ ساعت)", + + // Domain Setup Instructions in Farsi + DOMAIN_SETUP_VERIFICATION_TITLE = "مرحله ۱: تایید مالکیت دامنه", + DOMAIN_SETUP_VERIFICATION_DESC = "این رکورد TXT را اضافه کنید تا ثابت کنید مالک دامنه هستید:", + DOMAIN_SETUP_PROPAGATION_NOTE = "تغییرات DNS می‌تواند ۱۵ دقیقه تا ۴۸ ساعت در سراسر جهان منتشر شود", + DOMAIN_SETUP_TROUBLESHOOTING_1 = "- اطمینان حاصل کنید که رکوردها را به دامنه صحیح اضافه کرده‌اید", + DOMAIN_SETUP_TROUBLESHOOTING_2 = "- بعضی از ارائه‌دهندگان DNS برای دامنه‌های اصلی به نماد @ نیاز دارند", + DOMAIN_SETUP_TROUBLESHOOTING_3 = "- اطمینان حاصل کنید که مقادیر را دقیقاً همانطور که نشان داده شده کپی کرده‌اید", + DOMAIN_SETUP_TROUBLESHOOTING_4 = "- حداقل ۱۵ دقیقه قبل از بررسی وضعیت تأیید صبر کنید", } diff --git a/src/modules/businesses/businesses.controller.ts b/src/modules/businesses/businesses.controller.ts index d369908..480e64e 100644 --- a/src/modules/businesses/businesses.controller.ts +++ b/src/modules/businesses/businesses.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Get, Param, Patch, Post, UseInterceptors } from "@nestjs/common"; -import { ApiHeader, ApiOperation } from "@nestjs/swagger"; +import { ApiHeader, ApiOperation, ApiTags } from "@nestjs/swagger"; import { UpdateBusinessDomainDto } from "./DTO/business-domain.dto"; import { BusinessSlugParamDto } from "./DTO/business-slug-param.dto"; @@ -13,6 +13,7 @@ import { BusinessInterceptor } from "../../core/interceptors/business.intercepto @Controller("business") @ApiHeader({ name: "x-business-id", description: "Business ID" }) +@ApiTags("Business") @UseInterceptors(BusinessInterceptor) export class BusinessesController { constructor( @@ -22,86 +23,43 @@ export class BusinessesController { @Get("slug/:slug") @ApiOperation({ summary: "Get business by slug" }) - async getBusinessBySlug(@Param() params: BusinessSlugParamDto) { + getBusinessBySlug(@Param() params: BusinessSlugParamDto) { return this.businessesService.getBusinessBySlug(params.slug); } @Patch("settings") @ApiOperation({ summary: "Update business settings" }) @AuthGuards() - async updateBusinessSettings(@BusinessDec("id") businessId: string, @Body() settingsDto: UpdateBusinessSettingsDto) { + updateBusinessSettings(@BusinessDec("id") businessId: string, @Body() settingsDto: UpdateBusinessSettingsDto) { return this.businessesService.updateBusinessSettings(businessId, settingsDto); } @Get("settings") @ApiOperation({ summary: "Get business settings" }) @AuthGuards() - async getBusinessSettings(@BusinessDec("id") businessId: string) { + getBusinessSettings(@BusinessDec("id") businessId: string) { return this.businessesService.getBusinessSettings(businessId); } + // Domain management endpoints - simplified flow @Post("domain") - @ApiOperation({ summary: "Update business domain" }) + @ApiOperation({ summary: "Set/update business domain and get verification instructions" }) @AuthGuards() - async updateBusinessDomain(@BusinessDec() business: Business, @Body() domainDto: UpdateBusinessDomainDto) { - return this.domainVerificationService.updateBusinessDomain(business.id, domainDto); - } - - @Get("domain/status") - @ApiOperation({ summary: "Get business domain status" }) - @AuthGuards() - async getDomainStatus(@BusinessDec() business: Business) { - return this.domainVerificationService.getDomainVerificationStatus(business.id); + setDomain(@BusinessDec() business: Business, @Body() domainDto: UpdateBusinessDomainDto) { + return this.domainVerificationService.setDomain(business.id, domainDto); } @Post("domain/verify") - @ApiOperation({ summary: "Initiate domain verification" }) + @ApiOperation({ summary: "Verify domain ownership and connection" }) @AuthGuards() - async verifyDomain(@BusinessDec() business: Business) { - return this.domainVerificationService.initiateVerification(business.id); - } - - @Post("domain/verify/check") - @ApiOperation({ summary: "Check domain verification status" }) - @AuthGuards() - async checkVerification(@BusinessDec() business: Business) { + verifyDomain(@BusinessDec() business: Business) { return this.domainVerificationService.verifyDomain(business.id); } - // DNS-specific domain verification endpoints - @Post("domain/set-domain") - @ApiOperation({ summary: "Set domain and get verification instructions" }) + @Get("domain/status") + @ApiOperation({ summary: "Get current domain status" }) @AuthGuards() - async setDomainAndGetInstructions(@BusinessDec() business: Business, @Body() domainDto: UpdateBusinessDomainDto) { - return this.domainVerificationService.setDomainAndGetVerificationInstructions(business.id, domainDto.domain); - } - - @Get("domain/check-dns") - @ApiOperation({ summary: "Check DNS verification" }) - @AuthGuards() - async checkDnsVerification(@BusinessDec() business: Business) { - return this.domainVerificationService.verifyDnsTxtRecord(business.id); - } - - // Admin domain management endpoints - @Post("admin/:businessId/domain/verify") - @ApiOperation({ summary: "Admin initiate domain verification" }) - @AuthGuards() - async adminVerifyDomain(@Param("businessId") businessId: string) { - return this.domainVerificationService.initiateVerification(businessId); - } - - @Post("admin/:businessId/domain/verify/check") - @ApiOperation({ summary: "Admin check domain verification status" }) - @AuthGuards() - async adminCheckVerification(@Param("businessId") businessId: string) { - return this.domainVerificationService.verifyDomain(businessId); - } - - @Post("admin/:businessId/domain/check-dns") - @ApiOperation({ summary: "Admin check DNS verification" }) - @AuthGuards() - async adminCheckDnsVerification(@Param("businessId") businessId: string) { - return this.domainVerificationService.verifyDnsTxtRecord(businessId); + getDomainStatus(@BusinessDec() business: Business) { + return this.domainVerificationService.getDomainStatus(business.id); } } diff --git a/src/modules/businesses/services/domain-verification.service.ts b/src/modules/businesses/services/domain-verification.service.ts index ac4cfd3..50563aa 100644 --- a/src/modules/businesses/services/domain-verification.service.ts +++ b/src/modules/businesses/services/domain-verification.service.ts @@ -17,7 +17,7 @@ export class DomainVerificationService { private readonly resolveA = promisify(dns.resolve4); private readonly resolveCname = promisify(dns.resolveCname); - private readonly serverIP = "IP_OF_YOUR_SERVER"; + private readonly serverIP = "194.5.192.20"; private readonly serverDomain = "app.dzone.danakcorp.com"; constructor( @@ -26,21 +26,27 @@ export class DomainVerificationService { ) {} /** - * Update business domain + * Set Domain - Core method for setting/updating the domain and returning instructions + * + * This is the main entry point for users to set their domain */ - async updateBusinessDomain(businessId: string, domainDto: UpdateBusinessDomainDto) { + async setDomain(businessId: string, domainDto: UpdateBusinessDomainDto) { const business = await this.businessesService.getBusinessById(businessId); + // If domain hasn't changed and is already verified, just return success if (business.domain === domainDto.domain && business.isDomainVerified) { return { message: BusinessMessage.DOMAIN_ALREADY_VERIFIED, domain: business.domain, isVerified: business.isDomainVerified, + verifiedAt: business.domainVerifiedAt, }; } + // Generate verification token const verificationToken = this.generateVerificationToken(); + // Update domain info business.domain = domainDto.domain; business.isDomainVerified = false; business.domainVerificationToken = verificationToken; @@ -48,133 +54,33 @@ export class DomainVerificationService { await this.em.flush(); + // Return setup instructions return { - message: BusinessMessage.DOMAIN_UPDATED, + message: BusinessMessage.DOMAIN_VERIFICATION_INITIATED, domain: business.domain, - isVerified: business.isDomainVerified, + isVerified: false, dnsInstructions: this.getDomainSetupInstructions(business.domain, verificationToken), }; } /** - * Initiate domain verification with specific method + * Verify Domain - Check domain ownership and connection status + * + * This method checks if the domain is properly configured with TXT record and + * if it points to our servers */ - async initiateVerification(businessId: string) { - const business = await this.businessesService.getBusinessById(businessId); - - if (!business.domain) throw new BadRequestException(BusinessMessage.DOMAIN_INVALID); - - if (business.isDomainVerified) { - return { - message: BusinessMessage.DOMAIN_ALREADY_VERIFIED, - domain: business.domain, - isVerified: true, - verifiedAt: business.domainVerifiedAt, - }; - } - - if (!business.domainVerificationToken) { - business.domainVerificationToken = this.generateVerificationToken(); - await this.em.flush(); - } - - await this.em.flush(); - - return { - message: BusinessMessage.DOMAIN_VERIFICATION_INITIATED, - domain: business.domain, - instructions: this.getDomainSetupInstructions(business.domain, business.domainVerificationToken), - }; - } - - /** - * Set domain and get verification and connection instructions - */ - async setDomainAndGetVerificationInstructions(businessId: string, domain: string) { - const business = await this.businessesService.getBusinessById(businessId); - - // Domain hasn't changed, check if it's already verified - if (business.domain === domain && business.isDomainVerified) { - return { - message: BusinessMessage.DOMAIN_ALREADY_VERIFIED, - domain: business.domain, - isVerified: business.isDomainVerified, - dnsInstructions: business.domainVerificationToken - ? this.getDomainSetupInstructions(domain, business.domainVerificationToken) - : this.getDomainSetupInstructions(domain, ""), - }; - } - - // Generate verification token - const verificationToken = this.generateVerificationToken(); - - // Update the domain and verification data - business.domain = domain; - business.isDomainVerified = false; - business.domainVerificationToken = verificationToken; - business.domainVerifiedAt = undefined; - - await this.em.flush(); - - // Return DNS verification and setup instructions - return { - message: BusinessMessage.DOMAIN_VERIFICATION_INITIATED, - domain: business.domain, - isVerified: false, - dnsInstructions: this.getDomainSetupInstructions(domain, verificationToken), - }; - } - - //************************************** */ async verifyDomain(businessId: string) { const business = await this.businessesService.getBusinessById(businessId); - if (!business.domain || !business.domainVerificationToken) throw new BadRequestException(BusinessMessage.DOMAIN_VERIFICATION_METHOD_INVALID); - - if (business.isDomainVerified) { + // Validate required fields + if (!business.domain) { return { - message: BusinessMessage.DOMAIN_ALREADY_VERIFIED, - domain: business.domain, - isVerified: true, - verifiedAt: business.domainVerifiedAt, + hasDomain: false, + message: BusinessMessage.DOMAIN_NOT_FOUND, }; } - try { - let isVerified = false; - - isVerified = await this.checkDnsTxtRecord(business.domain, business.domainVerificationToken); - - if (isVerified) { - business.isDomainVerified = true; - business.domainVerifiedAt = dayjs().toDate(); - await this.em.flush(); - - return { - message: BusinessMessage.DOMAIN_VERIFICATION_SUCCESS, - domain: business.domain, - isVerified: true, - verifiedAt: business.domainVerifiedAt, - }; - } else { - return { - message: BusinessMessage.DOMAIN_VERIFICATION_FAILED, - domain: business.domain, - isVerified: false, - instructions: this.getDomainSetupInstructions(business.domain, business.domainVerificationToken), - }; - } - } catch (error: unknown) { - this.logger.error(`Domain verification failed: ${error instanceof Error ? error.message : String(error)}`); - throw new BadRequestException(BusinessMessage.DOMAIN_VERIFICATION_FAILED); - } - } - - //************************************** */ - async verifyDnsTxtRecord(businessId: string) { - const business = await this.businessesService.getBusinessById(businessId); - - if (!business.domain || !business.domainVerificationToken) throw new BadRequestException(BusinessMessage.DOMAIN_INVALID); + if (!business.domainVerificationToken) throw new BadRequestException(BusinessMessage.DOMAIN_VERIFICATION_TOKEN_REQUIRED); if (business.isDomainVerified) { const domainPointsToServer = await this.checkDomainPointsToServer(business.domain); @@ -185,23 +91,20 @@ export class DomainVerificationService { isVerified: true, verifiedAt: business.domainVerifiedAt, domainPointsToServer, - serverConnectionStatus: domainPointsToServer - ? "Your domain is properly set up and pointing to our servers" - : "Your domain is verified, but not properly pointing to our servers", - setupInstructions: !domainPointsToServer ? this.getDomainConnectionInstructions(business.domain) : null, + connectionStatus: domainPointsToServer ? BusinessMessage.DOMAIN_CONNECTED : BusinessMessage.DOMAIN_NOT_CONNECTED, + connectionInstructions: !domainPointsToServer ? this.getDomainConnectionInstructions(business.domain) : null, }; } try { - // First check domain ownership verification via TXT record + // Check domain ownership verification via TXT record const isVerified = await this.checkDnsTxtRecord(business.domain, business.domainVerificationToken); - // Then check if domain points to our server (A or CNAME record) + // Check domain points to our server const domainPointsToServer = await this.checkDomainPointsToServer(business.domain); - // If TXT verification passes, mark the domain as verified regardless of A/CNAME + // Update verification status if verified if (isVerified) { - // Update domain verification status business.isDomainVerified = true; business.domainVerifiedAt = dayjs().toDate(); await this.em.flush(); @@ -212,21 +115,18 @@ export class DomainVerificationService { isVerified: true, verifiedAt: business.domainVerifiedAt, domainPointsToServer, - serverConnectionStatus: domainPointsToServer - ? "Your domain is properly set up and pointing to our servers" - : "Your domain is verified, but not properly pointing to our servers", + connectionStatus: domainPointsToServer ? BusinessMessage.DOMAIN_CONNECTED : BusinessMessage.DOMAIN_NOT_CONNECTED, connectionInstructions: !domainPointsToServer ? this.getDomainConnectionInstructions(business.domain) : null, }; } else { + // Verification failed return { message: BusinessMessage.DOMAIN_VERIFICATION_FAILED, domain: business.domain, isVerified: false, domainPointsToServer, - serverConnectionStatus: domainPointsToServer - ? "Your domain is pointing to our servers, but ownership verification failed" - : "Both ownership verification and server connection failed", - setupInstructions: this.getDomainSetupInstructions(business.domain, business.domainVerificationToken || ""), + connectionStatus: domainPointsToServer ? BusinessMessage.DOMAIN_CONNECTED : BusinessMessage.DOMAIN_NOT_CONNECTED, + setupInstructions: this.getDomainSetupInstructions(business.domain, business.domainVerificationToken), }; } } catch (error: unknown) { @@ -237,38 +137,11 @@ export class DomainVerificationService { domain: business.domain, isVerified: false, error: error instanceof Error ? error.message : String(error), - setupInstructions: this.getDomainSetupInstructions(business.domain, business.domainVerificationToken || ""), + setupInstructions: this.getDomainSetupInstructions(business.domain, business.domainVerificationToken), }; } } - //************************************** */ - async getDomainVerificationStatus(businessId: string) { - const business = await this.businessesService.getBusinessById(businessId); - - if (!business.domain) { - return { - hasDomain: false, - }; - } - - // Check if domain points to our server (A or CNAME record) - const domainPointsToServer = await this.checkDomainPointsToServer(business.domain); - - return { - hasDomain: true, - domain: business.domain, - isVerified: business.isDomainVerified, - verifiedAt: business.domainVerifiedAt, - domainPointsToServer, - verificationStatus: business.isDomainVerified ? "Verified" : "Not Verified", - connectionStatus: domainPointsToServer ? "Connected" : "Not Connected", - fullSetupComplete: business.isDomainVerified && domainPointsToServer, - connectionInstructions: !domainPointsToServer ? this.getDomainConnectionInstructions(business.domain) : null, - setupInstructions: !business.isDomainVerified ? this.getDomainSetupInstructions(business.domain, business.domainVerificationToken || "") : null, - }; - } - //*********************************** */ async getDomainStatus(businessId: string) { const business = await this.businessesService.getBusinessById(businessId); @@ -276,7 +149,7 @@ export class DomainVerificationService { if (!business.domain) { return { hasDomain: false, - message: "No domain set for this business", + message: BusinessMessage.DOMAIN_NOT_FOUND, }; } @@ -288,8 +161,8 @@ export class DomainVerificationService { isVerified: business.isDomainVerified, verifiedAt: business.domainVerifiedAt, domainPointsToServer, - verificationStatus: business.isDomainVerified ? "Verified" : "Not Verified", - connectionStatus: domainPointsToServer ? "Connected" : "Not Connected", + verificationStatus: business.isDomainVerified ? BusinessMessage.DOMAIN_VERIFICATION_SUCCESS : BusinessMessage.DOMAIN_VERIFICATION_FAILED, + connectionStatus: domainPointsToServer ? BusinessMessage.DOMAIN_CONNECTED : BusinessMessage.DOMAIN_NOT_CONNECTED, fullSetupComplete: business.isDomainVerified && domainPointsToServer, setupInstructions: !business.isDomainVerified || !domainPointsToServer @@ -298,60 +171,54 @@ export class DomainVerificationService { }; } - /** - * Generate a random verification token - */ + //*********************************** */ + //private methods + private generateVerificationToken(): string { return `dzone-verify-${crypto.randomBytes(16).toString("hex")}`; } - /** - * Get domain connection instructions - */ + // Get domain connection instructions private getDomainConnectionInstructions(_domain: string) { - // The domain parameter is used for contextual purposes in some implementations - // but not directly in this template return { - title: "Point your domain to our servers", - description: "Choose ONE of these options to connect your domain:", + title: BusinessMessage.DOMAIN_CONNECTION_TITLE, + description: BusinessMessage.DOMAIN_CONNECTION_DESCRIPTION, options: [ { - title: "Option A: Using A Record (Direct IP)", + title: BusinessMessage.DOMAIN_CONNECTION_OPTION_A_TITLE, steps: [ - "1. Add an A record in your DNS settings", - "2. Set the host to @ or your subdomain (e.g., www)", - "3. Set the value to our server IP: " + this.serverIP, - "4. Set TTL to 3600 (1 hour) or the lowest available", + BusinessMessage.DOMAIN_CONNECTION_OPTION_A_STEP1, + BusinessMessage.DOMAIN_CONNECTION_OPTION_A_STEP2, + BusinessMessage.DOMAIN_CONNECTION_OPTION_A_STEP3 + this.serverIP, + BusinessMessage.DOMAIN_CONNECTION_OPTION_A_STEP4, ], }, { - title: "Option B: Using CNAME Record (Recommended)", + title: BusinessMessage.DOMAIN_CONNECTION_OPTION_B_TITLE, steps: [ - "1. Add a CNAME record in your DNS settings", - "2. Set the host to @ or your subdomain (e.g., www)", - "3. Set the value to: " + this.serverDomain, - "4. Set TTL to 3600 (1 hour) or the lowest available", - "Note: Some DNS providers don't allow CNAME for root domains (@)", + BusinessMessage.DOMAIN_CONNECTION_OPTION_B_STEP1, + BusinessMessage.DOMAIN_CONNECTION_OPTION_B_STEP2, + BusinessMessage.DOMAIN_CONNECTION_OPTION_B_STEP3 + this.serverDomain, + BusinessMessage.DOMAIN_CONNECTION_OPTION_B_STEP4, + BusinessMessage.DOMAIN_CONNECTION_OPTION_B_NOTE, ], }, ], troubleshooting: [ - "- Make sure you've added the records to the correct domain", - "- Some DNS providers require the @ symbol for root domains", - "- Check that you've copied the values exactly as shown", - "- DNS changes can take time to propagate (typically 15 minutes to 48 hours)", + BusinessMessage.DOMAIN_CONNECTION_TROUBLESHOOTING_1, + BusinessMessage.DOMAIN_CONNECTION_TROUBLESHOOTING_2, + BusinessMessage.DOMAIN_CONNECTION_TROUBLESHOOTING_3, + BusinessMessage.DOMAIN_CONNECTION_TROUBLESHOOTING_4, ], }; } - /** - * Get comprehensive domain setup instructions - */ + // Get comprehensive domain setup instructions private getDomainSetupInstructions(domain: string, token: string) { return { verificationInstructions: { - title: "Step 1: Verify domain ownership", - description: "Add this TXT record to prove you own the domain:", + title: BusinessMessage.DOMAIN_SETUP_VERIFICATION_TITLE, + description: BusinessMessage.DOMAIN_SETUP_VERIFICATION_DESC, host: "@", // Root domain type: "TXT", // Record type value: token, // Token value @@ -360,20 +227,18 @@ export class DomainVerificationService { connectionInstructions: this.getDomainConnectionInstructions(domain), general: { verificationEndpoint: `/business/domain/verify/check-dns`, - propagationNote: "DNS changes can take 15 minutes to 48 hours to propagate worldwide", + propagationNote: BusinessMessage.DOMAIN_SETUP_PROPAGATION_NOTE, troubleshooting: [ - "- Make sure you've added the records to the correct domain", - "- Some DNS providers require the @ symbol for root domains", - "- Check that you've copied the values exactly as shown", - "- Wait at least 15 minutes before checking verification status", + BusinessMessage.DOMAIN_SETUP_TROUBLESHOOTING_1, + BusinessMessage.DOMAIN_SETUP_TROUBLESHOOTING_2, + BusinessMessage.DOMAIN_SETUP_TROUBLESHOOTING_3, + BusinessMessage.DOMAIN_SETUP_TROUBLESHOOTING_4, ], }, }; } - /** - * Verify domain using DNS TXT record - */ + // Verify domain using DNS TXT record private async checkDnsTxtRecord(domain: string, token: string): Promise { try { this.logger.log(`Checking TXT records for domain: ${domain}`); @@ -392,9 +257,7 @@ export class DomainVerificationService { } } - /** - * Check if domain points to our server via A or CNAME record - */ + // Check if domain points to our server via A or CNAME record private async checkDomainPointsToServer(domain: string): Promise { try { // Try CNAME first