2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】未経験がはじめてのWebアプリを作ってみた

Posted at

はじめまして、ユータロー(@teq_yutaro)です。
前職はSES企業に勤めており、主にプロジェクト推進(PMに近い)の仕事をしていたのですが、だんだんと「創作」が好きだと感じ始め、徐々にWeb開発エンジニアとして働きたいと強く思うようになり、2024年11月にプログラミングスクール『RUNTEQ』に入学しました。

約4年間IT業界で仕事をしてきた私ですが、アプリなぞ作ったこともなく、「サーバーって結局何をしてるの?」というレベルの実質未経験でした。
そんな私でもアプリを作れるようになったということで、今回は制作したポートフォリオで使用した技術とこだわりについて紹介していきます。

1.  サービス概要

GamutCut   - ガマットカット -

使える色域を制限することで着彩に統一感を生み出せる「ガマットマスク」を作成できるツールサイトです。作成したマスクは ログイン不要 でもダウンロードできるようにしました。

  :point_down: サイトはこちら

  :point_down: GitHubはこちら

2.  制作背景

最初にも述べましたが、私は「創作」が好きなので、プライベートではデジタルイラストを描いています。

趣味とはいえ、日々上手くなるように練習をしているのですが、着彩がどうしても思うようにいかず悩んでいた中、YouTubeでとある動画に出会い、統一感を出しやすくする方法の1つとして「ガマットマッピング」という手法があることを知りました。

この着彩法は色相環上に三角形や四角形のマスクを設置し、その範囲内の色だけを使って着彩を行う手法で、このマスクのことを「ガマットマスク」と呼びます。

                                       
ガマットマスク

実は、ガマットマスクを作成できるサイトはすでにいくつか存在していました。
しかし、採用されていた色相環モデルはアナログイラストに適したものであり、デジタルイラストに適した色相環モデル を扱った作成サイトは見当たりませんでした。

