Mattermost改造チートシート

## この記事は何のためのもの？
この記事は、私がMattermostを改造するにあたって躓いた点や調べるのがしんどかった点を書き溜めたものとなっています。
「あれをするにはどうすれば良かったっけ？」となったときに記憶を辿らなくても済むようにする意図があります。
汎用的に役立ち得る情報かなと思ったので、記事として公開します。
今後も改造をしていく予定なので、新しい情報を随時追加していくつもりです。

## 前提条件
* 作業環境は「macOS Big Sur v11.x」とします。この記事の情報を他の環境で利用する際は、各部分を環境に合わせて適宜読み替えていただく必要があります。
* Mattermostのブラウザアプリが対象です。Mattermostのモバイルアプリ等は対象に含んでいません。
* 動かすMattermostのバージョンは、v5.30.2です。

## 01. Mattermostをソースから動かすためには何をインストールする必要がある？
必要なものは以下の通りです。
#### Dockerとdocker-compose
Dockerの公式サイトから最新版を取得し、インストールする。
以下のコマンドでdocker系コマンドが使えるようになっていることを確認する。

```shell:Dockerとdocker-composeをインストールした後の確認用コマンド
docker -v  # Dockerのバージョンが表示されればOK
docker-compose -v  # docker-composeのバージョンが表示されればOK
```
#### Go言語（v1.14.3）
こちらも公式サイトから最新版を取得し、インストールする。
インストール後、環境変数PATHとGOPATHが通っていることを確認し、通っていなければ通す。

```shell:Goをインストールした後の確認用コマンド
printenv PATH  # Goのパス（例：/usr/local/go/bin）が含まれていればOK
printenv GOPATH  # フォルダパスが表示されればOK
go version  # 「go version go1.14.3 darwin/amd64」と表示されればOK
```
#### Node.js（v10.20.1）
nvmが導入済みであれば、以下のコマンドでインストールできる。

```shell:Nodeのインストールと確認用のコマンド
nvm install v10.20.1  # すでにこのバージョンのNodeを取得済みであれば、バージョンの切り替えだけが行われる。
node -v  # 「v10.20.1」と表示されればOK
npm -v  #「6.14.4」と表示されればOK
```

#### Makeコマンド
以下のコマンドでmakeコマンドが導入済みであるかどうかを確認し、導入済みでなければ取得・インストールする。

```shell:Makeがインストール済みかどうかの確認用コマンド
make -v  # バージョン番号が表示されればOK
```

#### Gitコマンド
以下のコマンドでgitコマンドが導入済みであるかどうかを確認し、導入済みでなければ取得・インストールする。

```shell:Gitがインストール済みかどうかの確認用コマンド
git --version  # バージョン番号が表示されればOK
```


## 02. Mattermostのソースはどのように取得する？
改造するための大元となるMattermostのリポジトリ（Githubで公開されている）を取得します。
コマンドラインで以下の通りにコマンドを実行し、cloneします。

```shell:ソース取得用のコマンド
cd (ソースを設置したい任意のパス)
# 履歴の取得量を抑えつつ、対象バージョンのソースをcloneする。
git clone https://github.com/mattermost/mattermost-server.git -b v5.30.2 --depth 1  # サーバーサイドのソース
git clone https://github.com/mattermost/mattermost-webapp.git -b v5.30.2 --depth 1  # フロントサイドのソース
git clone https://github.com/mattermost/mattermost-redux.git -b v5.30.2 --depth 1  # Redux部分のソース
```
ソースが取得できたら、以下のように３つのフォルダが出来上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140394/63584a99-a803-3d9b-d960-a3784e4c5430.png)

## 03. Mattermostはどのようにビルド・起動させる？
各種リポジトリを取得してきたフォルダで、以下の通りにコマンドを実行します。

