Ruumarkerをリリースしました

本日、Ruumarker(ルーマーカー)というサービスをリリースしました。

入居時チェック表作成サービス「Ruumarker」

リリースについて

GitHub

https://github.com/kasai441/ruumarker

サービス概要

引越しした時、不動産管理者に入居時の部屋の状況を報告するための書類を作成するためのサービスです。

キズの位置とその写真が載っている「入居時チェック表」を作成してPDFでダウンロードできます。

もし入居時に部屋にキズがあった場合に、自分の過失でないことをあらかじめ説明しておけば、不当な修繕費の請求を避けられるかもしれません。

サービス構成

サービス構成

開発時期

2021年7月: サービス内容検討開始

2021年10月: 要件決定

2022年1月: 開発開始

2022年7月: リリース

開発背景

本サービスはフィヨルド・ブートキャンプの最終課題として開発しました。サービスの仕様・要件は当校のメンターに提案されたものです。また、開発手順は当校のカリキュラムに沿って開発され、各ステージにおいて多くのアドバイスをいただきました。

開発者

@kasai441

正味2年のシステム会社開発経験を経て、フィヨルド・ブートキャンプにて1年半に渡ってWEBアプリ開発の学習をしてきました。今後WEBアプリ開発の求職活動予定。元オンラインゲーム背景イラストレーター。

サービス紹介

Ruumarkerとは?

Ruumarkerは、入居時チェック表を作るサービスです。

入居時チェック表とは?

✅入居時にキズがあったら?

入居時に自分のつけていないキズや汚れがあったら、管理人や不動産会社に報告する必要があります。

✅どうして報告するの?

施工時についたキズなら直してもらえるかもしれません。賃貸なら敷金から修繕費が差し引かれるのを防げます。

✅どうやって作る?

1. 間取り図を用意

まずは部屋の間取り図を用意します。スマホのカメラで撮影できればOKです。

間取り図

2. チェック表を作成

「入居時チェック表を作成する」からチェック表作成を始めます。

間取り図アップロード
間取り図アップロード

間取り図にキズ情報を加えていきます。

キズ情報の追加
キズ情報の追加

3. 大家さんに提出

管理人や不動産会社にキズがあった旨を伝えて、チェック表を提出します。

チェック表 見本

drive.google.com

開発過程

エレベーターピッチ

自作サービス作成の最初のステップで、サービスの指針となる要件を決定します。これは、プロダクトオーナーに一言でサービス内容を提案・説明して採用してもらうという想定で、世の中に潜在する何らかの「問題」を提示し、それを「解決」するためのツールとしてのサービスを定義します。

何回か自分の提案がボツになった後、自分のアイディアでサービスを作ることを諦めて、思いつかない人用に用意されたサービス案の中から以下のサービスを作ることを決めました。

[新居チェック報告] というサービスは、[引っ越しをした際、新居に既に傷があった場合にそれを写真で撮って傷のあった場所と共に不動産屋に報告するのが困難な問題] を解決したい、[賃貸物件に引っ越したばかりの人] 向けの、[新居に既にあった傷とその位置を伝える書類作成]サービスです。ユーザーは [ブラウザ上で傷の位置とその写真が載っている書類を作成する]ことができ、[文章で傷の位置を伝えるの]とは違って、[アップロードした間取り図に傷の位置矢印で指定することができる]事が特徴です。

このサービスを作ろうと思った理由は、「あれば便利」と思えたこと、「ちょうど自分の技術より少し高度なことをしそう」と思ったことです。無理なく少し高いハードルを越えることで、実現性のあるステップアップをめざしました。

ペーパープロトタイプ

このステップでは画面設計を行いました。この段階では、デザインを詰めたり、UIについて最適化する必要はなく、画面に登場する要素をレイアウトして全体図を掴むのが目的となります。

今回はFigmaというオンラインのツールをつかって、以下のようにベタ書きで画面遷移図を書きました。(本来、Figmaは共通パーツを作ったりページ遷移に沿った画面作成ができますが、自分はそれらの機能は学ばず、単なるクラウドお絵かきツールとしてしか使っていません。)

ペーパープロトタイプ

この段階で決めた要素はほとんど最後まで残りましたが、遷移の順番やレイアウトは、開発を進めながら、技術的制約やコストやユーザービリティの観点で少しずつ異なっていきました。

技術検証

サービスの全容が固まったところで、実装のための技術を検証します。

フィヨルド・ブートキャンプでは、自作サービス課題に入る一つ前の課題で、実際に運用しているアプリのスクラム開発に参加します。

