97
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】韓国コスメでスキンケアのお悩みを解決するサービスを開発しました【Next.js + Rails API】

Last updated at Posted at 2024-04-02

はじめに

初めまして!りかと申します。
未経験からのWebエンジニア転職を目指して、日々学習を行っております。

今回、韓国コスメのスキンケア情報サービス「KoreCare(コリケア)」を開発しました。

サービス名

KoreCare
お試し機能を実装しましたので、ログインせずにお試しいただくこともできます。

korecare_image.png

▼サービスURL
https://korecare.jp/

▼GitHub URL
https://github.com/rk0325/korecare

サービス概要

韓国コスメに特化した、スキンケア情報サービスです。

具体的には、

  • ユーザーの肌質やお悩みに合った韓国コスメを提案します。
  • お肌の大敵である紫外線や乾燥から、ユーザーのお肌を守るサポートをします。
  • スキンケアコスメの使用期限切れを防ぐサポートをします。

サービスを作成した背景

K-POPを好きになったことがきっかけで韓国コスメを使うようになったのですが、比較的安価でありながら質が高いところに魅力を感じ、韓国コスメに馴染みがない方にも興味を持っていただくきっかけを作りたいと思いました。

韓国コスメに関してすでに知識がある方よりは、

「韓国コスメを使ったことはないけれど、何となく興味はある
「たくさん種類があって、何から手を出したらいいのかわからない
「どのスキンケアコスメを選んだらいいか迷ってしまう

といった、韓国コスメ初心者の方や、スキンケアについてお悩みを抱えている方を主なターゲットとし、韓国コスメ用語の解説ページを作成したり、アプリ内で紹介するコスメの種類を絞ることで、気軽に使っていただけるよう工夫しました。

また、UV指数や湿度の情報・使用期限のLINE通知機能を通して、ユーザーの皆さんに自身のスキンケアについてより関心を持っていただき、皆さんの美肌づくりをサポートできたら嬉しいなと思い、開発に至りました。

リリース後には、

「これを機に韓国コスメ使ってみようかな」
「肌質に合わせておすすめしてくれてありがたい」
「何を使ったらいいのか?は男性あるあるなのでありがたい」
「UV、湿度を教えてくれるの嬉しい」

など、たくさんのご感想をいただき、とっても嬉しかったです!

機能一覧

お試し韓国コスメ検索機能 韓国コスメ検索機能
Image from Gyazo Image from Gyazo
肌質・お悩みを選択すると、それぞれに合った韓国コスメを表示します。 肌質・お悩み・形態・金額を選択すると、それぞれに合った韓国コスメを表示します。
レコメンド機能(1) レコメンド機能(2)
Image from Gyazo Image from Gyazo
ユーザーが検索時に選択したキーワードに関連する商品をレコメンドします。 マイページにて設定していただいた肌質・お悩みに関連する商品をレコメンドします。
お気に入りコスメ登録機能 お気に入りコスメ一覧機能
Image from Gyazo Image from Gyazo
検索したコスメやレコメンドされたコスメをお気に入りに登録できます。 マイページ内でお気に入りに登録したコスメを確認できます。
紫外線/乾燥注意通知機能(設定) 使用期限通知機能(設定)
Image from Gyazo Image from Gyazo
マイページにて設定していただいたお住まいのUV指数と湿度の情報を毎朝10時に通知します。 コスメの製品タイプ、開封日、使用期限を設定していただくと、使用期限の5日前・3日前・前日に通知します。
紫外線/乾燥注意通知機能(通知画面) 使用期限通知機能(通知画面)
line_image_1.png line_image_2.png
実際の通知画面です。 実際の通知画面です。
レビュー投稿/一覧機能 レビュー編集/削除機能
Image from Gyazo Image from Gyazo
お気に入りに登録したコスメのレビューを投稿できます。 レビューの編集や削除も可能です。
レビュー検索機能 ログイン/ログアウト機能
Image from Gyazo Image from Gyazo
レビュー投稿時に付けられたタグ(肌質、お悩み、年代)により、該当するレビューを検索できます。 NextAuth.jsを使用したLINEログインが可能です。
現在の天気/UV指数/湿度の表示機能
Image from Gyazo
OpenWeatherMap APIを使用し、現在の天気、UV指数、湿度の情報を表示しています。
お気に入りコスメのXシェア機能 レビュー投稿のXシェア機能
Image from Gyazo Image from Gyazo
お気に入りコスメのXへのシェアができます。 レビュー投稿のXへのシェアができます。

