Webシステムにおける電話番号の扱い
2025年01月段階の話になっている。
## 標準仕様
色々と規格が散っていたり、ローカル特有の事情があったりするものの、形式的にはE.164仕様に準拠する形でストアしておけば困ることは少ないと思う。 ## well-known library
## フロントエンド
表示する際は、hrefにtel:prefixを付加しておけば、クリック・タップで電話アプリが起動するアレができる。
<a href="tel:080-0000-0000">080-0000-0000</a>
フォームを楽に入力してもらう場合、
type属性をtelにしておく
pattern属性を入れる
ただし、一つの正規表現で済ませられるのは、国際電話番号対応やその他特殊な対応をしないフォームに限られる
また、ハイフンをユーザーに打たせないフォームの方が、入力を完了してもらいやすい(ハイフンは類似文字が多い上に、クライアントの仮想キーボードがテンキーっぽいやつだった場合、そもそも入力できない場合がある)
## バックエンド
phone_numbersみたいにテーブルを切り出してあげるかはシステムがどう扱うかによる。ユーザーとか事業所とかの単位で持っていた方が便利なケースもある。
ストアする形式はやはり国際電話番号として通用する形式の方が良い。「国内サービスだから国外事情を考慮しなくて良い」という状況においても、そうすることには幾らかのメリットがある。
外部SaaS連携時に渡しやすい
ライブラリの恩恵を受けやすい
とはいっても、絶対にそうしなければならないという類ではないので、個々のコンテキストと相談。
永続化層ではしっかりめの形式、表示側は我々が普段見慣れている国内形式、というように分ける。
形式変換は(オブジェクト指向なら)PhoneNumberクラスで持って各所で使うか、ViewModelやPresenter的な層で変換かけてあげるか、あるいはその両方の組み合わせでやってあげると腐敗防止的によろしい。
ValueObject的にモデリングするのも悪くはないものの、システム固有ドメインに電話番号が影響を受けることは考えにくい(標準に近いところで話が済むケースが多いはず)ので、基本的にはライブラリにラッパー噛ませたものを引き回す方向性で良い、と筆者は思う。
## SMS Sendableな番号をどう判定するか
明らかに送れない番号系を判定することはできる。つまり、送れないことの十分条件は特定しやすい。国内なら例えば03-番号(東京都の市外局番、携帯電話ではない)はNot Sendableである。初回ストア段階で送信不能判定してしまって良い。
逆に、個別の携帯電話番号が実際にSMS Sendableかを事前に特定するのは厳しい。なので、実際に送って確認する。
多くの場合、SaaSのAPIを利用してSMSを送る仕組みを採用しているだろうから、そのレスポンスをみて、何らか妥当な規則で当該番号に対してステータスを付与してあげるのが良いと思われる。そのシステムにとって許容できるdead letterかどうか、というのは考慮する必要があるにしても。
ちなみにこの手の値はbool値で想定しない方がいい。例えば、'sendable' | 'not_sendable' | 'unknown'などのような列挙子を考えておくと、扱いやすい。
また、システムからSMSを送らない、あるいはSMS配信拒否状態の番号もあるはずだ。送れるかどうかとは別軸でこれも必要に応じてカラム追加しておくと良い。
## IP電話
余談に近いが、一応触れる。国内なら050などはIP電話に割り当てられている(そうだった気がしているが、ちゃんと裏取りはしていない)。
システムが単純な桁数判定で携帯電話判定をしていて、それをそのままSMS送信とかに流していると、この番号とかでエラーが生じたりする。ちゃんとハンドリングしているならすぐ分かるものの、場合によっては実際のリクエストログを追うところまで行きかねないのでそのあたりしっかり実装しよう(戒め)。
以前、Firebase AuthenticationのSMS認証を単要素で認証要素にしているシステムを触っていたが、実際それでユーザーが登録できずに困っていたことがある(ただ、これに関しては画面設計の問題でもあるように思う。単に電話番号ラベルと090番号のプレースホルダーをおいているだけでは、SMS送信できるかどうかが登録条件になっていることに気づかない。また、そもそもSMS受信可能な端末と回線契約を所持していることが条件になる分、知識要素認証などよりもアクセシビリティが落ちるということもある)。
## SaaSとか
SMSを送るサービスならTwilioがよく知られていて、コスト的に許容できるならこれで良い。
ただ、SMS送信はわりかし高価なので運用する通数対プライスでPL合理性が出るかどうか、という純粋に利益計算的な選定も必要となってくる。