Files
chktime/docs/superpowers/specs/2026-10-12-n8n-worklog-import-design.md
T
yoshikazuandClaude Opus 5.5 e16189153c n8n の work_log へ作業区間を送る機能の実装計画を追加
設計書のチケット検索 API を /api/redmine/search に改名
(/api/redmine/issues は起票の POST が使っているため)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:40:00 +09:00

11 KiB

chktime から n8n の work_log へ作業区間を送る — 設計

日付: 2026-10-12 対象: chktime (このリポジトリ) と n8n (https://n8n.yfox.jp) の work-tracker

目的

Claude Code での作業を、手で「作業開始・終了」を記録しなくても n8n の work_log に入るようにする。 入った記録は、手で記録したものと同じく、日報・月報・ガント・ダッシュボード・Redmine 工数同期 (work-tracker--redmine-sync) で使われる。

成功の条件

  • chktime の画面で期間を選ぶと、Claude のセッションから作った「作業区間」が一覧で出る。
  • 区間ごとにタスク名 (Redmine のチケットを選べる) を決め、選んだものだけを work_log に送れる。
  • 同じ区間を二度送っても、work_log に二重に入らない。
  • すでにある記録 (手で記録したもの・他の区間) と時間が重なる区間は、画面で分かり、最初は送らない状態になっている。
  • chktime に渡す権限は「work_log への取り込み」だけ。n8n の API キーは chktime に持たせない。

前提と決めたこと

項目 決定
目的 記録の手間を減らす
時間の数え方 連続した区間ごと (空き 30 分以上で切る)
タスク名 送る前に chktime の画面で決める
重なり 画面で知らせ、最初は送らない。送るかは利用者が決める
送り方 案 A: n8n に受け口のワークフローを作り、chktime から呼ぶ

1. 区間の作り方 (chktime)

材料は chktime の既存の「ターン」(人間の発言 1 回と、それに対する応答一式)。

  • 同じセッションの中で、前のターンの応答完了から次の発言までの空きが 30 分未満 ならつなぐ。 30 分以上なら区間を切る。
    • 開始 = 区間の最初の発言の時刻、終了 = 区間の最後のターンの応答完了の時刻。
  • 5 分未満 の区間は一覧から外す。
  • ターンの起点は既存の規則どおり (人間の発言だけ。サブエージェント・再開時のメタ行は起点にしない)。
  • date は区間の開始時刻のローカル日付 (日本時間)。日をまたぐ区間も開始日の記録。
  • 30 分と 5 分は設定 (n8n.json の gapMinutes / minMinutes) で変えられる。画面から変更できる。
  • セッションの最後の区間で、最後のターンがまだ応答中 (ログの最終更新から gapMinutes 経っていない、 または最後のターンに応答完了が無い) のものは「進行中」とし、送れない。
  • source = chktime:<セッションID>:<区間開始の epoch ミリ秒>。同じログからは毎回同じ値になる。

区間の計算は、HTTP やファイル読み込みから切り離した純粋な関数 (ターンの列と設定値 → 区間の列) にする。

2. n8n 側

データテーブル

  • work_log に source (string) の列を足す。chktime から入れた行だけ値が入り、手で記録した行は空。 既存のワークフローはこの列を書かないので影響しない。
  • work_log_deleted にも source を足し、work-tracker--delete の Backup Row で一緒にコピーする。

ワークフロー work-tracker--import

両方の Webhook に Header Auth の認証情報を付ける (ヘッダー X-WT-Token)。違えば n8n が 403 を返す。

GET /webhook/wt-import-rows?from=YYYY-MM-DD&to=YYYY-MM-DD

  • from / to を確かめる (形式、from <= to、最大 62 日)。不正なら {ok:false, error}。
  • work_log から date が from の前日 〜 to の行を返す (前日を含めるのは、日をまたぐ記録との重なりを見るため)。
  • 返す値: {ok:true, rows:[{id, date, start_time, end_time, task, status, source}], deletedSources:[...]} deletedSources は同じ期間の work_log_deleted の source (空でないもの)。

POST /webhook/wt-import

  • 本文: {rows:[{source, date, start_time, end_time, task, memo}]}、1 回に最大 200 件。
  • 1 行ずつ確かめる:
    • source が chktime: で始まる (500 文字以内)
    • date が YYYY-MM-DD、start_time / end_time が ISO 8601 で、終了 > 開始、長さ 24 時間以内
    • task が空でない (500 文字以内)、memo は 2000 文字以内
  • work_log に同じ source がある行はスキップ。
  • 新しい行は status: "done"、duration_min = 終了 − 開始 (分、四捨五入、丸めなし) で追加。
  • 返す値: {ok, inserted:[{source, id}], skipped:[{source, reason}], errors:[{source, error}]}。 ok は errors が 0 件のとき true。

認証情報

合言葉は利用者が決める。利用者が n8n の画面で Header Auth の認証情報 (例: 名前 wt-import token、 Name X-WT-Token) を作り、chktime の設定画面にも同じ値を入れる。Claude は合言葉を作らず、入力もしない。 認証情報の id は一覧 (中身を含まない) から取ってワークフローに設定する。

3. chktime 側

設定

  • n8n.json (git 管理外、.gitignore に追加。場所は --n8n-config で変更可): {"url": "https://n8n.yfox.jp", "token": "...", "verifySsl": false, "gapMinutes": 30, "minMinutes": 5}
  • GET /api/n8n/config は token の中身を返さず、hasToken だけ返す。POST /api/n8n/config で保存。 Redmine 設定 (RedmineHolder) と同じ作り。
  • verifySsl の既定は false (LAN からは n8n.yfox.jp の証明書名が一致しないため)。

サーバーの API (chktime 内)

ルート 内容
GET/POST /api/n8n/config 設定の取得 (合言葉は返さない) / 保存
GET /api/n8n/blocks?from=&to=&project= 期間の区間を計算し、n8n の wt-import-rows の結果で「送信済み / 削除済み / 重なり」を付けて返す。n8n に届かなくても区間は返し、n8nError を付ける
POST /api/n8n/send {items:[{source, task, memo}]} を受け、時刻はサーバーが source から区間を計算し直して n8n の wt-import に送る。結果をそのまま返す
GET /api/redmine/search?q= 既存の Redmine 連携で未完了チケットを検索 (チケット選択用)。/api/redmine/issues は起票 (POST) が使っているので別の名前にする

重なりの判定: 区間 [開始, 終了) と、work_log の行 (進行中は終了 = 今) または一覧の他の区間が 1 秒でも重なれば「重なりあり」。同じ source の行 (送信済みの自分) は除く。

画面

  • 右ペインのタブに「n8n へ送る」を足す。左で選んでいるプロジェクト (または すべて) が対象。
  • 期間: 初期値は直近 7 日。日付入力で指定もできる。
  • 一覧の 1 行 = 1 区間。列: 送る (チェック) / 日付 / 開始〜終了 / 時間 / プロジェクト / タスク名 (編集可) / チケット (選ぶ) / 状態。
  • タスク名の初期値は [作業フォルダ名] セッションのタイトル。チケットを選ぶと [Redmine のプロジェクト名] #番号 題名 にする (rich-start と同じ形。工数同期とガントの実績に載る)。
  • タスク名・チケットは、同じセッションの他の区間にも入れる (切り替え可)。セッションごとに ブラウザの localStorage に覚える (読み書きは try/catch で囲み、使えなくても動く)。
  • 状態の印: 送信済み / 削除済み / 重なりあり (カーソルで相手を表示) / 進行中。
  • 送るチェックの初期値: 問題の無い区間だけ on。送信済み・削除済み・重なりあり・進行中は off (送信済みと進行中はチェックできない)。
  • 「選んだ区間を送る」で送信し、追加・スキップ・エラーの件数と内訳を表示して一覧を読み込み直す。
  • 設定 (URL・合言葉・証明書の検証・30 分・5 分) は Redmine 設定と同じ形のダイアログ。

4. エラーの扱い

  • n8n に届かない / 403 / 5xx: 一覧は出し、上部に原因を表示して送信ボタンを無効にする。送信時の失敗は n8n の応答をそのまま表示。
  • 一部の行だけ失敗: 行ごとの結果を表示。source で二重登録を防ぐので、再送で失敗分だけ入る。
  • 同時に 2 回送った場合: n8n 側の「確認 → 追加」は一括の処理ではないので、二重に入る可能性がある。 使用者は 1 人なので許容し、README に書く。
  • 合言葉はログにも画面にも出さない。n8n.json は git に入れない。

5. テスト

chktime

  • 区間の計算を標準ライブラリの unittest で確かめる (tests/test_blocks.py)。 入力は手で組んだターンの列、またはスクラッチパッドに作ったテスト用 jsonl (実ログは書き換えない)。
    • 空き 29 分はつながり、30 分で切れる
    • 5 分未満は除外、5 分ちょうどは残る
    • 進行中の区間
    • サブエージェントの行を起点にしない
    • 日をまたぐ区間の date は開始日
    • source が同じ入力で毎回同じ
    • 重なりの判定 (接しているだけは重ならない、1 秒重なれば重なる、自分の source は除く)
  • サーバーは検証用に python chktime.py --port 8799 --no-browser で起動する (常用の 8787 には触れない)。

n8n

  • 2000-01-01 付けのダミー (source: chktime:test:...) で: 追加される / 再送でスキップ / 合言葉違いで 403 / 不正値でエラー / wt-import-rows に出る / 削除すると deletedSources に出る。
  • 終わったらダミーを work_log と work_log_deleted から直接削除する (削除 Webhook は使わない)。

全体

  • 8799 の chktime から、利用者が選んだ実際の区間を 1 件送り、ダッシュボードと日報に出ることを確かめる。

6. 文書

  • CLAUDE.md: 「外部通信は Redmine 連携だけ」を「Redmine 連携と n8n への送信だけ」に。API の表に n8n の系統を足す。
  • README.md: 「n8n へ送る」の使い方、設定、同時送信の注意。
  • .gitignore: n8n.json。
  • 保管庫: chktime と n8n のノートに追記。

対象外

  • 自動で定期的に送ること (送るのは利用者が画面で選んだときだけ)。
  • 送信後に chktime から work_log の行を編集・削除すること (編集・削除は既存の work-tracker の画面で行う)。
  • 他の Webhook への認証の追加 (今回の 2 本だけ。広げるのは別の作業)。