しごおわなので開発始める
ボチボチスマホアプリ化にも手を付けるかな〜(始めて3日目)
このコミュニティサイトは、Djangoというフレームワークを使って1から作りました。今回から10回に分けて、その開発の記録を書いていきます。 まず最初に決めたのは「どんな見た目のサイトにするか」でした。ただの掲示板ではなく、投稿・タグ・いいねがある、Twitterのタイムラインに近い見た目を目指しました。文字だけがずらっと並ぶ無機質なページではなく、誰かの日常が流れているような、温かみのある画面にしたいと考えていました。 配色は、サイト名の「Heaven Portal」に合わせて、ラベンダーがかった白背景に、空色と後光のような金色をアクセントカラーにしています。見出しには明朝体、本文にはゴシック体を使い分けて、柔らかい雰囲気を意識しました。フォントの組み合わせひとつで、サイト全体の印象がかなり変わるので、ここは何度か試行錯誤しました。 投稿一覧のカードデザインは、影を薄くつけて浮かび上がるようにし、投稿者のアイコン・本文・タグ・いいねボタンを1つのカードにまとめています。長い投稿は500文字を超えると自動で折りたたまれ、「続きを読む」で全文表示できるようにしました。 サイドバーには「新着記事」「アクセス数順」「いいね順」を表示し、どのページからでも人気の投稿にたどり着けるようにしています。こうしたデザインの細部は、一度作って終わりではなく、実際に使ってみて感じた「なんとなく使いにくいな」を、都度直していく繰り返しでした。 投稿作成画面についても、最初は文字数の上限をかなり短く設定していたのですが、実際に運用してみると窮屈に感じることが多く、後から思い切って上限を広げました。見た目の美しさと使いやすさは、頭の中で考えているだけでは分からず、実際に自分で触ってみて初めて気づくことが多いというのが、ここまでの一番の学びです。 次回は、投稿とタグの仕組みについて書きます。
今回は、サイトの中心的な機能である「投稿」と「タグ」について書きます。 投稿機能では、タイトル・本文・画像・タグをまとめて登録できます。画像のファイル名は、そのまま保存すると日本語や特殊文字が原因でエラーになることがあったため、ランダムな文字列に変換してから保存する仕組みにしました。実際、開発の途中で特定の画像だけアップロードに失敗する不具合が起きて、原因を探ったところ、日本語混じりのファイル名がストレージ側で受け付けられていなかったことが分かり、この対策を入れることになりました。 タグは投稿作成時にカンマ区切りで入力するだけで、自動的に新しいタグとして登録されます。日本語のタグ名にも対応していて、タグごとの一覧ページも自動で生成されます。ここでも一度、日本語タグのページだけ表示されないという不具合があり、URLの設定を見直して直しました。 タグの入力欄については、テンプレート側で参照している項目名がずれていたせいで、しばらくの間タグが正しく保存されないという不具合が続いていたこともありました。地道に原因を切り分けていく作業も、開発の醍醐味のひとつだと感じています。 さらに、投稿の一覧では、長い投稿を最初から全文表示すると画面が間延びしてしまうため、500文字を超える投稿は自動的に途中で折りたたみ、「続きを読む」ボタンで全文を展開できるようにしました。タイムライン全体の見やすさを保ちながら、長文もしっかり書けるようにする、両立が難しいポイントでした。 次回は、匿名投稿もできる掲示板機能について書きます。
今回は、匿名でも書き込める掲示板機能について書きます。 掲示板は、2ちゃんねる風の匿名投稿ができる仕組みにしました。名前を入力しなければ「名無し」として投稿でき、「名前#秘密の文字列」の形式で入力すると、その文字列をもとにした「トリップ」という短い符号が名前の後ろに付きます。同じ文字列を使い続ける限り、名乗らなくても同一人物だと分かる、昔ながらの仕組みです。 この掲示板機能は、もともと投稿機能と同じアプリの中に間借りする形で作っていたのですが、役割が大きく異なるため、途中で独立したアプリとして切り出しました。切り出す際には、データベースのテーブルを新しく作り直す形をとり、幸い当時はまだ利用者がいなかったため、データ移行の心配なく進めることができました。 また、同じ人が連続で投稿しすぎないように、投稿後30秒間は再投稿できない制限も入れています。荒らし対策として、匿名投稿者のIPアドレスも記録するようにしました。 掲示板を独立させる作業の中で、テンプレート内のリンク先の指定がひとつだけ古いままになっていて、レス投稿ボタンを押すとエラーになる不具合も起きました。こうした「移行時のうっかり漏れ」は、実際に手を動かしてみないと気づきにくいものだと実感しました。 トリップの仕組みは、入力された秘密の文字列をそのまま保存するのではなく、ハッシュ関数という一方向の変換をかけてから短く切り出して保存しています。これにより、元の文字列が漏れる心配をせずに「同じ人らしさ」だけを示せるようになっています。昔からある掲示板文化の知恵を、実際に自分で実装してみると、その巧妙さに感心させられます。 次回は、SNSアカウントでログインできる仕組みについて書きます。
今回は、GitHub・Google・Discord・X(旧Twitter)・LINEでログインできる仕組みについて書きます。 パスワードを別途覚えてもらう必要がないよう、普段使っているSNSアカウントでそのままログインできる仕組みを用意しました。django-allauthというライブラリを使うと、複数のSNS認証を比較的簡単に組み込めます。 苦労したのは、各SNSごとにプロフィール情報の形式がまったく違う点でした。アイコン画像ひとつとっても、GitHubは直接URLを返しますが、Discordは画像のハッシュ値からURLを組み立てる必要があり、LINEは長い署名付きのURLを返してきます。それぞれに合わせて、ログイン時にアイコンを自動取得して保存する処理を書きました。 LINEログインを追加したときは、権限の指定が足りずにエラーになったり、返ってきたアイコンURLが長すぎてデータベースに保存できなかったりと、いくつもの壁にぶつかりました。ひとつずつエラーメッセージを読み解きながら直していく作業は根気が要りますが、直った瞬間の達成感は大きいです。 複数の環境(クラウドと自宅サーバー)でサイトを同時に動かしている都合上、各SNSの管理画面に登録するコールバックURLも、環境の数だけ用意する必要がありました。プロバイダーによっては、1つのアプリに登録できるコールバックURLが1つに制限されているものもあり、環境を増やすたびに設定を見直す必要があることも分かりました。 こうして地道に対応を重ねた結果、今ではGitHub・Google・Discord・X・LINEの5種類のアカウントで、それぞれ気軽にログインできるようになっています。選択肢が多いほど、初めて訪れた人にとって「わざわざ新しいアカウントを作らなくていい」という安心感につながると感じています。 次回は、サイトの訪問者数やアクセス状況を記録する仕組みについて書きます。
今回は、サイトの訪問者数や、投稿ごとの閲覧数を記録する仕組みについて書きます。 このサイトには、投稿ごとの閲覧数を記録する機能と、サイト全体のユニーク訪問者数を記録する機能の2つがあります。ログインしている人はユーザーIDで、していない人はブラウザに保存したCookieで、重複してカウントされないようにしています。 サイト全体の訪問者数は「同じ人が同じ日に何度訪れても1カウント」という数え方にしています。実装の初期段階では、ログイン済みかどうかで検索の条件を変えてしまっていたため、未ログインで訪れた人が後からログインした瞬間にエラーになるという不具合がありました。原因を調べたところ、データベースの一意性制約に違反していたことが分かり、常に同じ条件で検索するよう修正しました。 集計したデータは、サイドバーの「新着記事」「アクセス数順」「いいね順」や、フッターの「累計訪問者数」として活用しています。数字が伸びていくのを見るのは、運営者としても素直に励みになります。 こうした指標は、単に眺めて満足するためのものではなく、どの機能が実際に使われているかを把握し、次に何を改善すべきかを考えるための材料としても活用しています。 なお、こうした記録の仕組みを作る際は、個人を特定できる情報をむやみに集めすぎないよう注意を払いました。IPアドレスなどの情報は不正対策のために最小限記録していますが、それが何のために使われるのかを、プライバシーポリシーのページできちんと説明するようにしています。数字を集めることと、利用者の信頼を保つことは、両方とも欠かせない要素だと考えています。 次回は、このサイトの収益化の仕組みについて書きます。
個人サイトを長く続けるには、多少なりとも運営費をまかなえる仕組みがあると助かります。今回は、このサイトに組み込んだ収益化の工夫について書きます。 まず取り入れたのは、Amazonアソシエイトともしもアフィリエイトという、アフィリエイト広告の仕組みです。紹介した商品がリンク経由で購入されると、紹介料の一部を受け取れます。Amazonアソシエイトは、登録してすぐに正式参加になるわけではなく、一定期間内に第三者による購入実績が必要という審査の仕組みがあることも、実際に申し込んでみて初めて知りました。 サイト内には「おすすめ商品」という管理用の仕組みを作りました。商品名・リンク・画像に加えて、提携先が発行するバナーコードをそのまま貼り付けられる欄も用意し、柔軟に広告を差し込めるようにしています。もしもアフィリエイトのように、広告ごとに掲載条件が細かく決まっているケースもあるため、規約を都度確認しながら組み込みました。 表示場所は2箇所です。1つはサイドバーで、タグページを見ているときはそのタグに関連する商品を表示します。もう1つは投稿の一覧で、10件ごとに「広告」と明記した形で自然に挟み込む仕組みにしました。広告だと分からないような紛らわしい表示は避け、必ずラベルを付けています。 収益化にあたっては、プライバシーポリシーと広告についてのページも作成し、どんな情報を集めているか、アフィリエイトプログラムに参加している事実をきちんと開示するようにしました。 広告を導入すると、どうしても「読者の体験を損なわないか」という点が気になります。表示位置や頻度を調整しながら、投稿本来の内容が埋もれてしまわないよう、控えめな見せ方を意識しました。今後は、投稿してくれたユーザー自身が、自分の投稿におすすめの商品リンクを添えられるような仕組みも育てていきたいと考えています。 次回は、検索エンジンに見つけてもらうためのSEO対策について書きます。
どれだけ良いサイトを作っても、検索エンジンに見つけてもらえなければ意味がありません。今回は、このサイトに施したSEO(検索エンジン最適化)対策について書きます。 まず基本として、各ページに「メタディスクリプション」という、検索結果に表示される説明文を設定しました。投稿詳細ページでは、その投稿の本文の冒頭が自動的に説明文として使われる仕組みにしています。 次に、SNSでシェアされたときの見た目を整えるOGPタグを設定しました。これにより、LINEやX(旧Twitter)にリンクを貼ったとき、タイトルや画像がきれいなカード形式で表示されます。この設定を入れる前は、リンクを貼ってもただの文字列にしか見えなかったので、見た目の印象がかなり変わりました。 検索エンジンに正しく認識してもらうために、サイトマップという一覧ファイルも自動生成しています。投稿やタグが増えるたびに、内容も自動で更新される仕組みです。さらに、投稿詳細ページには「構造化データ」という、Googleが記事の内容を理解しやすくするための特別なデータも埋め込みました。画像がない投稿でエラーになるという不具合が一度起きましたが、条件分岐を見直して解消しています。 こうした対策を一通り終えたあと、Google Search ConsoleとBingウェブマスターツールにサイトを登録し、サイトマップを送信しました。ドメインを独自のものに切り替えた際は、この登録情報もあわせて更新する必要があり、地味に見落としやすいポイントでした。 さらに、更新の頻度を検索エンジンに伝えるためのRSS配信も用意しました。SNSでの告知だけに頼らず、興味を持ってくれた人が自分の好きな方法で更新をチェックできる導線を増やすことも、地道ですが大切な取り組みだと感じています。 次回は、サイトを安全に保つためのセキュリティ対策について書きます。