前セッション(TDD 41〜47 + Codex 21ラウンド)で管理ダッシュボード・意見コマンド・マーケティングトラッカーは実装済み。 本セッションでは以下の 未実装3機能 + 1改修 を追加する:
CREATE TABLE conversation_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
line_user_id TEXT NOT NULL,
role TEXT NOT NULL, -- 'user' or 'bot'
content TEXT NOT NULL,
created_at INTEGER DEFAULT (unixepoch())
);
CREATE INDEX idx_conversation_logs_user ON conversation_logs(line_user_id, created_at);
認証コールの実発信を記録する。reminders テーブルに入らないため独自テーブルが必要。
CREATE TABLE verification_calls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
line_user_id TEXT NOT NULL,
created_at INTEGER DEFAULT (unixepoch())
);
ALTER TABLE feedback ADD COLUMN replied_at INTEGER;
ALTER TABLE feedback ADD COLUMN reply_content TEXT;
src/index.ts に追加)async function logConversation(db: D1Database, userId: string, role: "user" | "bot", content: string) {
await db.prepare(
"INSERT INTO conversation_logs (line_user_id, role, content) VALUES (?, ?, ?)"
).bind(userId, role, content).run();
}
async function replyAndLog(token: string, accessToken: string, text: string, db: D1Database, userId: string) {
await replyToLine(token, accessToken, text);
await logConversation(db, userId, "bot", text);
}
async function replyMessagesAndLog(token: string, accessToken: string, messages: unknown[], db: D1Database, userId: string, logText: string) {
await replyMessages(token, accessToken, messages);
await logConversation(db, userId, "bot", logText);
}
const text = event.message.text;(L636)の直後に1回 logConversation(db, userId, "user", text)replyToLine → replyAndLog に置換(約15箇所)replyMessages → replyMessagesAndLog に置換、altText をログに使用(約5箇所)handleScheduled(cron)の末尾に追加:
const ninetyDaysAgo = nowUnix - 90 * 86400;
await env.DB.prepare("DELETE FROM conversation_logs WHERE created_at < ?").bind(ninetyDaysAgo).run();
既存エンドポイント(L461-471)を拡張。各フィードバックの投稿前7日間の会話履歴(最大20件)を付与。
line_user_id はレスポンスに含めない(内部で reply に使う)。
{
"items": [{
"id": 1,
"content": "朝5時にも使いたい",
"created_at": 1710000000,
"replied_at": null,
"reply_content": null,
"conversation": [
{ "role": "user", "content": "明日5時に起こして", "created_at": 1709999000 },
{ "role": "bot", "content": "5時00分に電話するね", "created_at": 1709999001 }
]
}]
}
LINE Push API でフィードバック投稿者に返信。
POST /admin/feedback/:id/reply
Body: { "message": "ありがとう!改善したよ!" }
実装:
feedback から id で検索 → line_user_id 取得replied_at が既にあれば 409 ConflictPOST https://api.line.me/v2/bot/message/push) で送信replied_at + reply_content を更新注意: Push は月200通制限(LINE無料プラン)。β規模では問題なし。
makeCall at L862)は reminders テーブルに記録されないadmin/stats の budget/devCost はリマインダー通話のみ計上SAFETY_MARGIN_RATIO=0.8 で20%留保して雑に吸収// 認証コール発信記録
await c.env.DB.prepare(
"INSERT INTO verification_calls (line_user_id) VALUES (?)"
).bind(userId).run();
budget / devCost それぞれに verificationCalls + verificationCost を追加。
クエリ: verification_calls テーブルから今月分を集計(created_at >= monthStartUnix)。
オーナー/VIPの分は devCost 側に計上。
{
"budget": {
"completedCalls": 10,
"pendingCalls": 2,
"verificationCalls": 5,
"trackedCost": 130,
"verificationCost": 65,
"projectedCost": 221,
...
},
"devCost": {
"completedCalls": 3,
"pendingCalls": 1,
"verificationCalls": 2,
"trackedCost": 39,
"verificationCost": 26,
"projectedCost": 78
}
}
projectedCost = (completedCalls + pendingCalls + verificationCalls) × ¥13
バジェットカードに認証コール数を表示。例:
完了10件 + 予約2件 + 認証5件
開発費(別枠): ¥78(完了3 + 予約1 + 認証2)
第2条: (リマインダーの日時・内容の検出に使用) → (サービス提供・改善に使用)
第7条: 保存期間テーブルに追加:
| データの種類 | 保存期間 |
|---|---|
| 会話履歴データ(送受信メッセージ) | 送受信日から90日間 |
| # | 内容 | テスト数 |
|---|---|---|
| 1 | conversation_logs テーブル + logConversation / replyAndLog ヘルパー + 基本テスト |
+2 |
| 2 | webhook の全 replyToLine → replyAndLog 置換 + ユーザーメッセージログ |
+2 |
| 3 | verification_calls テーブル + 認証コール発信時の記録 |
+2 |
| 4 | admin/stats に認証コスト追加(budget + devCost) |
+2 |
| 5 | GET /admin/feedback 拡張(会話履歴 + replied_at/reply_content) |
+3 |
| 6 | POST /admin/feedback/:id/reply(Push送信 + 二重送信防止) |
+3 |
| 7 | ダッシュボード HTML 更新(フィードバック会話+返信 / バジェット認証コスト) | 0 |
| 8 | プライバシーポリシー更新 + 90日クリーンアップ | 0 |
合計: +14テスト
| ファイル | 種別 | 内容 |
|---|---|---|
schema.sql |
変更 | conversation_logs + verification_calls テーブル追加、feedback に2カラム追加 |
src/index.ts |
変更 | 会話ログ機能 + 認証コール記録 + admin/stats 拡張 + feedback 返信エンドポイント |
src/index.test.ts |
変更 | +14テスト |
public/admin/index.html |
変更 | フィードバック会話履歴+返信UI / バジェット認証コスト表示 |
docs/privacy-policy.html |
変更 | 第2条・第7条の微修正 |
public/privacy-policy.html |
変更 | 同上(Workers Static Assets 配信用コピー) |
tsc --noEmit && pnpm test(全テスト通過)~/bin/codex-full review で P1/P2 指摘がなくなるまで修正→再レビューを繰り返す