```shell:
# まず、フロントサイドをビルドする。
cd mattermost-webapp
make clean  # このコマンドは初回のビルドでは不要だが、2回目以降はゴミを巻き込まないようにするためにやっておいた方が良い。
make build  # ビルドが終わるまでしばらく待つ。
# 次に、フロントサイド（ビルドで生成されたもの）とサーバーサイドをリンクさせつつ、サーバーサイドをビルドする。
cd ../mattermost-server
ln -nfs ../mattermost-webapp/dist client
make run-server  # 起動に成功すると、コマンドライン上にログ情報が書き出され始める。
```
ここまでを実行したら、Webブラウザで「 http://localhost:8065 」を開きます。
Mattermostのアカウント作成画面が表示されれば起動成功です。

## 04. 起動させたMattermostはどのように停止させる？
サーバーサイドのソースのrootディレクトリで停止用コマンド（下記）を実行することで、停止させることができます。

```shell:
make stop-server
```

## 05. 公式のソースからそのまま起動させたMattermostはどのような構成で動いている？
以下のような構成で動いています。MySQLはコンテナ自体は立ち上がるものの使われておらず、DBとしてはPostgresが使用されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140394/83a2481e-50bf-258f-b853-b197a0bfc511.png)
後述の手順によって、DBをPostgresからMySQLに切り替えることが可能です。

## 06. Mattermost用のDBをPostgresコンテナからMySQLコンテナに変更するには？
MattermostがどのDBを使用するかは、mattermost-server/config/config.jsonで定義されています。
このファイルをテキストエディタで開き、以下のように編集・保存してからmattermost-serverを起動（make run-server）すれば、今度はMySQL（mattermost-mysqlコンテナ）が使用されるようになります。

```json:config.json（修正前）
・・・省略・・・
    "SqlSettings": {
        "DriverName": "postgres",
        "DataSource": "postgres://mmuser:mostest@localhost/mattermost_test?sslmode=disable\u0026connect_timeout=10",
・・・省略・・・
```

```json:config.json（修正後）
・・・省略・・・
    "SqlSettings": {
        "DriverName": "mysql",
        "DataSource": "mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8\u0026readTimeout=30s\u0026writeTimeout=30s",
・・・省略・・・
```
#### 補足1：DBの設定値（スキーマ名等）はどこにある？
このconfigファイルで指定しているDBのパラメーター（ユーザー名やポート番号等）は、Dockerコンテナ生成に使用する各定義ファイル（下記）に記載されています。

* mattermost-server/docker-compose.yaml
* mattermost-server/build/docker-compose.yml
* mattermost-server/build/docker-compose.common.yml

※後ろの2ファイルだけヤムルの拡張子が異なっていますが、問題なく動きます。

#### 補足2：config.jsonを直接編集するよりも多分良いやり方
このconfig.jsonファイルは、mattermost-server直下で以下のコマンドを実行することによりデフォルト値にリセットされる仕組みとなっています。

```shell:コマンド
make config-reset  # このコマンドで実行される処理内容の定義は、同ディレクトリにある「Makefile」の内容を参照。
```
そのため、編集後のconfig.jsonをコピーし、「config_mysql.json」等の名前で別途保存しておいた方が良いです。
「make run-server」を実行する前にconfig.jsonを差し替えれば、差し替えた通りの設定でサーバーが稼働するようになります。
Makefile内の「run-server:」区画にてconfig.jsonを差し替えるような処理を足せば、「make run-server」の都度、自動的にconfig.jsonが差し替わるようにすることも可能です。

## 07. Mattermost用のDBをDocker内に生成されるもの以外に変更するには？
例えば、任意のサーバー（AWS等）に立てたMySQLに変更するものとします。
まず、MySQLを立てた後、MySQLの中で以下のように設定を作成します。

| 設定項目名 | 値 |
|:--|:--|
| スキーマ名 | mattermost_test |
| ユーザー名 | mmuser |
| パスワード | mostest |
| ポート番号 | 3306 |

この設定を作成後、ユーザー「mmuser」に対してスキーマ「mattermost_test」の全操作権限を付与します。
その後、mattermost-server/config/config.jsonを以下のように編集することで、DBをこのMySQLに変更することができます。

