AI Host Club - メールアドレス任意化改修記録
📋 プロジェクト概要
地雷系テーマのAIホストクラブシステムにおいて、ユーザー登録時のメールアドレスを必須項目から任意項目に変更する改修を実施。将来の課金機能導入時にメールアドレスを必須化する設計も含めた、段階的なUX改善プロジェクト。
🎯 改修目的
ビジネス要件
- 新規ユーザーの登録ハードル低減: メールアドレス入力の心理的障壁を排除
- お試し利用の促進: 気軽に体験できる環境の提供
- 将来の収益化準備: 有料プラン利用時のメールアドレス必須化への布石
技術要件
- 既存ユーザーデータの完全保持
- Dockerコンテナ環境との互換性維持
- 自動マイグレーション機能の実装
🛠️ 技術スタック
- Backend: Flask + SQLAlchemy
- Database: SQLite (本番PostgreSQL対応)
- Container: Docker + Docker Compose
- Frontend: HTML5/CSS3 + JavaScript
📊 実装内容
1. データベースモデル変更
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=True) # 必須→任意
password_hash = db.Column(db.String(255), nullable=False)
is_admin = db.Column(db.Boolean, default=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
last_login = db.Column(db.DateTime)
has_premium = db.Column(db.Boolean, default=False) # 課金機能準備
主な変更点:
- email
フィールドをnullable=True
に変更
- has_premium
フィールドを追加(将来の課金機能用)
2. 登録フォームUI改善
<div class=\"input-group\">
<label for=\"email\" class=\"input-label\">📧 メールアドレス(任意)</label>
<input
type=\"email\"
id=\"email\"
name=\"email\"
class=\"form-input\"
placeholder=\"メールアドレスを入力(将来の有料機能利用時に必要)\"
>
<div style=\"color: #ff1493; font-size: 0.85rem; margin-top: 0.5rem;\">
💌 今は入力不要です。有料プラン利用時に必要になります。
</div>
</div>
UX改善:
- required
属性の削除
- 「任意」表記の明記
- 将来の有料機能について説明追加
3. バックエンド処理の最適化
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
email = request.form.get('email', '').strip() # 空文字を許可
password = request.form.get('password')
# メールアドレスが入力されている場合のみ重複チェック
if email and User.query.filter_by(email=email).first():
flash('そのメールアドレスは既に登録されています。')
return render_template('register.html')
# Noneまたは空文字での登録を許可
user = User(username=username, email=email if email else None)
user.set_password(password)
db.session.add(user)
db.session.commit()
処理改善:
- 空のメールアドレス処理の最適化
- 重複チェックの条件分岐追加
- エラーハンドリングの強化
🔧 技術的課題と解決策
課題1: データベースパス管理の複雑化
問題: 開発環境・Docker環境で異なるデータベースファイルパスを参照
解決策: 環境変数による動的パス設定
# 環境変数でデータベースパスを制御
database_url = os.getenv('DATABASE_URL')
if not database_url:
app_dir = os.path.dirname(os.path.abspath(__file__))
instance_dir = os.path.join(app_dir, 'instance')
os.makedirs(instance_dir, exist_ok=True)
db_filename = os.getenv('DATABASE_FILENAME', 'ai_host_club.db')
db_path = os.path.join(instance_dir, db_filename)
database_url = f'sqlite:///{db_path}'
効果:
- 開発環境: instance/ai_host_club.db
- Docker環境: 環境変数で制御可能
- 本番環境: PostgreSQLなど外部DB対応
課題2: 本番環境での自動マイグレーション
問題: Docker再デプロイ時の既存データ移行
解決策: 起動時自動マイグレーション機能
def perform_auto_migration():
\"\"\"自動マイグレーション実行\"\"\"
if database_url.startswith('sqlite:///'):
sqlite_path = database_url.replace('sqlite:///', '')
if os.path.exists(sqlite_path):
conn = sqlite3.connect(sqlite_path)
cursor = conn.cursor()
# スキーマチェック
cursor.execute(\"PRAGMA table_info(user)\")
columns = cursor.fetchall()
column_names = [col[1] for col in columns]
# 必要に応じてマイグレーション実行
if 'has_premium' not in column_names:
cursor.execute(\"ALTER TABLE user ADD COLUMN has_premium BOOLEAN DEFAULT 0\")
# NOT NULL制約の削除
if email_column_has_not_null_constraint:
# テーブル再作成による制約変更
安全性確保:
- 既存データの完全保持
- トランザクション処理によるロールバック対応
- スキーマバージョン管理
🎨 プロフィール設定機能の追加
ユーザーが後からメールアドレスを設定できる機能を実装:
@app.route('/profile')
@login_required
def profile():
return render_template('profile.html')
@app.route('/update_profile', methods=['POST'])
@login_required
def update_profile():
email = request.form.get('email', '').strip()
# 重複チェック(既存とは異なる場合のみ)
if email and email != current_user.email:
existing_user = User.query.filter_by(email=email).first()
if existing_user:
flash('そのメールアドレスは既に使用されています。')
return redirect(url_for('profile'))
current_user.email = email if email else None
db.session.commit()
機能特徴:
- メールアドレスの追加・変更・削除
- パスワード変更機能
- 将来の課金ステータス表示準備
📦 Docker対応の強化
環境別設定ファイル
.env (開発環境):
# Database Configuration
# 開発環境では相対パス
DATABASE_FILENAME=ai_host_club.db
.env.docker (本番環境):
# Database Configuration for Docker
DATABASE_URL=sqlite:////app/data/ai_host_club.db
FLASK_ENV=production
docker-compose.yml最適化
services:
ai-host-club:
build: .
volumes:
- ./instance:/app/instance # DB永続化
- ./.env:/app/.env:ro # 環境変数
environment:
- FLASK_ENV=production
📈 成果と効果
ユーザビリティ向上
- 登録フォーム項目削減: 必須項目3つ→2つ
- 心理的ハードル低減: メールアドレス入力の抵抗感排除
- 段階的エンゲージメント: まず体験→必要時に詳細情報
技術的改善
- 環境統一: 開発・Docker・本番での一貫したDB管理
- 自動化: マイグレーション処理の無人化
- 拡張性: 将来の課金機能への準備完了
開発効率化
- デプロイ自動化:
git push
→docker-compose up -d
で完了 - データ保護: 既存ユーザー情報の完全保持
- 回帰テスト: 既存機能への影響ゼロ
🚀 今後の展開
短期計画
- A/Bテスト実施(登録率の測定)
- ユーザーフィードバック収集
- プロフィール設定の利用状況分析
中期計画
- 課金機能実装時のメールアドレス必須化
- メール通知機能(有料ユーザー向け)
- パスワードリセット機能
長期計画
- マルチテナント対応
- 外部認証連携(OAuth)
- データ分析基盤の構築
📝 学び・ノウハウ
データベース設計
- NOT NULL制約の変更: SQLiteでは新しいテーブル作成が必要
- マイグレーション戦略: 段階的な構造変更とデータ保持
- 環境差異対応: 開発・本番での一貫性確保
Flask開発
- 環境変数活用: 設定の外部化による柔軟性向上
- エラーハンドリング: ユーザビリティを損なわない例外処理
- セキュリティ: 入力検証とSQLインジェクション対策
Docker運用
- ボリュームマウント: データ永続化とホスト連携
- 環境分離: 開発・本番での設定差異管理
- ヘルスチェック: 自動復旧機能の実装
💡 推奨事項
類似プロジェクトへの適用
- 段階的な要求情報収集: 初回は最小限、必要時に詳細化
- 自動マイグレーション: 本番運用での安全なスキーマ変更
- 環境統一: 開発から本番まで一貫したデータ管理
設計思想
- ユーザーファースト: 技術的制約よりユーザビリティ優先
- 将来拡張性: 現在の要件と将来計画のバランス
- 運用自動化: 人的ミスを排除する仕組み作り
本記事は、実際のWebアプリケーション改修プロジェクトの記録です。同様の課題を抱える開発者の参考になれば幸いです。