From 0f92307fcd508cf05e5fddafd6e876e752c59fc4 Mon Sep 17 00:00:00 2001 From: Alireza Hassani Date: Mon, 10 Aug 2026 09:53:15 +0330 Subject: [PATCH] Allow register to link existing Meshkee accounts after acknowledgement. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds optional acknowledgeExistingAccount and documents the CELL_EXISTS_OTHER_SITE → SMS link flow for storefronts. Co-authored-by: Cursor --- docs/website-api/AI_PROMPT.md | 2 +- .../Meshkee-Website-API.postman_collection.json | 2 +- docs/website-api/openapi.json | 6 +++++- src/auth/auth.service.ts | 2 +- src/auth/dto/register.dto.ts | 17 ++++++++++++++++- src/website-docs/static/AI_PROMPT.md | 2 +- .../Meshkee-Website-API.postman_collection.json | 2 +- src/website-docs/static/openapi.json | 6 +++++- 8 files changed, 31 insertions(+), 8 deletions(-) diff --git a/docs/website-api/AI_PROMPT.md b/docs/website-api/AI_PROMPT.md index ab740a3..05cb798 100644 --- a/docs/website-api/AI_PROMPT.md +++ b/docs/website-api/AI_PROMPT.md @@ -23,7 +23,7 @@ You are building a **Meshkee business website (storefront)**. You must use the M 1. Resolve tenant first: `GET /tenants/` → save `businessId` from `id`. 2. All public content uses `/tenants//...` (no auth). 3. Cart, orders, favorites use `/businesses//...` with `Authorization: Bearer `. -4. Customer register body must include `"domain": ""`. +4. Customer register body must include `"domain": ""`. If the cell already exists on another Meshkee site and the password differs, API returns `409` with `CELL_EXISTS_OTHER_SITE:...`. Retry register with `"acknowledgeExistingAccount": true` to link that account (password/profile stay unchanged), then complete SMS OTP. 5. Cell numbers are E.164 (`+98912...`). 6. Do not call dashboard/CMS routes (`/businesses/.../products` write APIs, media upload, domain-admin, etc.). 7. **Partner SMS** (`POST /public/sms/send`) is for external partner backends with an issued `X-Api-Key` only — not for normal storefront UI. See https://api.meshkee.com/docs/website/SMS.md diff --git a/docs/website-api/Meshkee-Website-API.postman_collection.json b/docs/website-api/Meshkee-Website-API.postman_collection.json index 4827c6f..583c737 100644 --- a/docs/website-api/Meshkee-Website-API.postman_collection.json +++ b/docs/website-api/Meshkee-Website-API.postman_collection.json @@ -171,7 +171,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"cellNumber\": \"+98XXXXXXXXXX\",\n \"password\": \"min8chars\",\n \"firstName\": \"First\",\n \"lastName\": \"Last\",\n \"email\": \"optional@example.com\",\n \"domain\": \"{{domain}}\"\n}" + "raw": "{\n \"cellNumber\": \"+98XXXXXXXXXX\",\n \"password\": \"min8chars\",\n \"firstName\": \"First\",\n \"lastName\": \"Last\",\n \"email\": \"optional@example.com\",\n \"domain\": \"{{domain}}\",\n \"acknowledgeExistingAccount\": false\n}" }, "url": "{{baseUrl}}/auth/register" } diff --git a/docs/website-api/openapi.json b/docs/website-api/openapi.json index c791420..58b3fbc 100644 --- a/docs/website-api/openapi.json +++ b/docs/website-api/openapi.json @@ -557,7 +557,11 @@ "firstName": { "type": "string" }, "lastName": { "type": "string" }, "email": { "type": "string" }, - "domain": { "type": "string", "description": "Same website apex as {domain}" } + "domain": { "type": "string", "description": "Same website apex as {domain}" }, + "acknowledgeExistingAccount": { + "type": "boolean", + "description": "If true, link an existing Meshkee account from another website without matching its password. Existing password and profile stay unchanged." + } } } } diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 726efb5..a974b80 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -79,7 +79,7 @@ export class AuthService { existingUser.passwordHash, ); - if (!passwordValid) { + if (!passwordValid && !dto.acknowledgeExistingAccount) { const otherNames = existingUser.businessCustomers .map((item) => item.business.nameFa?.trim() || item.business.name) .filter(Boolean); diff --git a/src/auth/dto/register.dto.ts b/src/auth/dto/register.dto.ts index 81469a3..dc74372 100644 --- a/src/auth/dto/register.dto.ts +++ b/src/auth/dto/register.dto.ts @@ -1,4 +1,11 @@ -import { IsEmail, IsOptional, IsString, Matches, MinLength } from 'class-validator'; +import { + IsBoolean, + IsEmail, + IsOptional, + IsString, + Matches, + MinLength, +} from 'class-validator'; export class RegisterDto { @IsString() @@ -27,4 +34,12 @@ export class RegisterDto { @IsString() @MinLength(3) domain!: string; + + /** + * When true, link an existing Meshkee account (other websites) to this tenant + * without requiring the existing password. Existing password and profile stay unchanged. + */ + @IsOptional() + @IsBoolean() + acknowledgeExistingAccount?: boolean; } diff --git a/src/website-docs/static/AI_PROMPT.md b/src/website-docs/static/AI_PROMPT.md index ab740a3..05cb798 100644 --- a/src/website-docs/static/AI_PROMPT.md +++ b/src/website-docs/static/AI_PROMPT.md @@ -23,7 +23,7 @@ You are building a **Meshkee business website (storefront)**. You must use the M 1. Resolve tenant first: `GET /tenants/` → save `businessId` from `id`. 2. All public content uses `/tenants//...` (no auth). 3. Cart, orders, favorites use `/businesses//...` with `Authorization: Bearer `. -4. Customer register body must include `"domain": ""`. +4. Customer register body must include `"domain": ""`. If the cell already exists on another Meshkee site and the password differs, API returns `409` with `CELL_EXISTS_OTHER_SITE:...`. Retry register with `"acknowledgeExistingAccount": true` to link that account (password/profile stay unchanged), then complete SMS OTP. 5. Cell numbers are E.164 (`+98912...`). 6. Do not call dashboard/CMS routes (`/businesses/.../products` write APIs, media upload, domain-admin, etc.). 7. **Partner SMS** (`POST /public/sms/send`) is for external partner backends with an issued `X-Api-Key` only — not for normal storefront UI. See https://api.meshkee.com/docs/website/SMS.md diff --git a/src/website-docs/static/Meshkee-Website-API.postman_collection.json b/src/website-docs/static/Meshkee-Website-API.postman_collection.json index 4827c6f..583c737 100644 --- a/src/website-docs/static/Meshkee-Website-API.postman_collection.json +++ b/src/website-docs/static/Meshkee-Website-API.postman_collection.json @@ -171,7 +171,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"cellNumber\": \"+98XXXXXXXXXX\",\n \"password\": \"min8chars\",\n \"firstName\": \"First\",\n \"lastName\": \"Last\",\n \"email\": \"optional@example.com\",\n \"domain\": \"{{domain}}\"\n}" + "raw": "{\n \"cellNumber\": \"+98XXXXXXXXXX\",\n \"password\": \"min8chars\",\n \"firstName\": \"First\",\n \"lastName\": \"Last\",\n \"email\": \"optional@example.com\",\n \"domain\": \"{{domain}}\",\n \"acknowledgeExistingAccount\": false\n}" }, "url": "{{baseUrl}}/auth/register" } diff --git a/src/website-docs/static/openapi.json b/src/website-docs/static/openapi.json index c791420..58b3fbc 100644 --- a/src/website-docs/static/openapi.json +++ b/src/website-docs/static/openapi.json @@ -557,7 +557,11 @@ "firstName": { "type": "string" }, "lastName": { "type": "string" }, "email": { "type": "string" }, - "domain": { "type": "string", "description": "Same website apex as {domain}" } + "domain": { "type": "string", "description": "Same website apex as {domain}" }, + "acknowledgeExistingAccount": { + "type": "boolean", + "description": "If true, link an existing Meshkee account from another website without matching its password. Existing password and profile stay unchanged." + } } } }