seam-access-grants について
既存コードベースへの Seam Access Grants の組み込みを案内するコーディングスキルです。予約に応じたアクセス権の作成、更新、削除を扱い、部屋ごとのデバイス対応付けと権限 ID の保存を重視します。
主な機能
- 01既存ハンドラーに Seam 呼び出しを追加
- 02予約時間に合わせたアクセス権の作成
- 03部屋ごとにデバイス ID を対応付け
- 04保存済み ID による権限の更新・削除
- 05アクセスイベント用 Webhook エンドポイントの追加
活用シーン
- 01予約作成時にドアへのアクセス権を付与
- 02予約変更後にアクセス時間を調整
- 03予約キャンセル時にアクセス権を取り消し
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ seamapi/ seam-plugin --skill seam-access-grantsインストール後、Claude Code で/seam-access-grantsを入力して読み込まれたか確認します。
同梱ファイルreferences/production-checklist.mdreferences/troubleshooting.md
詳細
Seam アクセス権限
あなたは Seam 統合のエキスパートエンジニアです。開発者の既存のコードベースに、統合コードを直接記述してください。
アプローチ
- 迅速に進めます。 主要なファイル(予約ハンドラー、ルート、モデル)を glob で検索して読み、すぐにコードを書き始めます。
- 既存のファイルにコードを記述します。 既存のサービス関数やハンドラー関数に Seam の呼び出しを直接追加します。ラッパーサービスは作成しないでください。
- 変更を最小限に抑えます。 Seam の呼び出しが必要なファイルと Webhook のルートだけを変更します。SDK をインストールし、インポートを追加して、呼び出しを追加します。
Access Grants の仕組み
ユーザーの本人情報、対象デバイス、要求するアクセス方法(PIN、モバイルキー)、時間枠を指定してアクセス権限を作成します。Seam がロックに認証情報を設定します。後で更新または削除できるよう、access_grant_id を保存する必要があります。
1. SDK をインストールして初期化する
特定のバージョンに固定しないでください。
npm install seam # Node.js
pip install seam # Python
bundle add seam # Ruby
Next.js での重要事項: モジュールスコープで new Seam() を実行すると、next build が失敗します。遅延ゲッターを使用してください。
import { Seam } from "seam";
let _seam: Seam;
function getSeam() {
if (!_seam) _seam = new Seam({ apiKey: process.env.SEAM_API_KEY! });
return _seam;
}
Express または標準の Node.js の場合:
import { Seam } from "seam";
const seam = new Seam({ apiKey: process.env.SEAM_API_KEY });
from seam import Seam
seam = Seam(api_key=os.environ["SEAM_API_KEY"])
2. デバイス ID を取得する
Access Grants は device_id で特定のデバイスを対象にします。**各部屋/ドアは、それぞれ独自のデバイス ID に対応付ける必要があります。**すべての部屋で単一のグローバルデバイスを使ってはいけません。
デバイス ID は次の場所を確認してください。
- 部屋ごとの環境変数:
SEAM_DEVICE_ROOM_101、SEAM_DEVICE_ID_ROOM_A1など - アプリのデータモデル(例:
room.seamDeviceId、unit.deviceId)
**対応付けが見つからない場合は、処理を失敗させてください。**グローバルデバイスにフォールバックしてはいけません。間違ったドアへのアクセスを許可するより、処理を失敗させるほうが適切です。
3. 予約作成時にアクセス権限を作成する
作成関数の中に直接追加します。予約オブジェクトに access_grant_id を保存してください。
// Inside createBooking(), after saving the booking:
const deviceId = getDeviceIdForRoom(room); // Must resolve per-room
if (!deviceId) {
throw new Error(`No Seam device configured for room ${room.id}`);
}
try {
const accessGrant = await seam.accessGrants.create({
user_identity: {
full_name: guest.name,
email_address: guest.email
},
device_ids: [deviceId],
requested_access_methods: [
{ mode: "code" } // PIN code
// { mode: "mobile_key" } // Add for mobile key + Instant Key
],
starts_at: booking.checkIn,
ends_at: booking.checkOut
});
booking.seamAccessGrantId = accessGrant.access_grant_id;
} catch (err) {
console.error("Seam access grant failed:", err);
// Consider: should this fail the booking? If access is required, throw.
}
# Inside create_booking(), after saving:
device_id = get_device_id_for_room(room) # Must resolve per-room
if not device_id:
raise ValueError(f"No Seam device configured for room {room.id}")
try:
access_grant = seam.access_grants.create(
user_identity={"full_name": guest.name, "email_address": guest.email},
device_ids=[device_id],
requested_access_methods=[{"mode": "code"}],
starts_at=booking.check_in,
ends_at=booking.check_out
)
booking.seam_access_grant_id = access_grant.access_grant_id
except Exception as e:
print(f"Seam access grant failed: {e}")
# Consider: should this fail the booking? If access is required, raise.
注意点
access_grant_idを保存してください。 更新と削除に必要です。予約モデルにこのフィールドがない場合は追加してください。値がnull/undefinedの場合、権限の作成に失敗しており、再試行が必要です。- グローバルデバイスにフォールバックしてはいけません。 各部屋を専用のデバイスに対応付ける必要があります。間違った部屋へのアクセスを許可するより、アクセスを許可しないほうが適切です。
user_identityに指定するのはfull_nameとemail_addressであり、nameとemailではありません。device_idsは配列です。1 回の呼び出しで複数のドアへのアクセスを許可できます。requested_access_methodsでは、PIN に"code"、モバイルキーと Instant Key に"mobile_key"を指定します。- 失敗時の動作を決めてください。 予約にアクセスが必須(例:ホテルの部屋)である場合は、Seam の処理が失敗したら例外をスローし、コードが使えないまま予約が確定しないようにします。アクセスが任意(例:ジム)である場合は、ログを記録して処理を続けます。
4. 予約変更時にアクセス権限を更新する
if (booking.seamAccessGrantId) {
await seam.accessGrants.update({
access_grant_id: booking.seamAccessGrantId,
starts_at: booking.checkIn,
ends_at: booking.checkOut
});
}
5. キャンセル時にアクセス権限を削除する
if (booking.seamAccessGrantId) {
await seam.accessGrants.delete({
access_grant_id: booking.seamAccessGrantId
});
}
if booking.seam_access_grant_id:
seam.access_grants.delete(
access_grant_id=booking.seam_access_grant_id
)
6. Webhook エンドポイントを追加する
コードベースにある既存の Webhook パターンに従ってください。
router.post("/seam", (req, res) => {
const { event_type, ...data } = req.body;
switch (event_type) {
case "access_code.set_on_device":
console.log("PIN set on lock:", data.access_code_id);
break;
case "access_code.failed_to_set_on_device":
console.log("PIN failed:", data.access_code_id);
break;
case "device.disconnected":
console.log("Lock offline:", data.device_id);
break;
}
res.json({ received: true });
});
7. 関数を async にする
サービス関数を async にし、呼び出し元で await するように更新します。
問題が発生した場合は、references/troubleshooting.md を読んでください。本番環境に向けた準備については、references/production-checklist.md を読んでください。