イラスト界隈でもまだ認知度が低い着彩法ですが、これを機に広めていきたい想いも重なり、デジタルイラストに適したガマットマスクを作成できるサイトを開発することに決めました。

                                       
この色相環はアナログに適したYRMBCGモデル
(※画像引用元はこちら

3.  テーマ

人生初めてのポートフォリオ。
中途半端なクオリティには絶対したくなかったので、『ストレスフリーでスピーディな操作の実現』をテーマに掲げ、技術選定を行っていきました。

最終的に、フロントエンドに Next.js を採用し、バックエンドにはRailsからビュー関連の機能を取り除いた RailsAPI を採用することに決めました。
開発環境の構築にはDockerを使用し、postgreSQL(dbコンテナ)とオープンソースのオブジェクトストレージサーバー MinIO を加えた計4つのサービスコンテナによる構成で開発を進めていきました。

pic_3.png

:point_down: 本サイトの開発環境構築について知りたい方はこちら

4.  こだわり

:art: 色相環

アナログは絵の具を重ねるほど濁っていく 減法混色の原理 に従うため、その色相環モデルの中心部分は中心に向かうほど彩度が低くなる表現を出すために直感的なグレーを使っています。一方で、デジタルはさまざまな色の光が混ざり合うほど白に近づく 加法混色の原理 に従います。

デジタルイラストに使うのであれば、加法混色の原理 に従って色相環モデルの中心に向かうほど白くなるべきということで、本サイトでは HSV色相環モデル を採用し、色相環自体の明度も調整できる ようにすることで色の三要素(色相、彩度、明度)が取りうるすべての色を抽出できるようにしました。

色相環の描画だけなら iro.jsColorPickerAPI などを使って表示することができますが、色相環の上にマスクを表示する処理とダウンロード処理の実装には内部canvasの情報へアクセスできる必要があり、APIで取得した色相環はそういった内部情報にはアクセスできないとのことで、今回は色相環自体を自前で作成しました。

色相環(HSVモデル)                                
色相環自体の明度も1〜100のスケールで調整できるようにすることで、
すべての色を再現できるようにしました。

:rosette: UI/UX

モダンなUIを実装したかったので、どうやって実装しようか検討していたところ、shadcn-uiというUIコンポーネントコレクションがあることを知り、Tailwind CSSで色や大きさなどを自分好みにカスタマイズできるとのことで採用しました。
本サイトで実装しているボタンや入力フォーム、サイドバーなどの部品(コンポーネントと呼びます)は、shadcn-uiで用意されているものを使っています。

shadcn-uiのCardコンポーネント ログインフォーム(Cardをカスタマイズ)
shadcn-uiが公開しているCardコンポーネント(※詳細はこちら Cardコンポーネントをカスタマイズして作成したログインフォーム

また、クリックしてイベントを発火するボタンやリンクなどには、マウスカーソルのホバー時にポインター(:point_up_2: )に切り替わるようにして、どこをクリックできるのか分かりやすく工夫しています。

5.  機能紹介

機能名の横に(:lock:)が付いている機能は、ログインユーザーのみ使用可能な機能です。

:art:   マスク追加機能 :inbox_tray:   ダウンロード機能
色相環上にマスクを3つまで追加できます。大きさや位置の調整も可能です。 作成したマスクをpng画像でダウンロードすることができます。
:floppy_disk:   マスク保存機能(:lock: :rocket:   オンボーディング機能
作成したマスクをMyマスクとして保存できます 使い方がわからない人に向けたクイックガイド機能です
:pen_fountain:   作品投稿(:lock: :globe_with_meridians:   作品公開設定(:lock:
イラスト作品を投稿できます。
投稿した作品は、編集・削除することが可能です。
投稿作品の公開設定を『下書き』『公開』で切り替えられます。
:satellite:   X(旧Twitter)シェア機能 :speech_balloon:   コメント機能(:lock:
投稿した作品をXにシェアできます。
動的OGPの実装により、シェア時の表示内容は作品ごとに変化するようになります。
投稿されている作品にコメントを投稿できます。更新、削除も可能です。
:pencil:   コピーして編集 :house:   マイページ(:lock:
他ユーザーが作成したマスクを使って着彩したい人向けの機能です。コピーしたマスクはすぐにダウンロード・Myマスクに保存できます。 会員登録すると、マイページでアバターアイコン設定やプロフィール設定が可能になります。
:mag_right:   リアルタイムサーチ機能                             
Reactの useEffect と検索機能を提供するGem「ransack」を組み合わせた機能。
入力するたびに部分一致による絞り込みを行い、作品を表示します。
入力中にデータを逐次取得する(※)ので、レスポンスの待機時間を感じさせません。

※1文字入力する毎にAPI呼び出しを行うとサーバーに負荷がかかるので、最後の入力から300ms経過して呼び出すよう、デバウンス処理 を施しています。

その他機能

・新規登録、ログイン機能(devise + jwt認証)
・SNS認証機能(Google認証、Twitter認証)
・メールアドレス変更機能
・パスワードリセット機能
・退会機能
・人気タグフィルター機能
・ソート機能
・お問い合わせ(Googleフォーム)
・ローディングアニメーション

認証について

本サイトでは jwt(JSON Web Token)による認証を実装しており、ログイン後はブラウザAPIの localStorage に認証トークン(authToken)を保存します。
作品投稿や作品編集など認可が必要な操作では、localStorage から authToken を取り出して、リクエストヘッダーに含ませることで権限を検証しています。

localStorage に保存された認証トークン(authToken)                             
localStorage に保存されている情報を確認する場合は、
検証ツール「アプリケーション」タブ > ストレージ > ローカルストレージ
で確認できます。

※localStorageの扱い方については、こちらの記事が簡潔で分かりやすかったです。

6.  技術スタック

今回制作したポートフォリオで使用した技術スタックの一覧です。
一部について、選定した理由も挙げていきます。

カテゴリ 採用技術
サーバーサイド言語 Ruby 3.4.2
サーバーサイドフレームワーク Rails 7.2.2
クライアントサイド言語 TypeScript 5.8.3
クライアントサイドライブラリ React 19.1.0
クライアントサイドフレームワーク Next.js 15.4.8
サーバーランタイム Node.js 22.16.0
CSSフレームワーク Tailwind CSS v4
データベース PostgreSQL 16
外部ストレージ(本番環境) Amazon S3
外部ストレージ(開発環境) MinIO
API Google API OAuth 2.0 / Twitter API
CDN Cloudfrare
ホスティングプラットフォーム Vercel / Render
開発環境構築ツール Docker
バージョン管理システム Git / GitHub

選定理由

React
モダンなUI実装が可能なため

Next.js
AppRouterと呼ばれるルーティングシステムにより、快適なUXを実装できるため(リダイレクト通信を行わずにページ遷移が可能)

RailsAPI
豊富なライブラリ(Gem)の存在、Active Storage と AWS S3 との相性の良さなど

shadcn-ui
モダンなUIのコンポーネント(ボタンやフォーム)が用意されており、カスタマイズも自由にできるため

Tailwind CSS
デザインのカスタマイズの自由度が高く、shadcn-ui との相性もいいため

PostgreSQL
色相環やマスクの描画データとして扱っているJSONB型との相性がいいため(JSONB型データの検索速度がMySQLより速い)

その他

Shadcn-UI(UIコンポーネントコレクション)
NextStep(オンボーディングライブラリ)
Motion(アニメーションライブラリ)
react-loader-spinner(ローディングアニメーションコレクション)
ransack(検索・ソート・フィルター機能を提供するGem)
canvas API(色相環、マスクの描画に使用)

7.  画面遷移図

  画面遷移図(Figma)

8.  ER図

卒制ER図.png

感想

初めてのポートフォリオを作った感想ですが、 簡単なアプリでもいいから一度プロジェクト生成からデプロイまでの経験をしておく ことがとても大事だなと思いました。
デプロイの他にも、AWS S3の連携やSNS認証の方法もどういう手順で何をするか全くわからず、とにかくスケジュールを立てようにも立てれないという状況がきつかったです。

RUNTEQのカリキュラムは、ある程度形ができているプロジェクトをローカルに落とて学習するスタイルなので、ポートフォリオ制作時は、環境構築の仕方すら右も左もわからない状態でのスタートでした。
クローンした環境ではなく、一度自分で真っさらな状態から環境を作り上げる練習さえしておけば、開発環境の構築に1ヶ月もかかることはなかったかもしれません笑

技術面の感想としては、Next.js(フロントエンドサーバー)とRails(バックエンドサーバー)を別々に立てたことによって、ブラウザ↔︎Railsの通信だけでなく、サーバー間通信(Next.js↔︎RailsAPI)があることを知れたのは非常に大きかったと思います。

これを知れたあたりから、今までなんとなく理解していた点と点が線に繋がることが多くなっていった気がするので、もしWebアプリをRuby on Rails単体でしか作ったことがないという人は、別オリジン構成のWebアプリ開発をやってみて欲しいです。

以下の記事は、本サイトと同じ開発環境を構築できる手順をまとめているので、もし、Next.jsとRailsAPIの開発環境を作ってみたい人はご覧ください。

謝辞

本記事の構成や流れについては、同じRUNTEQ生のまみむさん(@mirei-m )の記事を参考にさせていただきました:pray:
まみむさんのポートフォリオは、より素晴らしい出来となっているので是非ご覧ください!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?