Skip to content

Conversation

@mauriciozanettisalomao
Copy link
Contributor

@mauriciozanettisalomao mauriciozanettisalomao commented Oct 24, 2025

Overview

Jira ticket https://linuxfoundation.atlassian.net/browse/LFXV2-502

Implements email linking functionality that integrates with the Auth0 authentication service, allowing users to verify and link alternate email addresses to their accounts through a secure OTP verification flow.

Notes:

For now, to focus on removing non-auth-service integrations from the profile, we’ve disabled the delete email action until we implement it. The set primary email action is also on hold, as we need to check if it’s supported on the Auth0 side.

Changes

  • Backend Email Service: Added verifyAndLinkEmail(), linkIdentity(), and related methods to handle the complete email verification and linking workflow
  • Profile Controller: Implemented new endpoints for sending email verification codes and verifying/linking emails:
    • POST /api/profile/emails/send-verification - Sends OTP verification code
    • POST /api/profile/emails/verify - Verifies OTP and links email to account
  • NATS Integration: Added new NATS subjects for auth-service communication:
    • EMAIL_LINKING_SEND_VERIFICATION - Request verification code
    • EMAIL_LINKING_VERIFY - Verify OTP code
    • USER_IDENTITY_LINK - Link identity to user account
  • Frontend Components: Created email verification modal component for user-facing OTP verification flow
  • Authentication: Extended Auth0 scope to include update:current_user_metadata for identity linking operations

Technical Details

The implementation follows a three-step process:

  1. Send verification code to alternate email
  2. Verify OTP code and obtain id_token
  3. Link the verified identity to the primary user account

Screenshots:

Modal to provide the OTP

image

Incorrect code behavior

Screenshot 2025-10-24 at 13 46 39

Expired code behavior

image

Successful verification behavior

image image

Copilot AI review requested due to automatic review settings October 24, 2025 16:58
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Conventional Commits FTW!

@coderabbitai
Copy link

coderabbitai bot commented Oct 24, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a complete email verification feature: frontend modal and profile UI updates, new client methods, server endpoints and EmailService using NATS request/reply, plus shared NATS subject enum additions and new user-email types.

Changes

Cohort / File(s) Summary
Email Verification Modal
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html, apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
New standalone Angular modal implementing a 6‑digit OTP UI with a 5‑minute countdown, per‑digit inputs (keyboard/paste handling), submit/resend flows, expired/error states, and client UserService integration for verify/resend.
Profile Email Frontend
apps/lfx-one/src/app/modules/profile/email/profile-email.component.html, apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
Modified add‑email flow to call send verification and open the modal; added emailFieldError signal, DialogService usage/provider and dialog lifecycle handling, inline error placement, simplified labels/tooltips, and temporary stubs for delete/set‑primary actions.
Client User Service
apps/lfx-one/src/app/shared/services/user.service.ts
Added sendEmailVerification(email) and verifyAndLinkEmail(email, otp) methods that POST to new backend endpoints and return typed observables.
Server Controller & Routes
apps/lfx-one/src/server/controllers/profile.controller.ts, apps/lfx-one/src/server/routes/profile.route.ts
Added controller methods sendEmailVerification and verifyAndLinkEmail and POST routes /api/profile/emails/send-verification and /api/profile/emails/verify; rewrote getUserEmails to fetch and map NATS-backed user emails.
Backend Email Service
apps/lfx-one/src/server/services/email.service.ts
New EmailService orchestrating NATS flows: send verification, verify OTP, link identity, and combined verifyAndLinkEmail; includes payload/response decoding, validation, error mapping, and logging.
Backend User Service
apps/lfx-one/src/server/services/user.service.ts
Added getUserEmails(req, userArg) to request and decode user emails via NATS (USER_EMAILS_READ) with timeout/availability handling and logging.
Shared NATS Subjects & Types
packages/shared/src/enums/nats.enum.ts, packages/shared/src/interfaces/user-profile.interface.ts
Removed USERNAME_TO_USER_INFO; added USER_EMAILS_READ, EMAIL_LINKING_SEND_VERIFICATION, EMAIL_LINKING_VERIFY, USER_IDENTITY_LINK; added AlternateEmail, UserEmailsData, UserEmailsResponse interfaces.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as Client UI / Modal
    participant API as Backend API
    participant NATS as NATS Service

    User->>UI: Request verification for email
    UI->>API: POST /api/profile/emails/send-verification { email }
    API->>NATS: EMAIL_LINKING_SEND_VERIFICATION
    NATS-->>API: ack / success
    API-->>UI: { success: true }
    UI-->>User: Open verification modal (timer starts)

    User->>UI: Submit 6‑digit code
    UI->>API: POST /api/profile/emails/verify { email, otp }
    API->>NATS: EMAIL_LINKING_VERIFY
    NATS-->>API: { otp verified, id_token }
    API->>NATS: USER_IDENTITY_LINK (with id_token)
    NATS-->>API: identity linked
    API-->>UI: { success: true }
    UI-->>User: Modal closes — email linked
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay extra attention to:
    • Modal component: timer lifecycle, OTP input/paste handling, signal cleanup on destroy.
    • EmailService: multi‑step NATS interactions, error mapping, handling id_token for identity linking.
    • Controller/routes and UserService: request/response shapes, validation, and consistency with new shared interfaces.