```json:config.json（修正後）
・・・省略・・・
    "SqlSettings": {
        "DriverName": "mysql",
        "DataSource": "mmuser:mostest@tcp(************:3306)/mattermost_test?charset=utf8mb4,utf8\u0026readTimeout=30s\u0026writeTimeout=30s",
・・・省略・・・
```
↑この「************」の部分を、自身で立てたMySQLのサーバーのIPアドレス（AWSに立てた場合はエンドポイント）に書き換え、「make run-server」コマンドでMattermostを起動すれば、自身で立てたMySQLが使用されるようになります。
DBの各設定値を変える場合、このJSONの対応部分をそれに合わせて編集すれば大丈夫です。

## 08. PostgresとMySQLのDockerコンテナを生成しないようにするには？
上記手順でDBの接続先を外部に変更した場合、初期設定で作成されるPostgresとMySQLのDockerコンテナは不要となります。
これら不要なコンテナが作成されないようにするには、mattermost-server/config.mkを以下のように変更・保存します。

```:変更前
ENABLED_DOCKER_SERVICES ?= mysql postgres inbucket
```

```:変更後
ENABLED_DOCKER_SERVICES ?= inbucket
```

このように保存した後、以下のコマンドを実行し、Dockerコンテナの再生成とサーバーの再起動を行います。

```shell:コマンド
# mattermost-serverディレクトリで以下のコマンドを実行する。
make clean-docker
make run-server
```

ここまでを実行したら、Webブラウザで「 http://localhost:8065 」を開くことが可能となります。

## 09. Mattermost用のDBにテーブルを増やすにはどうすれば良い？
修正対象はGoのソースです。
＜後日追記予定＞

## 10. Mattermost用のDB上の既存のテーブルにカラムを増やすにはどうすれば良い？
修正対象はGoのソースです。
ここでは例として、Usersテーブルに「IsCosplayer」というbool型（MySQLだとtinyint型）のカラムを追加するものとします。

まず、mattermost-server/model/user.goを任意のテキストエディタで開きます。
このソースの中に、「User」という名前の構造体の定義があります。

```golang:User.goから抜粋
type User struct {
	Id                     string    `json:"id"`
	CreateAt               int64     `json:"create_at,omitempty"`
	UpdateAt               int64     `json:"update_at,omitempty"`
	/* ・・・中略・・・ */
	TermsOfServiceId       string    `db:"-" json:"terms_of_service_id,omitempty"`
	TermsOfServiceCreateAt int64     `db:"-" json:"terms_of_service_create_at,omitempty"`
}
```
ここに、以下のようにフィールドを足し、保存します。**必要な修正はこれだけです。**

```golang:User.goから抜粋
type User struct {
	Id                     string    `json:"id"`
	CreateAt               int64     `json:"create_at,omitempty"`
	UpdateAt               int64     `json:"update_at,omitempty"`
	/* ・・・中略・・・ */
	IsCosplayer            bool      `json:"is_cosplayer"`  // この行を任意の位置に追加
	/* ・・・中略・・・ */
	TermsOfServiceId       string    `db:"-" json:"terms_of_service_id,omitempty"`
	TermsOfServiceCreateAt int64     `db:"-" json:"terms_of_service_create_at,omitempty"`
}
```
修正後、必要に応じてUsersテーブルの既存データを退避させ、**DBのUsersテーブルを削除してから**「make run-server」を実行し、Mattermostを起動します。すると、Usersテーブルに上記のカラムが追加されます。
**Mattermostは不足しているテーブルの生成は自動で実行してくれるものの、カラムの変更や追加には自動では対応できない**ので、その点は注意が必要です。

## 11. Mattermost用のDBのER図を自動生成するにはどうすれば良い？
これに関してはMattermostに限った話ではありませんが、非常に便利で有用なのでTipsとして紹介します。
[SchemaSpy](http://schemaspy.org/)をDockerで実行し、ER図を含むDBの定義情報をドキュメント化する、という方法です。

**【注意点】**

* MattermostのDBは外部キーが貼られていないため、ER図上のリレーションに関しては、SchemaSpyが類推してくれたものが出力されます。自動生成されるドキュメント上に、リレーションが類推である旨の注意書きが記載されます。
* ここに記載する手順はMySQLを前提にしています。PostgreSQLを使用する場合、適宜読み替えていただく必要があります。

#### 生成されるドキュメントのイメージ
■テーブルの定義（例：Channelsテーブル）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140394/3d61a646-97c5-75fd-d0eb-86ee2486b190.png)
■リレーション
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140394/07044bef-6097-84b9-be46-bfd596158a59.png)

