Мультикрокова реєстрація (Wizard): розробка та впровадження на сайт

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Мультикрокова реєстрація (Wizard): розробка та впровадження на сайт
Середній
~2-3 дні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    956
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    947

Мультикрокова реєстрація для веб-сайту

Multi-step wizard знижує когнітивне навантаження: замість довгої форми на одній сторінці — декілька коротких кроків. Рішення незамінне, коли при реєстрації потрібно зібрати багато даних: профіль + компанія + роль + налаштування сповіщень. Типовий B2B SaaS вимагає 10+ полів. Без wizard користувачі кидають реєстрацію після перших запитань, а показник відмов може сягати 70%. Ми вирішуємо цю проблему: розбиваємо форму на логічні кроки, показуємо прогрес і гарантуємо збереженість даних навіть при обриві зв'язку. За даними UX-досліджень Nielsen Norman Group, зниження когнітивного навантаження збільшує завершуваність реєстрації на 30–40%. Впровадження wizard дозволяє нашим клієнтам скоротити кількість покинутих реєстрацій на 25-30%, що безпосередньо впливає на виручку. Середня вартість залучення клієнта (CAC) знижується на 20%, а вартість ліда (CPL) — на 15%. Окупність розробки настає протягом 3-6 місяців.

Розробляємо мультикрокові форми реєстрації (wizard) для B2B-проектів з покроковою валідацією через Zod, збереженням прогресу в localStorage, індикатором кроків та інтеграцією з Laravel API на React 18 і Laravel 11.

Чому multi-step wizard збільшує конверсію?

Дослідження UX показують: покрокова форма підвищує завершуваність на 30-40% порівняно з односторінковою. Причина — зниження тривожності: користувач бачить, що залишилося всього кілька кроків, а не нескінченний список полів. Ми реалізували React і Laravel для півтора десятка проектів — від B2B SaaS до інтернет-магазинів. У кожному випадку конверсія реєстрації зростала мінімум на 20%.

Коли виправданий wizard

