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
- Vue calls
PUT /api/user/profilewith{ name, email } UserController@updateProfilevalidates, updatesuserstable, nullsemail_verified_atif email changed- Returns updated user JSON;
useAuthupdates theuserref
Password update
- Vue calls
PUT /api/user/passwordwith{ current_password, password, password_confirmation } UserController@updatePasswordverifies current password viaHash::check, updates hash- Returns
200on success; Vue shows inline success message
Delete account
- User clicks "Delete account", enters password in a confirmation modal
- Vue calls
DELETE /api/userwith{ password } UserController@deleteAccountverifies password, deletes user, revokes Sanctum tokens- 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
422witherrorsobject; 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 threeRoute::livewireentries) - 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.phpif it exists - Remove
app/Concerns/ProfileValidationRules.phpandPasswordValidationRules.phpif unused elsewhere
Out of Scope
/login,/register, Fortify password reset flows — remain Livewire, untouched- Subscription management (separate feature)
- WhatsApp/SMS notification preferences (separate feature)