使用技術

カテゴリ 技術
フロントエンド TypeScript 5.3.3 / React 18.2.0 / Next.js 14.0.4
バックエンド Ruby 3.2.2 / Ruby on Rails 7.0.8(API モード)
データベース PostgreSQL
認証 NextAuth.js
環境構築 Docker
インフラ Vercel / Render
Web API 楽天市場商品検索API / LINE Messaging API / OpenWeatherMap API
その他 SWR / shadcn/ui / Sidekiq / Redis / ActiveJob

インフラ構成

image.png

選定理由

開発環境

開発環境には、環境ごとの差異を最小限に抑えられるとともに、docker-composeを使用することで、各コンテナの起動、停止、再構築をコマンド一つで実行できる点が開発の効率化に繋がると考え、Dockerを採用しました。

▼参考にした記事

フロントエンド

フロントエンドには、昨年チーム開発にてNext.jsを使用した経験を踏まえ、さらに深く掘り下げて学びたいと考え、Next.jsを採用しました。SSRやCSR、SSGなどレンダリング手法を考慮した上でパフォーマンス設計を行い、ユーザビリティを高められるよう意識しました。

バックエンド

バックエンドには、スクールで学んできたRuby on Railsを採用することで、実装スピードを上げられると考えました。

インフラ

Vercelは、Next.jsとの相性が良いこと、GitHubとの連携によりコードをpushすることで自動でデプロイが行われる点が、開発の効率化に繋がると思い採用しました。

Renderは、過去のアプリ開発での利用経験が豊富であったため、導入コストを抑えられることと、LINE通知機能においてバックエンドで要求されるキューイングシステムの構築に必要なRedisを提供していることから採用しました。

ER図

画面遷移図

画面遷移図

工夫したポイント

ログイン機能

ユーザー登録のハードルを下げたかったことと、セキュリティ面を考慮し、NextAuth.jsを使用したLINEログインを実装しました。

一部コード抜粋
front/app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import LineProvider from 'next-auth/providers/line';

const apiUrl = process.env.NEXT_PUBLIC_API_URL;

const handler = NextAuth({
  providers: [
    LineProvider({
      id: "line",
      name: "LINE",
      clientId: process.env.NEXT_PUBLIC_LINE_CLIENT_ID || '',
      clientSecret: process.env.NEXT_PUBLIC_LINE_CLIENT_SECRET || '',
      authorization: { params: { scope: "profile openid" } },
      token: "https://api.line.me/oauth2/v2.1/token",
      userinfo: "https://api.line.me/v2/profile",
      profile(profile) {
        return {
          id: profile.sub,
          name: profile.displayName,
          image: profile.pictureUrl,
        };
      },
    }),
  ],
  // 中略
});

export { handler as GET, handler as POST };
front/app/providers/NextAuth.tsx
'use client';

import { SessionProvider } from 'next-auth/react';
import { ReactNode } from 'react';

const NextAuthProvider = ({ children }: { children: ReactNode }) => {
  return <SessionProvider>{children}</SessionProvider>;
};

export default NextAuthProvider;

▼参考にした記事

LINE通知機能

この機能では、情報を決まった時間に自動的に送信することが目標でした。そのため、Sidekiqのスケジューリング機能と、Redisをバックエンドに使用するActiveJobを組み合わせて利用しました。さらに、Sidekiq-Cronを使ってCron式でジョブのスケジューリングを設定し、ジョブ失敗に備えてSidekiqの自動リトライ機能を設定しました。

