1. はじめに
- これはECサイトのオペレーター管理システムにおける中核となるモデル実装である
- システム管理者(system_admin)と店舗管理者(store_admin)の2つの権限を持つユーザーを管理し、セキュアなパスワード管理とデータの整合性を保証する
環境構成
主要な技術スタック:
Go v1.23.3
Gin Web Framework v1.10.0
GORM v1.25.12
PostgreSQL v17.0
2. モデル設計の特徴
2.1 権限管理システム
const (
RoleSystemAdmin = "system_admin" // システム管理者権限
RoleStoreAdmin = "store_admin" // 店舗管理者権限
)
定数として権限を定義することで、タイプセーフな権限管理を実現している
- 権限値の誤入力を防止
- コード補完による開発効率の向上
- 権限の一元管理が可能
2.2 詳細なモデル構造
type Operator struct {
ID string `gorm:"type:uuid;primary_key" json:"id"`
Email string `gorm:"unique;not null" json:"email" validate:"required,email"`
Username string `gorm:"not null" json:"username" validate:"required"`
PasswordHash string `gorm:"not null" json:"password_hash" validate:"required,password"`
Role string `gorm:"not null" json:"role" validate:"required,oneof=system_admin store_admin"`
StoreID string `gorm:"type:uuid;not null" json:"store_id" validate:"required,uuid"`
AvatarURL string `json:"avatar_url" validate:"omitempty,url"`
CreatedBy string `gorm:"type:uuid;not null" json:"created_by" validate:"required,uuid"`
UpdatedBy string `gorm:"type:uuid" json:"updated_by" validate:"required,uuid"`
DeletedBy *string `gorm:"type:uuid" json:"deleted_by,omitempty" validate:"omitempty,uuid"`
CreatedAt time.Time `gorm:"autoCreateTime;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
Store Store `gorm:"foreignKey:StoreID" json:"store"`
}
2.2.1 主要フィールドの詳細解説
-
識別子管理
-
ID
: UUIDv7形式を採用し、グローバルでユニークな識別子を保証 - データベース移行やシステム統合時の整合性を確保
-
-
認証情報
-
Email
: ユニーク制約付きで重複登録を防止 -
PasswordHash
: ハッシュ化されたパスワードを保存し、平文での保存を回避 -
Username
: システム内での表示名として使用
-
-
権限とアクセス制御
-
Role
: system_admin/store_adminの2値のみを許容 -
StoreID
: 所属店舗との紐付けによる適切なアクセス制御 -
Store
: 店舗情報との1対1のリレーション
-
-
監査証跡
-
CreatedBy
/UpdatedBy
/DeletedBy
: 操作者のトレーサビリティを確保 -
CreatedAt
/UpdatedAt
: 自動タイムスタンプによる操作日時の記録 -
DeletedAt
: 論理削除のサポート
-
-
プロフィール情報
-
AvatarURL
: オプショナルなプロフィール画像のURL
-
2.3 バリデーション機能
各フィールドに対して厳密なバリデーションルールを適用:
validate:"required,email" // メールアドレスの形式検証
validate:"required,password" // カスタムパスワードルール
validate:"required,oneof=system_admin store_admin" // 権限値の制限
validate:"required,uuid" // UUID形式の検証
validate:"omitempty,url" // URLフォーマットの検証
3. パスワードセキュリティ
3.1 パスワードポリシー
厳格なパスワードポリシーを実装し、セキュリティ要件を満たしている:
const minPasswordLength = 8
func validatePassword(fl validator.FieldLevel) bool {
password := fl.Field().String()
if len(password) < minPasswordLength {
return false
}
return hasRequiredCharacterTypes(password)
}
今回のパスワードは以下の要件を全て満たす
- 最小8文字以上の長さ
- 大文字(A-Z)を1文字以上含む
- 小文字(a-z)を1文字以上含む
- 数字(0-9)を1文字以上含む
- 記号(!@#$等)を1文字以上含む
3.2 文字種別チェックの実装
func hasRequiredCharacterTypes(password string) bool {
var (
hasUpper, hasLower, hasNumber, hasSymbol bool
)
for _, char := range password {
switch {
case unicode.IsUpper(char):
hasUpper = true
case unicode.IsLower(char):
hasLower = true
case unicode.IsNumber(char):
hasNumber = true
case unicode.IsPunct(char) || unicode.IsSymbol(char):
hasSymbol = true
}
if hasUpper && hasLower && hasNumber && hasSymbol {
return true
}
}
return false
}
このチェック機能により:
- 効率的な文字種別判定(1回のループで全条件をチェック)
- 早期リターンによるパフォーマンス最適化
- Unicode対応による多言語サポート
4. データベース連携
4.1 UUIDの自動生成
func (o *Operator) BeforeCreate(tx *gorm.DB) error {
if o.ID != "" {
return nil
}
id, err := uuid.NewV7()
if err != nil {
return err
}
o.ID = id.String()
return nil
}
GORMのフックを利用して:
- レコード作成前に自動的にUUIDを生成
- 既存IDの上書きを防止
- エラーハンドリングによる信頼性確保
4.2 データベース制約
-
gorm:"type:uuid;primary_key"
: UUIDタイプの主キー -
gorm:"unique;not null"
: ユニーク制約と非NULL制約 -
gorm:"index"
: インデックスによる検索最適化 -
gorm:"foreignKey:StoreID"
: 外部キー制約による参照整合性の確保
5. 拡張性と保守性
このモデルは以下の特徴により、高い拡張性と保守性を実現しています:
-
モジュール性
- 各機能が明確に分離され、独立してテスト可能
- カスタムバリデーションの追加が容易
-
型安全性
- 厳密な型チェックによるバグの早期発見
- コンパイル時のエラーチェック
-
監査対応
- 完全な操作履歴の追跡が可能
- コンプライアンス要件への対応
-
セキュリティ
- パスワードの安全な管理
- アクセス制御の適切な実装
6. まとめ
- このモデルは、セキュリティ、保守性、拡張性のバランスが取れた実装となっており、実際のプロダクション環境での使用に適している
- また、GORMやvalidatorなどの標準的なライブラリを活用することで、信頼性の高いシステムを効率的に構築することができる
- 今後の開発においても、このモデルを基盤として、さらなる機能拡張や改善を行うことが可能
- セキュリティ要件の変更やビジネスルールの追加にも、柔軟に対応できる設計となっている