【個人開発】様々な界隈のあるあるを神経衰弱で遊び、Xで交流するサービスを作りました！

# はじめに
はじめまして、ぱきら @pakira-56A と申します。
プログラミングスクール『RUNTEQ』に、未経験で入学し卒業したばかりの初学者です。
ポートフォリオとして[『**あるある神経衰弱：界隈探求ゲーム**』](https://aruaru-games.com/)を開発しました。
　
以下に`当サービスの概要` `開発した理由` `機能` `技術構成` `こだわった点(差別化ポイント/推しポイント)` `セキュリティ面` を記載します。
（特に`推しポイント`が、かなりファットです😊ｳﾌﾌ）

###  サービス 『あるある神経衰弱：界隈探求ゲーム』
https://aruaru-games.com
### Githubリポジトリ
https://github.com/pakira-56A/aruaru-game


# 1. 当サービスの概要
#### あらゆる`界隈のあるある`を、神経衰弱で遊んで交流する コミュニケーション✖️ゲームサービスです。

- ユーザーが投稿した`界隈あるある`５つを印字したカードで、神経衰弱として遊べる
- ユーザーは、ゆかりのある界隈のあるあるを投稿・シェアできる
  - シェアし合うことで、SNS上(Xなど)のあらゆるカルチャーのユーザーとも交流ができる
- 投稿された`界隈`とゆかりがある/なしに関わらず、メジャーから超ニッチまで・あらゆるカルチャーを遊んで知れる
- 共通の趣味・話題がない間柄でも、互いを知り・深く交流できるようサポートします

:::note info
『`界隈のあるある`を、神経衰弱で遊ぶ』とはどういうことか、イメージしづらいかと思います。
以下が、『投稿された`コナンくん映画`という界隈のあるあるを、神経衰弱で遊ぶ』様子です！🃏
<img src="https://i.gyazo.com/892f21e7ada508929638e838cc00d8f4.gif" alt="Image from Gyazo" width="400"/>

:::

以下に詳しく機能ごとの動画を貼ってますが
## [こちらのリンクは`当サービスの全体の操作の流れ`を撮影したもの(3分)](https://drive.google.com/file/d/1ANewasmQ9Rs_Pi6g4G_ywwmX-Y41VhOE/preview)です

# 2. 開発をした理由
### コミュニケーションツールとして
開発者の私自身　趣味が多い方ですが、それでも趣味が共通しない方はまだまだいらっしゃいます。
**「○○さんと仲良くなりたいけど、話せる共通の趣味や話題がない...😖」** という時、上辺だけの会話になりがちですよね。
　
「どんなものやカルチャーが好きで」「物事をどんな捉え方をする人物なのか」「なぜそのカルチャーはそんな`あるある`が発生するのか」
お互いの**パーソナルな情報**・**オタクみを交換/認識**して遊べるようなゲームがあれば
共通の趣味や話題がなくても、コミュニケーションを取りやすいのではと考え開発しました。
　
例えば！！！
- 新しいクラスメイト、新入社員と同僚、最近通い始めた美容師さん、気になるあの子...🤫 
 「初めまして」のコミュニケーションツールになって欲しいです！
- もちろん、既に仲良し同士さんでも「君にそんな界隈に属す一面が！？」なんて発見になります
- 神経衰弱が苦手なユーザーでも、ただ「めくってあるあるを知る」という奇妙な体験ができます

　
おまけ（ご興味があれば、以下のトグルを開いてみてください）
<details><summary>開発者の個人的な願望もあります...☺️</summary>

:::note info
- 開発者は、ラジオで不特定多数の趣味・趣向の話を聴くのが楽しくて好きです📻 
 **まだまだ知り得ない界隈や、想像もつかない`あるある`** が溢れかえっています。
 個人的に、その`界隈あるある`をもっと知りたいと思ったからです  
- そして、その`あるある`はどのような経緯で発生するものなのか、**考察したり・お話を聞けると楽しいだろうな**と思ったからです
:::

</details>

<details><summary>ゲームの中でも、なぜ神経衰弱をチョイスしたのか？🧠</summary>

:::note info
**ズバリ、`界隈`や`あるある`に興味をもってもらう為です**
　
ゆかりがない`界隈あるある`に興味を持ってもらうため、投稿された`界隈あるある`をただ読むだけでは「ふーん」で終わってしまいます。
誰もが遊んだことのあるトランプゲーム、その中でも神経衰弱は「覚える」「思い出す」という工程を強いられます。
さらに「前にめくったカードの絵柄なんだっけ！？早くめくってスッキリしたい！」という感覚にもなりますよね。
　
当サービスのカードには絵柄ではなく、テキストが印字されています。
２枚目をめくってペアじゃなかった時、読み終わる前に裏返ってしまって「あぁ！今のカードの内容気になる！」という感覚も加わり
`ゆかりがない界隈`でも「あるあるを知りたい！！」という心理を誘えるなと考えたからです。
　
やらしいですよねー神経衰弱って💛
:::

</details>




# 3. 機能
### メイン機能
|`界隈あるある`を、投稿（ログイン必須） | `界隈あるある`を、AIで生成 |
|:-----------|:-----------|
| <img src="https://i.gyazo.com/29a22c4fa690fe35bea623e6ba9db7b3.gif" alt="Image from Gyazo" width="250"/> | <img src="https://i.gyazo.com/5883f9998ac62037dd9fbe2a70bcfdbb.gif" alt="Image from Gyazo" width="250"/> |
|ユーザーは好きな界隈のあるあるを投稿できます（文字数カウンター付き） | AIに界隈名を送信すると、あるあるが生成され神経衰弱で遊べます　|

| `界隈あるある`を、神経衰弱で遊ぶ | ゲームクリア後、交流や投稿を誘導 |
|:-----------|:-----------|
| <img src="https://i.gyazo.com/a941cbc143757cbeb471ae2d742ca34c.gif" alt="Image from Gyazo" width="250"/> | <img src="https://i.gyazo.com/73be1e99f22a78fb4418dd82a2ed2011.png" alt="Image from Gyazo" width="480"/> |
|ペアを作りながら`あるある`を知ることができます | Xに遷移し`感想`をポスト・閲覧できることを提示（ユーザーのログイン状態によって誘導が変化）|

|`界隈あるある`をXシェア（動的OGP） | Xで`界隈あるある`の感想を閲覧できる |
|:-----------|:-----------|
| <img src="https://i.gyazo.com/d50a738f9f45d75a10f98067a450517b.gif" alt="Image from Gyazo" width="250"/> |<img src="https://i.gyazo.com/cf356fd03fef4a530501cc2d670d11ac.gif" alt="Image from Gyazo" width="250"/>|
|界隈名がX上でハッシュタグ化し、動的OGPが表示されます | 他ユーザーがシェアした感想をXで閲覧・交流ができる |

### サブ機能
| 投稿された`界隈`を、タグで絞り込み | 検索 |検索（ヒットしない場合）|
|:-----------|:-----------|:-----------|
| <img src="https://i.gyazo.com/c631388adb5ed9066e82a318b439e55c.gif" alt="Image from Gyazo" width="250"/> |<img src="https://i.gyazo.com/611e1f54f8062f1d65a1549c2c6981e8.gif" alt="Image from Gyazo" width="250"/>|<img src="https://i.gyazo.com/3337c830b4cda69e58d015c49adbd65d.gif" alt="Image from Gyazo" width="250"/>|
| 投稿されたタグから、近い界隈を検索できます | 界隈名を直接検索できます（オートコンプリート付き）|検索結果がヒットしない場合は新規投稿を促します |

|自作したあるある一覧・設定（ログイン必須） | お気に入り機能（ログイン必須） |
|:-----------|:-----------|
| <img src="https://i.gyazo.com/d540bd47616785b1fc7deac3adf99c58.gif" alt="Image from Gyazo" width="250"/> | <img src="https://i.gyazo.com/7a1f29b6c12a27ae30a56b57a7c6dafc.gif" alt="Image from Gyazo" width="250"/> |
|ログインしたユーザー名と、投稿した`界隈あるある`を確認し遊べます | 誰かが投稿した`界隈あるある`をお気に入り登録し、再び遊びやすくなります |

### その他
- gem "devise"・Google認証を使ったユーザー登録・ログイン機能
- 検索時のオートコンプリート機能
- 投稿時の文字数カウンター機能
- トップページに、遊び方を表示したモーダルを設置
- 存在しないURLに対するエラーハンドリング(IDを含むもの・その他)
- Cokkieを使ったセッション機能
- CSRF対策
- XSS対策
- GitHub Actionsによるテスト自動化(RSpec・RuboCop)
- スリープ対策に[Uptime Robot](https://uptimerobot.com/)を活用
- お問い合わせフォーム（Googleフォーム）
- 利用規約
- プライバシーポリシー




# 4. 技術構成
### 技術スタック
| カテゴリ | 技術 |
| ---- | ---- |
| フロントエンド | Rails 7.1.3, TailwindCSS, DaisyUI, JavaScript, Stimulus |
| バックエンド | Rails 7.1.3 (Ruby 3.2.3 ) |
| データベース | PostgreSQL |
| インフラ | Render.com, [Uptime Robot](https://uptimerobot.com/), AWS S3 |
| 認証 | [gem 'devise'](https://github.com/heartcombo/devise), [Omniauth](omniauth), Google認証 |
| 開発環境 | Docker |
| API | OpenAI |
| アナリティクス | [Google Analytics](https://developers.google.com/analytics?hl=ja) |

### [画面遷移図](https://www.figma.com/design/7i6BdzFdxvh2EU5cKqbr7q/%E3%81%82%E3%82%8B%E3%81%82%E3%82%8B%E7%A5%9E%E7%B5%8C%E8%A1%B0%E5%BC%B1%EF%BC%88%E6%9C%AC%E3%83%AA%E3%83%AA%E7%89%88%EF%BC%89?node-id=0-1&t=30LoFr3hdgxxuKdq-1)
[![Image from Gyazo](https://i.gyazo.com/370df50dcc8384335f46adf9ec1943cb.jpg)](https://gyazo.com/370df50dcc8384335f46adf9ec1943cb)
- [お問い合わせ](https://docs.google.com/forms/d/e/1FAIpQLSc7aPOWo9En9Ctwj0gOaXP418BtiicSvX2KXx5dLRnwWJRlIg/viewform)：Googleフォームに遷移します
- Xシェアボタン：Xに遷移し、ポストができます
- `遊んだみんなの感想をXで見る`ボタン：Xに遷移し、[#あるある神経衰弱](https://x.com/hashtag/%E3%81%82%E3%82%8B%E3%81%82%E3%82%8B%E7%A5%9E%E7%B5%8C%E8%A1%B0%E5%BC%B1?src=hashtag_click&f=live) がついたポストを見れます

### [ER図](https://dbdiagram.io/d/あるある神経衰弱-670531e2fb079c7ebdbde9aa)
[![Image from Gyazo](https://i.gyazo.com/b7c00230b096af7a39f110cb9d8b3192.png)](https://gyazo.com/b7c00230b096af7a39f110cb9d8b3192)
- あくまで投稿は`○○さんが思う△△あるある`という形で扱うため、`Posts`テーブルに`aruaru_one`~`aruaru_five`までを設けています




# 5. こだわった点



## 5-1. 他のサービスとの差別化ポイント
### ❶ `ニッチな`あるあるで遊べるという差別化ポイント
`あるある`を使ったゲームは沢山ありますが、`誰もが共感できる無難なテーマ(界隈)`が決まってるものが多いです（小学生あるある・恋愛あるあるなど）
　
当サービスの特徴は・・・
- ユーザーが投稿するので、**メジャー/ニッチを問わず どんな界隈でも遊べる！**
- さらに、**ゆかりのない`界隈のあるある`を知れる・シェアできる！！！**（例：作品や業種の界隈など）
- コミュニケーションツールは沢山あるが、よりパーソナルな部分（特にオタクみ）に焦点を当てている
- いつでも、どこでも、すぐに遊べる（AIで生成した`界隈あるある`で遊ぶ場合は１ブラウザ１日１回）

### ❷ 他の神経衰弱ゲームとの差別化ポイント
当サービスで使うトランプカードの表面（めくった後に表示される面）には  
`ユーザーが投稿したあるある５つ` or `AIで生成したあるある5つ`の**文字列**が表示されます！

- ニッチな内容も投稿して欲しいので、`界隈名`と`あるある`はそれぞれ40文字まで
- カードがペアになると、**ペア同士で文字の色が変化します**  
  <img src="https://i.gyazo.com/6f10e83bd5f3856612f8094b19b31560.gif" alt="Image from Gyazo" width="380"/><img src="https://i.gyazo.com/6dceded7d313a601af37eb3b6deffbf2.png" alt="Image from Gyazo" width="250"/>

ちなみに神経衰弱の機能は、JavaScriptのサンプルコードから実装しました！

https://step-learn.com/article/javascript/157-trump-game.html

https://note.com/one_programming/n/n96176e4825d2


　
## 5-2. 推しポイント
### ❶ ユーザビリティ重視
- 暇な時にもゴロゴロしながら遊んで欲しいので、レスポンシブはスマホ重視
- レイアウトやデザインのコンセプトは
  `シンプル` `POPに` `文字の少ない説明で明確に` `アイコンの配置で導線を明確に`
- ログイン状態によって必要なボタンを表示するなどし、**操作の導線を明確にした**
  - ログイン済みなら`投稿しよう！ボタン`を、未ログインなら`ログインして投稿しよう！ボタン`を表示して誘導
    <img src="https://i.gyazo.com/73be1e99f22a78fb4418dd82a2ed2011.png" alt="Image from Gyazo" width="480"/>
　
- 投稿フォームに**文字数カウンターを設置**
  <img src="https://i.gyazo.com/1f32a7c931358ea56d6bf8e7a9d3ebbf.gif" alt="Image from Gyazo" width="500"/>
  `界隈名`、神経衰弱のカードに印字される`5つのあるある`ともに40文字までしか投稿できません。
  あるあるを入力していると「あの要素も詰め込みたいけど入るか！？」という心理になります。
  絶妙な40文字という制限をフルに楽しんでもらうためにも、文字数カウンターを設置しました。
  （超ニッチな界隈も投稿できるように、`界隈名`フォームも40文字まで入力できます！）

　
### ❷ 楽しめる演出
- ❷ **- 1.** クリックするワクワク感を出したいので、**リンクホバー時の変化を大きくしました** 
  - ゲームの方式が`神経衰弱`というだけで、抵抗感があるユーザーもいると思うのでワクワク感が必要と考えました。  
    <img src="https://i.gyazo.com/3f98f36d4874f175b24e12748de4bcd3.gif" alt="Image from Gyazo" width="700"/>
 　
- ❷ **- 2.** 投稿された界隈を検索した際、**ヒットしなかった場合に新規投稿を誘導**
  - 検索し、ヒットした場合はオートコンプリートを表示させています。
    しかし、ヒットしなかった場合は **「まだないよ！投稿しよう！」というメッセージと、新規投稿画面に遷移するボタンを表示し誘導**
    <img src="https://i.gyazo.com/a49b120ec044b9aa64029d47d26eb305.gif" alt="Image from Gyazo" width="700"/>
    検索する際の心理として、「自分の好きな界隈のあるあるが投稿されていたらいいな🥳」という期待もあると思います。
    しかし、**検索して「無い」と知っただけでは楽しくないので、「自分で投稿してみよう💡」という発想になってもらうように設置しました。**

　
- ❷ **- 3.** Xで交流しやすいよう、**Xのハッシュタグを設置・動的OGP機能を実装**  
  <img src="https://i.gyazo.com/d3957da5b8d99fc79d8c5e235e7ddc45.gif" alt="Image from Gyazo" width="700"/>
  
  - **Xのハッシュタグを設置**
    投稿された界隈名が`ONEPIECE：イーストブルー編`なら、Xシェア時には [#ONEPIECEイーストブルー編](https://x.com/search?q=%23ONEPIECE%E3%82%A4%E3%83%BC%E3%82%B9%E3%83%88%E3%83%96%E3%83%AB%E3%83%BC%E7%B7%A8&src=typed_query&f=live) というようにハッシュタグに変換します。
    また、ハッシュタグが無効にならないよう、`:`はハッシュタグ化させてません。
    `ONEPIECE`が好きな他のユーザーさんと交流できるきっかけになればと思います👒🍖
    
    - また、[#あるある神経衰弱](https://x.com/hashtag/%E3%81%82%E3%82%8B%E3%81%82%E3%82%8B%E7%A5%9E%E7%B5%8C%E8%A1%B0%E5%BC%B1?src=hashtag_click&f=live) というハッシュタグも用意しているので、`遊んだみんなの感想をXで見る`ボタンも設置できました。
       <img src="https://i.gyazo.com/e5d58700ece8e40aff7de3f1612b08ac.gif" alt="Image from Gyazo" width="500"/>
       　
  - **動的OGP機能**
    シェアされたOGPを見た他のユーザーに、興味を持ってもらえるよう
    「○○さんが思う△△あるある」という文字と、モザイクがかかったカードの画像を表示させました。
    - 個人的に、実装の仕組みを理解するのが最初難しかったです。  
      結果的にどう実装したかを記載した記事はこちらです！
 
https://qiita.com/pakira-56A/items/2993e6dfd3074b14b835

　
### ❸ 無駄を省いた
- ❸ **-1**. ユーザー情報や投稿の詳細画面など、**煩わしい画面遷移を設けませんでした**
　
  - **ユーザー情報の詳細画面を設けなかった理由**
    当サービスは、Google認証で取得した`ユーザー名`しかユーザー情報が登録されません。
    自作あるある一覧に`カレントユーザー名`を表示させ、ユーザー情報の詳細画面の役割を担っています。
    <img src="https://i.gyazo.com/a2816043cf67113651be80bd05a282d4.gif" alt="Image from Gyazo" width="700"/>
    `ユーザー情報の詳細画面`を設けず、ユーザー名の編集画面へ直行でき
    ユーザー名を変更した際は、**メッセージにも`変更後のユーザー名`を表示させています。**
    これらによって、`カレントユーザー名`が確認できるので、`ユーザー情報の詳細画面`は設けませんでした。
　
  - **投稿の詳細画面を設けなかった理由**
    当サービスは、カレントユーザーが投稿した`界隈あるあるを編集` `界隈で神経衰弱で遊ぶ`という機能もあります。
    <img src="https://i.gyazo.com/e48376733dd34caacff315520ea90cd4.gif" alt="Image from Gyazo" width="700"/>
    なので投稿詳細画面で、**投稿した`界隈あるあるを確認`という動作はそもそもする機会が無い**と考えました。
    - もし、投稿した`界隈あるあるを確認`するならば
    「それは神経衰弱で遊びながらでないと、当サービスの趣旨とズレてしまうな」という考えもあります。

　
- ❸ **-2**. 投稿のタグは、**スペース以外でも区切れる**
    <img src="https://i.gyazo.com/3990f315c19984a009dedbf49207f3dc.png" alt="Image from Gyazo" width="700"/>  
    - タグ化させる際、ユーザーは**スペース区切りでの入力が一番楽**だと思っています  
    スマホで入力する時、いちいちキーボートを記号に切り替えるなんて手間なんで🤮   
    - でも、PCユーザーが当アプリの仕様がわからず  
      `、` `。` `,` `.`などのスペース以外の区切りで入力しちゃう可能性があります！ 
      そんな時、**`スペース区切りで入力し直してね`なんてフラッシュメッセージが表示されたら手間**なので、スペース以外でも区切れるようになっています💪
　
### ❹ AI🤖で`界隈あるある`を生成できる機能 について
AIに任意の`界隈名`を送信すると、その`界隈のあるある`を生成してくれる機能です。

#### 実装目的は２点
- **チュートリアルとして活用するため**  
  - 当サービスは、初見だと`遊び方がイメージしづらい`という問題があると思います。  
  誰かが投稿した`ゆかりがない界隈あるある`で遊ぶ前に  
  **`自分が興味ある界隈のあるあるで遊ぶ`という体験がないと「取っ付きにくいサービスだ」と認識されかねない**と考えました。
　
- **投稿意欲を促すため**  
  - この機能に対して、純粋に「AIが思うあるあるってどんなの？」と疑問がわくと思います
    実際に生成してみると「AIにもこの共感あるの！？」「これってあるあるか！？」と思う内容を返してきます😂
  - その結果を見て「もっとあるだろ！」「自分だったらこー書くなぁ」という印象を受けると  
  「自分で投稿し、あるあるを知ってもらいたい」という気持ちになってもらえると考えました。

#### 工夫したこと
- **AIロボットはん（キャラクター付け）**
  - 当サービスのAIロボットは関西弁で、生成する`界隈あるある`も関西弁です。
    これは当サービスで表示されるフラッシュメッセージ等の`標準語`の対比で、キャラクター性を出しています。
    <img src="https://i.gyazo.com/5883f9998ac62037dd9fbe2a70bcfdbb.gif" alt="Image from Gyazo" width="350"/>

  
  - また、AIが生成する`あるある`の内容は結構いい加減です。
    いい加減な出力内容でも、可愛がってもらえるのが関西弁と思っているので採用しました（開発者は関西人です🐙💛）


# 6. セキュリティ面


- **Cookieを使ったセッション機能**🍪
  AIであるあるを生成するのは、Open AIを使います。
  ただ、回数制限を超えて使えなくなる事態を回避したいので、当サービスでは`1ユーザー1日1回`という設定を設けました。
  - AI生成機能を使ったブラウザではCookieを取得させ、その日付で「今日はもう生成済みか」を判別させました。
      <details><summary>補足：なぜCookieセッションを選んだのか</summary>

    :::note info

    **「今日はもう生成済みか」を判別する手段として、なぜCookieセッションを選んだのか**
    
    データベースのストレージ容量が圧迫するリスクがあるので、AIで生成した投稿をデータベースに保存させない事にしました。
    そして、キャッシュを使って判別する方法を模索し
    **ブラウザのタブを行き来しても、キャッシュを反映させたかった**のでCookieセッションを採用しました。
    
    ```ruby
    # cookieに保存
    Time.zone = "Tokyo"
    cookies[:cookie取得名] = { 
        value: Time.zone.today.to_s,     # 日本時間で
        expires: Time.zone.now + 1.day,  # 1日後に期限切れ
        secure: Rails.env.production?,   # 本番環境で動いているときだけクッキーはHTTPSを使って配送され、クッキーが盗まれるリスクを減らす
        httponly: true,   # XSS対策
        same_site: :lax   # CSRF対策
        }
    ```

    - **`httponly: true`**（XSS対策）
      **JavaScriptからそのクッキーにアクセスできなくり、XSS攻撃でクッキーが盗まれにくくなる記載。**
      ユーザーに与えたCookieの情報は、当サービスでは`その日付か否かの判別`にしか使いません。
      JavaScriptでCookieの情報を取得したりする機能は実装していませんし、実装予定もないので記載しました。

 
    - **`same_site: :lax`**（CSRF対策）
      **クロスサイトリクエストフォージェリ（CSRF）攻撃を防ぐ記載。**
      ユーザーがリンクをクリックしたり、他サイトからのGETリクエストを通じて、意図しない操作を実行されるリスクを減らせます。
        
        </details>

　
- **IDを含むURLのエラーハンドリング**
  存在しないURLや、存在しないIDが含まれるURLにアクセスした際は、メッセージを表示させています
  
  - **なぜメッセージなのか？**
    404ページに遷移すると、当サービスの存在するURLにブラウザバックする手間が発生します。
    なので、投稿一覧に遷移しメッセージで処理し、**引き続き 投稿で遊んでもらうため**です。
    （以下は現在存在しないID:1000が含まれる`https://ドメイン/games/1000/start`というURLで検証した動画です）
    <img src="https://i.gyazo.com/5fd44b49ee1a3542fa5480815eb90f3c.gif" alt="Image from Gyazo" width="1000"/>
    

# おわりに
2024年4月にプログラミングスクール『RUNTEQ』に入学し、カリキュラムを終え
2024年10月にREADMEを書き、当サービスの本リリースを無事迎えられました！

入学してから今まで、運営様・受講生さん、沢山の方々に沢山助けて頂きました。
皆様、ありがとうございました！
　
今回の実装の際に、沼って沼って折れそうになった機能がたくさんありますが
「お世話になった皆に楽しんでもらうには、絶対に必要なんだ！」と信じ、成し遂げられたのは
支えてくださった皆様がいてこそでした、感謝してもしきれません💐本当にありがとうございました！

 　
長くなってしまいましたが、読んでいただいた方、ありがとうございました🙇‍♀️✨
- お気軽に遊んでもらえたら何よりも嬉しく思います🃏💛

https://aruaru-games.com

- 私めのX(旧Twitter)はこちらです！気が向いたら仲良くしてください☺️

https://x.com/pakira_rrr