プロジェクト

全般

プロフィール

AIタスク #10239

未完了

エピック #10236: [PathCollector] MVP開発 (Epic)

PC1-03 Collector SDK基本実装

Redmine Admin さんが19日前に追加. 18日前に更新.

ステータス:
解決
優先度:
通常
担当者:
-
開始日:
2026-07-21
期日:
2026-07-21 (18日 遅れ)
進捗率:

0%

予定工数:
from_agent:
to_agent:
lock_required:
context_json:
session_id:
priority_custom:
start_time:
end_time:
execution_time:
acceptance_criteria:
assigned_role:
human_gate:
gate_type:
chain_root_id:
10236
wave_id:

説明

[Phase1-収集基盤]

5章のSDK公開関数一式をTypeScriptで実装。
受入: テストサイトへ1タグでinit()が動作すること。


関連するチケット 1 (1件未完了0件完了)

次のチケットに先行 PathCollector - AIタスク #10240: PC1-04 rrwebイベント取得統合新規2026-07-222026-07-22

操作

Redmine Admin さんが19日前に更新

  • 期日2026-07-21 にセット
  • 開始日2026-07-19 から 2026-07-21 に変更
  • 次のチケットに後続 AIタスク #10238: PC1-02 プロジェクト・APIキー登録CLI を追加

Redmine Admin さんが19日前に更新

  • 次のチケットに先行 AIタスク #10240: PC1-04 rrwebイベント取得統合 を追加

