個人でブログ交流サイトを開発？

## 素人なのに、AI先生のアドバイスを受けながら、いきなり、ブログ交流サイト「広場でブログ」を開発しています。

これは、Webアプリの開発経験のない素人が、無謀にも、ブログ交流サイトの開発を始めたドキュメンタリーです。

## 出会い
春の足音が聞こえ始めた２０２３年３月、限りある日々を大切に過ごしたいという思いからブログをはじめました。完全匿名で記事を書けるinvilab社の[「memoブログ」](https://memo.invilab.jp/)です。ペットのこととか、本のこととか、菜園のこととか、些細な日常での気づきや感動を誰かと共有したかったのだと思います。

ブログを始めてから2か月ほどたったある日、[「ChatGPTとCopilotに要件だけ伝えて自動コーディングしてもらう(AIペアプロ), @tak001 at 2023/4/20」](https://qiita.com/tak001/items/951cee065d7c20e17a0e)というQiitaの記事に出会って刺激を受け、もしかしたら、AIを先生にしてWebアプリの大規模開発ができるのかも知れない、という妄想を抱き始めました。実は、memoブログではマークダウンが使えず不自由を感じていたので、**自分でほしい機能を追加できる** ブログサイトを作ってみたいと考えていたのです。

そこで、まずはこの記事を正しく理解しなければなりません。Next.js、React、TypeScript、KISSの原則、高階関数、単一責任の原則、オニオンアーキテクチャー、マジックナンバー、ミュータブルな変数、多重ループ処理、jestなど、知らない単語が並んでいます。最初の3つをカバーしている参考書「TypeScriptとReact/Next.jsでつくる実践Webアプリケーション開発, 手島拓也／吉田健人／高林佳稀, 技術評論社, 2022/8/6初版」を読み始めたのが、梅干しを漬け始めた5月下旬でした。

ブログのコンセプトは、誰もが匿名で参加でき、他のメンバーの記事にコメントできるブログ交流サイトです。まずは、タイトルを「広場でブログ」と定めて、梅干しが食べれるようになるまでに完成させたいと考えていました。ワクワクでした。

## 開発を始める
１０年前にもWebアプリを作りたくて、jQuery, Node.jsなどを勉強した経験はあるのですが、フロントエンド、データベース、セキュリティなど検討課題がありすぎ、自分には無理と悟って断念しました。今回は、Chat-GPTなどAI先生の指導を受けられること、React／Next.jsというフレームワークを利用できるというアドバンテージがあります。

とはいっても、設計、実装、テストといった工程を踏むのは面倒なので、テンプレートを探しました。①React/Next.jsで書かれていること、②マークダウンが使えること、の2点だけでVercel社の[「Next.js Contentlayer Blog Starter」](https://vercel.com/templates/next.js/nextjs-contentlayer)を採用してしまったのですが、これが最初の間違いでした。

当初、Next.jsのプラグインであるContentlayerを組み込んでマークダウンの使えるブログを考えていたのですが、クライアントから記事の投稿ができないような気がしてAI先生（Chat-GPT、以下同じ）に確認すると、①リアルタイム機能を備えたバックエンド、②WebSoketまたはリアルタイムAPI、③ヘッドレスCMS、の３つの選択肢を示してくれました。ということで、普通にバックエンドデータベースを使ってreact-markdownで変換することになりました。ちなみにreact-markdownはAI先生のお勧めです。

#### ★要件イメージ
**ブログ機能：**
1. マークダウンが使える
1. 写真をアップロードできる
1. サマリーを自動作成できる
1. 記事をダウンロードできる


**コミュニケーション機能：**
1. メンバー登録できる
1. 記事に「いいね／大変だね」
1. 記事にコメントできる

**管理機能：**
1. 定期的なバックアップ
1. 特定メンバーを利用停止できる
1. 違反記事パトロールの自動化

#### ★楽屋裏
**フロントエンド：** React/Next.js、Tailwind CSS
**バックエンド：** Firestore, Cloud Storage
**ホスティング：** Google App Engine

当初は、Vercel社のホスティングサービスとKVデータベースを使っていたのですが、写真のアップロード先になるBlobストーレッジが未完で使えなかったことから、Google Cloud Platformに変更しました（８月）。

「広場でブログ」開発用 URL: [https://blog-in-plaza.uc.r.appspot.com/](https://blog-in-plaza.uc.r.appspot.com/)



## メンバー管理と認証
最初に取り組んだのが、メンバー管理の作成です。メンバーの登録、編集、削除のためのコードは、ビューとCRUDコードを書くことになります。ここを技術的に乗り越えれば、ブログ記事の登録、編集、削除にも使えると考えて、最初の目標としました。

ビューはTailwindCSSの無料で使えるコンポーネントのコードをコピーし、CRUDコードは、自己流に登録、取得、更新、削除をセットでコーディングしました。結果として、自分にしか解らないコードになっています。

メンバーの認証情報を取得するコンポーネントを作成する際に、非同期で認証情報を取得するコードが解らず、AI先生のアドバイスを受けました。

**非同期関数の返り値をJSX要素に割り当てる方法：**
（質問）『Next.js コンポーネントから非同期関数を呼び出し、返されたオブジェクトを JSX 要素に割り当てることはできますか?』

（AI先生）『Next.js は React に基づいたフレームワークであるため、React コンポーネントでの非同期操作の処理方法に注意する必要があります。

コード例を次に示します。

```jsx
import { useState, useEffect } from 'react';

const MyComponent = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        // Call your asynchronous function here
        const response = await myAsyncFunction();

        // Once the response is received, update the state
        setData(response);
      } catch (error) {
        // Handle any errors that occur during the async operation
        console.error('Error fetching data:', error);
      }
    }

    fetchData();
  }, []); // The empty dependency array ensures the effect runs only once

  return (
    <div>
      {data ? (
        <div>{/* Render the data in your JSX */}</div>
      ) : (
        <div>Loading...</div>
      )}
    </div>
  );
};

export default MyComponent;
```

この例では、`useState` フックを使用して、非同期関数から取得したデータを維持します。 `useEffect`フックは、コンポーネントのマウント時にデータ取得操作をトリガーするために使用されます。

`useEffect`コールバック内で、非同期関数`fetchData`が定義されます。 この関数内で、非同期関数 `myAsyncFunction()` を呼び出し、その応答を待つことができます。 応答を受信したら、`setData`関数を使用して応答を`data`に割り当てることができます。

コンポーネントの JSX 部分で、`data`が null でないかどうかを確認します。 null でない場合は、データを使用して目的の JSX をレンダリングします。 それ以外の場合は、「Loading...」メッセージが表示されます。

`myAsyncFunction` を、必要な非同期操作を実行する実際の非同期関数に置き換えることを忘れないでください。』

Reactのフックに馴染みのない初心者でも理解できるように、的確で懇切丁寧な説明をしていただき、とても感謝しています。ありがとうございました。

AI先生には、これ以外にも、エラーメッセージの意味を説明していただいたり、暗号化用のライブラリとその使い方、チェックボックスの状態を取得する方法、画像の埋め込みマークダウンからURLを抽出する正規表現など、即座にご回答いただきました。

おかげさまで、7月上旬に、最小限度のメンバー管理機能ができしました。ただし、リカバリー部分は未完です。

そもそもメールアドレスとパスワードによる認証には課題が多すぎるので、パスワードを必要としないソーシャルログインへの変更を検討しています。

## 画像のアップロード
メンバー管理につづく技術的な課題は、画像のアップロードでした。
経験ゼロですので、まずはAI先生に質問しました。

（質問）『私は Web アプリ開発者です。 ユーザーが画像をアップロードできるブログを開発していますが、アップロードした画像をどのサーバーに保存できるのか、またそのサーバー内の画像を参照する方法がわかりません。 基本的な仕組みと何をすべきかを教えてください。』

AI先生の回答は、考慮すべき手順を示すものでした。先生の説明はいつも懇切丁寧で教育的な配慮がなされていますが、長文になるので要約しますと、

『考慮すべき基本手順は次のとおりです。
1. サーバーの選択
1. ストレージアクセス権限の構成
1. ローカルデバイスから画像をアップロード（フロントエンドフレームワーク）
1. サーバー側の処理
1. 一意のファイル名を生成する
1. 画像参照URIの保存
1. CDN (コンテンツ配信ネットワーク)
1. セキュリティ

といった事柄を考慮し、

1. ブログが拡大し、画像をアップロードするユーザーが増えるにつれて、読み込み時間を短縮し、ストレージを効率的に使用する最適化手法を検討する必要がある場合があります。
1. プライバシーとデータ保持のポリシーを常に念頭に置き、利用規約とプライバシー ポリシーをユーザーが認識できるようにしてください。』

といったアドバイスをしていただきました。

まずは、サーバーの選択です。7月時点でホスティングに使用していたVercel社には、画像などを保管できるBlobというサービスがあります。しかしその時点で未完成の状態でしたので、アマゾンのS3とグーグルのCloud Storageを検討しました。その結果、チュートリアルが理解しやすかったCloud Storageを選択しました。

ローカルデバイスから画像をアップロードするためのコードは、[「Vercel Blob Next.js Starter」](https://vercel.com/templates/next.js/blob-starter)を参考にしました。このテンプレートは、Vercel社のBlobに画像ファイルをアップロードするための簡単なコード例ですが、画像を選択してプリビューする部分をいただきました。

次に、アップロードした画像ファイルに一意の名前を付けてストレージに転送するため、API関数内でformidableを使用しました。これはAI先生のアドバイスです。

ところが、Vercel社のサーバーからCloud Storageに転送できません。formidableは、一旦、画像ファイルをホスティングサーバーに書き込んでから転送しているのですが、Vercel社のサーバーにクライアントから書き込むことができないようでした。私が利用していた格安プランでは、セキュリティの問題もあり、制限されているのではないか？ということは、他のサーバーでも同じではないか？一時は、開発を断念しなけらばならないのか？とガッカリしていました。８月上旬です。

ダメもとで、Cloud Storageと同じ会社にデプロイしてみようということで、GAE（Google App Engine）に変更したところ、成功しました！今から思えば当たり前のことですが、開発の道がつながり安堵しました。ならば、一層のことデータベースも変えてしまおうと、８月中旬、KVからグーグルのFirestoreに変更して、支払先を１つにまとめました。９月の課金は、「広場にブログ」を新たにデプロイしていないため、数十円です。

不要になった画像ファイルの自動削除など、まだまだ検討しなければならない事項が残されていますが、画像のアップロードができるようになり、ブログに最小限度必要な機能が揃いました。以降、memoブログへの投稿を止め、「広場でブログ」に、スタンダードプードルのニコ、茶トラのサンタと私だけで投稿を続けています。

## 今後の開発スケジュール
5月下旬に漬けた梅干しはすでにいただいていますが、「広場でブログ」は完成時期が見えません。

画像のアップロードに成功し必要最小限の機能が揃うと、次に気になったのが、セキュリティです。AI先生から、重要なセキュリティ問題として、次の事項をリストアップしていただきました。

1. インジェクション攻撃
1. クロスサイト スクリプティング (XSS)
1. クロスサイト リクエスト フォージェリ (CSRF)
1. セキュリティの誤った構成
1. 機密データの漏洩
1. 認証とセッション管理の失敗
1. 安全でない直接オブジェクト参照 (IDOR)
1. 未検証のリダイレクトと転送
1. 安全でないファイルのアップロード
1. セキュリティの誤った構成
1. サービス拒否 (DoS) 攻撃
1. フィッシングとソーシャル エンジニアリング
1. 機密データの保管
1. サードパーティのコンポーネント
1. ユーザー入力の検証

さらに、『潜在的なセキュリティ問題を事前に特定して対処するには、定期的なセキュリティ評価、脆弱性スキャン、侵入テストが不可欠です。セキュリティは継続的なプロセスであり、Web アプリケーションの安全性を維持するには、最新のセキュリティのベスト プラクティスと脅威を常に最新の状態に保つことが重要であることに注意してください。』

セキュリティ問題の対処には、バックエンドのインフラが重要になるわけですが、個人開発で利用できる便利なインフラとして、Firebaseの存在を知りました。10年以上前から存在していたようですが、私が知ったのは最近です。

今後は、インフラをFirebaseに変更します。

1. ソーシャルログインに変更
1. アプリの管理機能をFirebaseで作成

その後、利用規約とプライバシー・ポリシーを検討して、ローンチしたいと考えています。現在Firebase Authenticationを勉強中ですが、難しくてなかなか進みません。ソーシャルログインを開発後に、ローンチの時期を決めたいと考えています。

[「広場でブログ（開発中）」](https://blog-in-plaza.uc.r.appspot.com/)に興味を持っていただいた方は、是非、訪問してください。認証に使うメールアドレスはダミーで入れます。ただし、リカバリー機能が未作成ですので、パスワードを忘れないようにお願いします。

使い方は、ナビの「使い方」を参照してください。記事の投稿なども自由に行っていただいて結構です。皆さんからご意見などをいただければ、今後の開発に反映させていきたいと考えています。