本番移行設計(環境分離・Cognito・マルチ店舗)
デモ(mock)で作ったものを、設定変更中心で本番に上げるための設計。
1. 環境
| 環境 |
用途 |
ADAPTER |
AUTH_MODE |
DynamoDB |
Square |
| dev |
ローカル・デモ |
mock |
pin |
使い捨て |
なし |
| staging |
結合テスト |
sandbox |
cognito(テストプール) |
別テーブル |
Sandbox |
| production |
本番 |
production |
cognito |
別テーブル |
本番 |
- 同一コード、環境差分は設定のみ(SSM パスを
/{env}/shoptools/... に)
- スタックも環境ごとに分離(CloudFront・Webhook 購読・Cognito も別)
- 機能フラグ:
ADAPTER / AUTH_MODE / DEMO_ENABLED / FEATURE_SCAN / FEATURE_CASH / CHECKOUT_ENABLED
- 本番は
DEMO_ENABLED=false でモック用 API を 404 にする
2. 秘密情報
既定:SSM Parameter Store(SecureString)
| パラメータ |
内容 |
/{env}/shoptools/square/access_token |
Square アクセストークン(本番のみ) |
/{env}/shoptools/square/webhook_signature_key |
Webhook 署名キー |
/{env}/shoptools/auth/jwt_secret |
デモ JWT 署名鍵(本番は未使用) |
/{env}/shoptools/staff/pin_hash |
デモ PIN ハッシュ |
/{env}/shoptools/demo/token |
モック API 用トークン |
- AWS 管理キー(
aws/ssm)を使えば KMS 費用も無料
- Lambda 起動時に取得してメモリキャッシュ。失敗時のみ再取得
- 本番で OAuth(店舗ごとトークン)に進む段階で Secrets Manager へ移行
- 理由:ローテーション、監査、店舗数分のシークレット管理
アクセストークンの種類
| 方式 |
用途 |
備考 |
| Personal Access Token(PAT) |
自社アカウントのみ |
長期。失効は手動 |
| OAuth |
他社・複数店舗 |
有効期限あり。リフレッシュ必要 |
- 初期(1店舗・既存アカウント)は PAT
- 店舗が別アカウントになる、または SaaS 化する段階で OAuth
- スコープ:
DEVICE_CREDENTIAL_MANAGEMENT / MERCHANT_PROFILE_READ / PAYMENTS_READ / PAYMENTS_WRITE
3. Cognito(店員認証)
構成
User Pool(1つ)
├ Group: admin
├ Group: staff
└ App Client(PWA 用、SRP)
- ユーザーは管理者が作成(セルフサインアップ不可)
- MFA(TOTP)は任意
- PWA は Cognito SDK(
amazon-cognito-identity-js 等)でログインし、ID トークンを API に付与
認可
- Lambda は JWKS で JWT を検証(鍵はキャッシュ)
sub → STAFF#{sub} を引き、shopId / registerId / role / active を取得
- JWT にレジ情報を詰めない(異動・兼務に強い、トークン肥大を避ける)
- 端末はサーバー側で解決。クライアント指定を信用しない
- 退職・異動は DB の
active / registerId を更新(トークン失効を待たない)
デモとの差
|
デモ |
本番 |
| ログイン |
店舗PIN |
Cognito |
| トークン |
BE 署名 JWT |
Cognito ID トークン |
| 認可 |
PIN に紐づく固定レジ |
DB のスタッフ情報 |
| 監査 |
なし |
audit_log(誰が・いつ・どの注文) |
4. マルチ店舗設計(今は1店舗)
Merchant(Square アカウント)
└ Shop(Square Location)
└ Register(Terminal)
- 全データに
merchantId / shopId / registerId
- 店舗追加=同じ Square アカウントに Location を追加し
shopId を発行
- 別アカウントなら OAuth(
TokenStore を店舗ごとに)
- URL は
/s/{shopId}/...。将来は店舗ドメイン
- CloudFront の別名 + ACM(us-east-1)+ Route 53
- 完全隔離が必要なら店舗ごとにスタック分割(データモデルは同一)
5. 既存 Square アカウントを使う場合
- 既存 Terminal を Square POS(スタンドアロン)からサインアウトし、
CreateDeviceCode で本アプリにペアリングする
- 同時併用は不可。既存 POS 運用との競合を事前に合意する
- 既存の
Location ID を使用
- 既存カタログ・在庫・税設定はそのまま(BE は参照のみ)
- 商品バーコードが登録済みか確認(未登録ならスキャン不可。MVP はタイル+検索で回避)
- 領収書・返金・在庫は従来どおり Square Dashboard / 端末
- 税は
order.total_money を正とする(BE で再計算しない)
- Square for Retail 等の端末上機能は、Terminal API モードでは使えなくなる点に注意
6. 切替フェーズとロールバック
| Phase |
内容 |
完了条件 |
戻し方 |
| P1 |
mock デモ |
先方が再現できる |
— |
| P2 |
sandbox 結合 |
契約テスト全通過 |
ADAPTER=mock |
| P3 |
本番パイロット(1レジ・少額) |
実機 E2E・返金確認 |
CHECKOUT_ENABLED=false(新規決済停止) |
| P4 |
本番運用 |
監視・運用定着 |
同上 |
| P5 |
店舗追加 |
shopId 追加のみ(別アカウントは OAuth) |
店舗単位で停止 |
- 切替は設定変更のみ(コード再デプロイ不要)にしておく
- ロールバックは「新規決済の受付停止(
CHECKOUT_ENABLED=false)」まで。処理中の決済は完了させる。完了済み決済は Square の記録が正(返金は Dashboard)
- パイロット中は 1 レジ・少額・有人で実施
7. 監視・運用
| 項目 |
内容 |
| ログ |
構造化 JSON、correlationId(注文IDで追跡) |
| アラーム |
webhook 失敗、SENT 滞留、checkout 失敗率、金額不一致、カタログ同期失敗 |
| 非同期 |
SQS + DLQ(webhook 後処理、キュー送出) |
| ヘルス |
GET /api/health(DynamoDB / SSM / Square 到達性) |
| バックアップ |
PITR、日次エクスポート |
| ランブック |
端末オフライン、端末使用中、放置 checkout、返金、障害時の停止手順 |
8. 本番化チェックリスト
9. リスク
| リスク |
影響 |
対策 |
| 既存 Terminal の再ペアリング |
既存 POS が使えなくなる |
事前合意、必要なら端末追加 |
| Sandbox でペアリング不可 |
検証不足 |
本番パイロットで実機検証 |
| 単一アカウントで複数店舗の売上集約 |
資金移動・収納代行の論点 |
店舗ごとに OAuth、資金は店舗口座へ |
| Cognito 設定ミス |
ログイン不可 |
staging で検証、管理者作成手順を文書化 |
| OAuth トークン失効 |
決済不可 |
リフレッシュ実装、失効アラート |
| 税設定のズレ |
金額不一致 |
total_money を正、差分検知 |
| カタログ同期失敗 |
商品が出ない |
前回キャッシュ保持+アラート |
| 現金のドロワーが自動で開かない |
運用負荷・釣銭ミス |
手動ドロワー/Square POS 併用。現金管理は別運用 |