Skip to content

TODO: Student Import — Cell Validation Refactor

File: src/students/students.service.tsvalidateData() method (and related helpers)

Problem

The current per-cell validation is hand-written with inline checks for each column: required fields, max lengths, date parsing, regex patterns, referent pair logic, etc. This approach:

  • Doesn't reuse the existing DTO validation decorators (@IsDate, @MaxLength, @IsEmail, etc.)
  • Duplicates business rules that are already expressed in CreateStudentDto / scope DTOs
  • Is brittle — adding a field means updating both the DTO and the import validator separately
  • Produces a different error shape than the rest of the API

Goal

Replace the manual per-cell validation with a declarative approach that leverages the existing DTO validation pipeline or a shared schema definition, so import validation and API validation stay in sync.

Ideas to Explore

  • Map each parsed row to CreateStudentDto via plainToInstance() + validate(), then collect errors per row/column
  • Define a shared column-to-field schema that both the import validator and DTOs derive from
  • Use a validation library (e.g., zod, class-validator bulk mode) that can validate an array of rows and return structured per-cell errors
  • Keep the import-specific error response shape ({ column, rows, reason, allowedValues }) but generate it from DTO validation errors

Scope

  • validateData() — the main validation loop
  • validateHeaders() — header matching (likely stays as-is)
  • Error response shape — ImportValidationError with compressed row ranges (keep this UX)
  • Referent pair cross-column validation — custom logic that doesn't map to a single DTO field