Skip to content

feat(user): add phone number to user#3230

Open
modarah wants to merge 7 commits into
seerr-team:developfrom
modarah:feature/add-phone-number-to-users
Open

feat(user): add phone number to user#3230
modarah wants to merge 7 commits into
seerr-team:developfrom
modarah:feature/add-phone-number-to-users

Conversation

@modarah

@modarah modarah commented Jul 6, 2026

Copy link
Copy Markdown

Description

How Has This Been Tested?

  • ran pnpm test and pnpm build
  • added and removed phone number to user
  • used webhook to send the json payload with the phone number

AI

  • Asked claude chat about regex (because I suck at them) but it got too complicated so I went with a very simple regex

Screenshots / Logs (if applicable)

Screenshot 2026-07-06 at 19 57 57 Screenshot 2026-07-06 at 19 59 29 Screenshot 2026-07-06 at 20 01 30

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • New Features
    • Added optional phone number support across user creation, local user creation, and general user settings (validated as optional + plus 1–15 digits).
    • Phone number is now included in main user settings responses.
    • Webhooks now support new phone-number template variables for requester, reporter, and commenter.
  • Bug Fixes
    • Improved styling consistency for tel inputs to match other form fields.
  • Documentation
    • Updated webhook documentation with the new phone-number template variables.
  • Chores
    • Added i18n strings for phone number labels and validation messages (including German).

@modarah modarah requested a review from a team as a code owner July 6, 2026 18:13
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d0cf274e-8f0e-4870-9afa-a2810664a0b2

📥 Commits

Reviewing files that changed from the base of the PR and between 3a19174 and 5bace0c.

📒 Files selected for processing (1)
  • server/routes/user/usersettings.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/routes/user/usersettings.ts

📝 Walkthrough

Walkthrough

This PR adds phoneNumber support across user storage, APIs, webhook templates, and UI forms. It validates and persists the field, exposes it in settings and user creation, and adds translations and documentation.

Changes

User phone number support

