diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c90b0bf1bfb25f88bb4b76598342080ee31dbdf4..4e42c92cf3089453ab7e26dc398fc33d9684f964 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -35,9 +35,10 @@ deployToS3:
   before_script:
     - curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
     - unzip awscliv2.zip
-    - sudo ./aws/install
+    - ./aws/install
   script:
     - aws2 s3 rm s3://$S3_BUCKET_NAME/ --recursive
+    - npm run build
     - aws2 s3 cp dist s3://$S3_BUCKET_NAME/ --recursive --acl public-read
   when: manual
   only:
diff --git a/src/components/NavigationDrawer.vue b/src/components/NavigationDrawer.vue
index c247b9728334a28b0fc29cb34b310d69d183113f..3005d0bc4fd05f2aacd4a98666de490f2dc90587 100644
--- a/src/components/NavigationDrawer.vue
+++ b/src/components/NavigationDrawer.vue
@@ -5,10 +5,8 @@
     :value="isNavDrawerVisible"
   >
     <v-list>
-      <v-subheader>회원 관리</v-subheader>
-      <v-list-item-group
-        color="primary"
-      >
+      <v-subheader>회원</v-subheader>
+      <v-list-item-group color="primary">
         <v-list-item
           link
           :to="{ name: 'TraineeList' }"
@@ -17,14 +15,35 @@
             <v-icon>mdi-account-group</v-icon>
           </v-list-item-icon>
           <v-list-item-content>
-            <v-list-item-title>회원 목록</v-list-item-title>
+            <v-list-item-title>전체 회원</v-list-item-title>
+          </v-list-item-content>
+        </v-list-item>
+        <v-list-item
+          link
+          :to="{ name: 'DietList' }"
+        >
+          <v-list-item-icon>
+            <v-icon>mdi-pasta</v-icon>
+          </v-list-item-icon>
+          <v-list-item-content>
+            <v-list-item-title>식단 관리</v-list-item-title>
+          </v-list-item-content>
+        </v-list-item>
+        <v-list-item
+          link
+          :to="{ name: 'ExerciseList' }"
+        >
+          <v-list-item-icon>
+            <v-icon>mdi-pasta</v-icon>
+          </v-list-item-icon>
+          <v-list-item-content>
+            <v-list-item-title>운동 관리</v-list-item-title>
           </v-list-item-content>
         </v-list-item>
       </v-list-item-group>
-      <v-subheader>프로그램 관리</v-subheader>
-      <v-list-item-group
-        color="primary"
-      >
+
+      <v-subheader>프로그램</v-subheader>
+      <v-list-item-group color="primary">
         <v-list-item
           link
           :to="{ name: 'ProgramList' }"
@@ -33,7 +52,7 @@
             <v-icon>mdi-shape</v-icon>
           </v-list-item-icon>
           <v-list-item-content>
-            <v-list-item-title>프로그램 목록</v-list-item-title>
+            <v-list-item-title>전체 프로그램</v-list-item-title>
           </v-list-item-content>
         </v-list-item>
         <v-list-item
@@ -44,14 +63,13 @@
             <v-icon>mdi-ticket</v-icon>
           </v-list-item-icon>
           <v-list-item-content>
-            <v-list-item-title>이용권 목록</v-list-item-title>
+            <v-list-item-title>프로그램 이용권 관리</v-list-item-title>
           </v-list-item-content>
         </v-list-item>
       </v-list-item-group>
-      <v-subheader>일정 관리</v-subheader>
-      <v-list-item-group
-        color="primary"
-      >
+
+      <v-subheader>일정</v-subheader>
+      <v-list-item-group color="primary">
         <v-list-item
           link
           :to="{ name: 'ScheduleList' }"
@@ -60,14 +78,13 @@
             <v-icon>mdi-shape</v-icon>
           </v-list-item-icon>
           <v-list-item-content>
-            <v-list-item-title>일정 목록</v-list-item-title>
+            <v-list-item-title>전체 일정</v-list-item-title>
           </v-list-item-content>
         </v-list-item>
       </v-list-item-group>
-      <v-subheader>매장 관리</v-subheader>
-      <v-list-item-group
-        color="primary"
-      >
+
+      <v-subheader>매장</v-subheader>
+      <v-list-item-group color="primary">
         <v-list-item
           link
           :to="{ name: 'TrainerList' }"