#### 事前準備
mattermost-serverディレクトリ上で以下のコマンドを実行し、SchemaSpyで使用するためのMySQL用JDBCドライバを用意します。

```shell:コマンド
mkdir -p schemaspy/drivers
curl -L https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.23.tar.gz |
    tar xvzf - -C schemaspy/drivers --strip=1 mysql-connector-java-8.0.23/mysql-connector-java-8.0.23.jar
```
接続先のDBのバージョンが比較的新しい場合、SchemaSpy内にデフォルトで持っているJDBCドライバでは繋がらない場合があります。

#### Dockerコンテナ上のMySQLを使用している場合の生成手順
この記事に記載している手順でDBをDockerのMySQLに切り替えたと仮定した手順を記載します。
まず、mattermost-server/docker-compose.yamlを開き、以下のように「schemaspy」の定義を追記・保存します。

```yaml:mattermost-server/docker-compose.yaml（追記前）
・・・省略・・・
    command: postgres:5432 mysql:3306 minio:9000 inbucket:10080 openldap:389 elasticsearch:9200

networks:
  mm-test:
・・・省略・・・
```

```yaml:mattermost-server/docker-compose.yaml（追記後）
・・・省略・・・
    command: postgres:5432 mysql:3306 minio:9000 inbucket:10080 openldap:389 elasticsearch:9200

  schemaspy:
    image: schemaspy/schemaspy:snapshot
    networks:
      - mm-test
    depends_on:
      - mysql
    volumes:
      - ./schemaspy/drivers:/drivers
      - ./schemaspy/output:/output
    tty: true
    command: -t mysql -host mysql:3306 -db mattermost_test -u mmuser -p mostest -s mattermost_test -debug

networks:
  mm-test:
・・・省略・・・
```
MySQLのコンテナはDocker内のネットワーク「mm-test」に属しているので、SchemaSpyのコンテナも同じネットワークに属させる必要があります。そのため、「networks」の指定は必須となります。
command内の引数「-debug」は必須ではありませんが、SchemaSpy内のJavaの処理でエラーが発生した場合にその内容を出力してくれるようになるので、うまく動かなかった場合の調査に便利です。
追記・保存を終えたら、mattermost-serverディレクトリで以下のコマンドを実行します。

```shell:コマンド
docker-compose up schemaspy
```
「ERROR - dot -Tping:（以下略）」という内容のエラーが多数表示されることがありますが、SchemaSpy自体は問題なく動いています。
すると、docker-compose/schemaspy/outputディレクトリが生成されます。
その中にあるindex.htmlを開くと、ER図を含むDBの定義情報を見ることができます。

#### 外部のMySQLを使用している場合の生成手順
mattermost-server/docker-compose.yamlへの記載内容が異なる点を除き、Docker上のMySQLを使用している場合とほぼ同じになります。
このファイルに以下のように追記・保存します。

```yaml:mattermost-server/docker-compose.yaml（追記後）
・・・省略・・・
    command: postgres:5432 mysql:3306 minio:9000 inbucket:10080 openldap:389 elasticsearch:9200

  schemaspy:
    image: schemaspy/schemaspy:snapshot
    volumes:
      - ./schemaspy/drivers:/drivers
      - ./schemaspy/output:/output
    tty: true
    command: -t mysql -host ************:3306 -db mattermost_test -u mmuser -p mostest -s mattermost_test -debug

networks:
  mm-test:
・・・省略・・・
```
↑このyamlの中の「************」の部分を、自身で立てたMySQLのサーバーのIPアドレス（AWSに立てた場合はエンドポイント）に書き換えてください。
追記・保存を終えたら、mattermost-serverディレクトリで同じくコマンド「docker-compose up schemaspy」を実行することで、docker-compose/schemaspy/outputディレクトリ内にドキュメントが生成されます。

## 12. mattermost-webappをビルドしたときにエラーが発生したら何を確認すれば良い？

