# 居場所のない人の村

> 固有のユーザーネームで書き込める、スレッド式の匿名掲示板。

- 制作: [ワカメ](https://wakame.dev/)（個人で企画・開発）
- ステータス: 公開中
- 制作期間: 公開中
- カテゴリ: Web, Tool
- 使用技術: Cloudflare Workers, Cloudflare D1, Hono, TypeScript, SQLite, PBKDF2-SHA256
- 担当: 企画, DB設計, 認証実装, NGワードフィルタ設計, SEO実装, 公開・運用

## 概要

どこにも居場所がないと感じている人が書き込める場所として作った、スレッド式の匿名掲示板です。Cloudflare WorkersとD1だけで動かし、外部サービスに依存しない構成にしました。HonoによるサーバーサイドレンダリングでJSのビルドを不要にし、認証はメール不要のユーザー名＋パスワード（PBKDF2-SHA256）で実装。場の空気を守るためNGワードフィルタを厳しめに設計し、伏字や当て字にも対応させたうえで92ケースの回帰テストを用意しています。メタ情報・robots.txt・sitemap.xml・構造化データ・OGP画像の生成まで作り込みました。

## 「自分に向けた言葉は消さない」を実装に落とし込む

居場所のない人が書き込む場所で、つらさの表明ごと機械的に消してしまうと、掲示板の存在意義がなくなります。そこでNGワードの扱いを2段構えにしました。

他人に向けた誹謗中傷・差別・自殺教唆・暴力・性的な書き込み・出会い目的・違法行為・宣伝・個人情報は投稿自体を拒否し、記録を残して違反カウントを加算します。一方で「死にたい」「消えたい」など自分のつらさを表した言葉は投稿を通し、相談窓口の案内を添えるだけにしています。他人に向けた「死ね」は弾き、自分の「死にたい」は受け止める、という線引きです。

自嘲に使われやすい語（底辺・詰んでる・メンヘラなど）も単体では通し、「お前」「あいつ」といった二人称・三人称と近い位置に出てきたときだけ攻撃とみなして弾きます。さらに、弾いた投稿でもつらさが読み取れる場合には相談窓口を併記するようにしました。

## 伏字と当て字をすり抜けさせない正規化

NGワードは、そのまま書く人より記号や当て字でぼかす人のほうが多くなります。そこで照合の前に、Unicode正規化（NFKC）→ 小文字化 → 不可視文字の除去 → 記号と空白の除去 → カタカナのひらがな化、という順で文字列をならしてから判定しています。

この手の処理は条件を足すほど誤検知が増えて、無害な投稿まで弾き始めます。そのため判定は1ファイルに閉じ込めたうえで、92ケースの回帰テストを用意して、ルールを足すたびに過去の判定が壊れていないか確認できるようにしました。

## モデレーションを「勘」でやらない管理画面

管理画面には、概況・通報・住民・小屋（スレッド）・NG検出の5つのタブを用意しました。未処理の通報や24時間のNG検出数、住民数・投稿数といった数字を出し、異常値は赤く表示します。

運用でいちばん見ているのはNG検出タブの「よく検出される語」のランキングです。身に覚えのない語が上位に来ていたら、それは誤検知で無害な投稿が弾かれているサインなので、許可する語として登録します。弾かれた側からは何も言ってこないので、こちらから見つけにいく仕組みが要ります。

事故を防ぐための制約も入れました。管理者は自分自身をミュート・追放できません（自分を締め出して管理画面に入れなくなるのを防ぐため）。また、通報された投稿を削除すると、その投稿への通報は自動で処理済みになります。

## 外部サービスを使わない構成

Cloudflare Workers と D1 だけで完結させ、外部サービスは使っていません。画面はHonoによるサーバーサイドレンダリングで、フロントエンドのビルド工程自体がありません。

認証はユーザー名とパスワードのみでメールアドレスを取っていません。パスワードは PBKDF2-SHA256 でハッシュ化して保存しています。連絡先を預からないことは、匿名の掲示板としては機能ではなく前提だと考えました。

## 成果

- Cloudflare Workers + D1 で公開・運用中
- NGワードフィルタに92ケースの回帰テストを用意
- サーバーサイドレンダリングでビルド不要の構成

## リンク

- [サイト](https://mura.wakame.dev/)

## このサイトについて

- [ワカメの詳細プロフィール](https://wakame.dev/ai-profile/index.html.md)
- [llms.txt](https://wakame.dev/llms.txt)