@@ -76,7 +93,7 @@
             <v-icon>mdi-account-supervisor</v-icon>
           </v-list-item-icon>
           <v-list-item-content>
-            <v-list-item-title>트레이너 목록</v-list-item-title>
+            <v-list-item-title>트레이너 관리</v-list-item-title>
           </v-list-item-content>
         </v-list-item>
       </v-list-item-group>
diff --git a/src/router/index.js b/src/router/index.js
index d87b8ced91c19ba1e33e5eb20ca55438b2e5fb1c..63f34c259dde6430aeac16bc0381f341d1a85156 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -5,6 +5,10 @@ import Store from '@/store/index';
 import APISetting from '@/settings/api';
 import Login from '@/views/Login.vue';
 import Main from '@/views/Main.vue';
+import DietList from '@/views/DietList.vue';
+import DietDetail from '@/views/DietDetail.vue';
+import ExerciseList from '@/views/ExerciseList.vue';
+import ExerciseDetail from '@/views/ExerciseDetail.vue';
 import ProgramList from '@/views/ProgramList.vue';
 import ProgramCreate from '@/views/ProgramCreate.vue';
 import ProgramDetail from '@/views/ProgramDetail.vue';
@@ -35,6 +39,26 @@ const routes = [
     name: 'Main',
     component: Main,
   },
