Skip to content

feat(auth/talent): add linkedin_url + is_job_ready to /me; snake_case onboarding profile DTOs#159

Merged
oduwoleeyinojuoluwa44 merged 10 commits into
devfrom
feat/me-linkedin-job-ready-snake-case
May 28, 2026
Merged

feat(auth/talent): add linkedin_url + is_job_ready to /me; snake_case onboarding profile DTOs#159
oduwoleeyinojuoluwa44 merged 10 commits into
devfrom
feat/me-linkedin-job-ready-snake-case

Conversation

@oduwoleeyinojuoluwa44
Copy link
Copy Markdown
Collaborator

@oduwoleeyinojuoluwa44 oduwoleeyinojuoluwa44 commented May 28, 2026

Summary

Two related API consistency fixes requested by the frontend team.


1. GET /auth/me — new fields

linkedin_url and is_job_ready are now included for talent users:

{
  "id": "435b72ff-...",
  "email": "testtalent5@mailsac.com",
  "first_name": "Test",
  "last_name": "Talent",
  "fullname": "Test Talent",
  "avatar_url": null,
  "country": "Unknown",
  "role": "talent",
  "is_verified": true,
  "onboarding_complete": true,
  "track": "frontend_developer",
  "linkedin_url": "https://www.linkedin.com/in/alexsmith",
  "is_job_ready": true
}
  • linkedin_url — sourced from talent_profiles.linkedin_url; null when not set
  • is_job_readytrue when talent_profiles.status === 'job_ready', false otherwise
  • Non-talent roles receive both fields as null / false

2. PATCH /talent/onboarding/profile + POST /talent/profile — snake_case body

Before After
educationLevel education_level
linkedinUrl linkedin_url
avatarUrl avatar_url
linkedinProfile (POST /talent/profile) linkedin_url

Tests

  • 5 new unit tests for getProfile() covering all TalentProfileStatus values, null profile, and null linkedin url
  • 358/358 suite tests passing

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added secure password change functionality for authenticated users to update their account credentials
    • Enhanced user profiles now include LinkedIn URL and job-ready status indicators
  • Chores

    • Standardized API field naming conventions to snake_case format for consistency across profile-related endpoints

Review Change Stack

Copilot AI review requested due to automatic review settings May 28, 2026 10:41
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Warning

Review limit reached

@oduwoleeyinojuoluwa44, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 minutes and 26 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 170f7067-b49f-429d-b9e3-ab32eae05b38

📥 Commits

Reviewing files that changed from the base of the PR and between a486127 and 13272fc.

📒 Files selected for processing (3)
  • src/modules/auth/auth.service.ts
  • src/modules/talent/dto/set-profile.dto.ts
  • src/modules/talent/talent.service.ts
📝 Walkthrough

Walkthrough

This PR adds a new authenticated password-change endpoint with full validation and error handling, and extends the auth response to include talent profile fields (linkedin_url, is_job_ready) while standardizing talent DTO field names to snake_case across the codebase.

Changes

Change Password Feature

Layer / File(s) Summary
Change Password DTO and Messages
src/modules/auth/dto/change-password.dto.ts, src/shared/messages/error.messages.ts, src/shared/messages/success.messages.ts
ChangePasswordDto defines three password fields with Swagger and validator annotations. Error messages for wrong/same password and OAuth accounts, plus a success message for password-changed notification.
AuthService changePassword Implementation
src/modules/auth/auth.service.ts
changePassword method validates current password via Argon2, rejects password reuse, hashes the new password, and persists via usersService.updatePassword.
AuthService changePassword Tests
src/modules/auth/auth.service.change-password.spec.ts
Test suite covering success path, wrong current password rejection, same-password rejection, OAuth account rejection, and session revocation.
AuthController changePassword Endpoint and Tests
src/modules/auth/auth.controller.ts, src/modules/auth/auth.controller.change-password.spec.ts
Authenticated POST /change-password endpoint delegates to service, clears cookies on success; controller tests verify delegation, passthrough, and conditional cookie clearing.

Talent Profile Integration and DTO Migration

