docs: add settings Vue migration design spec
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user