借助 Airtable 搭建一個團隊共享的臨時號碼狀態看板

一個在團隊內部工具分享會上做演示的 QA 自動化架構師的實戰教學——每一步都有設計理由,每一列都有思考,每一個坑都提前替你踩平了。

真實的團隊協作混亂場景:QA 團隊三人同時測試註冊流程。A 在 5sim 上搶了號碼但忘了標記、B 用了同一個號碼觸發驗證碼被頂掉、C 找不到哪個號碼還能用。號碼衝突、狀態不清、重複勞動——這就是沒有共享看板的日常。
核心承諾:用 Airtable 搭一個所有人都能即時查看、更新、檢索的號碼狀態看板,三人共用同一份數據源,號碼衝突歸零。

一、完整的協作架構圖

整個方案圍繞「單一事實來源」原則設計——Airtable 是唯一的真相,所有人看到的是同一份數據。

[接碼平台 API] → [Python/Node 同步腳本] → [Airtable Base] ← [團隊三人同時查看/更新] ↓ ↓ ↓ ↓ 5sim / SMSPool 每5分鐘自動同步 單一事實來源 瀏覽器 / Airtable App

二、Step 1:設計 Airtable 表格結構(全文核心地基)

表格結構是整個看板的靈魂。以下欄位設計經過三個 QA 團隊的實戰打磨,每一列都有明確的設計理由。

欄位名稱 欄位類型 示例值 設計理由
號碼 Phone +1(234)567-8901 唯一標識,可點擊直接撥打(Airtable Phone 類型支援一鍵呼叫)
號碼狀態 Single Select 🟢可用 / 🟡使用中 / 🔴已失效 核心狀態列,一眼看全局。用顏色 Emoji 讓狀態在手機 App 上也清晰可辨
接碼平台 Single Select 5sim / SMSPool / SMS-MAN 追溯來源,方便比對不同平台的號碼品質
所用服務 Multiple Select Google / Telegram / WhatsApp 記錄該號碼在哪些服務可用——這是團隊的「知識資產」,新人接手無需重新測試
最後驗證時間 Date 2026-04-29 14:23 自動判斷是否過期,超過 3 天未驗證的號碼需重新確認可用性
持有者 User @張三 誰正在使用此號碼——避免兩人同時用同一個號碼觸發驗證碼
備註 Long Text 收 Telegram 驗證碼成功,50 秒延遲 自由補充資訊,如延遲時間、特殊注意事項

建立表格的實操步驟:在 Airtable 中新建 Base → 命名為「團隊號碼庫」→ 依上表逐欄新增欄位 → 設定 Single Select 的選項為🟢可用、🟡使用中、🔴已失效 → 設定 Multiple Select 的選項為常用服務(Google、Telegram、WhatsApp、TikTok、Amazon 等)。

三、Step 2:構建雙核心視圖——不同角色的視角切換

同一個 Base,兩個人打開看到的內容不同——這就是 Airtable 視圖的威力。以下兩種視圖覆蓋了 QA 測試和管理員兩種核心角色。

視圖一:QA 測試看板(Grid View)

這個視圖讓測試人員只看到「能用的號碼」,排除一切已失效的干擾。

配置項設定值理由
分組按「號碼狀態」分組可用/使用中/已失效三個區塊一目了然
篩選僅顯示狀態為「🟢可用」和「🟡使用中」已失效的號碼不出現在測試視圖中,減少干擾
排序按「最後驗證時間」降序最新驗證過的號碼排在最前面——越新鮮越可靠
隱藏欄位隱藏「接碼平台」欄測試人員不需要關心號碼來源,減少資訊過載

視圖二:管理員健康度看板(Grid View)

這個視圖讓管理員快速定位「哪些號碼需要重新驗證」,主動發現問題而非被動等待報告。

首先新增一個公式欄位「需驗證提醒」:

IF(
  DATETIME_DIFF(TODAY(), {最後驗證時間}, 'days') > 3,
  "⚠️ 需驗證",
  ""
)

這個公式自動標記超過 3 天未驗證的號碼。然後配置視圖:

配置項設定值理由
篩選顯示所有狀態 + 公式欄位「需驗證提醒」不為空只顯示需要關注的號碼
排序按「最後驗證時間」升序最久未驗證的排最前——優先處理
顏色規則「需驗證提醒」欄位包含「⚠️」時整行設為淡黃色背景視覺上快速掃描問題號碼

四、Step 3:編寫自動同步腳本——輪詢接碼平台並寫入 Airtable

以下 Python 腳本(約 50 行)負責從接碼平台拉取最新短信記錄,查重後寫入 Airtable,並更新已有號碼的狀態。使用 pip install pyairtable requests 安裝依賴。

import os, time, re
from pyairtable import Api as AirtableApi
import requests

AIRTABLE_API_KEY = os.getenv('AIRTABLE_API_KEY')
AIRTABLE_BASE_ID = os.getenv('AIRTABLE_BASE_ID')
AIRTABLE_TABLE_NAME = os.getenv('AIRTABLE_TABLE_NAME', '號碼庫')
FIVESIM_API_KEY = os.getenv('FIVESIM_API_KEY')

airtable = AirtableApi(AIRTABLE_API_KEY).table(AIRTABLE_BASE_ID, AIRTABLE_TABLE_NAME)