Layer / File(s) Summary
AuthUser Extension and getProfile Talent Mapping
src/modules/auth/auth.service.ts
AuthUser interface adds optional linkedin_url and is_job_ready fields. getProfile fetches talent profile linkedin_url and status, mapping to is_job_ready based on JOB_READY status.
AuthService getProfile Tests
src/modules/auth/auth.service.get-profile.spec.ts
Test suite verifying linkedin_url presence/nullability, is_job_ready mapping for JOB_READY status and other statuses, and fallback when talent profile is missing.
Talent DTO Field Renames to snake_case
src/modules/talent/dto/save-talent-profile.dto.ts, src/modules/talent/dto/set-profile.dto.ts
SaveTalentProfileDto and SetProfileDto rename fields from camelCase to snake_case (educationLeveleducation_level, linkedinUrl / linkedinProfilelinkedin_url, avatarUrlavatar_url) with validator messages updated.
TalentService Persistence Updates
src/modules/talent/talent.service.ts
saveTalentProfile and saveProfile methods updated to map and persist snake_case DTO fields into entity properties and recompute profile_verified using new field names.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: adding linkedin_url and is_job_ready to the /me endpoint, and converting onboarding profile DTOs to snake_case naming convention.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/me-linkedin-job-ready-snake-case

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 and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds frontend-requested API consistency updates by (1) extending /auth/me with talent profile-derived LinkedIn + job readiness fields, and (2) switching talent onboarding/profile DTO request bodies to snake_case; additionally introduces an authenticated password change endpoint.

Changes:

  • GET /auth/me: include linkedin_url (from talent_profiles.linkedin_url) and is_job_ready (derived from talent_profiles.status === 'job_ready').
  • PATCH /talent/onboarding/profile and POST /talent/profile: accept snake_case fields (education_level, linkedin_url, avatar_url).
  • Add POST /auth/change-password with throttling, validation, server-side refresh-token revocation (via updatePassword), and cookie clearing.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/shared/messages/success.messages.ts Adds PASSWORD_CHANGED success message used by change-password flow.