Possibly related PRs

Suggested labels

deploy-preview

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The PR description indicates Auth0 integration with custom OTP flow, but the linked issue LFXV2-502 specifically requires an Authelia mock implementation using KV storage. The implementation appears to target Auth0 rather than the mock Authelia system specified in the linked issue. Clarify whether this PR addresses the Auth0 implementation (separate from LFXV2-502) or if the Authelia mock implementation with KV storage is included. Ensure alignment with the linked issue requirements.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing email linking functionality integrated with the auth service, specifically referencing the Jira ticket LFXV2-502.
Description check ✅ Passed The description provides comprehensive context about the email linking functionality, including backend changes, endpoints, NATS integration, frontend components, and technical implementation details directly related to the changeset.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the email linking verification flow: new components for OTP entry, service methods for verification, NATS integration, and profile management updates. No extraneous changes detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/lfxv2-502-email-linking-from-auth-service

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 12134c9 and a8917d8.

📒 Files selected for processing (1)
  • apps/lfx-one/src/server/services/user.service.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/lfx-one/src/server/services/user.service.ts

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

Copy link
Contributor

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

This PR implements email linking functionality that integrates with Auth0 authentication, enabling users to verify and link alternate email addresses through a secure OTP verification workflow.

Key Changes:

  • Added backend email verification service with NATS integration for Auth0 communication
  • Created new API endpoints for sending verification codes and verifying/linking emails
  • Implemented frontend verification modal component with 6-digit OTP input and timer functionality

Reviewed Changes

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

Show a summary per file
File Description
packages/shared/src/interfaces/user-profile.interface.ts Added TypeScript interfaces for alternate emails and user email data structures
packages/shared/src/enums/nats.enum.ts Defined new NATS subjects for email linking and identity management operations
apps/lfx-one/src/server/services/email.service.ts Implemented core email verification service with OTP handling and identity linking
apps/lfx-one/src/server/services/user.service.ts Added getUserEmails method to fetch user email data via NATS
apps/lfx-one/src/server/routes/profile.route.ts Registered new email verification and linking API endpoints
apps/lfx-one/src/server/controllers/profile.controller.ts Implemented controller methods for email verification flow and updated getUserEmails to use NATS
apps/lfx-one/src/app/shared/services/user.service.ts Added frontend service methods for email verification API calls
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts Updated email management component to trigger verification modal and handle responses
apps/lfx-one/src/app/modules/profile/email/profile-email.component.html Modified UI to display email field errors and simplified email management text
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts Created modal component with OTP input handling, timer, and paste functionality
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html Implemented modal UI with 6-digit code input, countdown timer, and error messaging

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

@mauriciozanettisalomao mauriciozanettisalomao force-pushed the feature/lfxv2-502-email-linking-from-auth-service branch 5 times, most recently from 2b2abcc to 86b1dee Compare October 24, 2025 17:13
@mauriciozanettisalomao mauriciozanettisalomao changed the title [LFXV2-502] email linking from auth service feat(auth-service): email linking from auth service [LFXV2-502] Oct 24, 2025
@mauriciozanettisalomao mauriciozanettisalomao force-pushed the feature/lfxv2-502-email-linking-from-auth-service branch from 86b1dee to d89b6e4 Compare October 24, 2025 17:16
jordane and others added 11 commits October 24, 2025 14:17
…d users

- Add auto-join functionality that opens Zoom meetings automatically for signed-in users
- Implement timeout-based execution to prevent infinite loops and toast spam
- Add proper state management with hasAutoJoined signal to prevent multiple attempts
- Include fallback manual join option if auto-join fails
- Add component cleanup with ngOnDestroy to prevent memory leaks
- Update UI to show auto-join status with success message and manual fallback
- Respect existing timing constraints (early join time window)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
- Replace any timeout type with proper ReturnType<typeof setTimeout>
- Extract ternary logic from template into computed signals for better maintainability
- Add data-testid attributes for reliable e2e testing (join-status-message, join-meeting-button-*)
- Implement secure popup handling with opener clearing and popup blocker detection
- Add fallback messaging for blocked popups with auto-join flag reset
- Apply code formatting and resolve linting issues

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
… opening