def get_recent_sms_from_5sim():
    """從 5sim 獲取最近的短信記錄"""
    resp = requests.get('https://5sim.net/v1/user/orders',
        headers={'Authorization': f'Bearer {FIVESIM_API_KEY}', 'Accept': 'application/json'})
    if resp.status_code != 200:
        return []
    orders = resp.json().get('orders', [])
    records = []
    for order in orders:
        if order.get('status') == 'RECEIVED':
            for sms in order.get('sms', []):
                records.append({
                    'phone': order.get('phone'),
                    'sms_text': sms.get('text', ''),
                    'platform': '5sim',
                    'received_at': sms.get('created_at', '')
                })
    return records

def format_phone(raw_phone):
    """清洗號碼為 E.164 格式"""
    cleaned = re.sub(r'[^\d+]', '', raw_phone)
    if not cleaned.startswith('+'):
        cleaned = '+' + cleaned
    return cleaned

def sync_to_airtable():
    """查重後寫入或更新 Airtable"""
    sms_records = get_recent_sms_from_5sim()
    for record in sms_records:
        phone = format_phone(record['phone'])
        # 查重:用號碼欄位做唯一索引
        existing = airtable.all(formula=f"{{號碼}}='{phone}'")
        if existing:
            # 已存在:只更新狀態和時間
            airtable.update(existing[0]['id'], {
                '號碼狀態': '🟢可用',
                '最後驗證時間': record['received_at'][:10],
                '備註': f"最新短信: {record['sms_text'][:50]}"
            })
        else:
            # 新號碼:插入一筆記錄
            airtable.create({
                '號碼': phone,
                '號碼狀態': '🟢可用',
                '接碼平台': record['platform'],
                '最後驗證時間': record['received_at'][:10],
                '備註': f"初始短信: {record['sms_text'][:50]}"
            })
        time.sleep(0.3)  # 避免觸發 API 頻率限制
    print(f'✅ 同步完成:{len(sms_records)} 條記錄')

if __name__ == '__main__':
    sync_to_airtable()

設定定時執行(crontab)

每 5 分鐘自動同步一次,確保看板始終反映最新狀態:

*/5 * * * * cd /opt/sms-airtable && python3 sync.py >> /var/log/sms_sync.log 2>&1

也可使用 systemd timer 或 GitHub Actions 的 schedule 觸發器實現同等效果。

五、進階玩法:讓看板「活」起來

擴展一:狀態自動變色

在 Airtable 中為「號碼狀態」欄位設定條件顏色規則:🟢可用 → 綠色背景、🟡使用中 → 黃色背景、🔴已失效 → 紅色背景。設定後整張表格的狀態一眼可辨識,在手機 App 上尤其直覺。

擴展二:號碼過期自動提醒

使用 Airtable Automations——觸發條件設為「當記錄更新時」,條件為「最後驗證時間超過 3 天」,動作選擇「發送 Slack 通知」或「發送 Email」。當號碼庫中出現超過 3 天未驗證的號碼時,管理員會自動收到提醒。

擴展三:號碼統計儀表盤

使用 Airtable 的 Summary Bar 或第三方工具(如 Google Data Studio 連接 Airtable)展示核心指標:可用號碼總數、今日使用次數、最常用服務 Top 5、本週新增號碼數。這些指標幫助團隊了解號碼資源的消耗趨勢。

擴展四:直接在這裡讀碼!

增加一個「最新短信」Long Text 欄位,同步腳本即時更新此欄位內容。團隊成員無需再打開接碼平台——驗證碼會直接出現在 Airtable 記錄中,點開號碼記錄就能看到完整短信內容和自動提取的驗證碼。

六、排坑指南

坑一:Airtable API 頻率限制

症狀:腳本連續寫入多筆記錄後,Airtable 回傳 HTTP 429 Too Many Requests,後續寫入全部失敗。

原因:Airtable 免費版有每秒 5 次請求的限制,超過後會被暫時封鎖。

解法:在每次 API 呼叫之間加入 time.sleep(0.3)(約每秒 3 次請求,留有安全邊際)。如果團隊規模較大(超過 5 人同時使用),建議升級到 Airtable Pro 方案,頻率限制會放寬。

坑二:多用戶同時編輯衝突

症狀:兩人同時對同一行記錄進行編輯,後提交的人看到「此記錄已被他人修改」的提示。

解法:Airtable 會自動處理儲存格級衝突,但整行刪除需謹慎。建議設定權限——普通成員只能編輯「狀態」和「持有者」兩列,管理員才能刪除記錄。在 Base 右上角的「Share」中設定不同角色的編輯權限。

坑三:號碼欄位格式不統一

症狀:同一號碼在 Airtable 中出現了兩筆記錄——一筆帶 + 號、一筆不帶。查重失效,號碼池混亂。

原因:不同接碼平台回傳的號碼格式不同(5sim 帶 + 號、SMSPool 不帶國碼前綴、SMS-MAN 有時少了國碼)。

解法:同步腳本必須做格式清洗,統一存為 E.164 標準格式(如 +1234567890)。腳本中的 format_phone 函數已實現此邏輯——先移除所有非數字字元,再補上 + 號前綴。


結語:從「誰有能用的號」到「打開看板自己看」的團隊協作升級

這套方案為 QA 團隊帶來的三重價值:

行動建議:花 20 分鐘搭好表格結構,再花 30 分鐘把同步腳本跑起來,然後把它放在團隊的公共瀏覽器標籤頁裡——從此號碼管理不再靠吼。