##### 【ケース1】 npm ERR! mattermost-webapp@0.0.1 build: `cross-env NODE_ENV=production webpack --display-error-details --verbose`
mattermost-webappで「make build」を実行した際にエラーが発生し、エラー文言の中にこの一文が入っていた場合、ビルドしようとしているwebappとreduxが噛み合っていない可能性があります。
もしwebappに合わせてreduxに何かしら手を入れている場合、mattermost-webapp/package.json内の設定値「mattermost-redux」を確認してください。
この設定項目がデフォルト値となっている場合、Githubにある元々のmattermost-reduxを見に行っています。
この設定項目を自身でフォーク・改造したmattermost-reduxのリポジトリ及びブランチを参照するよう書き換えることで、ビルドが通るようになります。

## 13. 《Docker使用時限定》 いつも通り「make run-server」したら一部コンテナが起動しなくなった！どうすれば良い？
この現象が発生すると、「make run-server」を実行した際、ターミナルに以下のように書き出されます。

```shell:MySQLが動かなくなった場合の例
・・・省略・・・
Status: Downloaded newer image for mattermost/mattermost-wait-for-dep:latest
Creating mattermost-inbucket ... done
Creating mattermost-postgres ... done
Creating mattermost-minio    ... done
Creating mattermost-mysql    ... done
Creating chaplin-mattermost-server_start_dependencies_run ... done
Waiting for mysql to listen on 3306...
sleeping
nc: bad address 'mysql'
sleeping
nc: bad address 'mysql'
sleeping
nc: bad address 'mysql'
sleeping
nc: bad address 'mysql'
sleeping
nc: bad address 'mysql'
sleeping
nc: bad address 'mysql'
sleeping
・・・以下、延々と同じエラーが書き出され続ける・・・
```
この現象は、大体DBのコンテナで起こることが多いです。
まず、この現象が起こっているコンテナのログを確認してください。DockerDesktopを入れている環境であれば、GUIから見に行くと楽です。
そのログの中に、以下のようにいかにも「空き容量が枯渇しています」という意味のエラー文言があれば、こちらに書く手順でこの問題を解決することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140394/6412fefc-ec68-a06c-af7c-3e75670955f3.png)
早い話が、Dockerの容量を空ければ解決します。
以下のコマンドの中から状況に応じて実行可能なものを選択・実行していけば、空き容量を確保することが可能です。

```shell:コマンド
# 停止しているコンテナを一括削除しても問題ない場合、以下のコマンドでコンテナを削除する。
docker rm `docker ps -f "status=exited" -q`
# 削除するコンテナを個別に選びたい場合、まずは全コンテナを表示させる。
docker ps -a
# その中から削除可能なコンテナの「CONTAINER ID」を控え、以下のコマンドでそのコンテナを削除する。
docker rm <CONTAINER ID>
# コンテナから参照されていないvolumeを一括削除しても問題ない場合、以下のコマンドを実行する。
docker volume prune
# 使用されていないイメージを一括削除しても問題ない場合、以下のコマンドを実行する。
docker image prune --all
# 使用されていないネットワークを一括削除しても問題ない場合、以下のコマンドを実行する。
docker network prune
```

その後、再度「make run-server」を実行すれば、Mattermostが起動するようになります。

## 14. Mattermostをブラウザで開くたびに「翻訳しますか？」と聞かれて鬱陶しい。どう対処すれば良い？
これはMattermostに限った話ではありませんが、サイトの言語を日本語（ja）に変更すればこの問題は解決します。
要するに、htmlタグ内の「lang」の値を「"ja"」に変えることができれば直ります。
Mattermostの場合、手を入れるファイルは「mattermost-webapp/root.html」です。

```html:root.html（変更前）
<!DOCTYPE html>
<html lang="en">
<head>
・・・以下略・・・
```

```html:root.html（変更後）
<!DOCTYPE html>
<html lang="ja">
<head>
・・・以下略・・・
```
上記の通りに修正・保存した後、mattermost-webappをビルドし直します。

```shell:コマンド
# mattermost-webappディレクトリで以下のコマンドを実行する。
make clean
make build
```
あとはmattermost-serverにて「make run-server」を実行してMattermostを立ち上げればOKです。