Skip to main content

Central Validation Rules

Overview

A set of shared rules that admins create in the CMS and attach to questions across many forms — Thai mobile number formats, national ID numbers, employee codes, and so on. Each rule stores pattern (a regex), minLength, maxLength, errorMessage, and errorMessageTh in its properties column.

The feature exposes a single endpoint, named test in the code (inherited from the original source), but its real role is more significant: it is the service that Loading a Form's Structure calls to merge rules into questions, and it determines which pattern Form Answer Validation will apply.

Business Flow

GET /api/form-builder-rule returns the array of rules with status='active', read through a Redis cache.

The cache key is reproduced character for character from the source so that Go and Node land on the same key and can run side by side.

  1. optionsJSON is the string {"where":{"status":"active"}} — an exact copy of the JSON.stringify of the FindManyOptions the original controller passed in.
  2. The suffix is the first 10 characters of sha256(optionsJSON), produced by util.GenerateShortHash.
  3. The key takes the form FORM_BUILDER_RULE:findAll:{suffix}, following the ${MODULE_NAME}:${key} template.
  4. On a cache hit that unmarshals successfully, the value is returned immediately; a malformed cache entry falls through to the database.
  5. A successful database read writes the value back to the cache with the default TTL from REDIS_TTL.
  6. Every error is swallowed and an empty array is returned, matching the source, which never lets this endpoint return a 500.

There are two deliberately different entry points:

  • FindAllWithCache is used by the endpoint — cached, and error-swallowing.
  • FindAllActive is uncached and used by form-builder during transformPattern, because the source calls findAll rather than findAllWithCache at that point. With a cache there, an admin editing a rule would still see forms using the stale version.

If no Redis client named redis exists, the service degrades to reading live without panicking.

Key Files & Functions

ItemValue
RouteGET /api/form-builder-rule
Registerinternal/formbuilderrule/register.goRegister(r, deps)
Handlerinternal/formbuilderrule/handler.go(*Handler).Test
Serviceinternal/formbuilderrule/service.goFindAllWithCache, FindAllActive, getRedisKey
Repositoryinternal/formbuilderrule/repository.goFindAllActive
Entityinternal/formbuilderrule/entity.goFormBuilderRule, whose Properties is raw JSON
ConstantsmoduleName = "FORM_BUILDER_RULE", findAllKey = "findAll", and optionsJSON

Connections to Other Services

  • The form_builder_rule table (status and the jsonb properties).
  • internal/cache, a namespaced Redis wrapper backed by the client named redis; namespace and TTL come from deps.Config.RedisCache.
  • internal/util/hash.goGenerateShortHash.
  • Consumed by Loading a Form's Structure during transformPattern, and by Form Answer Submission through the formbuilder.Service it assembles in its own register.
  • The related client-web feature is form-fill, which uses the merged commonRule to validate on the client before submitting.