Skip to content

Auth Feature Design

Date: 2026-02-07

Overview

Full authentication flow for Partizap frontend: login, registration, email verification, password reset. Session-based auth with PHP backend (HTTP-only cookies, CSRF tokens).

Decisions

  • Separate pages (not tabs): /auth/login, /auth/register, /auth/verify-email, /auth/forgot-password, /auth/reset-password
  • Phone/SMS login: UI stubs (disabled), waiting for backend support
  • Password confirmation: client-side only via Zod refine, not sent to backend
  • User field: email_verified: boolean (per frontend-api-reference.md, not email_verified_at)
  • Reset password: standard token-in-URL approach (one-time, expiring, from email link)

File Structure

app/
├── shared/
│   └── schemas/auth.ts              — Zod validation schemas (login, register, etc.)
├── features/
│   └── auth/
│       └── composables/
│           └── useApiError.ts       — API error → form error mapping
├── stores/auth.ts                   — UPDATE: add fetchUser, login, register, logout
├── entities/
│   └── user/model/user.schema.ts    — UPDATE: email_verified boolean, add missing fields
├── middleware/
│   ├── auth.ts                      — Protect /cabinet/**, redirect to /auth/login
│   └── guest.ts                     — Redirect authenticated users away from /auth/**
├── plugins/auth.ts                  — Hydrate user on app init (GET /auth/me)
└── pages/auth/
    ├── login.vue                    — Email + password login
    ├── register.vue                 — Email + password + display_name registration
    ├── verify-email.vue             — 6-digit code verification
    ├── forgot-password.vue          — Request password reset email
    └── reset-password.vue           — Set new password (token from email)

Auth Store (stores/auth.ts)

ts
interface User {
  id: number
  email: string
  display_name: string
  phone: string | null
  account_type: 'personal' | 'business'
  email_verified: boolean
  avatar_url: string | null
  city_id: number | null
  district_id: number | null
  metro_station_id: number | null
  rating: string
  reviews_count: number
  products_count: number
  is_active: boolean
  is_admin: boolean
  created_at: string
}

state: { user: User | null, loading: boolean }
getters: { isAuthenticated, isEmailVerified, isAdmin }
actions: { setUser, clearUser, fetchUser, login, register, logout }

Validation Schemas (shared/schemas/auth.ts)

  • passwordSchema: 8-128 chars, uppercase, lowercase, digit, special char, no 3+ identical
  • loginSchema:
  • registerSchema:
  • forgotPasswordSchema:
  • resetPasswordSchema:
  • verifyEmailSchema:

Error Handling (features/auth/composables/useApiError.ts)

  • globalError: general error message for UAlert
  • fieldErrors: per-field errors mapped from 422 details
  • handleError(err): 422 → field mapping, 429 → rate limit with Retry-After, else → globalError
  • clearErrors(): reset all

Middleware

auth.ts: if !authenticated → fetchUser() → if still !authenticated → redirect /auth/login guest.ts: if !authenticated → fetchUser() → if authenticated → redirect /cabinet

Plugin (plugins/auth.ts)

On SSR and first client load: call fetchUser() to hydrate auth state from session cookie.

Pages UI

All pages use Nuxt UI components: UForm, UFormField, UInput, UButton, UAlert.

/auth/login

  • Email + Password fields
  • "Remember me" checkbox (visual stub)
  • "Forgot password?" link → /auth/forgot-password
  • "Login" button
  • Divider "or"
  • "Login via SMS" button — disabled, tooltip "Coming soon"
  • "No account? Register" → /auth/register

/auth/register

  • Phone field — disabled with tooltip "Coming soon"
  • Email + Password + Confirm password + Display name
  • "Register" button
  • "Already have an account? Login" → /auth/login
  • After success → redirect /auth/verify-email

/auth/verify-email

  • Text: "Enter 6-digit code sent to {email}"
  • Code input (inputmode="numeric", maxlength=6)
  • "Verify" button
  • "Resend code" button with 60s cooldown timer

/auth/forgot-password

  • Email field + "Send reset link" button
  • After success → success alert + link to login

/auth/reset-password

  • Token from ?token= query param (if missing → redirect /auth/forgot-password)
  • New password field with passwordSchema validation
  • After success → success alert + link to login

API Endpoints Used

ActionMethodEndpointAuth
RegisterPOST/auth/registerNo
LoginPOST/auth/loginNo
Current userGET/auth/meYes
Verify emailPOST/auth/verify-emailYes
Resend codePOST/auth/resend-verificationYes
Forgot passwordPOST/auth/forgot-passwordNo
Reset passwordPOST/auth/reset-passwordNo
LogoutPOST/auth/logoutYes

i18n

Add auth-related keys to i18n/locales/ru.json under auth.* namespace.

SEO

All auth pages: useSeoMeta({ title: '...', robots: 'noindex, nofollow' }).