Next.js + TypescriptでミニCMSを作る（1. 前提・要件・環境準備など）

## はじめに / なぜこの記事を書くのか？
かなり久々の投稿です。最新の投稿から３年くらい経ってますね。
この３年、家族都合で海外移住しまして、フリーランスしながら現地の自然言語とHello Worldしてました。人生何が起こるかわからないです。

その間にフロントエンドの流れも爆速で変わっていってるので、キャッチアップをしようとCMSのようなWEBアプリを作ることにしました。
今後もいつ別の案件やキャリアブレイクが入ってしまうかわからないので、自分や自分のバックグラウンドに似た人へ知見を残すため、記事を書こうと思います。

## 対象の技術スタック
この記事は、これから以下のスタックを学ぼうとしている人や、チュートリアルだけ終わらせたけどどう応用したらいいかわからないと思っている人に向いています。

 - Next.js
 - Typescript

他、必要に応じて以下も利用します。

- Docker
- Prisma ORM (Next.jsから各種DB操作を楽にします)
- Cloudinary (画像のストレージとして活用します)

以下の基礎的な知識はある前提です。

- HTML
- CSS
- JavaScript (ES6)
- MySQL

要件の話や設計なんかも少しメモを残すので、プログラマ・エンジニア双方ともに読める記事になったらいいなぁと思います。
 
## 仮想クライアントの設定
モノづくりするにあたって、どういうシチュエーションで何を作るのか定義します。
クライアントがいるプロジェクトでは要件定義ってありますよね。それの簡易版ケーススタディという感じで決めておきます。なるべく実務に近い感じで感覚を研ぎ澄ませておきたいものです。
これやっておくと、実装中に迷ったとき、質を取るか速さを取るかの指標にもなるので判断し易いと思います。
今回の仮想クライアントは以下の要件を持っている想定です。実際の案件でお世話になったクライアントさんをモデルにしているので、結構具体的です。

##### 前提
- クライアントは販売業を営んでいる（海外へ買付の出張をすることもある）
- 会社は小規模で、業務のオペレーションとWebサイトの管理を同一人物が行っている
- 現在、静的Webサイト(HTML/CSS/JavaScript)で、製品の紹介のみしている（販売は実店舗のみ）
- 製品ページには、ブログ記事やYoutube紹介動画などを製品レビューとして掲載している。一部記事はトップページにもピックアップを載せている。
- トップページはレビュー記事、ニュース記事、最新の製品情報を載せている
- 上述のWebサイトの更新は外注していて、必要な情報はExcelなどに書いてメールで送付している
- 製品ページの新規作成や掲載内容更新は月一回程度、レビューの更新は週一回程度
- 現在のサイト構成図（製品ページは20～30程度ありますが、割愛します）
![Site-Structure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547786/6ed99e7e-ee84-b03a-baac-e58f2afeb18b.png)



##### 要望
- 製品ページやレビューの更新のたびに開発者とのやり取りが発生するので、これを減らしたい
- Excelでは記載内容に間違いがあっても気付きにくいため、改善したい
- そろそろ動的Webサイトにリニューアルして、UI/UXを改善したい
- 社内の複数人で更新内容をレビューしたり、同時に更新したりしたい
- クライアントの顧客情報などはシステムで取り扱っていないため、品質よりはコストや速度重視で進めたい

##### 要件
1. 静的Webサイトを動的Webサイトにリニューアルする
1. 管理者用画面を作成し、以下を登録できるようにする
    - 製品紹介ページ
    - レビュー情報（掲載対象：製品ページ、トップページ）
    - ニュース記事（掲載対象：トップページ）
    - 最新の製品情報（掲載対象：トップページ）
1. 管理者用アカウントは複数発行できるようにする

作っているうちに気づいたら、要件等追加するかもしれません。

## 開発フェーズの設定
いきなりユーザー画面も管理者画面もまとめて作る！となると負荷が高くて挫折するので、なんとなくフェーズわけします。フェーズ１と２は逆でもいいかもしれませんが、今回はこの順番で進めちゃいます。
（レビュー投稿のほうが頻度が高く、途中で開発停止になっても活用できる可能性が高いと考えました。いろんな都合で全フェーズやりきれないこともありますから・・・！）

