chore: add domain logic

This commit is contained in:
Mahyargdz
2025-05-22 10:42:56 +03:30
parent 048abb40dd
commit 7566a061e0
4 changed files with 118 additions and 265 deletions
+6 -6
View File
@@ -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"
},
+32
View File
@@ -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 = "- حداقل ۱۵ دقیقه قبل از بررسی وضعیت تأیید صبر کنید",
}
+15 -57
View File
@@ -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);
}
}
@@ -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<boolean> {
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<boolean> {
try {
// Try CNAME first