一部コード抜粋
back/app/jobs/weather_notification_job.rb
class WeatherNotificationJob < ApplicationJob
  queue_as :default

  sidekiq_options retry: 1
  # Sidekiqはジョブの実行に失敗した場合、デフォルトで25回リトライするため、
  # 何度も通知が送られないよう、リトライ回数を1回に指定

  sidekiq_retry_in do |_count|
    60
  end
  # ジョブのリトライ間隔を60秒に設定

  def perform
    User.includes(:profile).find_each do |user|
      next unless user.profile
      next unless user.receive_notifications_weather

      prefecture_name = user.profile.prefecture
      next if prefecture_name.blank?

      weather_info = WeatherService.fetch_weather_data(prefecture_name)
      next if weather_info.blank?

      message = WeatherMessageGenerator.generate_message(prefecture_name, weather_info)
      LineNotifyService.send_message(user.uid, message) if user.uid.present?
    end
  end
end
back/config/initializers/sidekiq.rb
require 'sidekiq'
require 'sidekiq-cron'

Sidekiq.configure_server do |config|
  # Sidekiqサーバーの設定(ジョブを実行するサーバー側で適用される)
  schedule_file = 'config/schedule.yml'
  # 定期的に実行するジョブのスケジュールを記述したYAMLファイルのパスを指定
  config.redis = {
    url: ENV['REDIS_URL'],
    connect_timeout: 5,
    read_timeout: 5,
    write_timeout: 5
    # 接続、読み込み、書き込みそれぞれに5秒のタイムアウトを設定
  }

  Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file) if File.exist?(schedule_file)
  # config/schedule.ymlファイルが存在する場合、そのファイルを読み込み、
  # YAMLファイルに記述されたスケジュールに従って定期的なジョブを設定
end

Sidekiq.configure_client do |config|
  # Sidekiqクライアントの設定(ジョブをキューに投入する側で適用される)
  config.redis = {
    url: ENV['REDIS_URL'],
    connect_timeout: 5,
    read_timeout: 5,
    write_timeout: 5
    # サーバー側の設定と同様、RedisサーバーのURLとタイムアウトの設定を行う
  }
end

back/config/schedule.yml
weather_notification_job:
  cron: "0 10 * * *"
  class: "WeatherNotificationJob"
  # 毎朝10時に通知を送るよう設定

LINE通知機能の実装については、別の記事にて詳しく書きたいと思います。

説明用のモーダル

画面上にはあまり文章を載せないようにし、補足事項はモーダル内に格納するようにしました。また、ツールチップを使用し、ホバーした際に何の情報が書かれているのかわかるようにしました。

UV指数と湿度の目安 肌質の目安
Image from Gyazo Image from Gyazo

配色

韓国コスメはカラフルなパッケージのものが多いため、韓国コスメ自体が引き立つよう落ち着いた配色を意識しました。カラーコードはノグチデザインさん(@n_seitan)を参考にさせていただきました。

レスポンシブデザイン

メニューの表示方法をPCとスマートフォンで変更しました。スマートフォンでの使用が多いと想定し、片手で操作することを考え、手の届きやすいところにメニューボタンを配置しました。

PC スマートフォン
Image from Gyazo Image from Gyazo

今後の開発について

1.ランキング機能
お気に入りの数が多い順や、レビュー評価の高い順でのランキング機能を実装したいと考えています。

2.テスト
まだまだテストコードが書けていないので、カバレッジ率を上げていきたいです。

おわりに

今まで簡単なミニアプリは作成したことがありますが、0からテーブル設計などを考えて開発するのは初めてでした。わからないことばかりで大変ではありましたが、自分が思い描いたものを形にできてとても楽しかったです!

まだまだ至らない点ばかりですが、今回の経験を糧に今後も楽しみながら学んでいきたいです。

改めて、開発にあたりご協力いただいた皆さまに感謝申し上げます。

最後まで読んでいただきありがとうございました。

97
76
2

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
97
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?