フロントエンド初心者が家計簿Webアプリを作ってみた【Vue.js+MySQL】

# はじめに
フロントエンド周りの勉強のために家計簿のWebアプリを作ってみました。
ついでにコンテナの理解を深めたくて、アプリをコンテナ上に配置してみました。

MoneyFoward等の人気アプリほど高度の機能性ではありませんが、この自作のアプリで日々の収支を管理しています。一つの教材として参考いただければ幸いです。

# ソースコード
https://github.com/Ayoan/Oeconomica

# 主な参考サイト
アプリを載せる基盤部分（コンテナ）はこちらの記事を参考に構築しました。

https://qiita.com/niisan1ban/items/f70eb0ed891568f71f9b#vue%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%AE%E6%BA%96%E5%82%99

家計簿は以下の講座で作成したのを雛形に、好きな機能を追加していきました。
といってもロジックのコード実装はほぼオリジナルで、HTMLとCSS(見た目部分)だけ流用させてもらったという形です。

https://www.techpit.jp/courses/169

テーブルのフィルタ機能は以下を参考に実装しました。

https://webparts.cman.jp/table/filter/

# 前提条件
コンテナで起動されます。そのためDocker環境が必要になります。
筆者のDockerホストはMacでしたが、WindowsやUbuntuでも大丈夫と思います。

https://sukkiri.jp/technologies/virtualizers/docker/docker-mac_install.html

# 使用したソフトウェア等
+ macOS Ventura 13.4.1 (Intel Core i7)
+ Docker 20.10.17
+ Node.js 14.21.2
+ express 4.18.2
+ sequelize 6.32.1
+ sequelize-cli 6.6.1
+ Vue.js 3.2.47
+ VueCLI 5.0.0
+ MySQL 8.0.32

# デプロイ手順
細かい仕組みは差し置いて、コンテナを起動させてアプリを使用できるようにする手順はこちら。


## プロジェクト ダウンロード
gitからプロジェクトのディレクトリ群をローカルホストにダウンロードする。
```zsh:zsh
cd {ダウンロード先のパス}
git clone https://github.com/Ayoan/Oeconomica.git
```

Oeconomicaディレクトリがダウンロードされる
```zsh:実行ログ
% git clone https://github.com/Ayoan/Oeconomica.git
Cloning into 'Oeconomica'...
remote: Enumerating objects: 28872, done.
remote: Counting objects: 100% (28872/28872), done.
remote: Compressing objects: 100% (20167/20167), done.
remote: Total 28872 (delta 7718), reused 28872 (delta 7718), pack-reused 0
Receiving objects: 100% (28872/28872), 39.80 MiB | 25.59 MiB/s, done.
Resolving deltas: 100% (7718/7718), done.
Updating files: 100% (30331/30331), done.

% ls -l Oeconomica
total 16
-rw-r--r--   1 staff  staff   172  7 14 23:25 Dockerfile
drwxr-xr-x  16 staff  staff   512  7 14 23:26 api
drwxr-xr-x   5 staff  staff   160  7 14 23:26 db
-rw-r--r--   1 staff  staff  2013  7 14 23:26 docker-compose.yml
drwxr-xr-x  14 staff  staff   448  7 14 23:26 vue

```

## docker-compose 起動
ディレクトリ名がそのままコンテナの名称になるので、リネームしたければディレクトリ名を変更する。
事前にディレクトリに移動しておく。
```zsh:zsh
mv Oeconomica Kakeibo
ｃｄ Kakeibo
```

ディレクトリに移動して、docker-composeを立ち上げる（※1）
```zsh:zsh
docker-compose up -d
```
```zsh:実行ログ
% docker-compose up -d
Creating network "kakeibo_backend" with the default driver
Creating volume "kakeibo_mysqldata" with default driver
Creating kakeibo_db_1 ... done
Creating kakeibo_api_1 ... done
Creating kakeibo_vue_1 ... done
```
※1：もしもプロジェクトディレクトリに移動しないまま実行すると、
「docker-compose.yml」が直下にありませんというエラーになってしまう。
```docker:エラー
% docker-compose up -d
ERROR:
        Can't find a suitable configuration file in this directory or any
        parent. Are you in the right directory?

        Supported filenames: docker-compose.yml, docker-compose.yaml, compose.yml, compose.yaml
```