- Remove isJoining() dependency from auto-join effect to prevent re-triggering
- Eliminate hasAutoJoined flag resets that caused infinite loops
- Remove popup blocker detection and toast notifications
- Ensure all join buttons use click handler for consistent new tab behavior
- Simplify openMeetingSecurely method for reliable URL opening

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
Update the meeting join page login button to use LFX brand blue colors
instead of gray for better visibility and prominence when users are not
authenticated. Changes include:
- Apply bg-brand-500 (primary LFX blue) background
- Add hover:bg-brand-600 for darker blue on hover
- Use white text for high contrast
- Increase padding from px-2 py-1 to px-3 py-2
- Add font-medium weight and shadow-sm for visual emphasis

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…ion (#119)

* wip(dashboard): initial core persona developer dashboard implementation

Work in progress implementation for LFXV2-644. Adding foundational
components and structure for the Core Developer Persona dashboard.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>

* feat(dashboard): improve core developer persona dashboard UI

Reduce section header sizes from text-xl to text-lg for better visual hierarchy.
Enhance meetings section with modern card design, calendar icons, participant
badges, and Join buttons. Fix ESLint member ordering issues for LFXV2-644.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>

* fix(layout): prevent sidebar from floating during horizontal scroll

Change sidebar from fixed to sticky positioning within a flex container.
This ensures the sidebar stays in its designated column and doesn't cover
content during horizontal scrolling. Updates for LFXV2-644.

- Wrap sidebar in flex-shrink-0 container with fixed width
- Change sidebar positioning from fixed to sticky
- Remove margin-left from main content, use min-w-0 for proper scrolling
- Maintain sticky behavior for vertical scrolling within column

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>

* style(dashboard): further reduce section header sizes

Change section headers from text-lg to text-base for a more compact
and modern dashboard appearance. Reduces visual hierarchy emphasis
on section titles in favor of content focus for LFXV2-644.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>

* feat(dashboard): integrate meetings API with occurrence-based filtering

Replace hardcoded meeting data with live API integration that properly handles:
- Meeting occurrences for recurring meetings
- Time-based filtering with 40-minute buffer after meeting end
- Sorting by earliest time first
- Frontend limit to 5 meetings maximum
- Smart time formatting (Today/Tomorrow/Date)
- Total attendee count from registrants and committee members

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(dashboard): implement persona-based dashboard architecture

- Replace home-new component with modular dashboard architecture
- Add persona-specific dashboard components (my-meetings, my-projects, pending-actions, recent-progress)
- Implement persona service with reactive persona selection
- Update sidebar with footer navigation support and improved styling
- Match sidebar border/shadow styling with PrimeNG card components
- Add persona selector component with dropdown interface
- Update header to integrate persona selector
- Add persona constants to shared package
- Update main layout to support dynamic persona-based routing
- Update profile layout to handle persona changes
- Server-side: Fix user profile persona field mapping

Technical improvements:
- Sidebar: Remove border, update border-radius to 12px, match card shadow
- Sidebar: Add footer items support with separate navigation section
- Sidebar: Improve accessibility with consistent text sizing (text-sm)
- Remove icon hover animations for visual consistency

LFXV2-644

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* refactor(sidebar): replace function calls with computed signals

- Remove getTestId() function calls from template
- Add testId property to SidebarMenuItem interface
- Create computed signals (itemsWithTestIds, footerItemsWithTestIds) for test ID generation
- Use Angular signals pattern for better performance and change detection

Performance improvements:
- Computed signals only recalculate when input changes
- Eliminates repeated function calls during template rendering
- Leverages Angular 19 zoneless change detection optimization

LFXV2-644

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* fix(dashboard): resolve pr comments

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* fix(yarn): yarn.lock update

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* feat(dashboard): implement dashboard meeting card component

- Create reusable DashboardMeetingCardComponent for displaying meeting information
- Update MyMeetingsComponent to use new card component with Today/Upcoming sections
- Add conditional section rendering (hide sections when empty)
- Match React component styling with white card background, gray icons, rounded-xl borders
- Implement smart date filtering for today's meetings vs upcoming meetings
- Add meeting feature icons (YouTube, Recording, Transcripts, AI, Public/Private)
- Add DashboardMeetingCardProps and DashboardMeetingFeatures interfaces to shared package
- Update RecentProgressComponent styling to match React design
- Remove PrimeNG Card dependency in favor of semantic HTML with Tailwind

LFXV2-644

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* refactor(dashboard): update pending actions and meeting card layout

- Remove LFX card wrapper from pending actions component
- Add consistent header with "View All" button to pending actions
- Simplify pending action button styling to white background with slate-100 hover
- Update dashboard meeting card to use project_name from meeting data
- Add project_name enrichment in meeting service
- Remove projectName input from dashboard meeting card component
- Add project_name field to Meeting interface

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* refactor(dashboard): update my-projects with table layout

- Replace card-based layout with lfx-table component
- Implement 4-column table structure (Project, Affiliations, Code Activities, Non-Code Activities)
- Apply React-style formatting:
  - Equal column widths (w-1/4 for each column)
  - Fixed chart container width (12.5rem)
  - Grey borders (border-gray-200) on table cells
  - Rounded table container with overflow handling
  - Blue project name links (#009aff)
  - Help icons for activity columns
- Update chart colors:
  - Code Activities: #009AFF (blue)
  - Non-Code Activities: #10b981 (green)
- Add generateLabels() helper method for dynamic chart labels
- Remove unused CardComponent import
- Maintain all existing test IDs for E2E compatibility

Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Asitha de Silva <asithade@gmail.com>

* ci(gha): disable automatic quality check workflow

Disabled automatic PR quality checks as project is moving away from old UI.
Changed trigger from pull_request to workflow_dispatch for manual runs only.

LFXV2-644

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>

---------

Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>
Signed-off-by: Asitha de Silva <asithade@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…126)

* fix(meeting-join): refactor auto-join logic to prevent infinite loop

- Remove OnDestroy lifecycle and timeout cleanup
- Simplify auto-join using RxJS filter and take(1) operators
- Create fetchedJoinUrl signal for preemptive URL fetching
- Convert join buttons to use href instead of click handlers
- Add security attributes to button component links
- Fix project logo centering and sizing

LFXV2-669

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* fix(ui): pass in link target and rel for buttons

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* fix(ui): pass in link target and rel for buttons

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* fix(meeting-join): add loading and error handling for join URL

LFXV2-669

- Add loading spinner while fetching join URL
- Display error messages when join URL fetch fails
- Separate authenticated and unauthenticated user flows
- Add debouncing (300ms) to form status changes to prevent rapid re-fetches
- Improve user feedback with loading states in both authenticated and form sections
- Reset error state on each fetch attempt

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* refactor(meeting-join): simplify bindings and eliminate duplication

Simplified button href and disabled bindings by removing redundant canJoinMeeting() checks since fetchedJoinUrl() already returns undefined when the meeting cannot be joined.

Refactored initializeFetchedJoinUrl() to eliminate code duplication:
- Extracted common join URL fetching logic into fetchJoinUrl() method
- Removed duplicate API call handling for authenticated/unauthenticated flows
- Removed signal mutation anti-pattern (meeting.join_url assignment)
- Improved maintainability with single source of truth for fetch logic

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>

---------

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…#127)

- Add Maintainer as new persona option
- Migrate dashboard to new dashboards module structure
- Rename existing dashboard to Core Developer dashboard
- Create Maintainer dashboard with persona-specific metrics
- Implement persona-aware pending actions with computed signals
- Implement persona-aware progress metrics with line and bar charts
- Move shared dashboard components to centralized location
- Update routing to use new dashboard component structure

LFXV2-649

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…l and API integration

- Add EmailVerificationModalComponent for user to input verification code
- Implement sendEmailVerification and verifyAndLinkEmail methods in UserService
- Update ProfileEmailComponent to handle email verification process
- Remove old resend verification button and logic
- Integrate NATS communication for sending verification codes and verifying OTP
- Enhance server-side profile controller to manage email verification requests

Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-501

Generated with [Cursor](https://cursor.com/)

Signed-off-by: Mauricio Zanetti Salomao <mauriciozanetti86@gmail.com>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
#128)

Multiple enhancements across the application:

- LFXV2-670: Relocate footer to main layout for consistency
- LFXV2-671: Replace "old-ui" with "home" persona and simplify routing
- LFXV2-672: Add scrollable containers and refactor dashboard charts
- LFXV2-673: Add meeting attachments display with file type icons
- LFXV2-674: Enhance meeting join with password support and new tab
- LFXV2-675: Improve error handling and null safety across services

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
* feat(backend): add snowflake data warehouse integration (LFXV2-671)

- Add SnowflakeService with connection pooling, query execution, and caching
- Implement LockManager for distributed operations and resource coordination
- Add Snowflake-related interfaces, enums, and constants to shared package
- Add comprehensive architecture documentation for Snowflake integration
- Configure environment variables for Snowflake connection
- Add @snowflake-sdk/client dependency

This integration enables server-side data warehouse queries with proper
connection management, query optimization, and distributed locking.

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* feat(analytics): implement snowflake integration with error handling

- Add AnalyticsController with three endpoints:
  * GET /api/analytics/active-weeks-streak (52 weeks of activity data)
  * GET /api/analytics/pull-requests-merged (last 30 days)
  * GET /api/analytics/code-commits (last 30 days)

- Implement proper error handling:
  * AuthenticationError (401) for missing user email
  * ResourceNotFoundError (404) for no analytics data
  * Consistent error propagation via next(error)

- Use SQL window functions for accurate aggregations:
  * SUM(DAILY_COUNT) OVER () for totals across filtered results
  * DATEADD(DAY, -30, CURRENT_DATE()) for 30-day filtering

- Add analytics data interfaces to shared package:
  * ActiveWeeksStreakRow/Response
  * UserPullRequestsRow/Response
  * UserCodeCommitsRow/Response

- Update frontend dashboard with Chart.js visualizations:
  * Interactive tooltips with formatted dates and counts
  * Real-time data from Snowflake via analytics service

- Update Snowflake integration documentation:
  * Focus on service architecture and best practices
  * Add examples for parameterized queries and lazy initialization
  * Document error handling patterns for callers

- Update .env.example with analytics endpoint usage comments

LFXV2-671

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Asitha de Silva <asithade@gmail.com>

* feat(auth): add authelia support and refactor profile to use nats

- Add Authelia OIDC claims middleware for Auth0 compatibility
  - Transform standard OIDC claims to Auth0 format
  - Only activates for non-Auth0 users (issuer check)
  - Maps preferred_username, splits name into given/family
  - Modifies user object in-place (not replaceable)

- Refactor profile controller to use NATS exclusively
  - Remove Supabase dependency for user profile data
  - Construct UserProfile from OIDC token claims
  - Use NATS as sole authoritative source for metadata
  - Email management methods still use Supabase

- Change user metadata field from 'title' to 'job_title'
  - Update UserMetadata interface
  - Update frontend components (profile edit, layout, header)
  - Update backend validation logic
  - Ensure consistent field naming across all layers

- Clean up debug logging
  - Remove console.log statement from server.ts
  - Simplify authelia userinfo fetch logic

- Minor improvements
  - Remove unused 'open' dependency from angular.json
  - Fix header component formatting
  - Optimize auth-helper to use OIDC data directly

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* build: configure snowflake sdk logging and add to gitignore

- Set Snowflake SDK log level to ERROR by default
- Add SNOWFLAKE_LOG_LEVEL environment variable support
- Prevent snowflake.log from being committed to repository

Signed-off-by: Asitha de Silva <asithade@gmail.com>

* fix(server): remove middleware

Signed-off-by: Asitha de Silva <asithade@gmail.com>

---------

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
- Update ProfileEmailComponent to manage email input errors and provide user feedback for already linked emails.
- Modify email verification modal to display error messages for invalid verification codes and handle pasting of digits.
- Integrate NATS for fetching user emails and transform response for frontend compatibility.
- Temporarily disable email deletion and primary email management features, with informative messages for users.

Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502

Generated with [Cursor](https://cursor.com/)

Signed-off-by: Mauricio Zanetti Salomao <mauriciozanetti86@gmail.com>
Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
@mauriciozanettisalomao mauriciozanettisalomao force-pushed the feature/lfxv2-502-email-linking-from-auth-service branch from d89b6e4 to 7afef47 Compare October 24, 2025 17:17
…cation methods

- Refactor sendEmailVerification and verifyAndLinkEmail methods for better readability and consistency.
- Enhance error handling for invalid email and OTP inputs with detailed logging.
- Update documentation comments to clarify the email verification and linking flow steps.

Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-252

Generated with [Cursor](https://cursor.com/)

Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
@mauriciozanettisalomao mauriciozanettisalomao force-pushed the feature/lfxv2-502-email-linking-from-auth-service branch from c7a5197 to b74a40d Compare October 30, 2025 16:39
… and input events

- Clear previous error messages when submitting the verification code, typing, or pasting input.
- Improve user experience by ensuring error messages are reset appropriately during interactions.

Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502

Generated with [Cursor](https://cursor.com/)

Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
@mauriciozanettisalomao mauriciozanettisalomao force-pushed the feature/lfxv2-502-email-linking-from-auth-service branch from b74a40d to eb05bab Compare October 30, 2025 16:42
Copy link

@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: 3

🧹 Nitpick comments (5)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html (1)

51-102: Bring data-testid names in line with our convention

The new modal test ids (digit-*-input, resend-link, resend-code-button, etc.) don’t follow the required [section]-[component]-[element] format. Please rename them accordingly (e.g., profile-emailVerificationModal-digit-1-input, profile-emailVerificationModal-resend-link, profile-emailVerificationModal-resend-code-button), and update all new ids in this template so automated tests remain consistent. As per coding guidelines.

Also applies to: 128-149

apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)

69-71: Guard the valueChanges subscription lifecycle

valueChanges.subscribe in the constructor never tears down, so the component holds a live subscription for its entire lifetime. Pipe it through takeUntilDestroyed() (from @angular/core/rxjs-interop) so Angular disposes it when the component is destroyed.

-import { toSignal } from '@angular/core/rxjs-interop';
+import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
@@
-    this.addEmailForm.get('email')?.valueChanges.subscribe(() => {
+    this.addEmailForm
+      .get('email')
+      ?.valueChanges.pipe(takeUntilDestroyed())
+      .subscribe(() => {
       this.emailFieldError.set(null);
     });
apps/lfx-one/src/server/services/email.service.ts (2)

85-149: Consider error codes instead of string matching.

Lines 115 and 201 use string matching (includes('already linked')) to detect specific error cases. This is fragile and could break if error messages change.

Consider having the auth service return structured error responses with error codes:

-        if (result.error?.includes('already linked')) {
+        if (result.errorCode === 'EMAIL_ALREADY_LINKED') {
           throw ServiceValidationError.forField('email', 'This email address is already linked to an account', {

This would require coordinating with the auth service to return errorCode fields in error responses.


255-317: Consider basic token format validation.

The method only checks token presence but doesn't validate format. While the auth service will validate tokens, a basic JWT format check (three base64 segments separated by dots) could provide faster feedback for malformed tokens.

   // Validate tokens
   if (!userToken || !linkWithToken) {
     throw ServiceValidationError.forField('token', 'User token and link token are required', {
       operation: 'link_identity',
       service: 'email_service',
       path: '/nats/user-identity/link',
     });
   }
+
+  // Basic JWT format validation (three segments separated by dots)
+  const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/;
+  if (!jwtRegex.test(userToken) || !jwtRegex.test(linkWithToken)) {
+    throw ServiceValidationError.forField('token', 'Invalid token format', {
+      operation: 'link_identity',
+      service: 'email_service',
+      path: '/nats/user-identity/link',
+    });
+  }
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)

78-136: Consider simplifying code concatenation.

Line 87 manually concatenates all six digit values. This could be more maintainable using Object.values or an array approach.

-    const code = `${this.verificationForm.value.digit1}${this.verificationForm.value.digit2}${this.verificationForm.value.digit3}${this.verificationForm.value.digit4}${this.verificationForm.value.digit5}${this.verificationForm.value.digit6}`;
+    const code = Object.values(this.verificationForm.value).join('');

This is more concise and would work even if the number of digits changes in the future.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 53a3893 and e6001d5.

📒 Files selected for processing (11)
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.html (4 hunks)
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (7 hunks)
  • apps/lfx-one/src/app/shared/services/user.service.ts (1 hunks)
  • apps/lfx-one/src/server/controllers/profile.controller.ts (6 hunks)
  • apps/lfx-one/src/server/routes/profile.route.ts (1 hunks)
  • apps/lfx-one/src/server/services/email.service.ts (1 hunks)
  • apps/lfx-one/src/server/services/user.service.ts (2 hunks)
  • packages/shared/src/enums/nats.enum.ts (1 hunks)
  • packages/shared/src/interfaces/user-profile.interface.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • apps/lfx-one/src/app/shared/services/user.service.ts
  • packages/shared/src/interfaces/user-profile.interface.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-one/src/server/services/email.service.ts
  • apps/lfx-one/src/server/services/user.service.ts
  • apps/lfx-one/src/server/controllers/profile.controller.ts
  • packages/shared/src/enums/nats.enum.ts
  • apps/lfx-one/src/server/routes/profile.route.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-one/src/app/shared/services/user.service.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html
  • packages/shared/src/interfaces/user-profile.interface.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-one/src/server/services/email.service.ts
  • apps/lfx-one/src/server/services/user.service.ts
  • apps/lfx-one/src/server/controllers/profile.controller.ts
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.html
  • packages/shared/src/enums/nats.enum.ts
  • apps/lfx-one/src/server/routes/profile.route.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-one/src/app/shared/services/user.service.ts
  • packages/shared/src/interfaces/user-profile.interface.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-one/src/server/services/email.service.ts
  • apps/lfx-one/src/server/services/user.service.ts
  • apps/lfx-one/src/server/controllers/profile.controller.ts
  • packages/shared/src/enums/nats.enum.ts
  • apps/lfx-one/src/server/routes/profile.route.ts
apps/lfx-one/src/**/*.html

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-one/src/**/*.html: Always add data-testid attributes when creating new Angular components for reliable test targeting
Use data-testid naming convention [section]-[component]-[element]

Files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.html
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces

Files:

  • packages/shared/src/interfaces/user-profile.interface.ts
packages/shared/src/enums/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all enums in the shared package at packages/shared/src/enums

Files:

  • packages/shared/src/enums/nats.enum.ts
🧠 Learnings (2)
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to packages/shared/src/interfaces/**/*.ts : Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces

Applied to files:

  • packages/shared/src/interfaces/user-profile.interface.ts
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to packages/shared/src/enums/**/*.ts : Place all enums in the shared package at packages/shared/src/enums

Applied to files:

  • packages/shared/src/enums/nats.enum.ts
🧬 Code graph analysis (6)
apps/lfx-one/src/app/shared/services/user.service.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • AddEmailRequest (53-55)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
  • Component (30-345)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • UserEmail (25-35)
apps/lfx-one/src/server/services/email.service.ts (2)
apps/lfx-one/src/server/services/nats.service.ts (1)
  • NatsService (13-133)
packages/shared/src/constants/api.constants.ts (1)
  • NATS_CONFIG (28-43)
apps/lfx-one/src/server/services/user.service.ts (2)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • UserEmailsResponse (183-187)
packages/shared/src/constants/api.constants.ts (1)
  • NATS_CONFIG (28-43)
apps/lfx-one/src/server/controllers/profile.controller.ts (2)
apps/lfx-one/src/server/services/email.service.ts (1)
  • EmailService (68-348)
packages/shared/src/interfaces/user-profile.interface.ts (3)
  • UserEmail (25-35)
  • EmailManagementData (69-72)
  • AddEmailRequest (53-55)
🔇 Additional comments (10)
apps/lfx-one/src/server/controllers/profile.controller.ts (3)

7-7: LGTM - Imports and service initialization.

The imports and EmailService field initialization follow the same pattern as existing services in the controller.

Also applies to: 10-10, 19-19, 30-30


465-509: LGTM - Email verification endpoint.

The endpoint has appropriate validation, logging, and error handling. The EmailService performs additional validation including email format checking.


511-573: Verify authorization checks in the auth-service microservice repository.

The SSR server correctly delegates identity linking authorization to a separate NATS-based auth service. The endpoint passes both the user's bearer token and the identity token from OTP verification. However, the auth service implementation is in a separate microservice repository (not in this codebase), so I cannot verify that it performs the required authorization checks.

To complete this verification, manually confirm in the auth-service repository that the user-identity/link NATS handler validates:

  • Bearer token validity and user identity
  • User authorization to link the email to their account
  • Email is not already linked to another user

The current SSR code correctly delegates the responsibility; verification requires inspecting the auth-service implementation directly.

apps/lfx-one/src/server/services/email.service.ts (3)

14-73: LGTM - Interface definitions and constructor.

The internal interfaces are well-structured for the three-step verification flow. The NatsService is properly instantiated and manages connection pooling internally.


162-243: LGTM - OTP verification logic.

The method properly validates the 6-digit OTP format and handles error cases appropriately. The string matching concern is addressed in a previous comment.


329-347: LGTM - Orchestration logic is sound.

The method properly chains the OTP verification and identity linking steps, with appropriate validation between steps.

packages/shared/src/enums/nats.enum.ts (1)

13-19: LGTM - NATS subject additions.

The new enum members follow consistent naming conventions and are appropriately categorized with inline comments. They align with the email verification and linking flow implemented in the EmailService.

Based on learnings

apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (3)

29-49: LGTM - Timer and form initialization.

The 5-minute timer and 6-digit form setup with per-digit validation are appropriate for the OTP verification flow.


51-70: LGTM - Lifecycle hooks.

Proper initialization with auto-focus and cleanup with the destroy$ subject for subscription management.


211-309: LGTM - Keyboard navigation and paste handling.

The keyboard event handlers provide excellent UX with backspace, arrow key navigation, and comprehensive paste support. The duplicate paste logic concern is addressed in the previous comment.

…error handling

- Replace individual digit inputs with a single input for the 6-digit verification code to simplify user interaction.
- Update error messages for clarity and consistency, particularly for already linked emails.
- Enhance the timer functionality and cleanup logic to improve component lifecycle management.

Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502

Generated with [Cursor](https://cursor.com/)

Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
Copy link

@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: 2

🧹 Nitpick comments (1)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)

132-132: Remove debug console.log.

Debug logging should be removed before merging to production.

Apply this diff:

           // Set error message AFTER reset to prevent it from being cleared
           this.errorMessage.set(errorMsg);
-          console.log('Error message signal value:', this.errorMessage());
         },
       });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e6001d5 and 3b3e6b1.

📒 Files selected for processing (3)
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
🧬 Code graph analysis (2)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
  • Component (30-345)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • UserEmail (25-35)
🔇 Additional comments (4)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (2)

100-102: Feature flags properly documented.

The temporarily disabled features are clearly marked with inline comments and hard-coded flags. This approach provides transparency about the current implementation status.


152-186: Modal result handling is well-structured.

The three distinct outcomes (success, alreadyLinked, cancelled) are handled appropriately with different UI responses—inline errors for field-level issues and toasts for system-level feedback.

apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (2)

56-73: Lifecycle management is correct.

The use of takeUntilDestroyed() via destroyRef properly handles cleanup for the form subscription and timer intervals when the component is destroyed.


75-135: Error handling covers multiple scenarios well.

The method distinguishes between "already linked," OTP verification failures, and generic errors, providing appropriate feedback for each case. The sequence of resetting the form before setting the error message prevents the error from being immediately cleared.

…anagement

- Integrate takeUntilDestroyed for better subscription management in email input value changes.
- Improve component lifecycle handling by ensuring subscriptions are properly cleaned up.

Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502

Reviewed with [GitHub Copilot](https://github.com/features/copilot)

Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
Copy link

@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: 1

🧹 Nitpick comments (4)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (3)

130-152: Consider extracting error message detection logic.

The error message extraction and "already linked" detection logic (lines 134-143) is somewhat complex and similar patterns appear in the modal's error handling. Consider extracting this to a helper method to improve maintainability.

Example refactor:

private isAlreadyLinkedError(error: any): boolean {
  const specificMessage = error.error?.errors?.[0]?.message || '';
  const genericMessage = error.error?.message || error.message || '';
  const errorText = (specificMessage + ' ' + genericMessage).toLowerCase();
  return errorText.includes('already linked');
}

Then use it in both places:

if (this.isAlreadyLinkedError(error)) {
  this.emailFieldError.set('This email address is already in use.');
} else {
  // ... generic error handling
}

156-190: Extract duplicate error message string to a constant.

The error message "This email address is already in use." appears on both line 143 and line 181. Extract this to a private constant to maintain consistency.

Apply this diff:

 export class ProfileEmailComponent {
   private readonly userService = inject(UserService);
   private readonly confirmationService = inject(ConfirmationService);
   private readonly messageService = inject(MessageService);
   private readonly dialogService = inject(DialogService);
   private readonly destroyRef = takeUntilDestroyed();
+  
+  private readonly EMAIL_ALREADY_LINKED_ERROR = 'This email address is already in use.';

   // Dialog reference
   private dialogRef: DynamicDialogRef | undefined;

Then use it:

-            this.emailFieldError.set('This email address is already in use.');
+            this.emailFieldError.set(this.EMAIL_ALREADY_LINKED_ERROR);
-        this.emailFieldError.set('This email address is already in use.');
+        this.emailFieldError.set(this.EMAIL_ALREADY_LINKED_ERROR);

207-234: Consider removing commented-out code blocks.

The setPrimary method contains a large commented-out implementation (lines 215-233). Since this feature is temporarily disabled and tracked in the TODO comment, consider removing the commented code to reduce clutter. The implementation can be retrieved from git history when needed.

This same suggestion applies to the deleteEmail method (lines 245-274).

apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)

99-126: Consider extracting error handling logic to a shared utility.

The error extraction and classification logic (lines 99-126) has similarities with the parent component's error handling. Consider creating a shared error utility to handle email verification errors consistently across components.

Example utility:

// shared/utils/email-error.util.ts
export interface EmailVerificationError {
  isAlreadyLinked: boolean;
  isInvalidOtp: boolean;
  message: string;
}

export function parseEmailVerificationError(error: any): EmailVerificationError {
  const specificMessage = error.error?.errors?.[0]?.message || '';
  const genericMessage = error.error?.message || error.message || '';
  const errorCode = error.error?.error_code || '';
  const errorType = error.error?.error_type || '';
  const errorText = (specificMessage + ' ' + genericMessage + ' ' + errorCode).toLowerCase();
  
  return {
    isAlreadyLinked: errorText.includes('already linked'),
    isInvalidOtp: errorCode === 'OTP_VERIFICATION_FAILED' || errorType === '_MicroserviceError',
    message: errorText,
  };
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3b3e6b1 and 3894895.

📒 Files selected for processing (2)
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (8 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.
📚 Learning: 2025-10-31T14:39:34.327Z
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.

Applied to files:

  • apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧬 Code graph analysis (2)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • UserEmail (25-35)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
  • Component (30-349)
🔇 Additional comments (6)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (2)

68-76: LGTM! Subscription cleanup properly implemented.

The form subscription now uses takeUntilDestroyed() which properly cleans up the subscription when the component is destroyed, addressing the memory leak concern from the previous review.


18-18: LGTM! DynamicDialog integration properly configured.

The DynamicDialog imports, module registration, and service injection are correctly set up to support the new email verification modal flow.

Also applies to: 23-23, 43-43, 47-47, 54-55

apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (4)

1-3: LGTM! Required license header present.

The file includes the required Linux Foundation license header as per coding guidelines.


142-162: LGTM! Timer cleanup properly implemented.

The timer implementation now correctly prevents multiple concurrent intervals by tracking and unsubscribing the previous subscription (lines 144-146) before starting a new one. Combined with takeUntilDestroyed(), this ensures proper cleanup both on resend and component destroy.


57-74: LGTM! Thoughtful form subscription implementation.

The ngOnInit logic properly:

  • Retrieves email from dialog config
  • Starts the countdown timer
  • Subscribes to form changes with proper cleanup via takeUntilDestroyed()
  • Conditionally clears errors only when user is actively typing (line 70), preventing unwanted error clearing during programmatic form resets

164-201: LGTM! Resend flow properly implemented.

The resendCode method correctly:

  • Manages loading state with the resending signal
  • Resets all timer and form state on success
  • Restarts the timer (which properly handles cleanup)
  • Provides appropriate user feedback via toasts

- Removed console log statement that outputs the error message signal value to clean up the code and reduce unnecessary logging during error handling.

Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502

Reviewed with [GitHub Copilot](https://github.com/features/copilot)

Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
Copy link

@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

🧹 Nitpick comments (1)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)

96-135: Consider extracting error parsing logic.

The error handling correctly manages multiple backend formats (ServiceValidationError vs. microservice errors), and the special handling for "already linked" is appropriate. However, the parsing logic (lines 101-126) could be extracted to a helper method to improve testability and maintainability.

For example:

private parseVerificationError(error: any): { isAlreadyLinked: boolean; message: string } {
  const specificMessage = error.error?.errors?.[0]?.message || '';
  const genericMessage = error.error?.message || error.message || '';
  const errorCode = error.error?.error_code || '';
  const errorType = error.error?.error_type || '';
  const errorText = (specificMessage + ' ' + genericMessage + ' ' + errorCode).toLowerCase();
  
  if (errorText.includes('already linked')) {
    return { isAlreadyLinked: true, message: '' };
  }
  
  if (errorCode === 'OTP_VERIFICATION_FAILED' || errorType === '_MicroserviceError') {
    return { isAlreadyLinked: false, message: 'Invalid or expired verification code. Please try again.' };
  }
  
  return { isAlreadyLinked: false, message: 'Invalid verification code. Please try again.' };
}

Then simplify the error handler:

error: (error) => {
  console.error('Failed to verify code:', error);
  const parsed = this.parseVerificationError(error);
  
  if (parsed.isAlreadyLinked) {
    this.dialogRef.close({ alreadyLinked: true, email: this.email });
    return;
  }
  
  this.verificationForm.reset();
  this.errorMessage.set(parsed.message);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3894895 and 12134c9.

📒 Files selected for processing (1)
  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.
📚 Learning: 2025-10-31T14:39:34.327Z
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.

Applied to files:

  • apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧬 Code graph analysis (1)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
  • Component (30-349)
🔇 Additional comments (5)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (5)

1-24: LGTM! Clean component setup.

The license header, imports, and component configuration follow Angular best practices. Using a standalone component with localized MessageService provider is appropriate for this modal.


25-56: Well-structured state management.

The use of signals for reactive state and a simple FormGroup with pattern validation is clean. Timer subscription tracking ensures proper cleanup.


57-74: LGTM! Thoughtful initialization logic.

The conditional error clearing (only when value is truthy) prevents the message from disappearing on reset, which is good UX. Timer starts appropriately on init.


141-161: Excellent timer implementation.

The timer correctly prevents multiple concurrent intervals (lines 143-145) and uses takeUntilDestroyed() for automatic cleanup, which resolves the issues from previous reviews. The form disabling on expiry is appropriate.


163-200: LGTM! Clean resend flow.

The resend logic properly resets all state (timer, form, flags) and restarts the timer. The toast notifications provide clear user feedback.

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.

4 participants