4. 資料模型
4.1 庫存的四層結構
幣商 → 公司 → 遊戲 → 遊戲角色 → (幣 × 管道)
4.2 為什麼「遊戲角色」這層特別重要
- 遊戲幣不是放在「公司」裡,是放在具體的角色帳號裡
- 角色被遊戲商封鎖 → 該節點庫存死掉
- 一個角色有遊戲規則的存量上限
- 撮合時要確認「買家收貨的角色 ↔ 賣家出貨的角色」是同一款遊戲
4.3 進貨管道枚舉
| Channel | 來源 | 入庫方式 | 成本特性 |
| 玩家 | ATMatch 撮合的賣單 | 自動 | 變動 |
| 產包 | 跟遊戲商批發 | 手動進貨單 | 穩定但低毛利 |
| 同業 | 跟同業調貨 | 手動進貨單 | 應急用,毛利窄 |
| 活動贈送 | 遊戲商活動贈幣 | 手動進貨單 | 0 成本 |
| 自家持有 | 早期累積 / 獲利轉持 | 手動進貨單 | 視成本基礎 |
4.4 核心資料表(草案)
game_account(遊戲角色 = 庫存容器)
CREATE TABLE game_account (
id BIGINT PRIMARY KEY,
company_id BIGINT,
game_id BIGINT,
role_name VARCHAR(64),
role_id_in_game VARCHAR(64),
status ENUM('active', 'banned', 'locked'),
capacity_limit BIGINT
);
inventory_position(當前庫存快照)
CREATE TABLE inventory_position (
id BIGINT PRIMARY KEY,
company_id BIGINT,
game_id BIGINT,
game_account_id BIGINT,
coin_type VARCHAR(32),
channel ENUM('player', 'pack', 'peer', 'event', 'self'),
qty BIGINT,
avg_cost DECIMAL(12,4),
UNIQUE(company_id, game_id, game_account_id, coin_type, channel)
);
inventory_in(進貨事件,多管道)
CREATE TABLE inventory_in (
id BIGINT PRIMARY KEY,
company_id BIGINT,
game_id BIGINT,
game_account_id BIGINT,
coin_type VARCHAR(32),
channel VARCHAR(32),
qty BIGINT,
unit_cost DECIMAL(12,4),
total_cost DECIMAL(14,2),
source_type ENUM('atmatch_sell', 'manual_purchase', 'activity'),
source_ref VARCHAR(64),
in_at DATETIME
);
match_event(撮合事件,由 ATMatch 產出)
CREATE TABLE match_event (
id BIGINT PRIMARY KEY,
buy_order_id BIGINT,
sell_order_id BIGINT,
company_id BIGINT,
game_id BIGINT,
game_account_id BIGINT,
coin_type VARCHAR(32),
qty BIGINT,
amount_a DECIMAL(14,2),
amount_b DECIMAL(14,2),
fee_c DECIMAL(14,2),
channel VARCHAR(32),
matched_at DATETIME
);
unsettled_order(撮不完的單 = 預收 / 預付)
CREATE TABLE unsettled_order (
id BIGINT PRIMARY KEY,
type ENUM('buy', 'sell'),
company_id BIGINT,
game_id BIGINT,
coin_type VARCHAR(32),
qty BIGINT,
amount_twd DECIMAL(14,2),
aged_days INT,
blocked_reason VARCHAR(128),
created_at DATETIME
);
member(玩家會員)
CREATE TABLE member (
id BIGINT PRIMARY KEY,
name VARCHAR(64),
id_card VARCHAR(20),
phone VARCHAR(20),
is_business BOOLEAN,
monthly_sales DECIMAL(14,2),
risk_flags JSON,
kyc_status ENUM('pending', 'verified', 'rejected'),
bank_accounts JSON
);