## 初回起動失敗 対応
apiコンテナは初回起動に失敗する。
```zsh:apiコンテナ起動失敗ログ
% docker-compose ps
    Name                   Command               State                  Ports
-------------------------------------------------------------------------------------------
kakeibo_api_1   docker-entrypoint.sh sh -c ...   Exit 1
kakeibo_db_1    docker-entrypoint.sh mysqld      Up       0.0.0.0:3306->3306/tcp, 33060/tcp
kakeibo_vue_1   docker-entrypoint.sh npm r ...   Up       0.0.0.0:8080->8080/tcp

% docker-compose logs api
Attaching to kakeibo_api_1
api_1  |
api_1  | Sequelize CLI [Node: 14.21.2, CLI: 6.6.0, ORM: 6.29.0]
api_1  |
api_1  | Loaded configuration file "config/config.js".
api_1  | Using environment "development".
api_1  |
api_1  | ERROR: connect ECONNREFUSED 172.19.0.2:3306
api_1  |
```
細かい原因は掴めなかったが、docker-composeを再起動したらとりあえず治る
```zsh:docker-compose再起動
docker-compose restart
```

```zsh:実行ログ
% docker-compose restart
Restarting kakeibo_vue_1 ... done
Restarting kakeibo_api_1 ... done
Restarting kakeibo_db_1  ... done

% docker-compose ps
    Name                   Command               State                 Ports
------------------------------------------------------------------------------------------
kakeibo_api_1   docker-entrypoint.sh sh -c ...   Up      0.0.0.0:3000->3000/tcp
kakeibo_db_1    docker-entrypoint.sh mysqld      Up      0.0.0.0:3306->3306/tcp, 33060/tcp
kakeibo_vue_1   docker-entrypoint.sh npm r ...   Up      0.0.0.0:8080->8080/tcp

% docker-compose logs api
---(中略)---
api_1  | Sequelize CLI [Node: 14.21.2, CLI: 6.6.0, ORM: 6.29.0]
api_1  |
api_1  | Loaded configuration file "config/config.js".
api_1  | Using environment "development".
api_1  | == 20230226080028-create-oeconomica: migrating =======
api_1  | == 20230226080028-create-oeconomica: migrated (0.049s)
api_1  |
api_1  | == 20230610044255-create-subscription: migrating =======
api_1  | == 20230610044255-create-subscription: migrated (0.040s)
api_1  |
api_1  | == 20230624094542-create-category: migrating =======
api_1  | == 20230624094542-create-category: migrated (0.035s)
api_1  |
api_1  |
api_1  | > app@0.0.0 dev /app
api_1  | > nodemon ./bin/www
api_1  |
api_1  | [nodemon] 2.0.20
api_1  | [nodemon] to restart at any time, enter `rs`
api_1  | [nodemon] watching path(s): *.*
api_1  | [nodemon] watching extensions: js,mjs,json
api_1  | [nodemon] starting `node ./bin/www`
```

ログを見比べた感じ、初回はapiコンテナとdbコンテナの疎通がうまく行かなかった模様。
再起動後は、データベーステーブルのマイグレーションが正常に実行されている。

## docker-compose 確認
コンテナ状態
```zsh:log
% docker-compose ps
    Name                   Command               State                 Ports
------------------------------------------------------------------------------------------
kakeibo_api_1   docker-entrypoint.sh sh -c ...   Up      0.0.0.0:3000->3000/tcp
kakeibo_db_1    docker-entrypoint.sh mysqld      Up      0.0.0.0:3306->3306/tcp, 33060/tcp
kakeibo_vue_1   docker-entrypoint.sh npm r ...   Up      0.0.0.0:8080->8080/tcp
```

