Skip to main content

Personal Account Settings

Audience: Support (engineers for the technical section) · Where in app: Sidebar → Settings → Account (and Notifications / Working Hours) · Plan availability: All plans

Personal account settings are everything a team member can change about their own profile — name, contact details, photo, password, sign-in methods, personal working hours, timezone, and notification preferences. These live on the member's own UserModel row.

What it does

  • Edit profile (name, phone, designation, location, photo, display name shown to visitors).
  • Change password (requires current password) or reset it via email.
  • Change email (confirmed by a one-time code to the new address).
  • Manage sign-in methods (email/password, Google, Apple).
  • Set personal working hours, timezone, and notification preferences.

How it works

Profile edits go through PUT /user/:_id. Security-sensitive changes have guardrails: a password change requires the current password; an email change is staged — an OTP goes to the new address and the account email only changes after verification. There is no first-party 2FA — teams that want it rely on Google/Apple SSO.

Configuration & options

Profile fields (UserModel)

  • first_name, last_name, phone, designation, location.
  • photo_file (current profile photo; photo is a legacy field).
  • Display name shown to visitors during chats/calls.

Password

  • Change: POST /auth/change-passwordrequires the current password (verified server-side).
  • Reset: POST /auth/forget-password emails a reset token (reset_password_token, ~1 hour TTL) → POST /auth/reset-password/:token.
  • Password complexity rules are configurable in admin settings.

Email change (staged OTP flow)

Self-serve email change is a staged flow on userRoutes.js (all passport-authenticated, UserController):

  1. POST /user/email-change/request — stages the address in user.pending_email + pending_email_otp (TTL 1 h, EMAIL_CHANGE_OTP_TTL_HOURS) and emails the OTP to the new address. Rejects addresses already in use or parked as someone else's unexpired pending_email (case-insensitive).
  2. POST /user/email-change/verify — OTP correct → commits user.email, clears the pending fields, and syncs the Stripe customer email (StripeService.updateCustomerEmail).
  3. POST /user/email-change/resend — re-sends the OTP (60 s cooldown, pending_email_sent_at).
  4. DELETE /user/email-change — cancels the pending change.

The live user.email never changes until the OTP verifies — no lockout window, no takeover via session hijack.

Security note: POST /change-email (AuthController@changeEmailAddress) was moved from the unauthenticated route block into the passport-guarded block in authRoutes.js — previously it let an unauthenticated caller rewrite any account's email by passing its _id in the body. It remains only for signup-time correction (account exists but is not yet OTP-verified); verified accounts must use the staged flow above.

Sign-in methods

  • Email + password (primary).
  • Google OAuth (users.google_id; tokens in users.gtm_auth).
  • Apple Sign-In (users.apple_id) — mobile-oriented.
  • users.social_login flags accounts created via OAuth.

Personal working hours & timezone

  • users.working_hours overlays the org's working hours.
  • users.timezone (IANA) drives how times display in the dashboard.

Personal notification preferences

  • Email on new chat / new call, push on new chat/call, daily summary, notification sound (users.notification_tune).
  • A user-level toggle only fires when the company-level toggle allows it (org is the ceiling — see Organization Settings).

Behaviors & edge cases

  • Online status is user-controlled: availability (online_status: online/away/offline) is a manual toggle, not derived purely from working hours — see Team Management.
  • No self-serve account deletion: there is no "delete my account" button. Deletion is admin-only (DELETE /user/:_id, requires user_type === 'admin'); regular users must request it via support.
  • Owner can't self-delete: the company owner (web_owner) must transfer ownership before their account can be removed.
  • Password reset invalidates sessions: a reset/forces re-auth across sessions.
  • 2FA: not first-party — use Google/Apple SSO if MFA is required.
  • Photo precedence: a member's personal photo overrides any default agent avatar shown to visitors.
  • Privacy boundary (Nox): a user can ask Nox about their own record; others' personal info is gated.

Plan & limits

  • Account settings are available on all plans. No plan-specific limits here.

Technical implementation

  • Model: UserModel/home/bilal/Projects/knock-knock-app/backend/app/models/UserModel.js.
  • Routes: authRoutes.js (/auth/change-password, /auth/forget-password, /auth/reset-password/:token, passport-gated /change-email for signup-time correction only), userRoutes.js (/user/email-change/request|verify|resend, DELETE /user/email-change, PUT /user/:_id, DELETE /user/:_id/profile-image, PUT /user/online-status). Email-change staging fields: pending_email, pending_email_otp, pending_email_otp_expiry, pending_email_sent_at (UserModel); Stripe customer email synced on commit via StripeService.updateCustomerEmail.
  • OAuth: GoogleController (POST /google/authenticate), AppleController (POST /apple/authenticate).
  • Frontend: frontend/src/views/settings/Account.vue.
  • See backend service.