+  {
+    path: '/diet',
+    name: 'DietList',
+    component: DietList,
+  },
+  {
+    path: '/diet/:id',
+    name: 'DietDetail',
+    component: DietDetail,
+  },
+  {
+    path: '/exercise',
+    name: 'ExerciseList',
+    component: ExerciseList,
+  },
+  {
+    path: '/exercise/:id',
+    name: 'ExerciseDetail',
+    component: ExerciseDetail,
+  },
   {
     path: '/program',
     name: 'ProgramList',
diff --git a/src/settings/api.js b/src/settings/api.js
index a0b1dcd9198fb9d0f1aa99aefba8b52cfb708199..7d4efbe230c8147179b58744973369396d03f9c3 100644
--- a/src/settings/api.js
+++ b/src/settings/api.js
@@ -14,6 +14,10 @@ export default {
       list: `${host}/diet`,
       detail: id => (`${host}/diet/${id}`),
     },
+    exercise: {
+      list: `${host}/exercise`,
+      detail: id => (`${host}/exercise/${id}`),
+    },
     program: {
       list: `${host}/program`,
       detail: id => (`${host}/program/${id}`),
@@ -25,6 +29,10 @@ export default {
     trainee: {
       list: `${host}/trainee`,
       detail: id => (`${host}/trainee/${id}`),
+      booking: id => (`${host}/trainee/${id}/booking`),
+      diet: id => (`${host}/trainee/${id}/diet`),
+      exercise: id => (`${host}/trainee/${id}/exercise`),
+      inventory: id => (`${host}/trainee/${id}/inventory`),
     },
     trainer: {
       list: `${host}/trainer`,
diff --git a/src/views/DietDetail.vue b/src/views/DietDetail.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5d027a863ad603439dc4d5a18fd129166df64ed3
--- /dev/null
+++ b/src/views/DietDetail.vue
@@ -0,0 +1,186 @@
+<template>
+  <div class="diet-detail">
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="isProcessing">
+          <v-card-title>식단 정보</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ error.message }}
+            </v-alert>
+            <v-text-field
+              label="등록번호"
+              readonly
+              v-model="id"
+            ></v-text-field>
+            <v-textarea
+              auto-grow
+              label="식단"
+              readonly
+              v-model="diet.diet"
+            ></v-textarea>
+            <v-textarea
+              auto-grow
+              label="피드백"
+              v-model="diet.feedback"
+            ></v-textarea>
+            <v-text-field
+              label="등록 시각"
+              readonly
+              v-model="diet.createdAt"
+            ></v-text-field>
+            <v-text-field
+              label="최종 수정 시각"
+              readonly
+              v-model="diet.updatedAt"
+            ></v-text-field>
+          </v-card-text>
+          <v-card-actions>
+            <v-spacer></v-spacer>
+            <v-btn
+              color="error"
+              outlined
+              @click="deleteDiet(id)"
+            >
+              <v-icon left>mdi-delete</v-icon>
+              삭제
+            </v-btn>
+            <v-btn
+              color="primary"
+              outlined
+              @click="updateDiet(id)"
+            >
+              <v-icon left>mdi-content-save</v-icon>
+              저장
+            </v-btn>
+          </v-card-actions>
+        </v-card>
+      </v-col>
+    </v-row>
+  </div>
+</template>
+
+<script>
+import moment from 'moment';
+
+import APISetting from '@/settings/api';
+
+export default {
+  name: 'DietDetail',
+
+  data: () => ({
+    isProcessing: false,
+    error: {
+      isError: false,
+      message: '',
+    },
+    showDatePicker: false,
+    diet: {
+      diet: '',
+      feedback: '',
+      createdAt: '',
+      updatedAt: '',
+    },
+  }),
+
+  computed: {
+    id() {
+      if ('id' in this.$route.params) return this.$route.params.id;
+      return null;
+    },
+  },
+
+  methods: {
+    getDiet(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.diet.detail(id), APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 404) return Promise.all([null, res]);
+          if ([200, 400, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
+          if (res.status !== 200) throw new Error(json.message);
+          const { diet } = json;
+          diet.createdAt = moment(diet.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          diet.updatedAt = moment(diet.updatedAt).format('YYYY-MM-DD HH:mm:ss');
+          this.diet = diet;
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    updateDiet(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.diet.detail(id), APISetting.settings.put(this.diet))
+        .then((res) => {
+          if (res.status === 404) return Promise.all([null, res]);
+          if ([200, 400, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
+          if (res.status !== 200) throw new Error(json.message);
+          const { diet } = json;
+          diet.createdAt = moment(diet.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          diet.updatedAt = moment(diet.updatedAt).format('YYYY-MM-DD HH:mm:ss');
+          this.diet = diet;
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    deleteDiet(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.diet.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if ([204, 404].includes(res.status)) return Promise.all([null, res]);
+          if ([400, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
+          if (res.status !== 204) throw new Error(json.message);
+          return this.$router.push('/diet');
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+  },
+
+  created() {
+    this.getDiet(this.id);
+  },
+};
+</script>
diff --git a/src/views/DietList.vue b/src/views/DietList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..1b955629830f013410bc090bfd7aab569c7b7084
--- /dev/null
+++ b/src/views/DietList.vue
@@ -0,0 +1,164 @@
+<template>
+  <div class="diet-list">
+    <v-row>
+      <v-col cols="12">
+        <v-card>
+          <v-card-title>식단 목록</v-card-title>
+          <v-card-text>
+            <v-row justify="end">
+              <v-col
+                cols="12"
+                sm="4"
+                md="3"
+                lg="3"
+                xl="2"
+              >
+                <v-text-field
+                  append-icon="mdi-magnify"
+                  clearable
+                  label="식단 검색"
+                  v-model="dietList.searchKeyword"
+                ></v-text-field>
+              </v-col>
+            </v-row>
+            <v-data-table
+              :headers="dietList.headers"
+              item-key="id"
+              :items="dietList.data"
+              :loading="isProcessing"
+              loading-text="데이터를 불러오는 중입니다."
+              :search="dietList.searchKeyword"
+              no-results-text="일치하는 식단을 찾지 못했습니다."
+            >
+              <template v-slot:item.action="{ item }">
+                <v-icon
+                  small
+                  class="mr-2"
+                  @click="editDiet(item.id)"
+                >
+                  mdi-pencil
+                </v-icon>
+                <v-icon
+                  small
+                  @click="deleteDiet(item.id)"
+                >
+                  mdi-delete
+                </v-icon>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
+      </v-col>
+    </v-row>
+  </div>
+</template>
+
+<script>
+import moment from 'moment';
+
+import APISetting from '@/settings/api';
+
+export default {
+  name: 'DietList',
+
+  data: () => ({
+    isProcessing: false,
+    error: {
+      isError: false,
+      message: '',
+    },
+    dietList: {
+      headers: [
+        {
+          text: '#',
+          value: 'id',
+        },
+        {
+          text: '회원',
+          value: 'trainee.name',
+        },
+        {
+          text: '식단',
+          value: 'diet',
+        },
+        {
+          text: '피드백 여부',
+          value: 'hasFeedback',
+        },
+        {
+          text: '등록 시각',
+          value: 'createdAt',
+        },
+        {
+          text: '',
+          value: 'action',
+          sortable: false,
+        },
+      ],
+      data: [],
+      searchKeyword: '',
+    },
+  }),
+
+  methods: {
+    getDietList() {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.diet.list, APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 200) return res.json();
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((json) => {
+          this.dietList.data = json.diets;
+          this.dietList.data.forEach((diet) => {
+            // eslint-disable-next-line no-param-reassign
+            diet.hasFeedback = diet.feedback ? '완료' : '미완료';
+            // eslint-disable-next-line no-param-reassign
+            diet.createdAt = moment(diet.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          });
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    editDiet(id) {
+      this.$router.push(`/diet/${id}`);
+    },
+    deleteDiet(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.diet.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if (res.status === 204) return Promise.all([null, res]);
+          if ([400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 204) return this.getDietList();
+          throw new Error(json.message);
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = true;
+        });
+    },
+  },
+
+  created() {
+    this.getDietList();
+  },
+};
+</script>
diff --git a/src/views/ExerciseDetail.vue b/src/views/ExerciseDetail.vue
new file mode 100644
index 0000000000000000000000000000000000000000..1f7c67da19084324a6d5ae179abd1f7007b8bc91
--- /dev/null
+++ b/src/views/ExerciseDetail.vue
@@ -0,0 +1,186 @@
+<template>
+  <div class="exercise-detail">
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="isProcessing">
+          <v-card-title>운동 정보</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ error.message }}
+            </v-alert>
+            <v-text-field
+              label="등록번호"
+              readonly
+              v-model="id"
+            ></v-text-field>
+            <v-textarea
+              auto-grow
+              label="운동"
+              readonly
+              v-model="exercise.exercise"
+            ></v-textarea>
+            <v-textarea
+              auto-grow
+              label="피드백"
+              v-model="exercise.feedback"
+            ></v-textarea>
+            <v-text-field
+              label="등록 시각"
+              readonly
+              v-model="exercise.createdAt"
+            ></v-text-field>
+            <v-text-field
+              label="최종 수정 시각"
+              readonly
+              v-model="exercise.updatedAt"
+            ></v-text-field>
+          </v-card-text>
+          <v-card-actions>
+            <v-spacer></v-spacer>
+            <v-btn
+              color="error"
+              outlined
+              @click="deleteExercise(id)"
+            >
+              <v-icon left>mdi-delete</v-icon>
+              삭제
+            </v-btn>
+            <v-btn
+              color="primary"
+              outlined
+              @click="updateExercise(id)"
+            >
+              <v-icon left>mdi-content-save</v-icon>
+              저장
+            </v-btn>
+          </v-card-actions>
+        </v-card>
+      </v-col>
+    </v-row>
+  </div>
+</template>
+
+<script>
+import moment from 'moment';
+
+import APISetting from '@/settings/api';
+
+export default {
+  name: 'ExerciseDetail',
+
+  data: () => ({
+    isProcessing: false,
+    error: {
+      isError: false,
+      message: '',
+    },
+    showDatePicker: false,
+    exercise: {
+      exercise: '',
+      feedback: '',
+      createdAt: '',
+      updatedAt: '',
+    },
+  }),
+
+  computed: {
+    id() {
+      if ('id' in this.$route.params) return this.$route.params.id;
+      return null;
+    },
+  },
+
+  methods: {
+    getExercise(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.exercise.detail(id), APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 404) return Promise.all([null, res]);
+          if ([200, 400, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
+          if (res.status !== 200) throw new Error(json.message);
+          const { exercise } = json;
+          exercise.createdAt = moment(exercise.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          exercise.updatedAt = moment(exercise.updatedAt).format('YYYY-MM-DD HH:mm:ss');
+          this.exercise = exercise;
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    updateExercise(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.exercise.detail(id), APISetting.settings.put(this.exercise))
+        .then((res) => {
+          if (res.status === 404) return Promise.all([null, res]);
+          if ([200, 400, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
+          if (res.status !== 200) throw new Error(json.message);
+          const { exercise } = json;
+          exercise.createdAt = moment(exercise.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          exercise.updatedAt = moment(exercise.updatedAt).format('YYYY-MM-DD HH:mm:ss');
+          this.exercise = exercise;
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    deleteExercise(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.exercise.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if ([204, 404].includes(res.status)) return Promise.all([null, res]);
+          if ([400, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
+          if (res.status !== 204) throw new Error(json.message);
+          return this.$router.push('/exercise');
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+  },
+
+  created() {
+    this.getExercise(this.id);
+  },
+};
+</script>
diff --git a/src/views/ExerciseList.vue b/src/views/ExerciseList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9f35b71d875230914893300f8e23f64913b9900e
--- /dev/null
+++ b/src/views/ExerciseList.vue
@@ -0,0 +1,164 @@
+<template>
+  <div class="exercise-list">
+    <v-row>
+      <v-col cols="12">
+        <v-card>
+          <v-card-title>운동 목록</v-card-title>
+          <v-card-text>
+            <v-row justify="end">
+              <v-col
+                cols="12"
+                sm="4"
+                md="3"
+                lg="3"
+                xl="2"
+              >
+                <v-text-field
+                  append-icon="mdi-magnify"
+                  clearable
+                  label="운동 검색"
+                  v-model="exerciseList.searchKeyword"
+                ></v-text-field>
+              </v-col>
+            </v-row>
+            <v-data-table
+              :headers="exerciseList.headers"
+              item-key="id"
+              :items="exerciseList.data"
+              :loading="isProcessing"
+              loading-text="데이터를 불러오는 중입니다."
+              :search="exerciseList.searchKeyword"
+              no-results-text="일치하는 운동을 찾지 못했습니다."
+            >
+              <template v-slot:item.action="{ item }">
+                <v-icon
+                  small
+                  class="mr-2"
+                  @click="editExercise(item.id)"
+                >
+                  mdi-pencil
+                </v-icon>
+                <v-icon
+                  small
+                  @click="deleteExercise(item.id)"
+                >
+                  mdi-delete
+                </v-icon>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
+      </v-col>
+    </v-row>
+  </div>
+</template>
+
+<script>
+import moment from 'moment';
+
+import APISetting from '@/settings/api';
+
+export default {
+  name: 'ExerciseList',
+
+  data: () => ({
+    isProcessing: false,
+    error: {
+      isError: false,
+      message: '',
+    },
+    exerciseList: {
+      headers: [
+        {
+          text: '#',
+          value: 'id',
+        },
+        {
+          text: '회원',
+          value: 'trainee.name',
+        },
+        {
+          text: '운동',
+          value: 'exercise',
+        },
+        {
+          text: '피드백 여부',
+          value: 'hasFeedback',
+        },
+        {
+          text: '등록 시각',
+          value: 'createdAt',
+        },
+        {
+          text: '',
+          value: 'action',
+          sortable: false,
+        },
+      ],
+      data: [],
+      searchKeyword: '',
+    },
+  }),
+
+  methods: {
+    getExerciseList() {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.exercise.list, APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 200) return res.json();
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((json) => {
+          this.exerciseList.data = json.exercises;
+          this.exerciseList.data.forEach((exercise) => {
+            // eslint-disable-next-line no-param-reassign
+            exercise.hasFeedback = exercise.feedback ? '완료' : '미완료';
+            // eslint-disable-next-line no-param-reassign
+            exercise.createdAt = moment(exercise.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          });
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    editExercise(id) {
+      this.$router.push(`/exercise/${id}`);
+    },
+    deleteExercise(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.exercise.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if (res.status === 204) return Promise.all([null, res]);
+          if ([400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 204) return this.getExerciseList();
+          throw new Error(json.message);
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = true;
+        });
+    },
+  },
+
+  created() {
+    this.getExerciseList();
+  },
+};
+</script>
diff --git a/src/views/ScheduleDetail.vue b/src/views/ScheduleDetail.vue
index 4baf94fa8dcbf099358feb86946a4ca658c40db4..50f43518c43b662151e4bb9ef73e4fdd51728781 100644
--- a/src/views/ScheduleDetail.vue
+++ b/src/views/ScheduleDetail.vue
@@ -226,7 +226,10 @@ export default {
           const [json, res] = values;
           if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
           if (res.status !== 200) throw new Error(json.message);
-          this.schedule = json.schedule;
+          const { schedule } = json;
+          schedule.createdAt = moment(schedule.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          schedule.updatedAt = moment(schedule.updatedAt).format('YYYY-MM-DD HH:mm:ss');
+          this.schedule = schedule;
         })
         .catch((e) => {
           this.error.message = e.message;
diff --git a/src/views/TraineeDetail.vue b/src/views/TraineeDetail.vue
index bfadb67561ce1f43738aaf90eede6ef5b8a4f591..e287fe873b819357e1c83a0eaa9494c588b3ad50 100644
--- a/src/views/TraineeDetail.vue
+++ b/src/views/TraineeDetail.vue
@@ -82,6 +82,174 @@
         </v-card>
       </v-col>
     </v-row>
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="booking.isProcessing">
+          <v-card-title>예약 정보</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="booking.error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ booking.error.message }}
+            </v-alert>
+            <v-data-table
+              :headers="booking.list.headers"
+              item-key="id"
+              :items="booking.list.data"
+              :loading="booking.isProcessing"
+              loading-text="데이터를 불러오는 중입니다."
+              :search="booking.list.searchKeyword"
+              no-results-text="일치하는 예약을 찾지 못했습니다."
+            >
+              <template v-slot:item.action="{ item }">
+                <v-icon
+                  small
+                  class="mr-2"
+                  @click="editBooking(item.id)"
+                >
+                  mdi-pencil
+                </v-icon>
+                <v-icon
+                  small
+                  @click="deleteBooking(item.id)"
+                >
+                  mdi-delete
+                </v-icon>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
+      </v-col>
+    </v-row>
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="inventory.isProcessing">
+          <v-card-title>이용권 정보</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="inventory.error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ inventory.error.message }}
+            </v-alert>
+            <v-data-table
+              :headers="inventory.list.headers"
+              item-key="id"
+              :items="inventory.list.data"
+              :loading="inventory.isProcessing"
+              loading-text="데이터를 불러오는 중입니다."
+              :search="inventory.list.searchKeyword"
+              no-results-text="일치하는 이용권을 찾지 못했습니다."
+            >
+              <template v-slot:item.action="{ item }">
+                <v-icon
+                  small
+                  class="mr-2"
+                  @click="editInventory(item.id)"
+                >
+                  mdi-pencil
+                </v-icon>
+                <v-icon
+                  small
+                  @click="deleteInventory(item.id)"
+                >
+                  mdi-delete
+                </v-icon>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
+      </v-col>
+    </v-row>
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="diet.isProcessing">
+          <v-card-title>식단 정보</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="diet.error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ diet.error.message }}
+            </v-alert>
+            <v-data-table
+              :headers="diet.list.headers"
+              item-key="id"
+              :items="diet.list.data"
+              :loading="diet.isProcessing"
+              loading-text="데이터를 불러오는 중입니다."
+              :search="diet.list.searchKeyword"
+              no-results-text="일치하는 식단을 찾지 못했습니다."
+            >
+              <template v-slot:item.action="{ item }">
+                <v-icon
+                  small
+                  class="mr-2"
+                  @click="editDiet(item.id)"
+                >
+                  mdi-pencil
+                </v-icon>
+                <v-icon
+                  small
+                  @click="deleteDiet(item.id)"
+                >
+                  mdi-delete
+                </v-icon>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
+      </v-col>
+    </v-row>
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="exercise.isProcessing">
+          <v-card-title>운동 정보</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="exercise.error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ exercise.error.message }}
+            </v-alert>
+            <v-data-table
+              :headers="exercise.list.headers"
+              item-key="id"
+              :items="exercise.list.data"
+              :loading="exercise.isProcessing"
+              loading-text="데이터를 불러오는 중입니다."
+              :search="exercise.list.searchKeyword"
+              no-results-text="일치하는 운동을 찾지 못했습니다."
+            >
+              <template v-slot:item.action="{ item }">
+                <v-icon
+                  small
+                  class="mr-2"
+                  @click="editExercise(item.id)"
+                >
+                  mdi-pencil
+                </v-icon>
+                <v-icon
+                  small
+                  @click="deleteExercise(item.id)"
+                >
+                  mdi-delete
+                </v-icon>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
+      </v-col>
+    </v-row>
   </div>
 </template>
 
@@ -108,6 +276,146 @@ export default {
       createdAt: '',
       updatedAt: '',
     },
+    booking: {
+      isProcessing: false,
+      error: {
+        isError: false,
+        message: '',
+      },
+      list: {
+        headers: [
+          {
+            text: '프로그램 이름',
+            value: 'schedule.program.title',
+          },
+          {
+            text: '시작 시각',
+            value: 'schedule.startAt',
+          },
+          {
+            text: '메모',
+            value: 'memo',
+          },
+          {
+            text: '등록 시각',
+            value: 'createdAt',
+          },
+          {
+            text: '',
+            value: 'action',
+            sortable: false,
+          },
+        ],
+        data: [],
+        searchKeyword: '',
+      },
+    },
+    inventory: {
+      isProcessing: false,
+      error: {
+        isError: false,
+        message: '',
+      },
+      list: {
+        headers: [
+          {
+            text: '#',
+            value: 'id',
+          },
+          {
+            text: '프로그램 이름',
+            value: 'program.title',
+          },
+          {
+            text: '사용 완료 횟수',
+            value: 'usedCount',
+          },
+          {
+            text: '사용 가능 횟수',
+            value: 'maxCount',
+          },
+          {
+            text: '등록 시각',
+            value: 'createdAt',
+          },
+          {
+            text: '',
+            value: 'action',
+            sortable: false,
+          },
+        ],
+        data: [],
+        searchKeyword: '',
+      },
+    },
+    diet: {
+      isProcessing: false,
+      error: {
+        isError: false,
+        message: '',
+      },
+      list: {
+        headers: [
+          {
+            text: '#',
+            value: 'id',
+          },
+          {
+            text: '식단',
+            value: 'diet',
+          },
+          {
+            text: '피드백 여부',
+            value: 'hasFeedback',
+          },
+          {
+            text: '등록 시각',
+            value: 'createdAt',
+          },
+          {
+            text: '',
+            value: 'action',
+            sortable: false,
+          },
+        ],
+        data: [],
+        searchKeyword: '',
+      },
+    },
+    exercise: {
+      isProcessing: false,
+      error: {
+        isError: false,
+        message: '',
+      },
+      list: {
+        headers: [
+          {
+            text: '#',
+            value: 'id',
+          },
+          {
+            text: '운동',
+            value: 'exercise',
+          },
+          {
+            text: '피드백 여부',
+            value: 'hasFeedback',
+          },
+          {
+            text: '등록 시각',
+            value: 'createdAt',
+          },
+          {
+            text: '',
+            value: 'action',
+            sortable: false,
+          },
+        ],
+        data: [],
+        searchKeyword: '',
+      },
+    },
   }),
 
   computed: {
@@ -137,6 +445,10 @@ export default {
           trainee.createdAt = moment(trainee.createdAt).format('YYYY-MM-DD HH:mm:ss');
           trainee.updatedAt = moment(trainee.updatedAt).format('YYYY-MM-DD HH:mm:ss');
           this.trainee = trainee;
+          this.getBookingList(trainee.id);
+          this.getInventoryList(trainee.id);
+          this.getDietList(trainee.id);
+          this.getExerciseList(trainee.id);
         })
         .catch((e) => {
           this.error.message = e.message;
@@ -165,6 +477,10 @@ export default {
           trainee.createdAt = moment(trainee.createdAt).format('YYYY-MM-DD HH:mm:ss');
           trainee.updatedAt = moment(trainee.updatedAt).format('YYYY-MM-DD HH:mm:ss');
           this.trainee = trainee;
+          this.getBookingList(trainee.id);
+          this.getInventoryList(trainee.id);
+          this.getDietList(trainee.id);
+          this.getExerciseList(trainee.id);
         })
         .catch((e) => {
           this.error.message = e.message;
@@ -199,6 +515,220 @@ export default {
           this.isProcessing = false;
         });
     },
+    getBookingList(id) {
+      this.booking.error.isError = false;
+      this.booking.error.message = '';
+      this.booking.isProcessing = true;
+
+      fetch(APISetting.endpoints.trainee.booking(id), APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 200) return res.json();
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((json) => {
+          this.booking.list.data = json.bookings;
+          this.booking.list.data.forEach((item) => {
+            // eslint-disable-next-line no-param-reassign
+            item.schedule.startAt = moment(item.schedule.startAt).format('YYYY-MM-DD HH:mm:ss');
+            // eslint-disable-next-line no-param-reassign
+            item.createdAt = moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          });
+        })
+        .catch((e) => {
+          this.booking.error.message = e.message;
+          this.booking.error.isError = true;
+        })
+        .finally(() => {
+          this.booking.isProcessing = false;
+        });
+    },
+    editBooking(id) {
+      this.$router.push(`/booking/${id}`);
+    },
+    deleteBooking(id) {
+      this.booking.error.isError = false;
+      this.booking.error.message = '';
+      this.booking.isProcessing = true;
+
+      fetch(APISetting.endpoints.booking.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if (res.status === 204) return Promise.all([null, res]);
+          if ([400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 204) return this.getBookingList(id);
+          throw new Error(json.message);
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = true;
+        });
+    },
+    getDietList() {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.diet.list, APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 200) return res.json();
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((json) => {
+          this.diet.list.data = json.diets;
+          this.diet.list.data.forEach((diet) => {
+            // eslint-disable-next-line no-param-reassign
+            diet.hasFeedback = diet.feedback ? '완료' : '미완료';
+            // eslint-disable-next-line no-param-reassign
+            diet.createdAt = moment(diet.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          });
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = false;
+        });
+    },
+    editDiet(id) {
+      this.$router.push(`/diet/${id}`);
+    },
+    deleteDiet(id) {
+      this.error.isError = false;
+      this.error.message = '';
+      this.isProcessing = true;
+
+      fetch(APISetting.endpoints.diet.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if (res.status === 204) return Promise.all([null, res]);
+          if ([400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 204) return this.getDietList();
+          throw new Error(json.message);
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = true;
+        });
+    },
+    getInventoryList(id) {
+      this.inventory.error.isError = false;
+      this.inventory.error.message = '';
+      this.inventory.isProcessing = true;
+
+      fetch(APISetting.endpoints.trainee.inventory(id), APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 200) return res.json();
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((json) => {
+          this.inventory.list.data = json.inventories;
+          this.inventory.list.data.forEach((item) => {
+            // eslint-disable-next-line no-param-reassign
+            item.createdAt = moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          });
+        })
+        .catch((e) => {
+          this.inventory.error.message = e.message;
+          this.inventory.error.isError = true;
+        })
+        .finally(() => {
+          this.inventory.isProcessing = false;
+        });
+    },
+    editInventory(id) {
+      this.$router.push(`/inventory/${id}`);
+    },
+    deleteInventory(id) {
+      this.inventory.error.isError = false;
+      this.inventory.error.message = '';
+      this.inventory.isProcessing = true;
+
+      fetch(APISetting.endpoints.inventory.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if (res.status === 204) return Promise.all([null, res]);
+          if ([400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 204) return this.getInventoryList(id);
+          throw new Error(json.message);
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = true;
+        });
+    },
+    getExerciseList(id) {
+      this.exercise.error.isError = false;
+      this.exercise.error.message = '';
+      this.exercise.isProcessing = true;
+
+      fetch(APISetting.endpoints.trainee.exercise(id), APISetting.settings.get)
+        .then((res) => {
+          if (res.status === 200) return res.json();
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((json) => {
+          this.exercise.list.data = json.exercises;
+          this.exercise.list.data.forEach((item) => {
+            // eslint-disable-next-line no-param-reassign
+            item.hasFeedback = item.feedback ? '완료' : '미완료';
+            // eslint-disable-next-line no-param-reassign
+            item.createdAt = moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          });
+        })
+        .catch((e) => {
+          this.exercise.error.message = e.message;
+          this.exercise.error.isError = true;
+        })
+        .finally(() => {
+          this.exercise.isProcessing = false;
+        });
+    },
+    editExercise(id) {
+      this.$router.push(`/exercise/${id}`);
+    },
+    deleteExercise(id) {
+      this.exercise.error.isError = false;
+      this.exercise.error.message = '';
+      this.exercise.isProcessing = true;
+
+      fetch(APISetting.endpoints.exercise.detail(id), APISetting.settings.delete)
+        .then((res) => {
+          if (res.status === 204) return Promise.all([null, res]);
+          if ([400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          throw new Error('알 수 없는 응답입니다.');
+        })
+        .then((values) => {
+          const [json, res] = values;
+          if (res.status === 204) return this.getExerciseList(id);
+          throw new Error(json.message);
+        })
+        .catch((e) => {
+          this.error.message = e.message;
+          this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = true;
+        });
+    },
   },
 
   created() {