Layer / File(s) Summary
Entity, interfaces, and database migrations
server/entity/User.ts, server/interfaces/api/userSettingsInterfaces.ts, server/migration/postgres/*, server/migration/sqlite/*
Adds a nullable phoneNumber varchar(20) column to the user entity and response interface, with Postgres and SQLite migrations for adding and removing the column.
Backend API wiring
server/routes/user/index.ts, server/routes/user/usersettings.ts, server/constants/error.ts, seerr-api.yml
Reads and persists phoneNumber during user creation and settings updates, returns it from settings endpoints, validates it, and updates the POST /user schema.
Webhook template variables
server/lib/notifications/agents/webhook.ts, src/components/Settings/Notifications/NotificationsWebhook/index.tsx, docs/using-seerr/notifications/webhook.md
Adds phone-number variables for request, issue, and comment notifications to webhook mapping, default payloads, and documentation.
User forms, validation, and translations
src/utils/numberHelpers.ts, src/styles/globals.css, src/components/UserList/index.tsx, src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx, src/i18n/locale/{en,de}.json
Adds phone validation, telephone input styling, user form fields, and English and German translations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: gauthier-th, fallenbagel, 0xSysR3ll

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant UserSettingsRoute
  participant UserEntity
  participant Database
  Client->>UserSettingsRoute: Submit phoneNumber
  UserSettingsRoute->>UserSettingsRoute: Validate phoneNumber
  UserSettingsRoute->>UserEntity: Set user.phoneNumber
  UserEntity->>Database: Persist user
  Database-->>UserSettingsRoute: Return saved user
  UserSettingsRoute-->>Client: Return phoneNumber
Loading

Poem

A rabbit hops with digits new,
A phone number blooms in fields anew.
From webhook paths to forms so neat,
The little plus signs find a seat.
Squeak, save, and send! 🐰📞

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding a phone number to users.
Linked Issues check ✅ Passed The PR adds user phone storage and exposes it in webhook notifications, matching issue #751's requirements.
Out of Scope Changes check ✅ Passed The changes all support user phone numbers and webhook payload exposure, with no clear unrelated additions.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx (1)

158-172: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

phoneNumber initial value missing fallback, inconsistent with sibling fields.

displayName and email both fall back to '' when the loaded value is empty/undefined (Lines 159-160), but phoneNumber is set directly from data?.phoneNumber (Line 161). Since the DB column is nullable, data?.phoneNumber can be undefined, which makes the tel input start uncontrolled and switch to controlled once populated — triggering React's "component is changing an uncontrolled input to be controlled" warning.

🐛 Proposed fix
-          phoneNumber: data?.phoneNumber,
+          phoneNumber: data?.phoneNumber ?? '',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx` around
lines 158 - 172, The UserGeneralSettings form is passing phoneNumber directly
into the initialValues object, unlike displayName and email, so it can start as
undefined and make the tel input switch from uncontrolled to controlled. Update
the initialValues in UserGeneralSettings to give phoneNumber a safe empty-string
fallback when data?.phoneNumber is missing, matching the pattern used for the
other fields and keeping the input controlled from the start.
🧹 Nitpick comments (2)
docs/using-seerr/notifications/webhook.md (1)

138-138: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Wording says "requesting" instead of "reporting" user.

For the reportedBy_phoneNumber row (under the Issue section), the description should reference the "reporting" user, not "requesting" user. Note this mirrors an existing wording issue on the neighboring unchanged reportedBy_username/reportedBy_email rows (Lines 136-137), so this new row simply follows that same pre-existing pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/using-seerr/notifications/webhook.md` at line 138, Update the
`reportedBy_phoneNumber` row in the webhook notifications table so its
description matches the surrounding `reportedBy_username` and `reportedBy_email`
rows and refers to the “reporting” user instead of the “requesting” user. Keep
the wording consistent within the Issue section by editing the table entry in
the markdown content only.
server/routes/user/index.ts (1)

206-215: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider validating phoneNumber format server-side.

body.phoneNumber is persisted without any format validation, relying solely on frontend PHONE_REGEX. Since this value now feeds webhook payloads for external SMS/WhatsApp integrations, an unvalidated/malformed number here could silently break those notifications for admin-created users.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/user/index.ts` around lines 206 - 215, The user creation flow
in the User constructor is persisting body.phoneNumber without any server-side
validation. Add a phone number format check in the server route before
constructing the User, ideally using the same validation rules enforced
elsewhere so malformed numbers are rejected consistently. Update the user
creation handler to validate body.phoneNumber alongside the existing
email/username fields and only assign it when it passes validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@seerr-api.yml`:
- Around line 4267-4268: The shared User schema is missing the phoneNumber
field, so update the schema definition used by /user, /auth/me, and
/user/{userId} to include phoneNumber alongside the existing user properties.
Reuse the same schema component where the User object is defined rather than
only adding it to the POST /user request shape, so the OpenAPI response contract
stays consistent.

In `@server/entity/User.ts`:
- Around line 80-82: The nullable phoneNumber field in User should be typed to
match the DB nullability and sibling columns. Update the phoneNumber property in
the User entity to include null in its TypeScript type, consistent with
plexUsername and jellyfinUsername. Keep the `@Column`({ nullable: true }) mapping
unchanged and ensure the property reflects both undefined and null cases if
needed.

---

Outside diff comments:
In `@src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx`:
- Around line 158-172: The UserGeneralSettings form is passing phoneNumber
directly into the initialValues object, unlike displayName and email, so it can
start as undefined and make the tel input switch from uncontrolled to
controlled. Update the initialValues in UserGeneralSettings to give phoneNumber
a safe empty-string fallback when data?.phoneNumber is missing, matching the
pattern used for the other fields and keeping the input controlled from the
start.

---

Nitpick comments:
In `@docs/using-seerr/notifications/webhook.md`:
- Line 138: Update the `reportedBy_phoneNumber` row in the webhook notifications
table so its description matches the surrounding `reportedBy_username` and
`reportedBy_email` rows and refers to the “reporting” user instead of the
“requesting” user. Keep the wording consistent within the Issue section by
editing the table entry in the markdown content only.

In `@server/routes/user/index.ts`:
- Around line 206-215: The user creation flow in the User constructor is
persisting body.phoneNumber without any server-side validation. Add a phone
number format check in the server route before constructing the User, ideally
using the same validation rules enforced elsewhere so malformed numbers are
rejected consistently. Update the user creation handler to validate
body.phoneNumber alongside the existing email/username fields and only assign it
when it passes validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fdf887c7-c0e5-4f0c-b79d-7f64124bf20f

📥 Commits

Reviewing files that changed from the base of the PR and between 5ae70d0 and 2689893.

📒 Files selected for processing (16)
  • docs/using-seerr/notifications/webhook.md
  • seerr-api.yml
  • server/entity/User.ts
  • server/interfaces/api/userSettingsInterfaces.ts
  • server/lib/notifications/agents/webhook.ts
  • server/migration/postgres/1783161650264-AddPhoneNumberToUser.ts
  • server/migration/sqlite/1783161620407-AddPhoneNumberToUser.ts
  • server/routes/user/index.ts
  • server/routes/user/usersettings.ts
  • src/components/Settings/Notifications/NotificationsWebhook/index.tsx
  • src/components/UserList/index.tsx
  • src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx
  • src/i18n/locale/de.json
  • src/i18n/locale/en.json
  • src/styles/globals.css
  • src/utils/numberHelpers.ts

Comment thread seerr-api.yml
Comment thread server/entity/User.ts
@modarah modarah force-pushed the feature/add-phone-number-to-users branch from 2689893 to 6ac5f64 Compare July 6, 2026 19:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/routes/user/usersettings.ts (1)

115-120: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make phone-number validation unconditional. user.phoneNumber && !result.success only rejects bad input once a phone number already exists, so users with a phone number can’t clear it, and invalid input for users without one is ignored instead of returning 400. Allow an explicit empty value to clear the field and fail fast on any invalid format.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/user/usersettings.ts` around lines 115 - 120, Update the
phone-number validation in the user settings handler so any unsuccessful
phoneNumberSchema.safeParse result returns ApiError 400 InvalidPhoneNumber,
regardless of the existing user.phoneNumber value. Preserve explicit empty-value
support so a valid empty input clears the field, then assign the parsed value to
user.phoneNumber.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@server/routes/user/usersettings.ts`:
- Around line 115-120: Update the phone-number validation in the user settings
handler so any unsuccessful phoneNumberSchema.safeParse result returns ApiError
400 InvalidPhoneNumber, regardless of the existing user.phoneNumber value.
Preserve explicit empty-value support so a valid empty input clears the field,
then assign the parsed value to user.phoneNumber.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 86a17f57-fbf1-4ad0-a044-322a8ddd728a

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac5f64 and 974161f.

📒 Files selected for processing (2)
  • server/entity/User.ts
  • server/routes/user/usersettings.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/entity/User.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
server/routes/user/usersettings.ts (2)

30-30: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider requiring the + prefix and verify frontend regex parity.

The regex /^\+?[0-9]{1,15}$/ makes the + optional. For international SMS/WhatsApp delivery (the stated use case per PR objectives), E.164 numbers typically require the + prefix. The screenshot shows "123456453" stored without +, which may cause delivery failures depending on the downstream service.

Additionally, the frontend defines its own PHONE_REGEX in src/utils/numberHelpers.ts (per the stack context). If the two regexes diverge, a number that passes frontend validation could be rejected by the backend (or vice versa), causing a confusing UX. Verify they match.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/user/usersettings.ts` at line 30, Update phoneNumberSchema to
require the international “+” prefix for E.164-style numbers, and verify that
the frontend PHONE_REGEX in numberHelpers.ts uses the same validation rule. Keep
frontend and backend acceptance criteria identical so valid numbers are handled
consistently.

115-121: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Refactor for cleaner type narrowing on safeParse result.

result.data is accessed on line 120 without first narrowing on result.success. The throw condition req.body.phoneNumber && !result.success doesn't give TypeScript enough information to narrow the discriminated union, so result.data may be undefined on the failure branch. The ?? '' fallback handles this at runtime, but the pattern is fragile and non-idiomatic.

Restructuring so result.data is only accessed after a successful parse makes the type narrowing explicit and eliminates the reliance on ??:

♻️ Proposed refactor
-    const result = phoneNumberSchema.safeParse(req.body.phoneNumber);
-    if (req.body.phoneNumber && !result.success) {
-      throw new ApiError(400, ApiErrorCode.InvalidPhoneNumber);
-    }
-
-    user.phoneNumber = result.data ?? '';
+    if (req.body.phoneNumber) {
+      const result = phoneNumberSchema.safeParse(req.body.phoneNumber);
+      if (!result.success) {
+        throw new ApiError(400, ApiErrorCode.InvalidPhoneNumber);
+      }
+      user.phoneNumber = result.data;
+    } else {
+      user.phoneNumber = '';
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/user/usersettings.ts` around lines 115 - 121, Refactor the
phone number parsing flow around phoneNumberSchema.safeParse so result.data is
accessed only within an explicit result.success branch. Preserve the existing
InvalidPhoneNumber ApiError for provided invalid values, and assign
user.phoneNumber to the successfully parsed value or an empty string when no
phone number is provided, without relying on result.data ?? ''.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@server/routes/user/usersettings.ts`:
- Line 30: Update phoneNumberSchema to require the international “+” prefix for
E.164-style numbers, and verify that the frontend PHONE_REGEX in
numberHelpers.ts uses the same validation rule. Keep frontend and backend
acceptance criteria identical so valid numbers are handled consistently.
- Around line 115-121: Refactor the phone number parsing flow around
phoneNumberSchema.safeParse so result.data is accessed only within an explicit
result.success branch. Preserve the existing InvalidPhoneNumber ApiError for
provided invalid values, and assign user.phoneNumber to the successfully parsed
value or an empty string when no phone number is provided, without relying on
result.data ?? ''.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e771c7c-25bf-4a08-bd7b-fa42df7814d3

📥 Commits

Reviewing files that changed from the base of the PR and between 974161f and 3a19174.

📒 Files selected for processing (1)
  • server/routes/user/usersettings.ts

@modarah modarah force-pushed the feature/add-phone-number-to-users branch from 3a19174 to 5bace0c Compare July 11, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New attribute on users for saving phone number

1 participant