YOU // 使用者輸入
/workflows:feature-development
We need to handle Stripe webhooks for payment_intent.succeeded,
payment_intent.payment_failed, and customer.subscription.updated.
Database is Drizzle + Postgres. The handler should be idempotent
(use Stripe event ID as dedupe key), log every event to webhook_events table,
update the orders table accordingly, and send a Slack notification on failures.
Test coverage must be ≥85%.
ultrawork
CLAUDE // 內部展開(hook 攔截後注入)
# Injected context (hidden from you):
MODE: ultrawork
RULES:
- parallel subagents in single message
- TodoWrite immediately, update real-time
- no permission requests
- zero tolerance for partial implementation
- stop only when all todos done + validation passed
CLAUDE // 第 1 個訊息:建立 todo + 並行展開
TodoWrite created (7 items):
① Read existing API route structure ② Design webhook handler architecture
③ Add Drizzle schema for webhook_events ④ Implement Stripe signature verification
⑤ Implement three event handlers ⑥ Add Slack notifier ⑦ Write tests to ≥85% coverage
Spawning parallel subagents:
↳ librarian: 摘要 src/app/api/ 現有結構
↳ librarian: 摘要 drizzle/schema.ts 與 orders 表
↳ advisor: 找出 Stripe webhook 容易踩到的隱藏需求
CLAUDE // advisor 回報的隱藏需求
★ Insight ───────────────────────────────────────────
Stripe webhook hidden requirements you didn't mention:
1. Webhook signature verification needs raw body,
not parsed JSON — needs route segment config
2. Retry tolerance: Stripe retries failed webhooks
for up to 3 days, idempotency key MUST be persistent
3. Customer subscription events fire before
payment_intent — handle ordering or use eventual consistency
4. Test webhooks with Stripe CLI stripe listen,
not curl (signature won't match)
─────────────────────────────────────────────────────
CLAUDE // critic 審查計畫後產出檔案
// src/app/api/webhooks/stripe/route.ts
export const config = { api: { bodyParser: false } };
export async function POST(req: NextRequest) {
const body = await req.text();
const sig = req.headers.get('stripe-signature')!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(body, sig, env.STRIPE_WEBHOOK_SECRET);
} catch (err) {
return NextResponse.json({ error: 'invalid signature' }, { status: 400 });
}
// idempotency check using Stripe event.id
const existing = await db.query.webhookEvents.findFirst({
where: eq(webhookEvents.stripeEventId, event.id),
});
if (existing) return NextResponse.json({ received: true });
await db.insert(webhookEvents).values({
stripeEventId: event.id, type: event.type, payload: event, status: 'processing',
});
switch (event.type) {
case 'payment_intent.succeeded': await handlePaymentSuccess(event); break;
case 'payment_intent.payment_failed': await handlePaymentFailure(event); break;
case 'customer.subscription.updated': await handleSubscriptionChange(event); break;
}
return NextResponse.json({ received: true });
}
CLAUDE // validator 收尾
✓ validator finished:
— Type check: 0 errors
— Lint: 0 warnings
— Unit tests: 23/23 passing
— Integration tests: 7/7 passing
— Coverage: 89.2% (target was 85%) ✅
— All 7 todos marked complete. Session terminating.
此範例的三個關鍵點:
① 使用者只下一段 prompt,整個流程由 plugin 自動展開;
② advisor 主動補充了三個原始 prompt 未提及的需求(signature 須使用 raw body、retry 期限為 3 天、event 順序問題);
③ validator 完整執行後回報具體 coverage 數字(89.2%),確認達標後才結束 session。