OTP Verification Settings
Overview
OTP Config is a LINE OA level setting that determines whether phone number verification by OTP is enabled and, if so, how it behaves. It applies to forms that need confidence the phone number entered genuinely belongs to the person filling them in.
What makes this module unusual is that it is a per-OA singleton: the otp_config table has
a unique constraint on line_oa_id, so instead of multi-row CRUD there are only GET and PUT,
where PUT performs an upsert. If no configuration exists yet, GET returns an empty or default
config rather than a 404, because "not configured yet" is a normal and common state.
This module was written fresh for the Go implementation and has no NestJS predecessor.
Business Flow
- The user opens the OTP settings screen in cms-web, which calls
GET /api/otp-config. The service reads theotp_configrow matching thelineOaIdin CLS. When no row exists it returns a default or empty config representing the "not configured" state, without throwing. - The user fills in the settings — whether OTP is enabled, the delivery provider, code length, code lifetime, and message text — then saves.
PUT /api/otp-configperforms an upsert keyed online_oa_id, updating the existing row or creating one if none exists.- Forms with OTP enabled read this configuration at runtime. client-api sends the OTP to the respondent and only accepts the form submission once verification succeeds.
- With OTP disabled, forms accept submissions immediately with no verification step.
Key Files & Functions
Core code lives in internal/modules/otpconfig/, comprising controller.go, service.go,
and dto.go.
| Method | Route | Handler | Policy (metadata) |
|---|---|---|---|
| GET | /api/otp-config | ct.get | read otp-config |
| PUT | /api/otp-config | ct.upsert | update otp-config |
Both routes are registered on the authed group, which applies global JWT authentication; no
ModuleGate wraps them. The code follows the structure of the quickreply module, adapted to a
singleton as described in the doc comment in service.go.
Connections to Other Services
- Access control — requests must pass global
JwtAuthand the token must carry alineOaId. ThePolicyModuleOtpConfig = "otp-config"enum is aligned with cms-web'sMODULE_URL.OTP_CONFIG. - Tables —
otp_config, with a unique constraint online_oa_id. - Context — reads
lineOaIdfrom CLS to scope the record. - Design spec —
docs/superpowers/specs/2026-07-26-form-otp-verification-design.md, section "1. OTP config store". - Consumers — Form Builder and line-management-client-api-go, which actually sends and verifies the OTP.