GitHub - fjordllc/bootcamp: プログラマー向けEラーニングシステム

このアプリのサービス構成は、それまでの課程で学んできた言語とフレームワークを使ったものになっています。主に

を使用して実装を実践経験することができます。

新しいサービスを作ろうとする時は、スクラム開発課題での経験を引き継ぐ形で考えられます。そこから拡張して、どの程度独自性を発揮するかは、学習コストと技術アピールの兼ね合いで決まってくると思います。自分で調べて新たなスキルを導入すれば、より幅広いスキルをアピールできるでしょう。しかし、それ相応の学習コストがあるため、完成のための時間を余計にかけられるかどうかを見極める必要があります。

今回、自分のサービスの仕様を考えた時、経験していない実装方法、あるいは実装のための環境構築として以下のようなものがありました。

  1. 画像編集の機能をどのように実現するか
  2. RailsJavaScriptの連携をどのように実現するか
  3. フロントエンドのフレームワークを何にするか

これらについては、自分なりの技術選定を行う必要がありました。

1. 画像編集の機能をどのように実現するか

画像編集の機能は、ユーザーがアップロードした画像を拡大縮小したり回転したり上下左右をトリミングしたりできることが望まれました。

JSについてはDOM操作をほとんどしたことがなかったので、はじめはこれらを技術的に実現する方法が思いつきませんでした。メンターにインタビューするとCanvas APIというJavaScriptとHTML要素によるグラフィックを描画する方法があることを教えてもらいました。

おなじ課題に取り組んでいるブートキャンプの先輩のコードを覗いてみると、Canvasを簡単に操作できるJavaScriptのライブラリを使っているようでした。

JavaScriptのDOM操作については、Web書籍の『Eloquent JavaScript』やチュートリアル・サイトの『javascript.info』でも紹介されおり、Canvasの他にもSVGというマークアップ言語においても画像描画が可能なことを知りました。

これらのライブラリを使うかどうかに限らず、DOM要素を利用した何らかの方法で画像編集が実現できそうでした。具体的に何を使うかは確定していなかったのですが、検証で時間がかかりすぎていたので、「できそう」という手応えが得られた時点で技術的な検証はOKと判断しました。

最終的にはライブラリを利用しないDOM操作がメインで使用されましたが、Canvasは画像の回転や容量制限に用いられ、SVGはフォントのデザインに利用されました。いずれも何らかの形で採用されており、ここでの技術検証は非常に役立ちました。

2. RailsJavaScriptの連携をどのように実現するか

Railsは近年までWebpackerというライブラリを利用してJavaScriptのコードをコンパイルしてフロントエンドとの連携を構成するのが主流でした。ところが2021年の末に発表されたRailsのバージョン7において、Webpackerを公式にサポートせず、Webpacker自体の開発も終了されることが判明しました。

見本となるブートキャンプアプリは、Rails6 + Webpacker + Vue.jsの構成でしたが、すでにRails7のアナウンスが発表された後だったので、この構成はのちのち変更が必要なことがわかっていました。

そこで、今回は、学習コストをはらって、自分で調べてRails7を採用することに決めました。JavaScriptとの連携方法はこの時点では決断していません。

3. フロントエンドのフレームワークを何にするか

この段階ではフロントエンドのフレームワークにまで考えを巡らせることができませんでした。とにかく手を動かさないとモチベーションが保てなかったので、サーバーサイド開発を始めてしまいます。

サーバーサイド

かんばん

GitHubのプロジェクトツールを利用してまずは看板の作成をしました。これはGitHubのIssueやPull Requestと連動させてタスク管理できるツールで、開発初期の計画作りからリリース後のメンテナンスまで一貫して同じ手続きで管理していくことができます。

https://github.com/kasai441/ruumarker/projects/1

このツールが優秀なこと、加えるべきタスクの例がカリキュラムの課題文で提示されていたことから、非常に簡単にプロジェクトを起こすことができました。

やるべきことを箇条書きするだけで、思ったよりモチベーションが上がったので、とりあえず書き出してしまうのが良い方向につながりました。

サーバーサイド開発

プロジェクト立ち上げから、テストまでのサーバーサイドの行程は『現場で使える Ruby on Rails 5速習実践ガイド』を大いに参考にしました。この本については、フィヨルド・ブートキャンプ内のコミュニティで行われていた輪読会に参加して、精読したことがあったので、この本にそって開発を進めました。何も知らないところから実装まで、丁寧に解説されているため、難易度のレベル感があっていて、楽しく作業できました。

