Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
![group-manager-jpeg 001](https://user-images.githubusercontent.com/33748835/117114823-45700b00-adc7-11eb-8bab-7442f38a7065.jpeg)

### api
ruby 2.7.1 <br>
ruby 2.7.1 <br>
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] READMEに末尾のスペース取っちゃった変更が入ってるね😅 これは多分意図してないやつだと思うから、元に戻した方がいいかも💦

ruby 2.7.1 <br> 

こんな感じで末尾にスペース入れといた方が、マークダウンのフォーマットとして正しいよ~📝✨

Suggested change
ruby 2.7.1 <br>
ruby 2.7.1 <br>

Copilot uses AI. Check for mistakes.
rails 6.1.3.1<br>

### view(ユーザー画面)
Expand All @@ -31,3 +31,16 @@ nuxt.js<br>

## セットアップ
[git cloneをしたら](https://github.com/NUTFes/group-manager-2/wiki/git-clone-%E3%82%92%E3%81%97%E3%81%9F%E3%82%89)

## メール送信設定(Outlook SMTP)
本番環境でOutlook(Office365)のSMTPを利用する場合、以下の環境変数を設定してください。値は `.env` やインフラ側のシークレットマネージャ等で安全に管理します。

- MAILER_SENDER: 送信元メールアドレス(例: no-reply@group-manager.nutfes.net)
- MAILER_HOST: メール内のURLで利用するホスト名(例: group-manager.nutfes.net)
- MAILER_PROTOCOL: URLに使用するプロトコル。既定値は `https`
- MAILER_ASSET_HOST: メール内の静的アセットURLに使用するホスト。既定値は `https://group-manager.nutfes.net`
- SMTP_ADDRESS: SMTPサーバーのアドレス。既定値は `smtp.office365.com`
- SMTP_PORT: SMTPサーバーのポート番号。既定値は `587`
- SMTP_DOMAIN: SMTP認証で利用するドメイン(HELO/EHLO)。既定値は `group-manager.nutfes.net`
- SMTP_USERNAME: Outlookアカウントのユーザー名(メールアドレス)
- SMTP_PASSWORD: Outlookアカウントのパスワード
2 changes: 2 additions & 0 deletions api/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ end
group :development do
gem 'listen', '~> 3.2'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'letter_opener'
gem 'letter_opener_web'
gem 'r2-oas'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
Comment on lines 56 to 57
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

letter_openerとletter_opener_webがdevelopmentグループに入ってないよ~😱これだと本番環境にもインストールされちゃうから、ガチでヤバいかも💦

こんな感じで修正してね👇✨

group :development do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'listen', '~> 3.2'
  gem 'r2-oas'
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'letter_opener'
  gem 'letter_opener_web'
end

開発専用のgemは必ずdevelopmentグループに入れるのが鉄則だよ~💪🔥

Copilot uses AI. Check for mistakes.
Expand Down
18 changes: 18 additions & 0 deletions api/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,17 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
base64 (0.2.0)
bcrypt (3.1.16)
bootsnap (1.18.4)
msgpack (~> 1.2)
builder (3.2.4)
byebug (11.1.3)
childprocess (5.1.0)
logger (~> 1.5)
concurrent-ruby (1.1.8)
crass (1.0.6)
devise (4.7.3)
Expand Down Expand Up @@ -128,6 +132,17 @@ GEM
json (2.13.2)
key_flatten (1.0.0)
language_server-protocol (3.17.0.5)
launchy (3.1.1)
addressable (~> 2.8)
childprocess (~> 5.0)
logger (~> 1.6)
letter_opener (1.10.0)
launchy (>= 2.2, < 4)
letter_opener_web (2.0.0)
actionmailer (>= 5.2)
letter_opener (~> 1.7)
railties (>= 5.2)
rexml
lint_roller (1.1.0)
listen (3.5.1)
rb-fsevent (~> 0.10, >= 0.10.3)
Expand Down Expand Up @@ -158,6 +173,7 @@ GEM
racc
pdfkit (0.8.5)
prism (1.4.0)
public_suffix (6.0.2)
puma (4.3.7)
nio4r (~> 2.0)
r2-oas (0.5.0)
Expand Down Expand Up @@ -298,6 +314,8 @@ DEPENDENCIES
devise_token_auth
dotenv-rails
jbuilder (~> 2.7)
letter_opener
letter_opener_web
listen (~> 3.2)
mysql2 (>= 0.4.4)
pdfkit
Expand Down
10 changes: 10 additions & 0 deletions api/app/controllers/api/auth/passwords_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

module Api
module Auth
class PasswordsController < DeviseTokenAuth::PasswordsController
# Devise Token Auth 標準のパスワードリセットフローを利用します。
# 基本的な挙動は親クラスに委譲し、必要があればここでカスタマイズします。
end
end
end
2 changes: 1 addition & 1 deletion api/app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com'
default from: ENV.fetch('MAILER_SENDER', 'no-reply@group-manager.nutfes.net')
layout 'mailer'
end
78 changes: 78 additions & 0 deletions api/app/views/devise/mailer/reset_password_instructions.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<% email_label =
if @resource.respond_to?(:name) && @resource.name.present?
"#{@resource.name} 様"
elsif @resource.respond_to?(:email) && @resource.email.present?
"#{@resource.email} 様"
else
"ご利用者様"
end %>
<% uid =
if @resource.respond_to?(:uid) && @resource.uid.present?
@resource.uid
elsif @resource.respond_to?(:email) && @resource.email.present?
@resource.email
end %>
<% client_id =
if defined?(@client_id) && @client_id.present?
@client_id
elsif defined?(@client_config) && @client_config.present?
@client_config
end %>
<% redirect_base = defined?(@redirect_url) ? @redirect_url : nil %>
<% tokenised_link =
if redirect_base.present? && client_id.present? && uid.present?
query = { client_id: client_id, token: @token, uid: uid }.to_query
separator = redirect_base.include?('?') ? '&' : '?'
"#{redirect_base}#{separator}#{query}"
end %>
<% reset_link =
if tokenised_link.present?
tokenised_link
elsif respond_to?(:edit_password_url)
edit_password_url(@resource, reset_password_token: @token)
end %>
<% reset_link ||= '#' %>

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>パスワード再設定のご案内</title>
</head>
<body style="margin:0;padding:0;background-color:#f5f7fb;font-family:'Hiragino Kaku Gothic ProN',YuGothic,'メイリオ',sans-serif;color:#1f2933;">
<div style="max-width:620px;margin:0 auto;padding:32px 24px;">
<div style="background:#ffffff;border-radius:16px;padding:32px 28px;box-shadow:0 6px 18px rgba(15,23,42,0.08);">
<h1 style="margin:0 0 16px;font-size:22px;font-weight:700;color:#111827;">パスワード再設定のご案内</h1>
<p style="margin:0 0 16px;line-height:1.7;">
<%= email_label %>、こんにちは。<br />
パスワード再設定のお申し込みを受け付けました。以下のボタンをクリックし、パスワード再設定ページへ進んでください。
</p>

<div style="text-align:center;margin:28px 0;">
<a
href="<%= reset_link %>"
style="display:inline-block;padding:14px 28px;background:#2563eb;color:#ffffff;font-weight:700;border-radius:999px;text-decoration:none;"
target="_blank"
rel="noopener noreferrer"
>
パスワードを再設定する
</a>
</div>

<p style="margin:0 0 20px;line-height:1.7;">
ボタンが正しく動作しない場合は、以下のURLをコピーしてブラウザに貼り付けてください。
</p>
<p style="word-break:break-all;background:#f8fafc;padding:16px;border-radius:12px;border:1px solid #e2e8f0;margin:0 0 24px;">
<a href="<%= reset_link %>" style="color:#1d4ed8;text-decoration:none;" target="_blank" rel="noopener noreferrer"><%= reset_link %></a>
</p>

<p style="margin:0 0 8px;line-height:1.7;">
このリンクの有効期限は一度のみです。お心当たりのない操作の場合は、このメールを破棄してください。
</p>
<p style="margin:0;line-height:1.7;color:#6b7280;font-size:13px;">
本メールは送信専用です。ご返信いただいても対応いたしかねますのでご了承ください。
</p>
</div>
</div>
</body>
</html>
46 changes: 46 additions & 0 deletions api/app/views/devise/mailer/reset_password_instructions.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<% email_label =
if @resource.respond_to?(:name) && @resource.name.present?
"#{@resource.name} 様"
elsif @resource.respond_to?(:email) && @resource.email.present?
"#{@resource.email} 様"
else
"ご利用者様"
end %>
<% uid =
if @resource.respond_to?(:uid) && @resource.uid.present?
@resource.uid
elsif @resource.respond_to?(:email) && @resource.email.present?
@resource.email
end %>
<% client_id =
if defined?(@client_id) && @client_id.present?
@client_id
elsif defined?(@client_config) && @client_config.present?
@client_config
end %>
<% redirect_base = defined?(@redirect_url) ? @redirect_url : nil %>
<% tokenised_link =
if redirect_base.present? && client_id.present? && uid.present?
query = { client_id: client_id, token: @token, uid: uid }.to_query
separator = redirect_base.include?('?') ? '&' : '?'
"#{redirect_base}#{separator}#{query}"
end %>
<% reset_link =
if tokenised_link.present?
tokenised_link
elsif respond_to?(:edit_password_url)
edit_password_url(@resource, reset_password_token: @token)
end %>
<% reset_link ||= '#' %>

パスワード再設定のご案内

<%= email_label %>、こんにちは。

パスワード再設定のお申し込みを受け付けました。以下のURLからパスワード再設定ページへ進んでください。

<%= reset_link %>

このリンクの有効期限は一度のみです。お心当たりのない操作の場合は、このメールを破棄してください。

本メールは送信専用です。ご返信いただいても対応いたしかねますのでご了承ください。
6 changes: 6 additions & 0 deletions api/config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,10 @@
localhost
api
]
# パスワードメール送信用の開発環境設定(letter_opener)
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
config.action_mailer.asset_host = 'http://localhost:3000'
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
end
17 changes: 17 additions & 0 deletions api/config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@
# config.active_job.queue_name_prefix = "myapp_production"

