Skip to main content
This reference documents all validation schemas used for request validation in the application.

Authentication Validators

Location: apps/web/app/auth/validators.ts All authentication validators use VineJS for schema definition and validation.

signUpValidator

Validates user registration data.
export const signUpValidator = vine.compile(
  vine.object({
    fullName: vine.string().trim().minLength(3).maxLength(255),
    email: vine.string().email().toLowerCase().trim().unique({ table: 'users', column: 'email' }),
    password: vine.string().minLength(1).confirmed({ confirmationField: 'passwordConfirmation' }),
  })
)
fullName
string
required
User’s full nameValidation:
  • Trimmed whitespace
  • Minimum length: 3 characters
  • Maximum length: 255 characters
email
string
required
User’s email addressValidation:
  • Valid email format
  • Converted to lowercase
  • Trimmed whitespace
  • Must be unique in users table
password
string
required
User’s passwordValidation:
  • Minimum length: 1 character
  • Requires confirmation field
passwordConfirmation
string
required
Password confirmation (must match password)

signInValidator

Validates user login credentials.
export const signInValidator = vine.compile(
  vine.object({
    email: vine.string().email().toLowerCase().trim(),
    password: vine.string().minLength(1),
  })
)
email
string
required
User’s email addressValidation:
  • Valid email format
  • Converted to lowercase
  • Trimmed whitespace
password
string
required
User’s passwordValidation:
  • Minimum length: 1 character

forgotPasswordValidator

Validates forgot password request.
export const forgotPasswordValidator = vine.compile(
  vine.object({
    email: vine.string().email().trim().normalizeEmail({ gmail_remove_dots: false }),
  })
)
email
string
required
Email address to send reset linkValidation:
  • Valid email format
  • Trimmed whitespace
  • Normalized email format
  • Gmail dots are preserved

resetPasswordValidator

Validates new password during reset.
export const resetPasswordValidator = vine.compile(
  vine.object({
    password: vine.string().minLength(1).confirmed({ confirmationField: 'passwordConfirmation' }),
  })
)
password
string
required
New passwordValidation:
  • Minimum length: 1 character
  • Requires confirmation
passwordConfirmation
string
required
Password confirmation (must match password)

User Management Validators

Location: apps/web/app/users/validators.ts

createUserValidator

Validates data for creating a new user (admin function).
export const createUserValidator = vine.compile(
  vine.object({
    fullName: vine.string().trim().minLength(3).maxLength(255),
    email: vine.string().email().toLowerCase().trim().unique({ table: 'users', column: 'email' }),
    roleId: vine.number().exists({ table: 'roles', column: 'id' }),
    password: vine
      .string()
      .minLength(1)
      .maxLength(255)
      .confirmed({ confirmationField: 'passwordConfirmation' })
      .optional(),
  })
)
fullName
string
required
User’s full name (3-255 characters, trimmed)
email
string
required
Unique email address (lowercase, trimmed)
roleId
number
required
Role ID (must exist in roles table)
password
string
Optional password (auto-generated if not provided)Validation:
  • 1-255 characters
  • Requires confirmation if provided

editUserValidator

Validates data for updating an existing user.
export const editUserValidator = vine.withMetaData<{ userId: number }>().compile(
  vine.object({
    fullName: vine.string().trim().minLength(3).maxLength(255),
    email: vine
      .string()
      .email()
      .toLowerCase()
      .trim()
      .unique(async (_, value, field) => {
        const row = await User.query()
          .where('email', value)
          .whereNot('id', field.meta.userId)
          .first()
        return row ? false : true
      }),
    roleId: vine.number().exists({ table: 'roles', column: 'id' }),
    password: vine
      .string()
      .minLength(1)
      .maxLength(255)
      .confirmed({ confirmationField: 'passwordConfirmation' })
      .optional(),
  })
)
This validator uses metadata to pass the current user ID for email uniqueness validation.Usage:
const payload = await request.validateUsing(editUserValidator, {
  meta: { userId: params.id }
})
fullName
string
required
User’s full name (3-255 characters)
email
string
required
Email address (must be unique except for current user)
roleId
number
required
Role ID (must exist in database)
password
string
Optional new password (keeps existing if not provided)

updateProfileValidator