既に学んだことを思い出すのは楽しいです。今までカリキュラムで学んだことが、アプリ開発によってスムーズに実践されていきました。

  • DB設計、モデル作成
  • URL設計、ルーティング
  • コントローラー、仮のビュー作成
  • RspecによるE2Eテスト
  • AWS S3への接続
  • Herokuへのデプロイ

フロントエンド

フロントエンドの技術検証

先述の通り、フロントエンドの技術検証がしんどかったので、サーバーサイド開発を先にやってしまって、後回しにしていました。いざフロントの開発という段になって検証を始めたら、けっこう大変な作業となってしまいました。

まずは以下のような、サーバーサイドとフロントエンドの組み合わせを選択肢として挙げ、一つずつ吟味することにしました。

  1. Rails7 + バニラJS
  2. Rails7 + Webpack + Vue.js
  3. Rails6 + Webpacker + Vue.js
  4. Rails7 + Stimulus

実際に動かしてみないとストレスが溜まっていくので、それぞれのパターンのプロジェクトをデモ用のレポジトリーに構築して、起動できるかを確認しました。それぞれのファイル構成・内容の差分を確認していき、どうやら「2. Rails7 + Webpack + Vue.js」の組み合わせで構築できそうだと分かりました。

採用理由はやや混雑した思考で、

  • 新しいRails7が動かしたい
  • 昔からあるWebpackを知りたい
  • Vueができるからやっとく

みたいな感じでした。一度触ったことがあるものをもう少し詰めてみたくなる気持ちと、新しいものを知りたいという気持ちが混在しています。

詳細は以下の記事にまとめています。

Railsにどのようにフロントエンドを連携させるかの技術検証っぽいこと(Rails7 + Webpack + Vue.js3)

画像アップロードの実装

すでにサーバーサイド開発の時点で画像アップロード機能はRailsのみで実現できていました。しかし、Vue.jsでフォーム画面を作ると、入力された情報をJavaScriptAjax通信によってRailsへリクエストする必要が出てきました。幸い、次のブログ記事に、ほぼ同じ技術構成で画像をアップロードする機能の実装方法が書かれていたので、ほぼ丸ごと踏襲して実装しました。

【Rails API + Vue】Active Storageを使って画像をアップロード・表示する

Ajax通信のリクエストにはaxiosというライブラリを使っています。これで、FormDataクラスで作成したデータをそのままPUTリクエストに仕込むことができました。Railsへの書き込みリクエストで必要となるCSRFトークンをヘッダーに仕込む仕組みもaxiosを利用したものが多く検索でヒットしたので苦労なく実装できました。

この記事で使われているVuexは採用しませんでした。Vuexの公式のアナウンスで、複雑でないアプリでは非推奨と書いてあったことと、なるべく基本的なVueのSFCのデータ交換の仕組みを学びたかったためです。

if your app is simple, you will most likely be fine without Vuex https://vuex.vuejs.org/#when-should-i-use-it

画像をドラッグ&ドロップで移動して保存する。

フロントエンドで、ひいてはこのアプリ全体の技術の中で、最も重要で未知数だった実装は、画像のドラッグ&ドロップ編集機能でした。

この技術が使用される画面は二つあります。

  • 画像トリミング

間取り図とキズの写真をトリミングするために、ドラッグ&ドロップで画像を動かせるようにしたいです。目指したのはTwitterの画像編集画面です。

画像トリミング

  • キズ位置

間取り図の中にキズの位置を指定するために、ベースの画像をドラッグ&ドロップしてポイントを指定するようにしたいです。目指したのはタクシー配送アプリのGOです。

キズ位置

画像トリミングだけなら、それ専用のJavaScriptのライブラリがあったのですが、キズ位置の実装を実現するライブラリはうまく見つけられませんでした。そこで、キズ位置の実装は自力でコードを書くことにしましたが、そうすると画像トリミングの機能も似ているので、共通で同じ処理を書けばよく、ライブラリは使わない方向に決めました。

そのかわり、ここはシンプルなJavaScriptのコードを書きました。

この記事にはHTMLエレメントを直接スタイルによって動かす方法が紹介されています。これをVue.js上で実現できるように応用しました。

Vue.jsでのイベントハンドラの書き方はこちらを参考にしました。

JavaScriptのテスト

JavaScriptのE2Eテストには、Rspec・Capybaraを使いました。Capybaraは高機能で、ドラッグ&ドロップの動作もテストで実現できました。詳細は以下のIssueに記録しました。

