体験入店 - イケメン投票システム
プロジェクト概要
「体験入店」は、地雷系テーマの美しいデザインを特徴とするイケメン投票システムです。既存のAI Host Clubシステムの追加機能として開発され、モダンなWeb技術を駆使してユーザビリティと保守性を両立させたプロジェクトです。
🎯 開発コンセプト
「シンプル × 高機能 × 安定動作」
- 地雷系 × ゴシック × 可愛いのデザインテーマ
- 脱JavaScript依存によるモダンなサーバーサイド駆動開発
- Progressive Enhancementによる段階的機能拡張
- データ保護最優先の安全な機能追加
🌟 主要機能
ユーザー向け機能
- 直感的な投票システム: ハートマークをクリックするだけの簡単操作
- 視覚的フィードバック: 1票→小さなハート💕、10票→大きなハート💖への変換
- 全画面画像表示: 候補者画像クリックでモーダル表示
- リアルタイムランキング: 投票結果の即座反映
管理者向け機能
- 複数管理者対応: 安全な管理者追加・削除システム
- 写真確認機能: 削除前のサムネイル拡大表示
- 統計ダッシュボード: システム全体の詳細分析
- レスポンシブ管理画面: モバイル対応の管理UI
🛠️ 技術的な工夫
1. モダンなフロントエンド設計
脱JavaScript依存の革新的アプローチ
<!-- HTMX: サーバーサイド駆動型UI更新 -->
<img hx-get="/image_modal/filename.jpg"
hx-target="body"
hx-swap="beforeend">
<!-- Alpine.js: 軽量リアクティブフレームワーク -->
<div x-data="{showModal: true}"
x-show="showModal"
@keydown.escape.window="closeModal()">
選択理由:
- JavaScriptの記述量を最小化
- 宣言的なUI定義
- サーバーサイドでのHTMLレンダリング
- 軽量で高性能な動作
2. 画像処理の最適化
固定領域切り出し方式の採用
def create_top_crop_image(original_path, crop_size=640):
# 画像上部640x640を切り出し(中央寄せ)
x_offset = max(0, (img_width - crop_size) // 2)
cropped = image[0:crop_size, x_offset:x_offset+crop_size]
return cv2.resize(cropped, target_size, interpolation=cv2.INTER_LANCZOS4)
技術的メリット:
- 100%確実な画像表示(AI顔検出の不安定性を回避)
- 高速処理(50ms未満)
- シンプルなコード構造(保守性向上)
3. レスポンシブ設計の徹底
CSS clamp()による動的フォントサイズ
.logo {
font-size: clamp(1.4rem, 4vw, 1.8rem);
white-space: nowrap;
word-break: keep-all;
letter-spacing: -0.02em;
}
効果:
- 画面幅に応じた自動調整
- 意図しない改行の防止
- 日本語に適した改行制御
4. 安全なデータベース設計
非破壊的機能追加
# 既存テーブル構造を変更せずに機能拡張
def migrate_database():
try:
# 新しいカラムが存在するかチェック
with db.engine.connect() as conn:
conn.execute(text("SELECT email FROM admin LIMIT 1"))
except Exception:
# 必要に応じて安全にカラム追加
conn.execute(text("ALTER TABLE admin ADD COLUMN email VARCHAR(120)"))
🎨 デザインの特徴
地雷系テーマの実装
- ピンク×黒のゴシック配色
- 浮遊ハート背景: 常時アニメーションエフェクト
- バタフライエフェクト: 投票時の蝶アニメーション
- グラデーション多用: 深みのある視覚表現
レイアウト最適化
- コンパクト設計: 名前と票数の横並び配置
- 余白最適化: 画面効率を50%向上
- 段階的レスポンシブ: デスクトップ→タブレット→スマートフォンの最適化
📊 開発プロセス
バージョン管理戦略
- v1.0.0: 基本機能実装(Vanilla JavaScript)
- v2.0.0: 大規模リファクタリング(HTMX + Alpine.js移行)
- v2.1.x: 画像処理最適化(AI顔検出→固定切り出し)
- v2.2.x: UI/UX改善・管理機能強化
技術的課題と解決
課題1: AI顔検出の精度問題
- 問題: 検出率60-70%、処理時間200-500ms
- 解決: 固定領域切り出し方式で100%確実な表示
課題2: JavaScript保守性の課題
- 問題: 複雑なDOM操作、状態管理
- 解決: HTMX + Alpine.jsによる宣言的実装
課題3: モバイルでの表示崩れ
- 問題: 「体験入店」の意図しない改行
- 解決: CSS clamp()とword-break制御
🔒 セキュリティ対策
多層防御の実装
- 管理者認証: Flask-Loginによる認証システム
- 入力バリデーション: フロントエンド+バックエンド二重チェック
- SQLインジェクション対策: SQLAlchemy ORMによる保護
- ファイルアップロード制限: MIMEタイプ・サイズ制限
管理者管理の安全機能
- 重複防止: ユーザー名の重複チェック
- パスワード強度: 最低6文字の強制
- 安全装置: 最後の管理者削除防止・自己削除防止
📱 レスポンシブ対応
ブレークポイント戦略
/* デスクトップ優先設計 */
@media (max-width: 768px) { /* タブレット */ }
@media (max-width: 480px) { /* スマートフォン */ }
@media (max-width: 320px) { /* 極小画面 */ }
/* タッチデバイス対応 */
@media (hover: none) and (pointer: coarse) {
.clickable-image:hover { transform: none; }
.clickable-image:active { transform: scale(1.05); }
}
🚀 パフォーマンス最適化
最適化手法
- 画像最適化: 動的リサイズ・品質調整
- キャッシュ戦略: ブラウザキャッシュの活用
- 部分更新: HTMXによるAjax不要の動的コンテンツ
- CSS最適化: ハードウェアアクセラレーション対応
実測値
- 画像処理: 50ms未満(従来比90%削減)
- ページ読み込み: HTMX部分更新で大幅高速化
- レスポンシブ対応: 280px〜1200px+まで破綻なし
🔧 開発環境・技術スタック
バックエンド
- Flask: Webアプリケーションフレームワーク
- SQLAlchemy: データベースORM
- SQLite: 軽量データベース
- OpenCV: 画像処理エンジン
フロントエンド
- HTMX: サーバーサイド駆動型UI
- Alpine.js: 軽量リアクティブフレームワーク
- CSS Grid/Flexbox: モダンレイアウト
- CSS Transitions: 滑らかなアニメーション
開発ツール
- Python 3.7+: 開発言語
- Git: バージョン管理
- 環境変数管理: .envファイル活用
📈 成果・学び
技術的成果
- 保守性向上: JavaScript削減により可読性・保守性が大幅改善
- パフォーマンス向上: 画像処理最適化で90%の処理時間削減
- UI統一: コンポーネント化による一貫したユーザー体験
- 安全性向上: 非破壊的機能追加による既存データ完全保護
学習ポイント
- モダンWeb技術: HTMX + Alpine.jsによる脱JavaScript開発
- 画像処理: OpenCVを活用した実用的な画像最適化
- レスポンシブ設計: CSS新機能を活用した効率的な実装
- 段階的改善: 既存システムを破壊せずに機能追加する手法
🎯 今後の展開
機能拡張計画
- 投票制限機能: IPベース・時間ベースの制限
- カテゴリ機能: 候補者のグループ分け
- SNS連携: ソーシャルログイン・シェア機能
- 権限管理: 管理者権限レベルの細分化
技術的改善
- PWA対応: Service Worker実装
- リアルタイム通信: WebSocket導入
- 国際化対応: 多言語サポート
- アクセシビリティ: WCAG 2.1 AA準拠
💡 プロジェクトから得られた知見
このプロジェクトを通じて、「技術選択の重要性」と「段階的改善の価値」を実感しました。特に、AI顔検出から固定切り出しへの方針転換では、確実性と保守性を重視する判断の重要性を学びました。
また、HTMX + Alpine.jsによる「脱JavaScript依存」のアプローチは、従来のSPA開発とは異なる新しい可能性を示し、シンプルで保守しやすいWebアプリケーションの実現に大きく貢献しました。
🎉 素敵な投票システムライフをお楽しみください! 🦋✞