どうも、寒すぎて色々としんどい Xu です。
皆さんは LINE のオープンチャット機能を利用したことありますでしょうか?
オープンチャットについて
初めて公開されたのは 2019 年あたりだったかな、学生のときに当時の LINE Developers day に参加して、みんな気になってたけど賛否両論な意見がトボ回ってたのは今でも記憶に新しく、まだ AWS もロクに使えなくて、セッションの内容半分以上理解できなかったなーと...
オープンチャットの特徴としては、匿名性が高くて、誰でも参加可能(制限があったりもする)。
参加をリクエストするとまずはそのチャット用のプロフィールを新たに設定するので、本名を隠して利用することもできます。

きっかけ
さて、そんなオープンチャット(以下略して OC)ですが、筆者はよくエンジニアが集まる OC で色んなエンジニアと交流しており、ある日メンバーがローカル LLM の話で盛り上がり、じゃあ一緒になにか作ろうよという流れになっておりました。
筆者は最近家庭や千住Meetup! の運営で忙しく、なかなか他人のプロジェクトに参加する余裕がなく、ただただ眺めてましたが、せめてなにかしてあげようと思い、オープンチャット用に、アイディア発案者と興味を持った参加者が気軽にマッチングできるようなアプリを作ろうと思いました。
サービスの前提と機能設計
そうと決まればまずは要件定義から始めよう。
まずみんな OC のメンバーだ、そもそもの大前提として、OC 内で自由に他のメンバーを友だち追加することはできない。
そんな OC を利用する目的は、ただ簡単に交友関係を広げるだけでなく、普段のリアルな自分と切り離して完全に匿名で利用できることに参加しやすさがあるのではと思いました。
ビジネス要件
- 少なくとも表向きには匿名であり、個人情報を載せる必要がない
- アイディアを載せれて、OC 内の誰が載せたか、今何人挙手しているかわかりやすいようにする
- OC の利用規約に抵触しないように、オフラインでの接触を促したり、 OC 内に個人情報が流れたりしないようにする
- 話の流れを遮ったりせず、関心がない人の邪魔にならず、人前で話すのが苦手な人も参加しやすいように OC 以外でやり取りを推奨する
- 発案者と参加者がマッチングしたら自己責任で連絡先を交換できるようにする
- ストレージを買うお金ないからチャットルームやログイン機能は作らない
- できるだけ個人情報を含むデータをこっちで持たないようにする
機能設計
個人開発はまずは動くものを作るところから。機能は簡単で構いません。
やることとしてはほぼ ToDo アプリを作るようなもんです。
[入力情報]
- アイディアのタイトル
- 説明文
- ユーザー名(OC で使っているものと一致するのが望ましい)
- メールアドレス(通知受け取り、マッチング後のやり取り用)
- 参加ボタンクリック時:
- ユーザー名
- メールアドレス
[表示情報]
- 入力情報入力欄
- 募集開始ボタン
- サービスの利用方法
- 現在募集中のアイディア一覧:
- アイディア名
- 説明文
- 発案者
- 参加人数
- 参加ボタン
[バックエンド側の処理]
- 発案時:
- Blob に JSON ファイルを生成し、ユニークキーで命名して入力情報を保存
-
Index.jsonにユニークキーをリストに追加 - UI にアイディアを表示
- 参加申請完了時
-
<table>要素から Blob に対応する Id を取得し、Index.jsonから該当キーが存在するか確認 - 存在する場合は対応する JSON ファイルを読み取り発案者メールアドレスをメール送信モジュールに渡す
- Resend によるメール送信
-
今回は削除や修正などの機能はつけませんでした。
まずはある程度運営して見て、どれくらいの利用者数で、どのような機能があったらいいのかを見てから決めたいと思いました。
サービスも人のように時とともに成長するものだと思っております。
これらを踏まえて、以下のような技術選定をしました。
[技術選定]
- アプリ: Next.js
- ホスティングサービス: Vercel
- データ永続化方法: Blob 無料枠
- IP ドメイン: Cloudflare で取得
- マッチング通知/やり取り方法: Resend によるメール送信
なぜドメインを取ろうと思ったかというか、単純に OC 名が面白かったから先に取りたかったってだけです。
特に必要性はありません。
Next.js を選んだ理由は、どちらかというと、無料でホストできる Vercel を使うために今最も熱くてしっかりサポートされている言語を選んだ感じです。
- Vercel について
Blob を使うのはそこそこ無料枠があり、
- Blob について
Resend に関しては単純にどうせドメイン取るなら今回使ってみたいのと、できるだけ情報を持ちたくないので、なるべく処理を外部サービスにやらせたいと思いました。
- Resend について
月 3000 件まで無料で送信できるので、まあ十分でしょう。
開発フェーズ
ディレクトリ
project
|-app
| |-layout.tsx
| |-global.css
| |-pages.tsx
| |-api
| |-aplly
| | |-route.ts
| |-ideas
| |-route.ts
|
|-ideas-index.json
|-lib
| |-blob.ts
| |-mail.ts
| |-rateLimit.ts
| |-utils.ts
|
|-types-idea.ts
|-package.json
|-tsconfig.json
アプリ自体は本当に簡単で、ToDo に毛が生えたくらいの構成です。なので今回は一個一個コードは載せません。
気になる方は GitHub の方をご参照ください。
完成品はこちら、驚くくらいにシンプルですよね。サンプルとして 2 つくらいプロジェクトを載せときました。

工夫した点としては、荒らし対策としてリクエスト頻度と、あくまで他人のデータを扱うので sha256 暗号化通信を入れたところです。
const store = new Map<string, { count: number; time: number }>();
export function rateLimit(key: string, limit = 5, interval = 60_000) {
const now = Date.now();
const record = store.get(key);
if (!record) {
store.set(key, { count: 1, time: now });
return;
}
if (now - record.time > interval) {
store.set(key, { count: 1, time: now });
return;
}
if (record.count >= limit) {
throw new Error("Too many requests");
}
record.count++;
}
import crypto from "crypto";
export function sha256(text: string) {
return crypto.createHash("sha256").update(text).digest("hex");
}
export function now() {
return new Date().toISOString();
}
### Cloudflare と Resend 設定
Resend は直接公開メールサーバーをプロバイダーとして設定できず、カスタムドメインを取得する必要があります。
基本的に Cloudflare の Email Routing を使って転送し、Gmail をメールサーバとしてます。
具体的な設定手順は以下の記事て詳細にまとめられているので、ここでは省略します。
ドメイン設定
ほぼ Vercel 側で自動的にやってくれます。
Settings → Domains → + Add
実際にリリースして
というわけで、開発は終わったので、早速 OC の方たちにシェアしてしばらく経ちました。
全く使われている痕跡がないです笑。まあこれは割と想定通りです。
一部メールアドレスを登録するのがハードル高いとフィードバックをいただきました。
正直現状で他にもっと心理的ハードルが低くて、みんなが使っているサービスも思いつかないのが現状(Discord や X などは全員やっているわけでもなさそうですし、交換したいとも限らない)。
メールアドレスなんて、マッチングして連絡先交換するまでの使い捨てのものでも作っとけばいいじゃん!と思ってしまった次第でした。
あとがき
一旦ざっくりとした感じで今回は書きましたが、前述したように、自分や家族にとって今はかなり忙しいく、余裕がない時期であるため、ご了承いただければと思います。
今のところは、成果報告機能でも追加していいのかなと思ってます。
メールアドレスを入力して予め作成時に入力したものと一致すれば投稿できるような感じで。
まあそれはまた追々お話をする機会があればと思います。
それでは今回はこれにて失礼いたします。
