【文系PMの作る】nuxt+netlify+firebaseで作る最高の睡眠を記録するwebアプリ（前編）

こんばんは、そしてはじめましてyou8といいます。普段はプロダクトマネージャーをしてて、趣味で休日にコードを書いています。

最近30代を迎えて体調管理をしたいなと思って色々調べてたらドハマリしてしまい、いろんな数値をログとって遊んでいます。ただいろんなログとっても一般的にいい数字と照らし合わせられるけど結局自分の体にどれくらいが適正かはよくわからないなと。例えば睡眠６−７時間がいいと言われていても実際は6時間ぐらいがちょうどーいいなーとか。

結局清々しい寝起きだったの？一日気分良かったなど100%主観的な体調を記録できたらいいな。それをグラフとかで見れたら最高だなと思って

* 簡単にログが取れて
* 簡単にグラフにできる

webアプリを作ろうかなーと思って色々調べました。ちなみに僕は文系PMなんで本職エンジニアじゃない人間が趣味で作るときにどんなことを勉強して、どんなことを調査してプロダクト作っているかも書いていきます。

# 要件

* 簡単に日々の快眠度を10段階で送れる
* 勝手に日付もつけて送ってくれる
* それをいい感じのグラフに見せる

# 仕様

## 【PM観点】スケールなど将来のことを考える

webアプリケーションは最初の設計で躓くと後々のスケールが非常に困難になったりします。（DB設計やフレームワークの選定など）PMはエンジニアとこのプロジェクトが将来的にどうなるのか？スケールを考慮したほうがいいのか？どういうDB絡むが追加される可能性があるのかを意識合わせできるとあとで困らないのかなと思います。

今回のプロジェクトで言うと最初googleスプレッドシートをDBかわりにしようと考えていました。（入力した数値をスプレッドシートで色々編集できると楽しそうなので）ただ調べていく中でgoogleスプレッドシートだと反映が遅そうなので複数人同時で使う場合不便そうだなと思いました。そもそもDB目的のものじゃないので後でメンテも大変そうだなと。将来似た形で公開サービスとしても出す可能性もあるなと思ったので今回はfirebaseに値を送り、DB代わりにして余力があればfirebaseからgoogleスプレッドシートにGASで値を送ることにしました。

## 今回はnuxtを使うことに

普段はrailsで色々書くんですが今nanaではwebで色々やっていてSPAにも興味が出てきました。アプリをメインにするサービスで今後webをクライアントの一つと捉えてフロントエンドのフレームワーク+APIという構成は増えるはず。その中でSSR周りに強いものに興味があったのでnuxtを勉強してみることにしました。SPAとSSRを勉強したいが今回のモチベ。

## バックエンドはfirebaseに

firebaseもよく聞くけどあまり使ってこなかったのでこの際一緒に勉強することにしました。

## 画面構成

画面構成は入力+グラフ見るだけなので下記

