【データベース設計】Supabase×Alembicで実現するローカルプレイヤーの国別メタデータ拡張
ユーザー登録不要の匿名対戦ゲームにおいて、世界のプレイヤーの対戦であることを表現するために国旗・国名メタデータをDBモデルへ安全に追加・移行したAlembic実践ログです。
1. はじめに:匿名対戦における国情報表示のねらい
Doodle Fighterは「会員登録ゼロ・即プレイ開始」を売りにしています。
ランキング画面や対戦画面で「🇯🇵 日本 の 描画ファイター」や「🇺🇸 アメリカ の 挑戦者」といった国旗アイコンが表示されると、非同期対戦の臨場感が一気に増します。
2. データベースモデルの拡張(SQLAlchemy & Pydantic)
既存の `players` テーブルに対し、ISO国コード(例: `JP`, `US`, `FR`)を保持するカラム `country_code` を安全に追加しました。
SQLAlchemy モデル (backend/models.py)
# backend/models.py
class Player(Base):
__tablename__ = "players"
id = Column(String, primary_key=True)
nickname = Column(String, nullable=False)
country_code = Column(String(5), nullable=True, default="JP") # 新規追加
created_at = Column(DateTime(timezone=True), server_default=func.now())
3. Alembicによる安全なマイグレーション手順
運用中のSupabase(PostgreSQL)環境でデータを保持したままカラムを追加するため、Alembicマイグレーションスクリプトを作成・実行しました。
Alembic スクリプト (alembic/versions/f7c87faaa133_add_country_code_to_players.py)
"""add_country_code_to_players
Revision ID: f7c87faaa133
Create Date: 2026-07-16 23:36:22
"""
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('players', sa.Column('country_code', sa.String(length=5), nullable=True, server_default='JP'))
def downgrade():
op.drop_column('players', 'country_code')
4. フロントエンドでの国旗絵文字変換(JavaScript)
国コード(`JP` 等)をユニコード絵文字の国旗(🇯🇵)に変換するロジックをフロントエンドに実装しました。国コードの各文字から `0x1F1E6` オフセットを加算するだけで絵文字化が可能です。
// frontend/static/js/app.js
function getFlagEmoji(countryCode) {
if (!countryCode || countryCode.length !== 2) return '🌐';
const codePoints = countryCode
.toUpperCase()
.split('')
.map(char => 127397 + char.charCodeAt(0));
return String.fromCodePoint(...codePoints);
}
5. まとめ
匿名プレイの気軽さを保ちながら、メタデータ(国情報)をスキーマに追加することで、Web対戦の賑わいと没入感を大幅に向上させることができました。