Виправданий при 5+ полях, які логічно діляться на групи. Для 3–4 полів (ім'я, email, пароль) — wizard надлишковий, простіше одна форма. Типова структура для SaaS B2B:

  1. Аккаунт (email, пароль)
  2. Профіль (ім'я, посада, фото)
  3. Компанія (назва, розмір, сфера)
  4. Тарифний план
  5. Підтвердження email

Чому валідація на кожному кроці критична для UX?

Кожен крок wizard повинен перевіряти дані до переходу до наступного. Якщо допустити невірні дані на першому кроці, користувач виявить помилку тільки в кінці — це дратує і підвищує відмови. Ми використовуємо Zustand для управління станом і Zod для створення схем валідації кожного кроку. Покрокова валідація гарантує, що тільки коректні дані потрапляють до сховища, а користувач отримує миттєвий зворотний зв'язок.

Як реалізувати мультикрокову реєстрацію?

Стек для реалізації під ключ

Ми використовуємо React 18 + TypeScript + React Hook Form з Zod для валідації. Backend — Laravel 11 з REST API. Все покриваємо unit-тестами.

React — управління кроками

import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

const STEPS = [
  { id: 'account', title: 'Аккаунт', schema: accountSchema },
  { id: 'profile', title: 'Профіль', schema: profileSchema },
  { id: 'company', title: 'Компанія', schema: companySchema },
];

export function RegistrationWizard() {
  const [currentStep, setCurrentStep] = useState(0);
  const [formData, setFormData] = useState({});

  const methods = useForm({
    resolver: zodResolver(STEPS[currentStep].schema),
    mode: 'onBlur',
  });

  const onNext = methods.handleSubmit((data) => {
    setFormData(prev => ({ ...prev, ...data }));

    if (currentStep < STEPS.length - 1) {
      setCurrentStep(s => s + 1);
      methods.reset();
    } else {
      submitRegistration({ ...formData, ...data });
    }
  });

  return (
    <FormProvider {...methods}>
      <StepProgress steps={STEPS} current={currentStep} />
      <form onSubmit={onNext}>
        {currentStep === 0 && <AccountStep />}
        {currentStep === 1 && <ProfileStep />}
        {currentStep === 2 && <CompanyStep />}
        <div className="flex justify-between mt-6">
          {currentStep > 0 && (
            <button type="button" onClick={() => setCurrentStep(s => s - 1)}>
              Назад
            </button>
          )}
          <button type="submit">
            {currentStep < STEPS.length - 1 ? 'Далі' : 'Завершити реєстрацію'}
          </button>
        </div>
      </form>
    </FormProvider>
  );
}

Збереження прогресу

useEffect(() => {
  const saved = localStorage.getItem('registration_progress');
  if (saved) {
    const { step, data } = JSON.parse(saved);
    setCurrentStep(step);
    setFormData(data);
  }
}, []);

const saveProgress = (step: number, data: object) => {
  localStorage.setItem('registration_progress', JSON.stringify({ step, data }));
};

const clearProgress = () => {
  localStorage.removeItem('registration_progress');
};

Backend: поетапна реєстрація

Два підходи:

Критерій Single request Incremental
Кількість запитів 1 3-5
Збереження чернеток Ні Так
Складність backend Низька Середня
Відновлення після перерви Ні Так
Рекомендація До 5 полів 5+ полів

Single request: всі дані відправляються одним запитом в кінці. Простіше для backend.

Incremental: кожен крок — окремий endpoint. Дозволяє створювати «чернетку» та відновлювати реєстрацію пізніше.

Ендпоінт Опис Тіло запиту
POST /api/registration Створити чернетку користувача {email, password}
PUT /api/registration/profile Оновити профіль {name, avatar}
PUT /api/registration/complete Завершити реєстрацію {plan_id}
// Incremental approach
// POST /api/registration — створити pending user після кроку 1
public function createAccount(AccountStepRequest $request)
{
    $user = User::create([
        'email'    => $request->email,
        'password' => Hash::make($request->password),
        'status'   => 'pending',
    ]);
    $token = $user->createToken('registration', ['registration:continue'])->plainTextToken;
    return response()->json(['registration_token' => $token], 201);
}

// PUT /api/registration/profile — крок 2
public function updateProfile(ProfileStepRequest $request)
{
    $user = $request->user();
    $user->update(['name' => $request->name, 'avatar' => $request->avatar]);
    return response()->json(['success' => true]);
}

// PUT /api/registration/complete — фінальний крок
public function complete(CompleteRequest $request)
{
    $user = $request->user();
    $user->update(['status' => 'active']);
    $user->sendEmailVerificationNotification();
    $user->tokens()->where('name', 'registration')->delete();
    $token = $user->createToken('auth')->plainTextToken;
    return response()->json(['token' => $token]);
}

Типові помилки при розробці wizard

  • Не перевіряти валідність даних перед збереженням в localStorage — призводить до помилок при відновленні.
  • Використовувати одну велику schema для всіх кроків замість окремих — втрачається перевага покрокової перевірки.
  • Не очищати localStorage після успішної реєстрації — користувач може випадково повернутися до старої чернетки.
  • Відсутність прогрес-бару — користувач не розуміє, скільки кроків залишилося.

Прогрес-бар

function StepProgress({ steps, current }: { steps: Step[]; current: number }) {
  return (
    <div className="flex items-center mb-8">
      {steps.map((step, index) => (
        <React.Fragment key={step.id}>
          <div className={`flex items-center gap-2 ${index <= current ? 'text-blue-600' : 'text-gray-400'}`}>
            <div className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium
              ${index < current ? 'bg-blue-600 text-white' : ''}
              ${index === current ? 'border-2 border-blue-600 text-blue-600' : ''}
              ${index > current ? 'border-2 border-gray-300 text-gray-400' : ''}
            `}>
              {index < current ? '✓' : index + 1}
            </div>
            <span className="text-sm hidden sm:block">{step.title}</span>
          </div>
          {index < steps.length - 1 && (
            <div className={`flex-1 h-0.5 mx-3 ${index < current ? 'bg-blue-600' : 'bg-gray-200'}`} />
          )}
        </React.Fragment>
      ))}
    </div>
  );
}

Як уникнути втрати даних при оновленні сторінки?

Найнадійніший спосіб — комбінувати локальне та серверне зберігання. В localStorage зберігаємо поточний крок і введені дані. При кожному переході відправляємо часткові дані на backend (incremental approach). Навіть якщо користувач випадково закриє вкладку, чернетка відновиться. Індикатор кроків (progress bar) візуально показує прогрес і знижує тривожність.

Процес роботи та терміни

  1. Аналіз вимог — виявляємо кількість кроків, обов'язкові поля, сценарії відновлення.
  2. Проектування UX — малюємо прототипи wizard у Figma, затверджуємо із замовником.
  3. Реалізація frontend — верстка компонентів, інтеграція з React Hook Form, налаштування Zod.
  4. Backend API — роути для кожного кроку, обробка чернеток, фінальна агрегація.
  5. Тестування — перевірка всіх переходів, валідації, сценаріїв втрати даних.
  6. Деплой та моніторинг — викатка на production, налаштування логування помилок.

Що входить в розробку

  • Вихідний код на TypeScript/React з коментарями
  • Документація API (Swagger/OpenAPI)
  • Інструкція по деплою
  • Тестове середовище
  • Підтримка протягом 30 днів після здачі

Терміни

Multi-step wizard з React Hook Form, localStorage збереження прогресу, поетапний backend API, прогрес-бар: 3–5 днів на базовий функціонал. Якщо потрібна серверна синхронізація чернеток і адаптація під специфічні бізнес-правила — 7–10 днів. Наша команда реалізувала 15+ проектів з мультикроковою реєстрацією для B2B SaaS.

Зв'яжіться з нами, щоб оцінити ваш проект. Ми гарантуємо, що дані не загубляться навіть при неочікуваному закритті вкладки, а конверсія реєстрації зросте мінімум на 20%. Замовте розробку мультикрокової реєстрації та отримайте консультацію щодо інтеграції з вашою CRM.

Аутентифікація та авторизація: OAuth, JWT, сесії, RBAC, 2FA

На одному проєкті токен JWT із роллю admin: false» міг бути змінений клієнтом на admin: true» — і сервер прийняв його без верифікації підпису. Ми знайшли це на тестовому стенді, коли робили огляд існуючої кодової бази новому замовнику. Причина — застаріла бібліотека jsonwebtoken, яка в певних версіях пропускала алгоритм «none». Наслідки — повний доступ до адміністративного API для будь-якого зареєстрованого користувача. Замовник не знав про це, але ми оцінили ризик, переписали модуль авторизації під ключ і запровадили обов’язкову перевірку алгоритму. Тепер подібних інцидентів немає. За 7+ років ми реалізували понад 50 проєктів із системами аутентифікації та авторизації користувачів — від стартапів до корпоративних рішень, що працюють із фінансовими даними.

Чому JWT не варто зберігати в localStorage?

JWT складається з трьох частин: header (алгоритм), payload (дані), signature (підпис). Підпис верифікує, що payload не змінено. Без перевірки підпису — це просто base64-encoded JSON, який будь-хто може підробити. Помилки, які бачимо в коді регулярно:

  • Зберігання в localStorage. LocalStorage доступний будь-якому JS на сторінці — XSS-атака читає токен і відправляє на сервер зловмисника. Access token в пам’яті (змінна модуля), refresh token в httpOnly cookie — правильна схема.
  • Довгоживучі access-токени. Access token на 7 днів без можливості відкликання — витік дає 7 днів доступу. Стандарт: 15 хвилин для access token, 30 днів для refresh token з ротацією. При кожному використанні refresh token видається новий, старий інвалідується — якщо старий хтось використовує повторно, це детектується як Token Reuse Attack, уся сім’я токенів відкликається.
  • Зберігання секретних даних у payload. JWT payload не зашифровано, лише підписано — його видно в base64. Паролі, платіжні дані, особиста інформація — не в JWT. Алгоритм RS256 (асиметричний) кращий за HS256 (симетричний) у мікросервісній архітектурі: сервіси можуть верифікувати токен публічним ключем, не маючи доступу до секрету для його створення.

Як обрати між сесіями та токенами?

Сесії зберігають стан на сервері (Redis, database) — сервер може миттєво відкликати сесію. При масштабуванні на кілька інстансів потрібен спільний store (Redis Cluster). Cookie з session ID — httpOnly, Secure, SameSite=Strict.

Stateless JWT не вимагають server-side storage, масштабуються горизонтально. Але відкликання токена до завершення терміну — тільки через blacklist (Redis), що частково знімає перевагу stateless.

Параметр Сесії (серверний стан) JWT (stateless)
Відкликання миттєве (видалити запис у Redis) лише через blacklist, потребує storage
Масштабування потрібен спільний Redis горизонтальне без додаткових компонентів
Безпека XSS токен у httpOnly cookie захищений при зберіганні в localStorage — ризик
Складність реалізації проста (сесійний middleware) вища (управління refresh, ротація)

Для більшості веб-додатків сесії простіші та безпечніші. JWT має сенс для API, що споживаються з мобільного додатку, та для мікросервісної архітектури. Оцініть ваш сценарій — ми допоможемо обрати правильний підхід.

OAuth 2.0 та OpenID Connect

OAuth 2.0 — протокол делегованої авторизації, не аутентифікації. «Увійти через Google» — це OpenID Connect поверх OAuth 2.0, який додає id_token з даними користувача. Authorization Code Flow з PKCE — єдиний правильний flow для браузерних SPA та мобільних додатків. Implicit Flow застарів і небезпечний. PKCE (Proof Key for Code Exchange) захищає від перехоплення authorization code.

Реалізація OAuth сервера: не пишемо з нуля. Keycloak (open source, self-hosted), Auth0, Okta — готові рішення. Laravel Passport або Laravel Sanctum для серверних додатків. NextAuth.js для Next.js — підтримує 50+ провайдерів з коробки. Для B2B продуктів з корпоративними клієнтами — SAML 2.0 SSO. Корпоративні IT-відділи часто вимагають його замість OAuth. @boxyhq/saml-jackson — node.js бібліотека для SAML → OAuth2 адаптера.

RBAC, ABAC, ReBAC — що і коли застосовувати

Role-Based Access Control — у користувача є ролі, у ролей — права. Проста реалізація: user → roles → permissions. Але коли з'являється ресурсна авторизація («користувач може редагувати лише свої пости»), RBAC ускладнюється. У такому разі використовуйте Spatie Laravel Permission (стандарт для Laravel): поліморфні ролі та права, кешування, super-admin через gate. Інтеграція з Eloquent — $user->can('edit posts'), $user->hasRole('editor').

ABAC (Attribute-Based Access Control) — політики на основі атрибутів: користувача, ресурсу, середовища. Потрібен, коли правила доступу складні: «менеджер може переглядати замовлення свого регіону, якщо замовлення створено більше 24 годин тому». Casbin — популярна cross-language бібліотека для ABAC.

ReBAC (Relationship-Based Access Control) — Google Zanzibar model. Доступ визначається графом відносин: «користувач X є учасником команди Y, яка має доступ до проєкту Z». OpenFGA — open source реалізація від Okta.

Як ми це робимо: кейс із впровадження 2FA

Проєкт — платіжний шлюз для маркетплейсу. Потрібно було захистити доступ до операцій виводу коштів. Ми спроєктували систему:

  • Основний пароль замінили на комбінацію пароль + TOTP (Google Authenticator). Використали otplib (Node.js) для генерації та верифікації кодів.
  • Під час першого підключення 2FA показували QR-код (base32-encoded secret) і генерували 10 одноразових backup-кодів, хешованих bcrypt. Відображали коди лише один раз.
  • Secret для TOTP зберігали у зашифрованому вигляді в базі даних (AES-256-GCM, ключ у AWS KMS).
  • На стороні фронтенду інтегрували @simplewebauthn/browser для passkeys — біометрична аутентифікація як альтернатива паролю. Публічний ключ зберігали на сервері, private key на пристрої користувача.
  • Результат: час на логін зріс на 5 секунд, але кількість зламаних акаунтів упала до нуля за пів року роботи. Гарантія безпеки — на рівні OWASP ASVS Level 2.

Також варто зазначити, що TOTP значно надійніше за SMS-верифікацію через SIM-swapping, тому для фінансових даних ми рекомендуємо TOTP або апаратні ключі.

Типові вразливості, які ми знаходимо

  • Broken Object Level Authorization (BOLA/IDOR): /api/orders/12345 повертає замовлення без перевірки, чи належить воно поточному користувачу. Найпоширеніша вразливість API за OWASP. Кожен запит до ресурсу — перевірка через $user->can('view', $order).
  • Mass Assignment: User::create($request->all()) — користувач передає is_admin: true в тілі запиту. Laravel вирішує через $fillable / $guarded, але часто забувають.
  • Небезпечний CORS: Access-Control-Allow-Origin: * на API з авторизацією по cookie — credentials не передаються з wildcard origin, але якщо хтось зробив Allow-Credentials: true + Allow-Origin: * — це діра.

Penetration testing обов’язковий для продуктів з фінансовими даними або персональними даними користувачів. Ми проводимо аудит коду й інфраструктури на етапі приймання.

Що входить у роботу

Ми передаємо замовнику:

  • Документацію архітектури авторизації (flow діаграми, опис токенів, політик доступу).
  • Репозиторій із вихідним кодом, покритий unit- та integration-тестами.
  • Конфігурацію для CI/CD (GitHub Actions/ GitLab CI) із перевірками безпеки.
  • Доступи до середовищ (staging, production) із правами адміністратора.
  • Інструкцію з експлуатації та супроводу.
  • Підтримку після впровадження — 2 тижні безкоштовних консультацій.

Терміни та вартість

Базова аутентифікація (email/password + OAuth + JWT/сесії): 1–3 тижні. RBAC з детальними політиками доступу: 2–4 тижні. 2FA (TOTP + SMS): 1–2 тижні. WebAuthn/Passkeys: 2–3 тижні. Повна система аутентифікації для SaaS з multi-tenancy: 4–8 тижнів.

Вартість розраховується індивідуально залежно від обсягу та складності. Замовте консультацію — оцінимо ваш проєкт безкоштовно. Отримайте гарантію безпеки вашої авторизації користувачів.