Validates profile updates for authenticated users.
export const updateProfileValidator = vine.compile(
  vine.object({
    fullName: vine.string().trim().minLength(3).maxLength(255),
    avatar: vine
      .file({
        extnames: ['png', 'jpg', 'jpeg', 'gif'],
        size: 1 * 1024 * 1014,
      })
      .nullable(),
  })
)
fullName
string
required
User’s full name (3-255 characters)
avatar
File
Profile picture uploadValidation:
  • Allowed formats: PNG, JPG, JPEG, GIF
  • Maximum size: ~1MB (1,038,336 bytes)
  • Nullable (can be empty)

updatePasswordValidator

Validates password change requests.
export const updatePasswordValidator = vine.compile(
  vine.object({
    password: vine
      .string()
      .minLength(1)
      .maxLength(255)
      .confirmed({ confirmationField: 'passwordConfirmation' }),
  })
)
password
string
required
New password (1-255 characters, requires confirmation)

listUserValidator

Validates user listing/search parameters.
export const listUserValidator = vine.compile(
  vine.object({
    ...baseSearchValidator.getProperties(),
    roleIds: vine.array(vine.number().exists({ table: 'roles', column: 'id' })).optional(),
  })
)
page
number
Page number (positive integer, no decimals)
perPage
number
Results per page (positive integer, no decimals)
q
string
Search query (1-255 characters)
roleIds
number[]
Array of role IDs to filter by (each must exist in roles table)

createTokenValidator

Validates API token creation.
export const createTokenValidator = vine.compile(
  vine.object({
    name: vine.string().trim().minLength(3).maxLength(255).optional(),
  })
)
name
string
Optional token name (3-255 characters, defaults to “Secret Token”)

inviteUserValidator

Validates user invitation data.
export const inviteUserValidator = vine.compile(
  vine.object({
    email: vine.string().email().toLowerCase().trim().unique({ table: 'users', column: 'email' }),
    description: vine.string().trim().optional(),
    roleId: vine.number().exists({ table: 'roles', column: 'id' }),
  })
)
email
string
required
Invitee’s email address (must be unique)
description
string
Optional invitation message
roleId
number
required
Role to assign to the invited user

Common Validators

baseSearchValidator

Base schema for search and pagination parameters. Location: apps/web/app/common/validators/search.ts
export const baseSearchValidator = vine.object({
  page: vine.number().withoutDecimals().positive().optional(),
  perPage: vine.number().withoutDecimals().positive().optional(),
  q: vine.string().minLength(1).maxLength(255).optional(),
})
page
number
Current page numberValidation:
  • Must be a positive integer
  • No decimal values
  • Optional (defaults to 1)
perPage
number
Number of results per pageValidation:
  • Must be a positive integer
  • No decimal values
  • Optional (defaults to 10)
q
string
Search query stringValidation:
  • Minimum length: 1 character
  • Maximum length: 255 characters
  • Optional

Validation Usage

import { signInValidator } from '#auth/validators'

export default class SignInController {
  async handle({ request }: HttpContext) {
    const { email, password } = await request.validateUsing(signInValidator)
    // Data is now validated and type-safe
  }
}

Validation Rules Reference

  • trim() - Remove leading/trailing whitespace
  • toLowerCase() / toUpperCase() - Convert case
  • minLength(n) - Minimum character count
  • maxLength(n) - Maximum character count
  • email() - Valid email format
  • normalizeEmail() - Normalize email addresses
  • confirmed({ confirmationField }) - Match another field
  • withoutDecimals() - Integer only
  • positive() - Greater than zero
  • min(n) / max(n) - Range validation
  • exists({ table, column }) - Must exist in database
  • extnames([]) - Allowed file extensions
  • size - Maximum file size in bytes
  • Example: 1 * 1024 * 1024 = 1MB
  • unique({ table, column }) - Must be unique in table
  • exists({ table, column }) - Must exist in table
  • Custom async validation with database queries
  • optional() - Field is not required
  • nullable() - Accepts null values
  • withMetaData<T>() - Add metadata for validation context

i18n Configuration

Validation messages are automatically translated:
import i18nManager from '@adonisjs/i18n/services/main'
const i18n = i18nManager.locale('fr')
vine.messagesProvider = i18n.createMessagesProvider()
Custom error messages can be defined in your i18n files:
{
  "validation": {
    "email": "The {{ field }} must be a valid email address",
    "minLength": "The {{ field }} must be at least {{ options.minLength }} characters",
    "unique": "The {{ field }} is already taken"
  }
}

Build docs developers (and LLMs) love