From e027cc96eacabc6a314bf8f0f789c12b06f2fdfe Mon Sep 17 00:00:00 2001 From: Alireza Hassani Date: Fri, 21 Aug 2026 12:07:17 +0330 Subject: [PATCH] Replace Meshkee password when linking an existing account to a new site. Cross-site register now updates the password to the signup value and documents passwordUpdated for storefronts. Co-authored-by: Cursor --- docs/PROJECT_CONTEXT.md | 2 +- docs/website-api/AI_PROMPT.md | 2 +- docs/website-api/openapi.json | 2 +- src/auth/auth.service.ts | 29 +++++++++++++++++++++------- src/auth/dto/register.dto.ts | 3 ++- src/website-docs/static/AI_PROMPT.md | 2 +- src/website-docs/static/openapi.json | 2 +- 7 files changed, 29 insertions(+), 13 deletions(-) diff --git a/docs/PROJECT_CONTEXT.md b/docs/PROJECT_CONTEXT.md index f102900..9c8be3f 100644 --- a/docs/PROJECT_CONTEXT.md +++ b/docs/PROJECT_CONTEXT.md @@ -253,7 +253,7 @@ All routes are prefixed with `/api/v1`. | Method | Path | Description | |--------|------|-------------| -| POST | `/auth/register` | Customer registration by domain | +| POST | `/auth/register` | Customer registration by domain. Cross-site link updates Meshkee password to the new signup password (`passwordUpdated`). | | POST | `/auth/login` | Cell + password | | POST | `/auth/login-otp` | Passwordless login with SMS OTP | | POST | `/auth/reset-password` | Reset password with SMS OTP | diff --git a/docs/website-api/AI_PROMPT.md b/docs/website-api/AI_PROMPT.md index 0825749..8410d8b 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": ""`. 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. +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 (profile unchanged; **password is replaced** with the new signup password), 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/openapi.json b/docs/website-api/openapi.json index 74b06ab..caa31ef 100644 --- a/docs/website-api/openapi.json +++ b/docs/website-api/openapi.json @@ -1557,7 +1557,7 @@ }, "acknowledgeExistingAccount": { "type": "boolean", - "description": "If true, link an existing Meshkee account from another website without matching its password. Existing password and profile stay unchanged." + "description": "If true, link an existing Meshkee account from another website without matching its password. Profile stays unchanged; password is replaced with the new signup password. Response may include passwordUpdated: true." } } } diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 7c090ac..24a2f78 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -97,10 +97,19 @@ export class AuthService { } } + const linkedExistingAccount = Boolean(existingUser); + const user = await this.prisma.$transaction(async (tx) => { - const account = - existingUser ?? - (await tx.user.create({ + let account = existingUser; + + if (account) { + // Cross-site join: replace Meshkee password with the one entered on this signup. + account = await tx.user.update({ + where: { id: account.id }, + data: { passwordHash }, + }); + } else { + account = await tx.user.create({ data: { cellNumber: dto.cellNumber, passwordHash, @@ -109,7 +118,8 @@ export class AuthService { lastName: dto.lastName, cellVerifiedAt: smsEnabled ? null : new Date(), }, - })); + }); + } await tx.businessCustomer.create({ data: { @@ -143,10 +153,15 @@ export class AuthService { const tokens = await this.issueTokens(authUser); return { - message: smsEnabled - ? 'Registration successful. Please verify your cell number with OTP.' - : 'Registration successful. SMS verification is disabled — account auto-verified.', + message: linkedExistingAccount + ? smsEnabled + ? 'Joined this website. Your Meshkee password was updated to the one you just entered. Please verify your cell number with OTP.' + : 'Joined this website. Your Meshkee password was updated to the one you just entered.' + : smsEnabled + ? 'Registration successful. Please verify your cell number with OTP.' + : 'Registration successful. SMS verification is disabled — account auto-verified.', smsEnabled, + passwordUpdated: linkedExistingAccount, user: this.serializeUser(authUser), registeredBusiness: { id: business.id, diff --git a/src/auth/dto/register.dto.ts b/src/auth/dto/register.dto.ts index dc74372..25fd6c6 100644 --- a/src/auth/dto/register.dto.ts +++ b/src/auth/dto/register.dto.ts @@ -37,7 +37,8 @@ export class RegisterDto { /** * When true, link an existing Meshkee account (other websites) to this tenant - * without requiring the existing password. Existing password and profile stay unchanged. + * without requiring the existing password. Profile stays unchanged; the password + * is replaced with the one submitted in this registration. */ @IsOptional() @IsBoolean() diff --git a/src/website-docs/static/AI_PROMPT.md b/src/website-docs/static/AI_PROMPT.md index 0825749..8410d8b 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": ""`. 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. +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 (profile unchanged; **password is replaced** with the new signup password), 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/openapi.json b/src/website-docs/static/openapi.json index 74b06ab..caa31ef 100644 --- a/src/website-docs/static/openapi.json +++ b/src/website-docs/static/openapi.json @@ -1557,7 +1557,7 @@ }, "acknowledgeExistingAccount": { "type": "boolean", - "description": "If true, link an existing Meshkee account from another website without matching its password. Existing password and profile stay unchanged." + "description": "If true, link an existing Meshkee account from another website without matching its password. Profile stays unchanged; password is replaced with the new signup password. Response may include passwordUpdated: true." } } }