AppCotton では、product_slug が「あなたの製品を一意に識別する主キー」に相当します。
SDK・REST・DB・購入UI・ドメイン認証の全レイヤーで参照されるため、最初の設計が将来の運用コストを大きく左右します。
目的と位置づけ
- 一意識別子:人間可読 & URL/コードに安全に埋め込める ID(例:
combpass_premium) - 永続性:バージョンや価格改定、販売形態が変わっても変えない(製品ラインを変えるときのみ新規発行)
- 外部公開:SDK 設定、クライアント側コード、REST クエリ、ショートコードで公開される前提
命名ルール(推奨)
- 英小文字 + 数字 + アンダースコアのみ
- 正規表現:
^[a-z0-9_]+$
- 正規表現:
- 先頭は英字
- 例:
combpass_basicは OK、123_basicは非推奨
- 例:
- 単語は
_で区切る(ハイフンは使わない)- 例:
appcotton_sdk_pro
- 例:
- 短く・意味がわかる(20〜40 字目安)
- 例:
combpass_premium,foxpot_enterprise
- 例:
- 製品ライン + エディション(/販売系) を基本形に
- 例:
{line}_{edition}→combpass_premium - エディション例:
free,basic,pro,premium,enterprise
- 例:
- 環境や店舗などの局所情報は含めない
*_staging,*_jp,*_2025campaignは避ける- 期間限定販売は plan で表現する
予約・禁止パターン
- 予約接頭辞:
wp_,appcotton_,system_(内部で使用する可能性) - 予約語:
default,test,null,true,false,none - 禁止文字:スペース、ハイフン、記号、全角文字、絵文字
- 将来の衝突を避けるため、自プロダクトの接頭辞を付ける(例:
cbp_,foxpot_など)
変更ポリシー
- 原則、後から変更しない(既発行ライセンス・アクティベーション・Webhook・外部連携が壊れる)
- 製品の統合/分割やブランド変更が必要な場合は:
- 新 slug を新規発行 → 旧 slug を「非推奨(deprecated)」マーク → 段階的移行
- REST で旧→新マッピングを提供(期間限定)
バージョンとエディションの扱い
- バージョン番号は slug に含めない(例外:長期共存させる別製品として扱う場合のみ)
- ✅
combpass_premium+ バージョンは メタ情報/プラン で管理 - ❌
combpass_premium_v2(将来の分岐とデータ移行が複雑化)
- ✅
- エディション差は plan(プラン) に寄せる
- 例:
combpass_premium(プロダクト)に1-site,3-sites,unlimited等のプラン
- 例:
スラグ衝突の回避
- ユニーク制約を DB レベルで保持(重複登録を弾く)
- 管理 UI 保存時に重複チェック + サジェスト
- 例:
combpass_premiumが存在 →combpass_premium2を提案しない(悪手) - 提案は 意味を維持:
combpass_enterpriseなど
- 例:
短縮形と拡張形のバランス
- 過度な略称(
cp_prem)は避ける - 長すぎる説明的名前(
combpass_premium_license_server_edition)も避ける - 可読性 > 数文字短縮 を優先
国際化(i18n)
- slug は英数固定(翻訳しない)
- 表示名・説明は各ロケールで翻訳(
name,descriptionフィールド) - 複数ブランド展開でも slug は共通にしておくと SDK/REST が単純化
スラグ生成アルゴリズム(参考)
- 製品ライン表示名から ASCII に正規化(記号・スペース除去、
-→_) - 英小文字化
- 先頭英字でなければ
x_を付加 - 禁止語と衝突チェック → サフィックス提案(
_plus,_proなど)
function generateSlug(name):
s = ascii_slugify(name) // "CombPass Premium" -> "combpass_premium"
s = s.toLowerCase()
s = s.replace("-", "_")
s = s.replaceAll(/[^a-z0-9_]/, "")
if not s[0].isAlpha(): s = "x_" + s
if isReserved(s) or existsInDB(s): s = suggestVariant(s) // e.g. "_pro", "_edition"
return s
運用 FAQ
Q1. プロモや年度キャンペーンでスラグを分けたい?
A. 分けない。プランや価格ルールで表現(期間限定プラン・クーポン・クレジット)
Q2. 無料/有料で別スラグにすべき?
A. 原則 同一スラグ + 別プラン(無料→有料アップグレードを差額課金で一本化)
Q3. 同一エンジンの別製品(例:Lite/Studio)?
A. 機能が大きく分岐し、将来も独立提供なら 別スラグ。
片方が上位互換なら 同スラグ + プラン差 を検討。
SDK/REST との対応関係
- SDK 設定例
AppCotton_SDK::init([ 'endpoint' => 'https://example.com/wp-json/appcotton/v1', 'product_slug' => 'combpass_premium', ]); - REST 例
GET /licenses/validate?license_key=XXXX&item_slug=combpass_premium&domain=https://site.example
→ slug を単純・堅牢にしておくほど、すべての呼び出しが簡潔になります。
データ移行(やむを得ず変更する場合)
- 新 slug を作成(旧は保持)
- ライセンス・注文・アクティベーションの 移行マップ を内部テーブルで用意
- REST/SDK で旧 slug を受けたら 新 slug に透過変換(移行期間のみ)
- ドキュメントと UI に移行告知
- 期間終了後、旧 slug を 廃止(参照が残るなら read-only リダイレクト)
セキュリティ観点
- slug は「推測可能」で問題ない(鍵ではない)
- ただし 列挙耐性のため、REST/閲覧で 内部 ID を出さず slug 固定で参照
- 監査ログで slug + license_key(マスク) + domain を記録
例:良い/悪い
- ✅
combpass_premium/foxpot_enterprise - ✅
cbp_pro(自ブランド prefix + edition) - ❌
Comb-Pass Premium(大文字・ハイフン・スペース) - ❌
combpass_premium_2025spring(季節要素) - ❌
combpass_premium_v2(バージョンを含める)
まとめ
- 変えない前提で設計(寿命は製品ラインと同じ)
- 短く・意味明確・英数+アンダースコア
- エディション/価格/期間は plan 側で表現
- マイグレーション時は新 slug + 透過変換 + 期間明記
これらを守ると、SDK/REST/UI/課金/監査の全体が一貫し、将来の手戻りを最小化できます。