Redmine Admin さんが19日前に更新

  • 次のチケットに後続 を削除 (AIタスク #10238: PC1-02 プロジェクト・APIキー登録CLI)

Redmine Admin さんが19日前に更新

  • ステータス新規 から 実行中 に変更

Claude Code (claude -p --permission-mode dontAsk, model=sonnet) をVPS-root上でバックグラウンド起動し着手。作業ディレクトリ: /root/.worktrees/pc-track-b-sdk (branch: pc-track-b-sdk)。ログ: /root/projects/pathcollector/.run-logs/pc1-03.log

Redmine Admin さんが19日前に更新

  • ステータス実行中 から 解決 に変更

完了。apps/collector-sdk配下にSDK公開関数一式(init/consent/optOut/track/mask/flush等)をTypeScriptで実装。tsupでESM/CJS/IIFE(1タグ用)+型定義をビルド、Vitest単体テスト一式、test-site配下にモック配信サーバでHTTP経由のバッチ受信まで実機確認済み。※元仕様書の関数シグネチャ詳細はRedmine経由で取得できなかったため、提示された関数名一覧+SPEC.mdの受入条件から工学的判断でAPI設計を補完(引数/戻り値/デフォルト値)。masterブランチへマージ済み。commit 33118e3

Redmine Admin さんが19日前に更新

レビューで仕様逸脱を発見したため再オープン。修正項目:

  1. 認証: X-Api-Keyのみを廃止し、仕様F-012通りX-PC-Write-Key + X-PC-Timestamp + X-PC-Signature(HMAC-SHA256、timestamp+bodyを署名)に変更
  2. 圧縮: 送信ボディをgzip圧縮しContent-Encoding: gzipヘッダを付与
  3. ConsentState: 現状'granted'|'denied'|'pending'を廃止し、仕様F-003通り'unknown'|'granted'|'denied'|'essential_only'の4値に変更。F-003の判定規則テーブルをそのまま実装(unknownは原則未計測、essential_onlyはPathCollector計測しない)
  4. consentMode: PathCollectorConfigにconsentMode?: "explicit"|"implicit"を追加(既定explicit)
  5. 意味付きマスキング: addMaskSelector(selector, maskType?: MaskType)に引数追加。9.2の11値(name/email/phone/postal_code/address/card_number/password/token/date_of_birth/account_id/sensitive)をMaskType型として定義。masking.tsの自動検知(現状email/phone/cardの3種)に加え、氏名/郵便番号/住所等の検出も可能な限り実装(完全な名前検出は難しいのでNLPなしでできる範囲でよい)。各MaskTypeに対応する[MASKED_XXX]トークンをF-010の表に合わせる
  6. オプトアウト保存先: localStorageを廃止し、F-004通りファーストパーティCookie(名前pc_opt_out、値1、400日、SameSite=Lax、Secure=true)に変更
  7. init(): 同期 void を Promise に変更。許可ドメイン確認(F-001のproject_domains相当)のフックポイントを追加(MVPでAPI未実装なのでスタブでも可)
  8. setPageContext: 引数を{pageType?, contentId?, campaignId?, experimentId?}に変更(仕様通り)。url/path/title/referrerの上書き機能とは別に分離(後者はClientContextとして自動取得のままでよい)
  9. buffer.ts: 256KBバイトサイズ到達でもflushする第3のトリガーを追加(F-011)
  10. track(): propertiesをSafeValue型(string|number|boolean|null及びその配列/オブジェクト)に制限し、文字列長・キー数の上限を実装
  11. optOut/resetSession/destroyを仕様通りPromiseに変更(低優先度)
    ※ docs/SPEC.mdを元仕様書全文に差し替え済み。F-003/F-004/F-010/F-011/F-012/9.1/9.2/9.3を必ず参照。

Redmine Admin さんが19日前に更新

Codex CLIによるクロスレビューでFAIL。以下6項目を修正してください(src以下):

  1. 同意拒否(denied/essential_only)変更時にも未送信バッファを破棄する。現状optOut時のみ破棄されており、setConsent('denied')ではバッファが残り、後からflushされてしまう(F-003違反、index.ts)
  2. visibilitychange/pagehideのsendBeacon経路が通常送信(fetch)と違いgzip圧縮とX-PC-Write-Key/X-PC-Timestamp/X-PC-Signatureヘッダを使っていない。独自の非圧縮authフィールド方式を廃止し、F-012の形式に統一(transport.ts)
  3. PathCollectorConfigが9.1と不一致: 仕様にない必須projectIdを削除(init({writeKey,endpoint,consent})の単体呼び出しが通るように)。batchMaxEvents/batchMaxBytes/sessionTimeoutMinutes/maskTextSelectorsの名前を仕様通りに戻す。sampleRate/maskAllInputs/captureClicks/captureInputs/captureScroll/captureErrors/captureMouseMove/allowedQueryParams/blockedQueryParamsの9項目を実装(types.ts)
  4. F-010検出優先順位6「周辺ラベル」判定を実装(masking.tsで現在明示的に未実装となっている箇所)
  5. verifyAllowedDomain()が常にtrueを返すスタブのまま。F-001のproject_domainsはAPI未実装なので完全実装は不要だが、少なくともSDK設定のallowedDomainsリストとwindow.location.hostnameを照合する程度は実装(domain.ts)
  6. buffer.tsの256KB判定が各イベントJSONバイト数の単純合計のみで、実際の送信本文(projectId/eventsラッパー等含む)と並離している。実際のシリアライズ後ボディサイズに近い値で判定するよう修正
    ※ node_modules未導入でbuild/test未実行だったので、修正後はnpm installからbuild/testを必ず実行して確認すること。

Redmine Admin さんが19日前に更新

Codex CLIクロスレビューFAILの指摘6項目を修正済み(commit d054e98, [PC1-03-fix2])。

  1. setConsent(denied/essential_only)変更時も未送信バッファを破棄するようindex.tsのsyncRecordingStateを修正
  2. sendBeacon(visibilitychange/pagehide)経路もfetch(keepalive:true)によるgzip圧縮+X-PC-Write-Key/X-PC-Timestamp/X-PC-Signature署名(F-012)に統一。sendBeaconはフェッチ不可時のみのフォールバックとし、ヘッダ非対応のためクエリパラメータで同じ署名情報を送信
  3. PathCollectorConfigをSPEC.md 9.1に完全一致させ、projectIdを削除。batchMaxEvents/batchMaxBytes/sessionTimeoutMinutes/maskTextSelectorsに改称し、sampleRate/maskAllInputs/captureClicks/captureInputs/captureScroll/captureErrors/captureMouseMove/allowedQueryParams/blockedQueryParamsの9項目を実装(recorder.ts/index.tsまで実効的に配線)。allowedDomainsはproject_domains API未実装のためのSDK側フックとして追加(9.1の抵拔仕様に対する明示的な拡張)
  4. F-010検出優先順位6「周辺ラベル」判定をmasking.tsに実装(label[for]→wrapping label→直前の兄弟要素の順)
  5. verifyAllowedDomainをconfig.allowedDomainsとwindow.location.hostnameを照合する実装に変更(domain.ts)。ワイルドカード*.example.com形式対応
  6. buffer.tsの256KB判定を実際のシリアライズ後ボディ({"events":[...]}エンベロープ)サイズに近似する実装に修正

npm install / npm run typecheck / npm run build / npm test を実行し、全47テストがパスすることを確認済み。domain.test.ts新規追加、masking.test.ts/buffer.test.ts/integration.test.tsに関連テストを追加。

Redmine Admin さんが19日前に更新

Codex CLIの再検証でFAIL(2回目)。以下4項目を修正。

  1. sendBeaconフォールバック: sendBeacon()はカスタムヘッダーを設定できない仕様制約なので、write_key/timestamp/signatureはクエリのままでよい(write_keyは公開鍵なので露出リスクは低い)。signatureは通常経路(fetch)と同一の正準文字列(timestamp+body)で計算し、実装を共通化すること(重複禁止)。Content-Encodingヘッダーは設定不可なためbeaconのみ非圧縮JSONで送信(Blob type='application/json')。なせasendBeaconだけ挙動が違うのかをF-012を引用してコメントで明記。完了条件: beacon経路の単体テスト追加、fetch経路(gzip+HMAC)は無変更で既存47テストが引き続き通ること。

  2. verifyAllowedDomain(): F-001の許可ドメインはサーバー登録のproject_domainsが正であり、SDKローカル設定値では代替できない。init()内でGET /v1/sdk/config/{write_key}(13章Collector API)を呼び、サーバー側許可ドメイン一覧を取得してhostnameと照合。このAPIはサーバー側(PC1-06)が未実装なので、取得失敗(ネットワークエラー/404等)でもinit()をブロックしない(フェイルオープン、debug時のみ警告ログ)。完了条件: domain.tsにfetchAllowedDomains(writeKey, endpoint)を実装し、成功/失敗/タイムアウトをモックした単体テストを追加。サーバー側未実装である旨と期待レスポンス形状をコメント/READMEに明記しPC1-06着手時に参照できるようにすること。

  3. 仕様外allowedDomains: PathCollectorConfigからallowedDomainsを削除。ドメイン検証は項目2のサーバー取得値に一本化。完了条件: grep -r allowedDomains apps/collector-sdk/srcが公開型PathCollectorConfigにヒットしないこと。SPEC.md 9.1と過不足なく一致(内部専用の状態値として別名で持つのは可)。

  4. 256KB判定: これは機能不具合ではなく仕様の読み違え。F-011の256KBはバッファ蓄積量(非圧縮)に対する送信トリガーであり、圧縮後512KB上限(16章)とは別の制約。挙動は変更せず、buffer.tsのコメントを「F-011の非圧縮バッファサイズ判定であり、圧縮後の送信バイト数とは異なる」と訂正。完了条件: 機能変更なしで65テスト全て通ること。

全体の完了条件・回帰防止:

  • 前回修正済み6項目(同意拒否時バッファ破棄/F-010周辺ラベル/PathCollectorConfig命名/fetch経路gzip+HMAC等)を絶対に後退させない
  • npm install && npm run build && npm testが全てグリーン(現行47件以上)
  • Redmineコメントに「なぜこの2箇所は仕様の文字通りではなく意図的な設計判断なのか」(sendBeaconのAPI制約、GET /v1/sdk/config未実装への依存)を明記し、Phase1のAPI側チケット(PC1-06)に引き継げること

Redmine Admin さんが19日前に更新

Codex CLIによるクロスレビュー3回目でPASS。sendBeaconフォールバック(クエリ認証+非圧縮JSON、署名ロジックはsignBody()でfetch経路と共通化)、verifyAllowedDomain(GET /v1/sdk/config/{write_key}呼び出し+フェイルオープン)、allowedDomains削除、256KB判定コメント訂正、いずれも確認済み。前回修正6項目の後退もなし。npm install/typecheck/build/test実行、7テストファイル61テスト全てグリーン。実装→レビュー→修正2回(合計3サイクル)で完了。

Redmine Admin さんが18日前に更新

[Producer監査] 解決済みだが終了未遷移だったため終了へクローズ

他の形式にエクスポート: Atom PDF