リファクタリング方針(共通化)

  • 作成日: 2026-10-30
  • 状態: 実施済み(第1弾 P1〜P4 / 第2弾 P5〜P9 / 第3弾 P10〜P14 / 第4弾 P15〜P19)
  • 関連: staff-pos.md / terminal-options.md

コードの重複を減らし、顧客PWA・店員POS・Terminal・サーバー・テストで同じ処理を使い回すための構成。


1. 共有パッケージ

パッケージ 役割
packages/api-types API DTO(ShopConfig / CatalogItem / OrderSummary / FeedOrder / RegisterState / StaffSession / TerminalSession 等)。型のみ
packages/api-client ApiError / request() / formatApiError() / createPoller()
packages/format yen() / formatJst() / formatUtc() / formatElapsed()
packages/cart カート演算(add/change/remove/total/toOrderItems/バーコード解決)
packages/ui-cart ProductGrid.svelte / CartLines.svelte
packages/core ドメイン型・状態遷移・価格・コード・ULID・newClientToken(/token サブパス)
packages/terminal-ui Terminal モックUI(実機比率の端末フレーム)
  • ブラウザから @shop-tools/core の値を import すると node:crypto を巻き込むため、newClientToken は @shop-tools/core/token を使う
  • api-types は型のみなので、サーバー・アプリ双方から安全に参照できる

2. サーバー構成

共通ヘルパー

ヘルパー 役割
lib/orderAccess.ts requireShopOrder() / resolveTerminalId() / assertRegisterAvailable()
lib/events.ts emitOrderEvent()(toFeedOrder を内包)
lib/orderInput.ts 注文明細の解決(価格・数量検証)
lib/hmac.ts HMAC署名(注文トークンとWSチケットで共用)
lib/shopView.ts toShopConfig()(config / bootstrap で共用)
lib/ddb.ts putIfAbsent()
lib/db.ts rawClient() / doc()
lib/notification/ NotificationTransport(LocalTransport / ApiGatewayTransport)

ディレクトリ分割

server/src/
  repo/orders/        create / read / write / mapper / index
  api/routes/staff/   auth / orders / register / ws / index
  • repo/orders と routes/staff は index.ts で再エクスポートし、既存のimportパスを維持
  • 通知は wsMode に応じて transport を選択(将来 SQS/SNS 追加が容易)

3. クライアント構成

apps/customer/src/
  App.svelte                 # レイアウトのみ
  lib/session.svelte.ts      # カタログ/カート/注文/キャッシュ
  lib/api.ts                 # api-client 利用
  components/ CatalogView / CartView / CodeView / DoneView / CartBar

apps/staff/src/
  App.svelte                 # レイアウト・タブ・配線のみ
  lib/session.svelte.ts      # セッション/選択注文/ロック/ポーリング
  lib/feed.svelte.ts         # WS/フィード/フォールバック
  lib/posCart.svelte.ts      # POSカート
  lib/beep.ts                # 通知音
  components/ LoginCard / BlockingBanner / FeedPane / PosPane / CheckoutPane
  • 状態はセッション(または専用ストア)に集約し、画面は props 中心
  • ポーリングは createPoller() に統一(顧客/Terminal)

Vite / Svelte 設定

  • tsconfig.app.json を各アプリで extends(共通)
  • Vite / Svelte 設定はアプリごとに保持(workspace の依存解決で共通化すると @sveltejs/vite-plugin-svelte の解決に失敗するため)

4. テスト・ツール

対象 内容
tests/e2e/lib/harness.mjs record / summary / call / startProcess / waitForHttp / killTree / randomPort
tests/e2e/ api-flow / local-flow / ui-smoke がハーネスを共用
tools/local-api/ env.mjs(.env/env.local)/ event.mjs(Lambdaイベント整形)/ ws.mjs(WS)/ server.mjs
tools/demo-launcher/ net.mjs(LAN IP/probe)/ page.mjs(HTML)/ server.mjs

