Розроблення особистого кабінету покупця для інтернет-магазину
Особистий кабінет — точка утримання покупця. Тут зберігається історія заказів, управляються адреси та підписки, доступні бонуси та повернення. Слабкий кабінет вимушує звонити в поддержку; сильний — зменшує навантаження на поддержку та повишує retention. Розроблення повноцінного особистого кабінету займає 7–12 робочих днів.
Структура розділів
Типовий особистий кабінет інтернет-магазину включає:
| Розділ | URL | Основний функціонал |
|---|---|---|
| Обзор | /account |
Останні закази, бонуси, сповіщення |
| Закази | /account/orders |
Історія заказів, фільтри, трекинг |
| Повернення | /account/returns |
Статус RMA-запитів |
| Адреси | /account/addresses |
CRUD адрес доставки |
| Дані профілю | /account/profile |
Ім'я, телефон, email, зміна пароля |
| Підписки | /account/subscriptions |
Email-розсилки, push-сповіщення |
| Список бажаного | /account/wishlist |
Збережені товари |
| Бонуси | /account/bonuses |
Баланс, історія начислень/списань |
Роутинг та захист
Всі маршути кабінету захищені middleware auth:
Route::middleware(['auth', 'verified'])->prefix('account')->group(function () {
Route::get('/', [AccountController::class, 'dashboard'])->name('dashboard');
Route::get('/orders', [OrderController::class, 'index'])->name('orders.index');
Route::get('/orders/{order}', [OrderController::class, 'show'])
->can('view', 'order')
->name('orders.show');
Route::resource('addresses', AddressController::class);
});
Policy OrderPolicy гарантує, що користувач видит тільки свої закази.
Dashboard — головний екран
Екран обзору збирає дані з кількох джерел, але робить це одним запитом:
public function dashboard(Request $request): Response {
$user = $request->user()->load([
'orders' => fn($q) => $q->latest()->limit(3)->with('items.product'),
'bonusAccount',
'activeReturns',
]);
return Inertia::render('Account/Dashboard', [
'recentOrders' => OrderResource::collection($user->orders),
'bonusBalance' => $user->bonusAccount?->balance ?? 0,
'pendingReturns' => $user->activeReturns->count(),
'notifications' => $user->unreadNotifications()->limit(5)->get(),
]);
}
Управління адресами
У користувача може бути кілька адрес: дім, офіс, пункт самовивозу. Одна адреса помічається як default:
class Address extends Model {
protected $fillable = [
'user_id', 'label', 'full_name', 'phone',
'country', 'region', 'city', 'street', 'house',
'apartment', 'postal_code', 'is_default',
];
public function setAsDefault(): void {
DB::transaction(function () {
$this->user->addresses()->update(['is_default' => false]);
$this->update(['is_default' => true]);
});
}
}
Зміна email та двохфакторна верифікація
Зміна email — чутлива операція. Процес:
- Користувач вводит новий email
- На новий email відправляється письмо з токеном підтвердження
- Тільки після переходу по ссилці email оновлюється в БД
- На старий email відправляється сповіщення об змині
public function updateEmail(Request $request): void {
$request->validate(['email' => 'required|email|unique:users,email']);
$token = Str::random(64);
Cache::put("email_change:{$token}", [
'user_id' => $request->user()->id,
'new_email' => $request->email,
], now()->addHours(2));
Mail::to($request->email)->send(new EmailChangeConfirmation($token));
}
Управління підписками
Центральне місце для управління комунікаційними перевагами:
const SubscriptionSettings = () => {
const { preferences, toggle } = useNotificationPreferences();
const options = [
{ key: 'order_updates', label: 'Статус заказів' },
{ key: 'promotions', label: 'Акції та скидки' },
{ key: 'back_in_stock', label: 'Товар снова в наявності' },
{ key: 'price_drops', label: 'Зниження цін на избране' },
{ key: 'newsletter', label: 'Еженедельна розсилка' },
];
return (
<div className="space-y-3">
{options.map(({ key, label }) => (
<div key={key} className="flex items-center justify-between">
<span>{label}</span>
<Switch checked={preferences[key]} onCheckedChange={() => toggle(key)} />
</div>
))}
</div>
);
};
Безпека: зміна пароля
Зміна пароля вимагає введення поточного пароля та підтвердження нового:
public function updatePassword(Request $request): void {
$request->validate([
'current_password' => ['required', 'current_password'],
'password' => ['required', 'min:8', 'confirmed'],
]);
$request->user()->update([
'password' => Hash::make($request->password),
]);
Auth::logoutOtherDevices($request->password);
event(new PasswordChanged($request->user()));
}
Видалення аккаунту (GDPR)
По вимогам GDPR користувач повинен мати можливість видалити свій аккаунт. Soft delete з анонімізацією персональних даних:
public function deleteAccount(Request $request): void {
$user = $request->user();
$user->update([
'email' => "deleted_{$user->id}@removed.invalid",
'name' => 'Видалений користувач',
'phone' => null,
'deleted_at' => now(),
]);
Auth::logout();
}
Закази при цьому зберігаються для бухгалтерської звітності — тільки персональні дані анонімізуються.
Мобільна адаптація
Кабінет на мобільних — окремий layout з нижньою навігацією (tab bar) замість бічної. Критичні операції (зміна статусу заказу, просмотр трекингу) повинні бути доступні в 2–3 клики від головного екрана.







