Skip to content

feat(kyc): expose validation formats so clients don't hardcode the swissPaymentText regex#3911

Open
TaprootFreak wants to merge 1 commit into
developfrom
feat/expose-validation-formats
Open

feat(kyc): expose validation formats so clients don't hardcode the swissPaymentText regex#3911
TaprootFreak wants to merge 1 commit into
developfrom
feat/expose-validation-formats

Conversation

@TaprootFreak

Copy link
Copy Markdown
Collaborator

Closes #3910

What

Adds a lightweight, cacheable GET /v1/config endpoint that surfaces the authoritative input validation pattern(s) from Config.formats, so API consumers validate user input against an API-provided value at runtime instead of hardcoding a mirror of the regex.

// GET /v1/config
{
  "formats": {
    "swissPaymentText": {
      "pattern": "^[\\x20-\\x7E…ß\\n]*$",
      "flags": "u"
    }
  }
}

Clients compile new RegExp(pattern, flags) once per session and use it for inline validation. The server keeps re-validating authoritatively (@IsSwissPaymentText(), unchanged).

Why

Per CONTRIBUTING.md → "API as Decision Authority", which characters are valid is a business rule the API owns and clients render, not re-implement. Today the RealUnit app keeps a byte-for-byte copy of the regex; if Config.formats.swissPaymentText changes, every consumer's hardcoded copy silently diverges. This also tempted a client into a stricter-than-API postal-code rule that blocked foreign alphanumeric ZIPs (NL 1011 AB, UK EC1A 1BB, …).

Design notes

  • Single source of truth — the endpoint derives pattern/flags directly from Config.formats; nothing is duplicated. A unit test recompiles the exposed pattern and asserts it behaves identically to the server-side validator for representative inputs (no-drift guard).
  • Static info in Swagger (capability rule Feature/kyc userdata #2) — the endpoint is documented (ConfigDto) rather than per-user on /v2/user.
  • YAGNI (rule Using KYC table #3) — ships only swissPaymentText (the concrete consumer need). The typed FormatsDto map lets further patterns be added additively/backwards-compatibly.
  • Backward compatible — additive endpoint; legacy clients keep their current behaviour, new clients consume the pattern.
  • CacheableCache-Control: public, max-age=3600.
  • Keyboard type stays a pure client affordance — the API does not dictate UI keyboards.

Cross-consumer

Benefits every consumer that mirrors the regex. Adoption happens in follow-up pair-PRs (e.g. RealUnit app) once this lands on develop, deleting the local mirror in the same PR (rule #6).

Tests

src/app.controller.spec.ts:

  • exposes swissPaymentText with pattern/flags equal to Config.formats.swissPaymentText
  • recompiled pattern matches the server-side validator for accepted (Swiss diacritics, foreign ZIPs) and rejected (emoji, Cyrillic, CJK) samples

Run locally on m5me (node 20.20.2): format:check, type-check, eslint, and the spec — all green.

…issPaymentText regex

Add a lightweight, cacheable GET /v1/config endpoint that surfaces the
authoritative input validation pattern(s) from Config.formats. Clients
fetch it once and validate user input against the API-provided regex at
runtime instead of keeping a hardcoded mirror that silently drifts when
Config.formats changes.

Currently exposes swissPaymentText (the allowed character set for
name/address fields). The response shape is a typed formats map, so
additional patterns can be added additively without breaking clients.
The field is optional from a consumer's perspective: legacy clients keep
their existing behaviour, new clients consume the API pattern. The server
keeps re-validating authoritatively.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(kyc): expose address validation pattern so clients don't hardcode the swissPaymentText regex

1 participant