5. スクリプト

  • scripts/_common.ps1: Get-RepoRoot / Add-ToolPaths / Invoke-BuildServer / Wait-TcpPort / Start-LocalDatabase
  • api.ps1 / local.ps1 / deploy.ps1 / db.ps1 / stop.ps1 は共通関数を利用
  • PowerShell 5.1 のため UTF-8 BOM を付与
  • npm run verify で「DB起動→型→unit→統合→ローカルE2E→UI→build」を一括実行

6. 設定の正(どこを直すか)

値 ローカル開発 AWS(デプロイ後)
店舗/レジ/端末ID .env → scripts/use-env.ps1 infra/template.yaml のパラメータ
BEの環境変数 infra/env.local.json(ASCIIのみ) template.yaml の Globals / パラメータ
AWS認証情報/MFA ~/.aws/config(.env はプロファイル名のみ) 同左(デプロイ端末)
アプリ機能フラグ config/{env}.json と features.* SSM /{env}/shoptools/config/flags
シークレット .env(ローカルのみ) SSM SecureString
WSエンドポイント WS_MODE=local / /ws SSM /{env}/shoptools/ws/endpoint

7. 検証

  • npm run verify
  • npm run test:e2e(sam)
  • sam validate --lint / sam build
  • npm run dev → npm run stop
  • スマホ実機で POS→決済→完了

8. 第3弾 P10〜P14(カタログ・在庫・注文の整理)

Phase 内容
P10 lib/catalog.ts にカタログ読込・検索・可用数付与を集約。bootstrap と注文価格解決を mock 固定から snapshot 参照へ変更
P11 core/orderIntake.ts に「冪等→引当→作成→失敗時解放」を集約。顧客/店員の注文作成を共通化
P12 repo/inventory.ts(在庫CRUD)と repo/reservations.ts(引当/解放/掃除)に分割。sync/scheduler.ts と api/routes/index.ts を追加
P13 顧客 lib/cartDraft.ts、店員 lib/catalogStore.svelte.ts を抽出。同期DTOを api-types へ移動
P14 CatalogItem / Availability を api-types の正とし、core は type re-export に変更

追加された構成

server/src/
  lib/catalog.ts          # loadCatalog / filterCatalog / toCustomerItems / toStaffItems
  lib/syncStatus.ts       # staleSecondsOf
  core/orderIntake.ts     # createReservedOrder
  repo/reservations.ts    # reserve/release/getReserve/cleanup
  sync/scheduler.ts       # runScheduledSync
  api/routes/index.ts     # ルート表

apps/customer/src/lib/cartDraft.ts
apps/staff/src/lib/catalogStore.svelte.ts

挙動の変更

  • /api/bootstrap と注文価格は snapshot(Square同期結果) を参照。snapshot未作成のローカルのみ mock にフォールバック
  • 引当競合(楽観ロック)は1回だけ再試行
  • 期限切れ引当の掃除は同期の有無にかかわらず実行

9. 第4弾 P15〜P19(同期・adapters・ツール・店員状態の整理)

Phase 内容
P15 lib/syncStatus.ts に toSyncStatus / isSyncDue / cooldownRemainingMs を集約。syncStatusHandler の再帰呼び出しを廃止。readBody() を共通化
P16 adapters の旧API(listCatalog / findCatalogItem / MockTerminalAdapter)を削除。注文価格の解決を lib/catalog.ts 経由に統一
P17 Square同期を sync/mock.ts / sync/square/(client・mappers・types)へ分割。API呼び出しに10秒タイムアウト
P18 tools/shared/env.mjs に .env パーサーを集約。launcher はシェル優先、local-api は従来の上書き順
P19 店員の注文・決済・ポーリングを lib/orderSession.svelte.ts へ抽出。StaffSessionStore はログイン/POS/同期/フィードに集中

構成

server/src/
  lib/syncStatus.ts        # toSyncStatus / isSyncDue / cooldownRemainingMs
  sync/mock.ts
  sync/square/{client,mappers,types,index}.ts

apps/staff/src/lib/orderSession.svelte.ts
tools/shared/env.mjs

挙動の変更

  • SyncStatus.catalogVersion は string | null
  • SyncRunResult.mode は "mock" | "square"
  • Square API呼び出しは10秒でタイムアウト
  • 店員UIの公開プロパティ(selected / blockingOrderId)はgetterで維持