TS×React×Express×Firebase×Render でアプリケーションを作りました

# 投稿目的
・備忘
・今後、開発時の技術について記事を執筆するという宣言



# 作ったアプリケーションについて
名前は「__社内食べログ__」としています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/54d31f24-9445-4c52-9334-fce345becf6c.png)


## できること

#### ログイン前
・新規会員登録 (会社コード・メールアドレス・パスワード)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/4839fa2b-d8a8-457f-8e1c-9e82b95143e6.png)
・新規会社作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/2fc76065-16af-419b-9c9b-ad2f87934595.png)
・お店の情報の検索/閲覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/8b12b5e2-a322-412d-a105-0e30a71af96d.png)

#### ログイン後
・会員情報更新 (パスワード変更・ユーザ情報更新)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/d1970572-b044-4cb9-9b8c-5274fc227aa2.png)
・退会
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/0b68b355-3715-48a6-9900-f827dc32d598.png)
・お店の情報の検索/閲覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/3c8e5ffe-def0-46ec-8a5a-81703f19b860.png)
・お店に関する口コミ投稿
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/39f7c199-59f0-40c1-9ea3-56afdd7a7700.png)
・お店をお気に入り登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/a4cbef51-0a11-4780-a3e0-45ffcf465efb.png)
・同じ会社に所属するユーザの口コミ/お気に入り閲覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/b333ec32-6fd2-4fb7-8b29-60547d0be440.png)


## フロント側
`TypeScript`×`React`で構築しました。
`Firebase Hosting`を利用し、デプロイしています。
>【パッケージ】
```json
  "dependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-router": "^7.1.5"
  },
  "devDependencies": {
    "@emotion/react": "^11.14.0",
    "@emotion/styled": "^11.14.0",
    "@eslint/compat": "^1.2.6",
    "@eslint/eslintrc": "^3.2.0",
    "@eslint/js": "^9.20.0",
    "@formkit/tempo": "^0.1.2",
    "@mui/icons-material": "^6.4.4",
    "@mui/material": "^6.4.4",
    "@tanstack/eslint-plugin-query": "^5.66.1",
    "@tanstack/react-query": "^5.66.0",
    "@types/node": "^22.13.1",
    "@types/react": "^19.0.8",
    "@types/react-datepicker": "^7.0.0",
    "@types/react-dom": "^19.0.3",
    "@types/react-paginate": "^7.1.4",
    "@types/react-router": "^5.1.20",
    "@types/styled-components": "^5.1.34",
    "@typescript-eslint/eslint-plugin": "^8.24.0",
    "@typescript-eslint/parser": "^8.24.0",
    "@vitejs/plugin-react-swc": "^3.8.0",
    "axios": "^1.7.9",
    "eslint": "^9.20.1",
    "eslint-import-resolver-typescript": "^3.7.0",
    "eslint-plugin-import": "^2.31.0",
    "eslint-plugin-react-hooks": "^5.1.0",
    "eslint-plugin-react-refresh": "^0.4.19",
    "globals": "^15.14.0",
    "prettier": "^3.5.0",
    "react-datepicker": "^7.6.0",
    "react-error-boundary": "^5.0.0",
    "react-paginate": "^8.3.0",
    "rollup-plugin-visualizer": "^5.14.0",
    "styled-components": "^6.1.15",
    "typescript": "^5.7.3",
    "vite": "^6.1.0",
    "vite-tsconfig-paths": "^5.1.4"
  },
  "volta": {
    "node": "22.12.0",
    "bun": "1.2.1"
  },
  "engines": {
    "node": "22.12.0",
    "bun": "1.2.1"
  }
```

## サーバ側
`TypeScript`×`Express`で構築しました。
[`Render`](https://render.com/)を利用し、デプロイしています。
ユーザ認証には[`Firebase Authentication`](https://firebase.google.com/docs/auth?hl=ja)、お店や口コミの情報を保存するデータベースは[`Cloud Firestore`](https://firebase.google.com/docs/firestore?hl=ja)、ユーザのアバター画像を保存するストレージには[`Cloud Storage for Firebase`](https://firebase.google.com/docs/storage?hl=ja)、お店の情報の取得は[`Hotpepper API`](https://webservice.recruit.co.jp/doc/hotpepper/reference.html)を利用しています。
>【パッケージ】
```json
"dependencies": {
    "axios": "^1.7.9",
    "body-parser": "^1.20.3",
    "cors": "^2.8.5",
    "express": "^4.21.2",
    "firebase": "^10.14.1",
    "firebase-admin": "^13.1.0",
    "https": "^1.0.0"
  },
  "devDependencies": {
    "@eslint/compat": "^1.2.6",
    "@eslint/eslintrc": "^3.2.0",
    "@eslint/js": "^9.20.0",
    "@formkit/tempo": "^0.1.2",
    "@types/body-parser": "^1.19.5",
    "@types/cors": "^2.8.17",
    "@types/express": "^5.0.0",
    "@types/firebase": "^3.2.3",
    "@types/node": "^22.13.4",
    "@typescript-eslint/eslint-plugin": "^8.24.1",
    "@typescript-eslint/parser": "^8.24.1",
    "eslint": "^9.20.1",
    "eslint-import-resolver-typescript": "^3.8.1",
    "eslint-plugin-import": "^2.31.0",
    "globals": "^15.15.0",
    "prettier": "^3.5.1",
    "rollup-plugin-visualizer": "^5.14.0",
    "ts-patch": "^3.3.0",
    "tsc-alias": "^1.8.10",
    "tsx": "^4.19.2",
    "typescript": "^5.7.3",
    "typescript-eslint": "^8.24.1",
    "typescript-transform-paths": "^3.5.3",
    "vite": "^6.1.0",
    "vite-express": "^0.20.0",
    "vite-plugin-node": "^4.0.0"
  },
  "volta": {
    "node": "22.12.0",
    "bun": "1.2.1"
  },
  "engines": {
    "node": "22.12.0",
    "bun": "1.2.1"
  }
  ```



  # 終わりに
  まず、誰でもアクセスできる形でアプリケーションを構築・公開できた点は非常に達成感があります!
  バックエンドの構築や`GitHub actions`によるCI/CDなど、自分がやったことのないことにも触れられた点は、今後の業務にもつなげていければと思っています。

  また、様々な便利なサービス・パッケージも発見することができたため、今後記事を執筆していきたいと思います!

  その一方で、「要件定義(作りたいアプリケーション像の構築)が不十分」「汎用的な部品の切り出しができなかった」など、反省点も多々あります。
  今後の記事へのコメントなどで、改善すべき点をご教示いただけますと幸いです m(_ _)m