config.action_mailer.perform_caching = false
config.action_mailer.default_url_options = {
host: ENV.fetch('MAILER_HOST', 'group-manager.nutfes.net'),
protocol: ENV.fetch('MAILER_PROTOCOL', 'https')
}
config.action_mailer.asset_host = ENV.fetch('MAILER_ASSET_HOST', 'https://group-manager.nutfes.net')
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: ENV.fetch('SMTP_ADDRESS', 'smtp.office365.com'),
port: ENV.fetch('SMTP_PORT', 587).to_i,
domain: ENV.fetch('SMTP_DOMAIN', 'group-manager.nutfes.net'),
user_name: ENV.fetch('SMTP_USERNAME'),
password: ENV.fetch('SMTP_PASSWORD'),
authentication: :login,
enable_starttls_auto: true
}

# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
Expand Down
2 changes: 1 addition & 1 deletion api/config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
config.mailer_sender = ENV.fetch('MAILER_SENDER', 'no-reply@example.com')

# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
Expand Down
5 changes: 4 additions & 1 deletion api/config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

Rails.application.routes.draw do
mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?

# 識別番号割り当て
Comment on lines +4 to 6
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] letter_opener のマウント設定が Rails.env.development? でガードされてるのはめっちゃいいね👏でも、ルートの定義位置がちょっと気になるかも🤔

Railsの慣習的には、開発ツール系のルートは config/routes.rb の一番下か、他のnamespaceの外側に書くことが多いよ💡 今の位置だとちょっと見づらいかもだから、こんな感じで一番下に移動するとキレイになるよ✨

Rails.application.routes.draw do
  # 既存のルート定義
  # ...
  
  namespace :api do
    mount_devise_token_auth_for 'User', at: 'auth', controllers: {
      registrations: 'api/auth/registrations',
      passwords: 'api/auth/passwords'
    }
    namespace :auth do
      resources :sessions
    end
  end
  
  # 開発ツール系は最後に
  if Rails.env.development?
    mount LetterOpenerWeb::Engine, at: '/letter_opener'
  end
end

まあこれはスタイルの話だから、そこまでマストってわけじゃないけどね😊

Copilot uses AI. Check for mistakes.
get 'group_identification' => 'group_identification#index'
post 'group_identification' => 'group_identification#create'
Expand Down Expand Up @@ -336,7 +338,8 @@

namespace :api do
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
registrations: 'api/auth/registrations'
registrations: 'api/auth/registrations',
passwords: 'api/auth/passwords'
}
namespace :auth do
resources :sessions
Expand Down
Loading