![IMG_0053.PNG](https://qiita-image-store.s3.amazonaws.com/0/193389/b33381b7-10e7-85e7-7319-2e3e7cda7123.png)


## 機能

* gmailでログインする機能
* 数値、日付を入力する機能
* 数値をgoogleスプレッドシートに入力する機能（ここは後回しに変更）
* グラフ出力

# 勉強すること

* javascript
* googleappsscript
    * googleスプレッドシートの入力、取得
* nuxt
* firebaseのgoogleアカウントlogin

# nuxtで画面を作る

## nuxtのルーティングめちゃくちゃ便利

nuxtはvuerouterでルーティングしていてファイルを作成すると自動的にルーティングしてくれる。つまり静的なルーティングに関してはファイル作るだけ。超簡単。

## グラフ作成をchart.jsで

chart.jsがすごく便利そうだったからこれを使うことに。どうやって書いていくかは後編に書くぞ！

# netlifyにデプロイ

今回netlifyでデプロイして公開することに。正直herokuとちゃんと使い分けれてはないけどbuildもしてくれるし色々便利。SPAでは今後も使いたいかも。nuxtにもドキュメントがあって下記。

https://ja.nuxtjs.org/faq/netlify-deployment/

## netlifyの設定

![スクリーンショット 2018-11-24 12.39.16.png](https://qiita-image-store.s3.amazonaws.com/0/193389/e47f9346-3491-c166-2b9d-420e13c8b343.png)

設定はこんな感じ。distにbuildして公開する。

## githubと連携

ブランチは一応masterではなくreleaseを作り、ここにpushしたら自動で

# 予定を変更してview→gasからview→firebase→gasに

最初は直接いろいろ編集しやすいようにgasでgoogleスプレッドシートに直接書き込もうとしたんですがセル制限があることやもともとDBではないので書き込みが遅いという情報があったのでfirebaseを挟むことにした。別にこのアプリケーションは遅くてもいいし、実際にはセル制限に引っかかるほど使う気はないんだけどせっかく勉強するなら他のwebサービス作るときに応用できるスケール可能な実装を勉強したなと思って変更。

# ログイン機能

ログインはgoogleでFirebase Authentication経由でログインします。最初user_idを振ろうと思ったんですがFirebase Authenticationはindex番号的なのを取得できず、（ってか無い。多分）uidで管理するのでそれをもとにuserページを作ることに。

## 設計

![IMG_0052.PNG](https://qiita-image-store.s3.amazonaws.com/0/193389/93072f9a-3e71-2f12-2f14-2a5c11b317c2.png)

こんな感じで

* components/home.vueからsignInWithRedirectでsignin
* それをpages/index.vueのonAuthStateChangedで観測してサインインしたらvuexにcommitする
* store/index.jsに書いているvuexでmutation通してstateを変更

## firebaseをnuxtにinstall

```
npm install firebase --save
```

上記でinstallしてpluginsにfirebase.jsの記述。

```javascript:plugins/firebase.js
import firebase from 'firebase'

if (!firebase.apps.length) {
  firebase.initializeApp({
    apiKey: "",
    authDomain: "",
    databaseURL: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: ""
  })
}

export default firebase
```

## store/index.js

## 

## signInWithRedirectでサインイン

```javascript:components/home.vue
<template>
    <button @click="googleLogin">googleでログイン</button>
</template>

<script>
import firebase from '@/plugins/firebase'
export default {
  name: 'home',
  methods: {
    googleLogin: function() {
      firebase.auth().signInWithRedirect(new firebase.auth.GoogleAuthProvider());
    }
  }
}
</script>
```

## onAuthStateChangedで変更時に処理

```javascript:pages/index.vue
 mounted: function() {
   firebase.auth().onAuthStateChanged(user => {
     var user = firebase.auth().currentUser;
     if (user) {
       this.isLogin = true;
       this.userData = user;
       this.$store.commit('login',this.userData)
     } else {
       this.isLogin = false;
       this.userData = null;
     };
   })
 }
```

こんな感じでvuexにcommitする。

>オブザーバーを使うと、現在ログインしているユーザーを取得するときに Auth オブジェクトが中間状態（初期化など）ではないことを確認できます。signInWithRedirect を使用する場合、onAuthStateChanged オブザーバーは getRedirectResult が解決された後にトリガーされます。

引用：https://firebase.google.com/docs/auth/web/manage-users?hl=ja

onAuthStateChangedをトリガーにuser情報を取得user情報があればcommit。

## vuexの設定

```javascript
/*一部省略*/
    mutations: {
      login(state, user) {
        state.user = user
        var uid,name;
        state.uid = state.user.uid;
        state.name = state.user.displayName;
      }
/*一部省略*/
```

https://qiita.com/m_mitsuhide/items/f16d988ec491b7800ace

vuexよくわからなかったんですが

https://qiita.com/m_mitsuhide/items/f16d988ec491b7800ace

この記事だいぶわかりやすかった。

# 数値入力機能

睡眠快適度をfirebaseに送る。設計は下記で

```javascript
    saveContent: function(value) {
      var newNoteKey = firebase.database().ref().child('notes').push().key;
      var today = Date.now();
      firebase
        .database()
        .ref('notes/' + this.user.uid　+ '/' + newNoteKey)
        .set({content:value,date:today});
    }
```

user.uidの下に

* 数値
* 日付

を入れてあとで線グラフに最高の睡眠度を表示。

# CSS

## CSSの設計

「nuxtでのcss設計」
https://qiita.com/you8/items/36c9031c55fecac402ec

css設計についてはここにまとめた。

## bootstrapvueの導入

今回はbootstrapvueを導入したので

```
npm i bootstrap-vue --save
```

してnuxt.config.jsに以下を追加。

```javascript:nuxt.config.js
{
  modules: [
    'bootstrap-vue/nuxt',
  ]
}
```

# nuxtを触った所感

SSRが簡単にできるし、状態管理、ルーティングも簡単なので非常に使いやすかった。ルーティングはファイルの命名でほとんど自動なので状態管理のvuexさえ勉強すればすぐ使えるレベルだと思う。導入コストがそこまで高くない。（そんなに使いこなせていないけど）

# PMがプログラミングを勉強する必要はあるのか？

PM、ディレクターなら一度くらいはプログラミングを勉強してみようと頑張ってみた経験があるはず。9割がた失敗すると思うけど果たしてプログラミングをエンジニアではなくPM、ディレクター職が勉強する必要があるのかというと必要はない。と思うが非常に費用対効果の高い投資だなと思う。

別にプログラミングに限らず、PMが各職種の技術やノウハウを把握しているのはディレクションの質や戦略の綿密さに直結する。今お願いしようとしているのは誰に頼むべきなのか？サーバサイドか？クライアントか？なんの情報をとってきて作る機能か？一つ一つエンジニアに説明してもらうコストを支払ってもらうのか一度勉強してそれをなくすか。説明する側のコストをディレクションする側が払うことで何人分ものコストを消すことができる。

もちろん一人の人間に習得できる技術はある程度決まっているのでどこまでやるかだけどwebサービスのPMならエンジニアと接することが多いのでプログラミングが最も費用対効果高い。

少なくともサーバーからクライアントサイドまでめっちゃ簡単なアプリケーション作って流れを把握するだけでだいぶ違うかなと。

# 後編へ続く！

長くなりそうなので12月下旬にアドベントカレンダーに後編を書きます！