src/shared/messages/error.messages.ts Adds change-password specific error messages.
src/modules/talent/talent.service.ts Updates onboarding/profile persistence to read snake_case DTO fields.
src/modules/talent/dto/set-profile.dto.ts Renames onboarding profile DTO fields + validation messages to snake_case.
src/modules/talent/dto/save-talent-profile.dto.ts Renames talent profile DTO fields + validation messages to snake_case.
src/modules/auth/dto/change-password.dto.ts Introduces DTO + validation for change-password request body.
src/modules/auth/auth.service.ts Implements changePassword() and extends getProfile() to return new /me fields.
src/modules/auth/auth.service.get-profile.spec.ts Adds unit tests for /me linkedin/job-ready derivation (talent scenarios).
src/modules/auth/auth.service.change-password.spec.ts Adds unit tests for changePassword() success and failure modes.
src/modules/auth/auth.controller.ts Adds POST /auth/change-password endpoint (auth + throttled) and clears cookies on success.
src/modules/auth/auth.controller.change-password.spec.ts Adds controller-level unit tests for change-password delegation and cookie clearing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/modules/auth/auth.service.ts Outdated
Comment on lines +59 to +62
/** LinkedIn URL — only present for talent users; null when not set. */
linkedin_url?: string | null;
/** True when the talent has reached Job Ready status. */
is_job_ready?: boolean;
Comment on lines 488 to 503
async getProfile(userId: string): Promise<AuthUser> {
const user = await this.usersService.findOne(userId);
const profile =
user.role === UserRole.TALENT
? await this.talentProfileRepository.findOne({
where: { user_id: userId },
select: { track: true },
select: { track: true, linkedin_url: true, status: true },
})
: null;

return {
...this.toAuthUser(user),
track: profile?.track ?? null,
linkedin_url: profile?.linkedin_url ?? null,
is_job_ready: profile?.status === TalentProfileStatus.JOB_READY,
};
Comment on lines +10 to +18
/**
* Controller-level tests for POST /auth/change-password.
*
* Focus:
* - Delegates to authService.changePassword with the correct userId and DTO
* - Calls clearAuthCookies so the browser loses its auth cookies after the change
* - Surfaces the service result directly to the caller
* - ThrottlerGuard is applied (cannot brute-force currentPassword)
*/
…eady-snake-case

# Conflicts:
#	src/modules/auth/auth.controller.change-password.spec.ts
#	src/modules/auth/auth.service.change-password.spec.ts
#	src/modules/auth/auth.service.ts
#	src/modules/auth/dto/change-password.dto.ts
#	src/modules/talent/dto/set-profile.dto.ts
#	src/modules/talent/talent.service.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
src/modules/talent/talent.service.ts (1)

188-214: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider updating logged field names to snake_case for consistency.

The personalise() method still logs 'educationLevel' (camelCase) in availableDataPoints and incompleteFields while the entity and DTO now use education_level. This creates inconsistency in logged/analytics data if downstream systems expect consistent naming.

♻️ Suggested fix for consistent logging
     const availableDataPoints: string[] = ['track'];
     if (profile.goal) availableDataPoints.push('goal');
     if (profile.region) availableDataPoints.push('region');
-    if (profile.education_level) availableDataPoints.push('educationLevel');
+    if (profile.education_level) availableDataPoints.push('education_level');

     const isFullyPersonalised =
       !!profile.goal && !!profile.region && !!profile.education_level;

     try {
       this.logger.log(
         JSON.stringify({
           event: 'talent_personalisation',
           userId,
           timestamp: new Date().toISOString(),
           availableDataPoints,
           assessmentsGenerated: true,
           recommendationsGenerated: isFullyPersonalised,
           incompleteFields: isFullyPersonalised
             ? []
-            : ['goal', 'region', 'educationLevel'].filter(
-                (f) =>
-                  !profile[
-                    f === 'educationLevel'
-                      ? 'education_level'
-                      : (f as keyof TalentProfile)
-                  ],
+            : ['goal', 'region', 'education_level'].filter(
+                (f) => !profile[f as keyof TalentProfile],
               ),
         }),
       );
🤖 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/modules/talent/talent.service.ts` around lines 188 - 214, In
personalise(), ensure logged field names use snake_case to match the entity/DTO:
update availableDataPoints to push 'education_level' instead of
'educationLevel', and when building incompleteFields change the array
['goal','region','educationLevel'] to ['goal','region','education_level'] and
adjust the filtering logic that checks profile[...] to reference
profile['education_level'] (or keep the existing conditional mapping but return
'education_level') so both availableDataPoints and incompleteFields consistently
use 'education_level'; keep the rest of the logging structure unchanged.
🤖 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 `@src/modules/talent/talent.service.ts`:
- Around line 188-214: In personalise(), ensure logged field names use
snake_case to match the entity/DTO: update availableDataPoints to push
'education_level' instead of 'educationLevel', and when building
incompleteFields change the array ['goal','region','educationLevel'] to
['goal','region','education_level'] and adjust the filtering logic that checks
profile[...] to reference profile['education_level'] (or keep the existing
conditional mapping but return 'education_level') so both availableDataPoints
and incompleteFields consistently use 'education_level'; keep the rest of the
logging structure unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9d55f65a-436e-45ea-bdac-bce057c645d1

📥 Commits

Reviewing files that changed from the base of the PR and between 56445b1 and a486127.

📒 Files selected for processing (11)
  • src/modules/auth/auth.controller.change-password.spec.ts
  • src/modules/auth/auth.controller.ts
  • src/modules/auth/auth.service.change-password.spec.ts
  • src/modules/auth/auth.service.get-profile.spec.ts
  • src/modules/auth/auth.service.ts
  • src/modules/auth/dto/change-password.dto.ts
  • src/modules/talent/dto/save-talent-profile.dto.ts
  • src/modules/talent/dto/set-profile.dto.ts
  • src/modules/talent/talent.service.ts
  • src/shared/messages/error.messages.ts
  • src/shared/messages/success.messages.ts

@oduwoleeyinojuoluwa44 oduwoleeyinojuoluwa44 merged commit d1773c7 into dev May 28, 2026
6 checks passed
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.

2 participants