イメージ一覧
```zsh:log
% docker-compose images
  Container     Repository        Tag           Image Id       Size
---------------------------------------------------------------------
kakeibo_api_1   node         14.21.2-buster   29794de631e6   915.6 MB
kakeibo_db_1    mysql        8.0.32-debian    9569167b4b40   835.3 MB
kakeibo_vue_1   node         14.21.2-buster   29794de631e6   915.6 MB
```

ボリューム一覧 → mysqlのデータ領域が作成されている
```zsh:zsh
% docker volume ls
DRIVER    VOLUME NAME
local     kakeibo_mysqldata
```

(備忘)
・クラウド上のVMにも同じ手順でデプロイできるか検証する

# 使い方
webブラウザから8080ポートにアクセスする。
```
http://localhost:8080
```

家計簿の画面が表示される。
![スクリーンショット 2023-07-22 19.19.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/2a226011-56d8-be46-c6f8-b6e0d791ce9d.png)

## カテゴリ設定（必須）
はじめに設定タブから収支カテゴリを登録する。
自分の生活に合わせて、収入（例：給与）、支出（例：食費、家賃）の種類を設定する。
![スクリーンショット 2023-07-22 19.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/30b6b41f-b9fe-6bff-d3d4-c87cfab107de.png)

画面上から設定するのがめんどくさければ、DBに直接データを入れ込むのでもOK.
```zsh:データ挿入手順
# DBコンテナに接続
% docker-compose exec db /bin/bash
root@4552e0239b3d:/#
# DBログイン(パスワードは.envに記載しているのをそのまま使えばいい)
root@4552e0239b3d:/# mysql -u root  -pmypassword oeconomica;

# 支出カテゴリ挿入
INSERT INTO Categories (category, balance, createdAt, updatedAt)
VALUES ('食費', '支出', NOW(), NOW()),
       ('日用品', '支出', NOW(), NOW()),
       ('交通費', '支出', NOW(), NOW()),
       ('家賃', '支出', NOW(), NOW()),
       ('水道・光熱費', '支出', NOW(), NOW()),
       ('通信費', '支出', NOW(), NOW()),
       ('趣味', '支出', NOW(), NOW()),
       ('サブスク', '支出', NOW(), NOW()),
       ('その他', '支出', NOW(), NOW());


# 収入カテゴリ挿入
INSERT INTO Categories (category, balance, createdAt, updatedAt)
VALUES ('給与', '収入', NOW(), NOW()),
       ('投資収入', '収入', NOW(), NOW()),
       ('その他', '収入', NOW(), NOW());
```
ブラウザをリロードしたらデータが登録されている。
![スクリーンショット 2023-07-22 19.49.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/be157b20-e616-8fa0-f068-250e3452e48b.png)

## サブスク登録（任意）
サブスクを登録すると、設定した支払日に自動で家計簿に支出を登録させることができるようになる。
（アプリ読み込み時に今日日付に応じて登録がキックされる仕様）
![スクリーンショット 2023-07-22 19.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/05825ec4-563b-0d38-710e-d9e599ad9763.png)

## 家計簿登録
入力タブの画面から各値を入力して、「登録ボタン」を押すだけ
![INPUT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/bb99e1f5-71ee-e5ea-4e9c-93226b9dee27.png)

入出金一覧に表示される。
![スクリーンショット 2023-07-22 19.57.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/c09b06ac-749e-36de-7f4a-f8aecbd18e56.png)
※「delete」を押したら一覧からレコードが削除され、レコードの値を変更して「change」を押したら変更が反映される。


## 月データ・年データ
「月データ」、「年データ」タブからは、そのぞれ月間と年間の家計を確認できる。
![スクリーンショット 2023-07-22 20.06.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/a0709a65-193e-d1ee-89f6-98459c59b318.png)
![スクリーンショット 2023-07-22 20.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510731/0fc21479-bc88-a4ca-0813-1c52a1cc1db1.png)

# あとがき
実用性を第一にして作りましたが、「ここをこうしたらどうなるんだろう？」という知的好奇心で実装を行なった部分もあるので、動作が完璧でない部分も多分にしてあります。

あくまで教材として参考にしていただければありがたいです。

もしかしたら今後も機能を追加していくかもなので、その際は、このページにも更新内容を上げるかもです。