【ChatGPTとペアプロ】 #2 設計検討からモックの作成まで

## 概要
ChatGPTとペアプロでアプリを作るのが流行っているのでやってみました。

次のような構成を予定しています。

[【ChatGPTとペアプロ】 #1 アイデア出しから設計検討まで](https://qiita.com/nisim/items/90f6268401c1f8783d06)
【ChatGPTとペアプロ】 #2 設計検討からモックの作成まで ← いまここ
【ChatGPTとペアプロ】 #3 モックの作成から詳細設計まで
【ChatGPTとペアプロ】 #4 モックの作成から仕様決定まで
【ChatGPTとペアプロ】 #5 仕様決定から開発


## 前回決まったこと

#### 要件定義

仕事・家事・育児が同時並行で進んでいく共働きの夫婦の負担を解消することを今回のアプリ作成の目的にしました。

ChatGPTを使って色々アイデア出しを行いましたが、まずは最小の機能を持ったアプリを開発したいので不満を共有して改善できる場を作成することを目的としました。

* ターゲットは共働きの夫婦
* 不満を共有して改善できることを目的としたアプリを作成する
* 追加機能を盛り込めるような前提でのアプリとする

#### 機能要件

1. 不満投稿機能：共働きの夫婦がそれぞれの不満を投稿できるようにする。テキスト入力欄と送信ボタンを設ける。
2. 不満表示機能：投稿された不満を夫婦の双方が閲覧できるようにする。不満が投稿されるとリスト形式で表示される。
3. 不満へのコメント機能：投稿された不満に対して、夫婦双方がコメントを残すことができるようにする。これにより、改善策の議論が可能になる。
4. カテゴリ分け機能：不満をカテゴリ別に分類できるようにする。例えば、「家事」「育児」「コミュニケーション」などのカテゴリを設定し、投稿時に選択できるようにする。
5. 進捗管理機能：改善策が決まったら、進捗を管理できるようにする。進捗状況を「未着手」「進行中」「完了」の3段階で表示できるようにする。
6. 通知機能：新しい投稿やコメントがあった際に、夫婦双方に通知が届くようにする。メールやプッシュ通知を利用することで、リアルタイムで情報を共有できる。
7. ユーザーアカウント機能：夫婦それぞれがアカウントを作成し、ログインできるようにする。これにより、個別の情報が保護される。
8. 追加機能の前提：将来的に追加機能を実装できるような設計を行う。例えば、カレンダー機能やタスク管理機能などが考えられる。

#### 機能要件フロー

1. ユーザーアカウント作成・ログイン
    - 夫婦がそれぞれアカウントを作成し、ログインします。

2. 不満投稿
    - 夫婦がそれぞれの不満をテキスト入力欄に入力し、送信ボタンを押します。
    - カテゴリを選択して投稿します。

3. 不満表示
    - 投稿された不満がリスト形式で表示されます。
    - 夫婦がそれぞれの不満を閲覧できます。

4. 不満へのコメント
    - 夫婦が投稿された不満に対してコメントを入力し、送信ボタンを押します。

5. 進捗管理
    - 改善策が決まった場合、進捗状況を選択し更新します。

6. 通知
    - 新しい投稿やコメントがあった際に、夫婦にメールやプッシュ通知が送られます。


#### 技術要素

* フロントエンド
    * Vueを採用
* バックエンド
    * Pythonを採用
* AWS インフラ
    * サーバレスアーキテクチャを採用


## 設計検討

前回の内容から実際にソースコードを作成してフロントエンドのモックを作っていきます。


### フロントエンド

ここでもChatGPTを中心にコンポーネントを作成していきます。

```
作成していただいたプロトタイプに提案いただいた下記の機能要件を満たすようなコンポーネントをステップバイステップで追加してください。

機能要件：

不満投稿機能：共働きの夫婦がそれぞれの不満を投稿できるようにする。テキスト入力欄と送信ボタンを設ける。
不満表示機能：投稿された不満を夫婦の双方が閲覧できるようにする。不満が投稿されるとリスト形式で表示される。
不満へのコメント機能：投稿された不満に対して、夫婦双方がコメントを残すことができるようにする。これにより、改善策の議論が可能になる。
カテゴリ分け機能：不満をカテゴリ別に分類できるようにする。例えば、「家事」「育児」「コミュニケーション」などのカテゴリを設定し、投稿時に選択できるようにする。
進捗管理機能：改善策が決まったら、進捗を管理できるようにする。進捗状況を「未着手」「進行中」「完了」の3段階で表示できるようにする。
通知機能：新しい投稿やコメントがあった際に、夫婦双方に通知が届くようにする。メールやプッシュ通知を利用することで、リアルタイムで情報を共有できる。
ユーザーアカウント機能：夫婦それぞれがアカウントを作成し、ログインできるようにする。これにより、個別の情報が保護される。
追加機能の前提：将来的に追加機能を実装できるような設計を行う。例えば、カレンダー機能やタスク管理機能などが考えられる。
```

#### 回答

```
以下の手順で、提案された機能要件を満たすようなコンポーネントを追加していきます。

1. 不満投稿機能
  - `CreatePost.vue`というコンポーネントを作成します。
  - テキスト入力欄と送信ボタンを配置します。
  - 入力されたテキストを親コンポーネントに送信するイベントを実装します。

2. 不満表示機能
  - `PostList.vue`というコンポーネントを作成します。
  - 不満を表示するためのリストを作成します。
  - 親コンポーネントから渡された不満データを表示します。

3. 不満へのコメント機能
  - `CommentSection.vue`というコンポーネントを作成します。
  - 不満に対するコメントを表示する部分と、コメントを追加する入力欄を配置します。
  - 入力されたコメントを親コンポーネントに送信するイベントを実装します。

4. カテゴリ分け機能
  - `CategorySelect.vue`というコンポーネントを作成します。
  - カテゴリの選択肢をドロップダウンリストで表示します。
  - 選択されたカテゴリを親コンポーネントに送信するイベントを実装します。

5. 進捗管理機能
  - `ProgressTracker.vue`というコンポーネントを作成します。
  - 進捗状況を「未着手」「進行中」「完了」の3段階で表示します。
  - 進捗状況の変更を親コンポーネントに送信するイベントを実装します。

6. 通知機能
  - 通知機能はバックエンドとの連携が必要なため、フロントエンドだけでは実装できません。バックエンドでメールやプッシュ通知を送信する機能を実装し、フロントエンドと連携させます。

7. ユーザーアカウント機能
  - `Login.vue`と`Signup.vue`の2つのコンポーネントを作成します。
  - ログインおよびアカウント作成のフォームをそれぞれのコンポーネントに配置します。
  - ログインおよびアカウント作成の処理はバックエンドと連携して実装します。

このように、機能要件に従ってVueコンポーネントを作成し、それらを組み合わせてアプリケーションを構築します。また、追加機能を簡単に実装できるように、コンポーネント化された設計を採用しています。これにより、今後カレンダー機能やタスク管理機能などを追加する際にも、新たなコンポーネントを作成し、既存のコンポーネントと連携させることで容易に機能拡張が可能です。

最終的なアプリケーションでは、これらのコンポーネントを適切に配置し、親コンポーネントやルーティング設定を通じてそれらの連携を実現します。また、バックエンドとのデータ通信には、APIクライアントを用いてデータの取得や送信を行います。

こうした手法により、提案された機能要件に対応するVueフロントエンドアプリケーションが構築されます。
```

## コンポーネント間の関係整理

コンポーネント間の関係を整理しておきます。

```
あなたは、プロのVue３コンポーネント設計者です。
以下の入力文と制約条件を元に、テキストベースでの関係図を出力してください。

# 入力：
・提示いただいた機能要件のコンポーネント間の関係を整理してください。

# 出力：
```

#### 回答

こちらに、提示いただいた機能要件のコンポーネント間の関係図をテキストベースで表現いたします。

```
App.vue
 ├── Navbar.vue
 ├── router-view
 │    ├── Home.vue
 │    │    ├── CreatePost.vue
 │    │    ├── PostList.vue
 │    │         ├── PostItem.vue
 │    │              ├── CategorySelect.vue
 │    │              ├── CommentSection.vue
 │    │              ├── ProgressTracker.vue
 │    ├── Login.vue
 │    └── Signup.vue
 └── Notification.vue
```

この関係図において、`App.vue` がルートコンポーネントであり、その他のコンポーネントがネストされています。以下は、各コンポーネントの役割を簡単に説明しています。

- `App.vue`: ルートコンポーネントで、全体のレイアウトを管理します。
- `Navbar.vue`: ナビゲーションバーを表示し、ログインや新規登録へのリンクを提供します。
- `router-view`: Vue Router によって現在のルートに応じたコンポーネントが表示されます。
- `Home.vue`: 不満投稿機能、不満表示機能、カテゴリ分け機能、進捗管理機能を含むメインのページです。
  - `CreatePost.vue`: 不満投稿機能を提供するコンポーネントです。
  - `PostList.vue`: 投稿された不満をリスト形式で表示するコンポーネントです。
    - `PostItem.vue`: 個々の不満投稿を表示するコンポーネントです。
      - `CategorySelect.vue`: 不満投稿時にカテゴリを選択するコンポーネントです。
      - `CommentSection.vue`: 不満投稿に対してコメントを残すことができるコンポーネントです。
      - `ProgressTracker.vue`: 改善策の進捗状況を管理するコンポーネントです。
- `Login.vue`: ユーザーがログインするためのフォームを提供するコンポーネントです。
- `Signup.vue`: ユーザーが新規登録するためのフォームを提供するコンポーネントです。
- `Notification.vue`: 新しい投稿やコメントがあった際に通知を表示するコンポーネントです。


## コンポーネントの中身の作成

先ほど作成した関係図を踏まえてコンポーネントを作成してもらいます。

```
あなたは、プロのVue3プログラマーです。
以下の入力文と制約条件を元に、各コンポーネントのプログラムを出力してください。

# 制約条件：
1. Vue3を使用する
2. Composition APIを使用する

# 入力：
・提示いただいたコンポーネントの中身のプログラムを一つずつ作成してください。また、その際に提示いただいた機能要件のコンポーネント間の関係図を考慮してください。

# 出力：
```

#### 回答

以下は、各コンポーネントのプログラムです。それぞれのコンポーネントを作成し、Composition API を使用しています。

1. CreatePost.vue
```javascript
<template>
  <div>
    <input v-model="postText" placeholder="不満を書いてください..." />
    <button @click="submitPost">投稿する</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const postText = ref('');

    const submitPost = () => {
      console.log('投稿内容:', postText.value);
      // 実際には、API エンドポイントにデータを送信する
    };

    return {
      postText,
      submitPost,
    };
  },
});
</script>
```

2. PostList.vue
```javascript
<template>
  <div>
    <div v-for="(post, index) in posts" :key="index">
      <PostItem :post="post" />
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';
import PostItem from './PostItem.vue';

export default defineComponent({
  components: {
    PostItem,
  },
  setup() {
    // 実際には、API エンドポイントからデータを取得する
    const posts = ref([{ text: '不満1' }, { text: '不満2' }]);

    return {
      posts,
    };
  },
});
</script>
```

3. PostItem.vue
```javascript
<template>
  <div>
    <p>{{ post.text }}</p>
    <button @click="showComments = !showComments">
      コメント{{ showComments ? 'を非表示' : 'を表示' }}
    </button>
    <CommentSection v-if="showComments" :post="post" />
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';
import CommentSection from './CommentSection.vue';

export default defineComponent({
  props: {
    post: {
      type: Object,
      required: true,
    },
  },
  components: {
    CommentSection,
  },
  setup() {
    const showComments = ref(false);

    return {
      showComments,
    };
  },
});
</script>
```

4. CommentSection.vue
```javascript
<template>
  <div>
    <div v-for="(comment, index) in comments" :key="index">
      {{ comment.text }}
    </div>
    <input v-model="commentText" placeholder="コメントを入力..." />
    <button @click="submitComment">コメントを投稿</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  props: {
    post: {
      type: Object,
      required: true,
    },
  },
  setup() {
    const comments = ref([{ text: 'コメント1' }, { text: 'コメント2' }]);
    const commentText = ref('');

    const submitComment = () => {
      console.log('コメント内容:', commentText.value);
      // 実際には、API エンドポイントにデータを送信する
    };

    return {
      comments,
      commentText,
      submitComment,
    };
  },
});
```

5. CategorySelect.vue

```javascript
<template>
  <div>
    <select v-model="selectedCategory">
      <option v-for="(category, index) in categories" :key="index" :value="category">
        {{ category }}
      </option>
    </select>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const categories = ref(['家事', '育児', 'コミュニケーション']);
    const selectedCategory = ref(categories.value[0]);

    return {
      categories,
      selectedCategory,
    };
  },
});
</script>
```

6. ProgressTracker.vue
```javascript
<template>
  <div>
    <select v-model="progressStatus">
      <option v-for="(status, index) in progressStatuses" :key="index" :value="status">
        {{ status }}
      </option>
    </select>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const progressStatuses = ref(['未着手', '進行中', '完了']);
    const progressStatus = ref(progressStatuses.value[0]);

    return {
      progressStatuses,
      progressStatus,
    };
  },
});
</script>
```

7. Login.vue
```javascript
<template>
  <div>
    <input v-model="email" type="email" placeholder="メールアドレス" />
    <input v-model="password" type="password" placeholder="パスワード" />
    <button @click="login">ログイン</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const email = ref('');
    const password = ref('');

    const login = () => {
      console.log('ログイン情報:', email.value, password.value);
      // 実際には、API エンドポイントにデータを送信し、認証を行う
    };

    return {
      email,
      password,
      login,
    };
  },
});
</script>
```

8. Signup.vue
```javascript
<template>
  <div>
    <input v-model="email" type="email" placeholder="メールアドレス" />
    <input v-model="password" type="password" placeholder="パスワード" />
    <button @click="signup">アカウント作成</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const email = ref('');
    const password = ref('');

    const signup = () => {
      console.log('サインアップ情報:', email.value, password.value);
      // 実際には、API エンドポイントにデータを送信し、アカウントを作成する
    };

    return {
      email,
      password,
      signup,
    };
  },
});
</script>
```

これらのコンポーネントを使用して、提示いただいた機能要件を満たすフロントエンドのアプリケーションを作成できます。必要に応じて、API エンドポイントにデータを送信し、データを取得する処理を追加してください。また、関係図に従って、これらのコンポーネントを適切に親子関係で配置し、コンポーネント間でデータをやり取りできるようにしてください。

たとえば、App.vue（メインコンポーネント）でいくつかのコンポーネントを組み合わせることができます。

App.vue
```javascript
<template>
  <div>
    <Signup />
    <Login />
    <CreatePost />
    <CategorySelect />
    <PostList />
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import Signup from './components/Signup.vue';
import Login from './components/Login.vue';
import CreatePost from './components/CreatePost.vue';
import CategorySelect from './components/CategorySelect.vue';
import PostList from './components/PostList.vue';

export default defineComponent({
  components: {
    Signup,
    Login,
    CreatePost,
    CategorySelect,
    PostList,
  },
});
</script>
```

上記の例では、App.vue で各コンポーネントをインポートして使用しています。しかし、実際のアプリケーションでは、適切なルーティングや状態管理（Vuex など）を使用して、コンポーネント間でデータのやり取りや表示の制御を行う必要があります。

上記のコンポーネントを使用し、Composition API を活用して、機能要件を満たす Vue3 のフロントエンドアプリケーションを構築できます。API エンドポイントとの通信や、状態管理を実装することで、アプリケーションを完成させることができます。

#### ここまでのまとめ

単一ファイルでエラーがでないことはもちろんですが、事前にコンポーネント間の関係をうまく取り込んだことでコンポーネント間のインポートでもエラーがでていませんでした。

一方でルーティング設定などは考慮してくれていないためモックとは言えないレベルのものができてしまいました。

![スクリーンショット 2023-04-22 20.12.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1654639/28a2b0e1-4e5b-069a-c5f5-77e646a838e5.png)

## ルーティングの設定

ルーティングの設定をしてもらうために処理フローの条件をつけてみました。

```
あなたは、プロのVue3プログラマーです。
以下の入力文と制約条件を元に、各コンポーネントのプログラムを出力してください。

# 制約条件：
1. Vue3を使用する
2. Composition APIを使用する
3. 次の処理フローを考慮した画面遷移になるようにルーティングの設定も行う

処理フロー
1. ユーザーアカウント作成・ログイン
    - 夫婦がそれぞれアカウントを作成し、ログインします。
2. 不満投稿
    - 夫婦がそれぞれの不満をテキスト入力欄に入力し、送信ボタンを押します。
    - カテゴリを選択して投稿します。
3. 不満表示
    - 投稿された不満がリスト形式で表示されます。
    - 夫婦がそれぞれの不満を閲覧できます。
4. 不満へのコメント
    - 夫婦が投稿された不満に対してコメントを入力し、送信ボタンを押します。
5. 進捗管理
    - 改善策が決まった場合、進捗状況を選択し更新します。
6. 通知
    - 新しい投稿やコメントがあった際に、夫婦にメールやプッシュ通知が送られます。

# 入力：
・提示いただいたコンポーネントの中身のプログラムを一つずつ作成してください。また、その際に提示いただいた機能要件のコンポーネント間の関係図を考慮してください。

# 出力：
```

#### 回答

以下の各コンポーネントのプログラムを出力します。また、画面遷移を考慮したルーティングの設定も行います。

1. ルーティング設定 (router.ts)

```javascript
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Signup from './components/Signup.vue';
import Login from './components/Login.vue';
import Home from './components/Home.vue';

const routes: RouteRecordRaw[] = [
  { path: '/signup', component: Signup },
  { path: '/login', component: Login },
  { path: '/', component: Home, meta: { requiresAuth: true } },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;
```

2. メインアプリケーションエントリポイント (main.ts)

```javascript
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

createApp(App).use(router).mount('#app');
```

3. メインアプリケーションコンポーネント (App.vue)

```vue
<template>
  <div>
    <router-view></router-view>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({});
</script>
```

4. ホームコンポーネント (Home.vue)

```vue
<template>
  <div>
    <CreatePost />
    <CategorySelect />
    <PostList />
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import CreatePost from './CreatePost.vue';
import CategorySelect from './CategorySelect.vue';
import PostList from './PostList.vue';

export default defineComponent({
  components: {
    CreatePost,
    CategorySelect,
    PostList,
  },
});
</script>
```

これで、アプリケーションのルーティング設定が完了しました。ユーザーがログインしていない場合、サインアップ画面またはログイン画面が表示され、ログイン後にはホーム画面に遷移します。

これまでに提供した各コンポーネントのコードを組み合わせて、Vue3アプリケーションを構築してください。また、APIエンドポイントとの通信や状態管理（Vuexなど）を実装してアプリケーションを完成させてください。

前提のディレクトリ構成を理解していないのでrouter.tsに記載しているimportのパスが間違っていますが大きな問題はないと思います。

ルートディレクトリ(`/`)にメイン機能が作成されました。

![スクリーンショット 2023-04-22 20.29.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1654639/9287b1b8-a59b-6f42-bc80-7a352e00b971.png)

`/signin`と`/login`にそれぞれサインインとログインのコンポーネントが配置されるようになりました。

## 今回はここまで

正直かなり苦戦しましたが、やはり適切な前提知識や制約条件を指定することでイメージにあったものを作ってくれることがわかりました。