Files
fuel-price/docs/superpowers/specs/2026-04-11-settings-vue-migration-design.md
2026-04-11 12:41:27 +01:00

5.1 KiB

Settings Vue Migration — Design Spec

Date: 2026-04-11
Status: Approved

Goal

Migrate the Livewire settings pages (Profile, Security, Appearance) into the Vue SPA so the app is fully unified under one frontend. Auth pages (/login, /register, Fortify) remain Livewire and are untouched.


Architecture

Routing

New Vue Router routes nested under /dashboard/settings:

/dashboard/settings             → redirect to /dashboard/settings/profile
/dashboard/settings/profile
/dashboard/settings/security
/dashboard/settings/appearance

A SettingsLayout.vue wraps all three views, providing a sub-nav sidebar (Profile / Security / Appearance) that mirrors the existing Livewire settings layout structure and uses the same warm colour palette (#faf6f3, #bb5b3e, #89726c, #4a3f3b, #e5ded7).

Top Nav — User Dropdown

DashboardLayout.vue top nav: replace the plain {{ user?.email }} text with a user avatar button showing the user's initials (e.g. "OU"). Clicking opens a dropdown showing:

  • Avatar + full name + email
  • Settings link → /dashboard/settings
  • Log out (calls POST /api/auth/logout, clears user, redirects to /)

The dropdown is implemented with Alpine.js x-data / x-show inline, consistent with the project's existing Alpine usage pattern.


Components

New files

File Purpose
resources/js/views/dashboard/settings/SettingsLayout.vue Sub-nav wrapper (Profile / Security / Appearance)
resources/js/views/dashboard/settings/Profile.vue Name/email form + delete account
resources/js/views/dashboard/settings/Security.vue Password change + 2FA management
resources/js/views/dashboard/settings/Appearance.vue Light/dark/system theme toggle

Modified files

File Change
resources/js/router/index.js Add /dashboard/settings routes
resources/js/views/dashboard/DashboardLayout.vue Replace email text with user dropdown
resources/js/composables/useAuth.js Expose updateProfile, updatePassword, deleteAccount methods
app/Http/Controllers/Api/UserController.php Add updateProfile, updatePassword, deleteAccount actions
routes/api.php Register 3 new endpoints
routes/settings.php Remove Livewire settings routes

Data Flow

Profile update

  1. Vue calls PUT /api/user/profile with { name, email }
  2. UserController@updateProfile validates, updates users table, nulls email_verified_at if email changed
  3. Returns updated user JSON; useAuth updates the user ref

Password update

  1. Vue calls PUT /api/user/password with { current_password, password, password_confirmation }
  2. UserController@updatePassword verifies current password via Hash::check, updates hash
  3. Returns 200 on success; Vue shows inline success message

Delete account

  1. User clicks "Delete account", enters password in a confirmation modal
  2. Vue calls DELETE /api/user with { password }
  3. UserController@deleteAccount verifies password, deletes user, revokes Sanctum tokens
  4. Vue calls logout, redirects to /

2FA (uses Fortify web routes directly)

Fortify's web routes accept application/json and work with session cookies (axios already sends these via withCredentials: true):

Action Endpoint
Enable POST /user/two-factor-authentication
Disable DELETE /user/two-factor-authentication
Confirm code POST /user/confirmed-two-factor-authentication
Get QR code SVG GET /user/two-factor-qr-code
Get secret key GET /user/two-factor-secret-key
Get recovery codes GET /user/two-factor-recovery-codes
Regenerate recovery codes POST /user/two-factor-recovery-codes

A separate axios instance (base URL /, same credentials) is used for these Fortify calls to avoid the /api prefix.

Appearance

Theme preference stored in localStorage under key appearance with values light / dark / system. Applied via a class on <html>. No backend call needed.


Error Handling

  • Validation errors from API returned as 422 with errors object; displayed inline under each field
  • Network errors shown as a generic top-level message within the form card
  • 2FA setup errors (QR fetch failure, bad confirmation code) shown inline with retry option
  • Delete account modal clears and closes on any error; error shown inside the modal

Cleanup (after Vue implementation verified)

  • Remove routes/settings.php (all three Route::livewire entries)
  • Remove app/Livewire/Settings/ directory (Profile, Security, Appearance, DeleteUserForm, TwoFactor/RecoveryCodes)
  • Remove resources/views/livewire/settings/ directory
  • Remove resources/views/components/settings/layout.blade.php
  • Remove resources/views/partials/settings-heading.blade.php if it exists
  • Remove app/Concerns/ProfileValidationRules.php and PasswordValidationRules.php if unused elsewhere

Out of Scope

  • /login, /register, Fortify password reset flows — remain Livewire, untouched
  • Subscription management (separate feature)
  • WhatsApp/SMS notification preferences (separate feature)