##### フェーズ１：管理者画面の新規作成
- 管理者ログイン機能
- レビュー投稿機能　(CRUD操作ができる)

##### フェーズ２：製品情報の登録
- 製品の登録機能(CRUD操作ができる)
- 製品ジャンルやシリーズなどの登録機能
- トップページの編集機能

##### フェーズ３：公開画面のリニューアル
- フェーズ１&２で登録できるようになったデータをユーザーが閲覧する公開画面に反映する

##### フェーズ４：ブラッシュアップ
- 管理画面のブラッシュアップ（投稿時のプレビュー画面やロギングなどを想定）
- デプロイやリリース作業など

## 開発環境準備

最初はDockerの上にDBサーバ(MySQL)、WEBサーバ(Next.js)を用意して開発をしようとしていました。しかし、やってみると **DockerとNext.jsのホットリロードの相性が非常に悪く、開発速度に支障が出た** のでやめました。
ということで、ローカル上にNext.js, Docker上にMySQLサーバを立てて会話をしていただくことにしました。

### DBの準備
**注意：後ほど利用するPrismaというORMの仕様にあわせて、タイムゾーンはUTCで統一しています。ご注意ください。**

```
sample-db
│  docker-compose.yml
│  Dockerfile
│  .env
│
└─mysql
    ├─ conf.d
    │  my.cnf
    │
    └─ init.d
       └─ setup.sql
```

Docker,Docker-composeのインストール後、以下のファイルを作成します。

```yaml:docker-compose.yml
version: '3'

services:
  db:
    image: mysql:latest
    container_name: mysql
    restart: always

    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      TZ: UTC      # Next.js Prismaの設定に合わせるため、データベースはUTCにする
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      # 設定ファイルディレクトリにマウントする
      - ./mysql/conf.d:/etc/mysql/conf.d
      # DB初期化ディレクトリにマウントする
      - ./mysql/init.d:/docker-entrypoint-initdb.d
      # DBデータ保存場所
      - db_data:/var/lib/mysql
      
volumes:
 db_data:

```

```:Dockerfile
FROM mysql
 COPY ./conf.d/my.cnf /etc/mysql/conf.d/my.cnf
 CMD chmod 644 /etc/mysql/conf.d/my.cnf
```

```:my.conf
[mysqld]
default-time-zone = UTC
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-authentication-plugin = mysql_native_password

[client]
default-character-set = utf8mb4

[mysql]
default-character-set=utf8

[mysqldump]
default-character-set=utf8
```

```:.env
MYSQL_HOST=localhost
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=database
MYSQL_USER=hoge
MYSQL_PASSWORD=huga
```
↑お好みのユーザー名とパスワードを設定してください。


`setup.sql`にSQLを書いておくと、Docker立てた際に初期化できますが、今回はまとめてPrismaに頼ることにしたので今回は空っぽです。
後述の通り`my.cnf`が効かなかった事があり、`docker-compose.yml`と`my.cnf`両方で文字コードの指定をしています。下記の問題が解消したら、どちらかお好みの方で大丈夫だと思います。

:::note warn
注意
Windowsを利用している方は、my.cnfの権限設定に気を付けてください。

参考にさせていただきました：
[[Docker+Windows]mysqlのdockerイメージがmy.cnfのマウントのエラーで起動しない時の対処法](https://qiita.com/rabbitbeef/items/14433a2c0a6f85c3b476)

:::

### Next.jsの準備

良い記事がたくさん出ているので、インストール方法は割愛します。
[Next.js公式サイト](https://nextjs.org/docs/getting-started/installation)等をご参考にしていただき、`create-next-app`が完了した状態にしましょう。
私の場合は、以下のように設定しましたので、今後の記事もこの設定に則って書く予定です。

Would you like to use TypeScript? 　**→ Yes**
Would you like to use ESLint? 　**→ Yes**
Would you like to use Tailwind CSS?　**→ No**(また今度勉強します)
Would you like to use `src/` directory?　**→ No**
Would you like to use App Router? (recommended)　**→ Yes**
Would you like to customize the default import alias (@/*)?　**→ Yes**
What import alias would you like configured? 　**→ そのままEnter押す**

必要なもののインストールは都度やっていきます。

# 次回

DBサーバとNext.jsをつなぐPrisma ORMを設定していきます。
DB設計もしていくよ！