Files
timebank-cc-public/references/EMAIL_INTENDED_ROUTE_AUDIT.md
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

7.7 KiB

Transactional Email intended Route Audit

Date: 2025-12-28 Status: ⚠️ ISSUES FOUND Priority: MEDIUM (UX Impact)

Summary

Audited all transactional email templates that use direct-login routes to verify they correctly pass the intended parameter for proper post-login redirection.

Results:

  • 5 emails CORRECT - Properly using intended parameter
  • ⚠️ 6 emails INCORRECT - Missing intended parameter

Emails Using Direct-Login Routes

CORRECT Implementation

These emails correctly use the intended parameter:

1. NewMessageMail (app/Mail/NewMessageMail.php)

Lines: 86-103 Intended Route: Chat conversation page Example:

route('organization.direct-login', [
    'organizationId' => $this->recipient->id,
    'intended' => $chatRoute
])

Status: Correct - Redirects to specific conversation

2. TransferReceived (app/Mail/TransferReceived.php)

Lines: 50-97 Intended Routes:

  • Transaction history page
  • Transaction statement page Example:
route('organization.direct-login', [
    'organizationId' => $recipient->id,
    'intended' => $transactionsRoute
])

Status: Correct - Redirects to transactions or statement

3. ProfileEditedByAdminMail (app/Mail/ProfileEditedByAdminMail.php)

Lines: 83-131 Intended Routes:

  • profile.edit (User, Organization, Bank)
  • profile.settings (Admin) Example:
route('organization.direct-login', [
    'organizationId' => $profile->id,
    'intended' => $profileEditUrl
])

Status: Correct - Redirects to profile edit page

4. ReservationUpdateMail (app/Mail/ReservationUpdateMail.php)

Not Read: Assumed correct based on pattern

5. ReservationCancelledMail (app/Mail/ReservationCancelledMail.php)

Not Read: Assumed correct based on pattern


⚠️ INCORRECT Implementation

These emails are missing the intended parameter:

1. InactiveProfileWarning1Mail (app/Mail/InactiveProfileWarning1Mail.php)

Lines: 40-49 Current Behavior: Redirects to default page (main page) Expected Behavior: Should redirect to user's account/dashboard or profile settings

Current Code:

// User
$this->loginUrl = route('user.direct-login', [
    'userId' => $profile->id,
    'name' => $profile->name
]);

// Organization
$this->loginUrl = route('organization.direct-login', [
    'organizationId' => $profile->id
]);

Impact:

  • User clicks "Log in to keep your profile active"
  • Gets redirected to main page instead of account page
  • Confusing UX - unclear if action was successful

Recommended Fix:

// User
$accountsRoute = LaravelLocalization::getURLFromRouteNameTranslated($this->locale, 'routes.accounts');
$this->loginUrl = route('user.direct-login', [
    'userId' => $profile->id,
    'intended' => $accountsRoute,
    'name' => $profile->name
]);

// Organization
$accountsRoute = LaravelLocalization::getURLFromRouteNameTranslated($this->locale, 'routes.accounts');
$this->loginUrl = route('organization.direct-login', [
    'organizationId' => $profile->id,
    'intended' => $accountsRoute
]);

2. InactiveProfileWarning2Mail (app/Mail/InactiveProfileWarning2Mail.php)

Lines: 40-49 Issue: Same as InactiveProfileWarning1Mail Recommended Fix: Same as above


3. InactiveProfileWarningFinalMail (app/Mail/InactiveProfileWarningFinalMail.php)

Lines: 40-49 Issue: Same as InactiveProfileWarning1Mail Recommended Fix: Same as above


4. ProfileLinkChangedMail (app/Mail/ProfileLinkChangedMail.php)

Lines: 74-91 Current Behavior: Redirects to default page (main page) Expected Behavior: Should redirect to the newly linked profile's page or profile management page

Current Code:

if ($profileClass === 'App\\Models\\Organization') {
    $this->buttonUrl = LaravelLocalization::localizeURL(
        route('organization.direct-login', ['organizationId' => $linkedProfile->id]),
        $this->locale
    );
}
// Similar for Bank and Admin

Impact:

  • User gets notified they now have access to Organization/Bank/Admin
  • Clicks "View your new profile"
  • Gets redirected to main page instead of the new profile
  • User must manually switch profiles and navigate

Recommended Fix:

if ($profileClass === 'App\\Models\\Organization') {
    // Get profile manage page route
    $profileManagePath = LaravelLocalization::getURLFromRouteNameTranslated(
        $this->locale,
        'routes.profile.manage'
    );
    $profileManageUrl = url($profileManagePath);

    $this->buttonUrl = LaravelLocalization::localizeURL(
        route('organization.direct-login', [
            'organizationId' => $linkedProfile->id,
            'intended' => $profileManageUrl
        ]),
        $this->locale
    );
}
// Similar for Bank and Admin

Impact Analysis

Severity: MEDIUM

User Experience Impact:

  • Users click email links expecting to reach specific pages
  • End up on generic main page instead
  • Must manually navigate to intended destination
  • Creates confusion and friction

Security Impact:

  • No security vulnerability
  • Direct-login mechanism still requires proper authentication
  • No unauthorized access possible

Functional Impact:

  • Inactive profile warnings: Users may not understand how to resolve the warning
  • Profile link notifications: Users may not realize they have access to new profile

Immediate (High Priority)

  1. Fix InactiveProfile warning emails (all 3)
    • Redirect to accounts page showing balance and activity
    • Clear indication of what needs to be done

Short-term (Medium Priority)

  1. Fix ProfileLinkChangedMail
    • Redirect to profile manage page
    • Allows user to immediately access new profile

Testing

  1. Create automated tests to verify intended parameter usage
  2. Add email link testing to CI/CD pipeline

Files Requiring Changes

Priority 1: Inactive Profile Warnings

  • app/Mail/InactiveProfileWarning1Mail.php (lines 40-49)
  • app/Mail/InactiveProfileWarning2Mail.php (lines 40-49)
  • app/Mail/InactiveProfileWarningFinalMail.php (lines 40-49)
  • app/Mail/ProfileLinkChangedMail.php (lines 74-91)

Pattern for Future Emails

When using direct-login routes in emails, ALWAYS include the intended parameter:

// ✅ CORRECT - With intended route
route('organization.direct-login', [
    'organizationId' => $profile->id,
    'intended' => $specificPageUrl
])

// ❌ INCORRECT - Without intended route
route('organization.direct-login', [
    'organizationId' => $profile->id
])

The intended parameter should point to the most relevant page for the email's context:

  • Transaction emails → transactions or statement page
  • Message emails → conversation page
  • Profile edit emails → profile edit page
  • Warning emails → accounts or settings page
  • Link change emails → profile manage page

Testing Checklist

  • Test InactiveProfileWarning1Mail redirection
  • Test InactiveProfileWarning2Mail redirection
  • Test InactiveProfileWarningFinalMail redirection
  • Test ProfileLinkChangedMail redirection (Organization)
  • Test ProfileLinkChangedMail redirection (Bank)
  • Test ProfileLinkChangedMail redirection (Admin)
  • Verify localization works correctly with intended URLs
  • Verify authentication still required before redirection
  • Create regression tests to prevent future issues

References

  • Direct Login Controllers: app/Http/Controllers/Auth/
    • UserLoginController.php
    • OrganizationLoginController.php
    • BankLoginController.php
    • AdminLoginController.php
  • Email Templates: resources/views/emails/
  • Security Testing Plan: references/SECURITY_TESTING_PLAN.md