- Stack:
api/(NestJS GraphQL) - Target: all GraphQL mutations named
create*andupdate* - Goal: systematic, coherent, maintainable input format validation
- Central regex base added in
api/src/common/REGEX.ts - Reusable scalar family added in
api/src/graphql/common/scalars/input-value.scalars.ts - Existing
VideoUrlscalar aligned to shared regex source inapi/src/graphql/common/scalars/video-url.scalar.ts - Scalars applied across create/update inputs (including nested input objects used by these mutations)
- Password argument validation applied on non-input mutations in
api/src/graphql/user/user.resolver.ts
- Resolvers scanned: all
*.resolver.tsunderapi/src/graphql - Create/update mutations found:
57 - Input classes covered by those mutations:
55 - Input fields inventoried:
384total fields (102unique names)
Top repeated field names in create/update inputs:
label(30)locale(28)visibility(26)id(24)description(14)
LocaleCodeScalar: locale values (ex:fr,en,fr-FR)EmailAddressScalar: email formatPhoneNumberScalar: phone formatPersonNameScalar: person/city/country-like namesShortLabelScalar: short labels/titles/subjectsSafeTextScalar: free text blocks (notes, descriptions, comments)DateYMDScalar: strictYYYY-MM-DDstring formatTokenCodeScalar: technical code/token-like valuesPasswordTextScalar: password text format gateEntityIdScalar: technical ID strings (ObjectId/UUID/id-like)VideoUrlScalar: absolute HTTP(S) video URL
createManualAgendaEvent(CreateManualAgendaEventInput)sourceParentId: EntityIdScalar,sourceId: EntityIdScalar,date: DateYMDScalar
athleteInfo_create|athleteInfo_update(Create/UpdateAthleteInfoInput)medicalConditions/allergies/notes: SafeTextScalar
coachAthlete_create|coachAthlete_update(Create/UpdateCoachAthleteInput)note: SafeTextScalar
wellnessReport_create|wellnessReport_update(Create/UpdateWellnessReportInput)reportDate: DateYMDScalar,notes: SafeTextScalar,painZones: [ShortLabelScalar]
document_admin_create|document_admin_update(Create/UpdateDocumentInput)name: ShortLabelScalar,version: TokenCodeScalar,file_name: TokenCodeScalar,locale: LocaleCodeScalar
note_create|note_update(Create/UpdateNoteInput)label: ShortLabelScalar,description: SafeTextScalar
task_create|task_update(Create/UpdateTaskInput)label: ShortLabelScalar
supportMessage_create|supportMessage_update(Create/UpdateSupportMessageInput)subject: ShortLabelScalar,description: SafeTextScalar
meal_create|meal_update(Create/UpdateMealInput)locale: LocaleCodeScalar,label: ShortLabelScalar,foods: SafeTextScalar,videoUrl: VideoUrlScalar
mealDay_create|mealDay_update(Create/UpdateMealDayInput)locale: LocaleCodeScalar,label: ShortLabelScalar,description: SafeTextScalar
mealPlan_create|mealPlan_update(Create/UpdateMealPlanInput+ nested)- Root:
locale: LocaleCodeScalar,label: ShortLabelScalar,description: SafeTextScalar - Nested day:
locale,label,description,eventDates: [DateYMDScalar] - Nested meal:
locale,label,description,foods,videoUrl: VideoUrlScalar
- Root:
mealReport_create|mealReport_updateState(Create/UpdateMealReportInput)eventDate: DateYMDScalar,comment: SafeTextScalar
mealType_create|mealType_update(Create/UpdateMealTypeInput)locale: LocaleCodeScalar,label: ShortLabelScalar,icon: ShortLabelScalar
- Taxonomy create/update (
prospectActivityPreference,prospectLevel,prospectObjective,prospectSource)locale: LocaleCodeScalar,label: ShortLabelScalar
prospect_create|prospect_update(Create/UpdateProspectInput)firstName/lastName: PersonNameScalaremail: EmailAddressScalar,phone: PhoneNumberScalarlevelId/sourceId: EntityIdScalarmedicalConditions/allergies/notes/dealDescription: SafeTextScalar
- Taxonomy create/update (
category,equipment,muscle,tag)locale: LocaleCodeScalar,label: ShortLabelScalar
exercise_create|exercise_update(Create/UpdateExerciseInput)locale: LocaleCodeScalar,label/series/repetitions/charge: ShortLabelScalardescription/instructions: SafeTextScalar,videoUrl: VideoUrlScalar
session_create|session_update(Create/UpdateSessionInput)locale: LocaleCodeScalar,label: ShortLabelScalar,description: SafeTextScalar
program_create|program_update(Create/UpdateProgramInput+ nested)- Root:
locale: LocaleCodeScalar,label: ShortLabelScalar,description: SafeTextScalar - Nested session/exercise fields aligned to label/text/date/url families
- Root:
sessionReport_create|sessionReport_updateState(Create/UpdateSessionReportInput+ nested)sessionId: EntityIdScalar,eventDate: DateYMDScalar,comment/notes: SafeTextScalar
createIncomeUser(CreateIncomeUserInput)first_name/last_name: PersonNameScalar,email: EmailAddressScalar,phone: PhoneNumberScalarpassword/confirm_password: PasswordTextScalar,captchaToken: TokenCodeScalar
user_create(CreateUserInput)- same identity fields +
initialSubscriptionPlanCode: TokenCodeScalar
- same identity fields +
user_update/me_update(UpdateUserInput/UpdateMeInput)first_name/last_name/email/phonescalars aligned
user_update_password/me_update_password(resolver args)password: PasswordTextScalar
IDfields (@Field(() => ID)) were intentionally kept as GraphQLIDfor contract compatibility.EntityIdScalaris used for technical string IDs only where field type is string (not GraphQLID).- Regexes are format validators, not business-rule validators.
- Regex/scalar validation is not an injection defense by itself.
- Format validation: GraphQL scalars (this work)
- Business validation: use cases/services (existing architecture)
- Injection/security controls: repository/query hygiene, parameterization, and backend safeguards
npm testpassed (204suites,903tests)npm run lintpassednpm run buildpassed