https://github.com/kasai441/ruumarker/issues/112

Canvasでのリサイズ

大きな容量の画像を指定のサイズまで縮小するために、Canvasを利用しました。画像ファイル情報を読み込んで、所定のサイズで再描画する処理となりました。以下の記事を参考にしてCanvasの操作を実装しました。

大きな画像をJavaScriptでリサイズしてからAjax送信する方法 - CONSOLE DOT LOG

ここでは、生成された画像をVue.jsでの同期的な処理で行っていましたが、同様の処理を切り出して使い回すために、非同期処理に直す必要があったので、以下の記事を参考にして、メソッド切り出しを行いました。

PromiseベースでImage().onloadする

Capybaraではスタイルを当てられたあとの画像サイズは簡単に取得できるのですが、この機能のテストでは画像の元サイズが変更されているかどうかを確かめる必要があります。元サイズを参照するには、ブラウザ操作ツールのSeleniumにおいてJavaScriptを操作して、画像のnaturalWidthを取得することで実現できました。

it '画像幅が元のままとなる' do
  show_image = page.find_by_id('show-image')
    expect(execute_script('return arguments[0].naturalWidth', show_image)).to eq 88
end

このSeleniumJavaScriptを実行させる方法は次の記事で見つけました。苦労して検索したので、貴重な情報なのではないかと思います。

How To Test For Broken Images

実装時の記録は以下のIssueになります。

https://github.com/kasai441/ruumarker/issues/131

デザイン

CSSフレームワークにはTailwindを採用しました。

技術選定と環境構築

Vue.jsのバージョン3に対応していて、cssbundlingで簡単に実装できそうなTailwindを選択しました。

以下が、CSSフレームワークの技術検証とTailwindインストールのIssueです。 https://github.com/kasai441/ruumarker/issues/84

cssbundling-railsの公式ガイドに沿ってビルドはかなりスムーズにできました。jsbundling-railsを先にビルドしていたので、環境が揃っていたことが大きかったです。

Tailwindの使用感

TailwindはCSSファイルを全く自分では触らないで、すべて用意されたクラスをHTMLタグに書き込んで、内部的にCSSを生成させるフレームワークです。クラスがTailwind特有なので学習コストがかかるっぽく見えますが、クラスの命名CSSのプロパティから推測されやすくなっているので、ドキュメントは参照する程度で、使用感はフルスクラッチCSSを書いている感覚になります。クラス命名のクセを覚えたあとは、読むのも容易いので、作業中にフレームワークのクセで詰まるシーンはほとんどなかったです。

セキュリティ

セキュリティについては既にブログの記事にしているので以下に示します。それぞれの概要は次のとおりです。

CORS

CORS(オリジン間リソース共有)の設定について調べています。Vue.jsとRailsでの通信でクロスオリジンが発生する構成にしていないので、ほとんど場合、クロスオリジンは発生しません。そこでCORSの設定はデフォルトで、基本はクロスオリジンを許可しない設定にしました。

開発後半で、AWS S3において、画像を回転するとCORSに引っかかる、という不具合が発生しました。これは、AWS側の設定において回避できましたが、CORSについて事前に学んでおいたのでスムーズにバグ解消できたのがよかったです。

該当Issue: https://github.com/kasai441/ruumarker/issues/241

CSP

CSPはWebブラウザで使える機能を制限する機能ですが、デフォルトでは全てOFFになっているので、アプリが動く程度まで強い制限に設定し直しました。

ランダムURL

このアプリではユーザーのログインなしでサービスを利用できるようにしてユーザビリティを高めています。ユーザー情報のプライバシーはURLをランダムにすることで事実上他人にはアクセスできないようにして実現しました。このため、実際にはユーザーデータは公開されています。その脆弱性について検討したのが以上の記事です。

この記事を読んでもらってメンターから検索避けをしたほうがよいというアドバイスをいただきました。検索避けの実装は以下のIssueになります。

https://github.com/kasai441/ruumarker/issues/178

まとめ

長期間にわたって開発をおこなったのでこの記事をまとめることで自分でも忘れていたところを思い出すきっかけになりました。

この記録によって今後のWEBサービス開発作成をしている方の助力になれば幸いです。かなり端的に書いたので分かりにく所があればご質問お寄せください。

また、このサービスはなるべくなら今後も不足している部分をアップデートしていけたらと思っています。OSSなので何か改善案があればご意見お寄せください。