sobriety-tools-guardian について
sobriety.toolsの高速化とオフライン対応を重視する開発スキルです。危機時に重要な処理経路の最適化、性能監視、回帰検出を扱います。
主な機能
- 01ミーティング検索のキャッシュ最適化
- 02連絡先のオフライン利用
- 03チェックイン処理の高速化
- 04性能とバンドルサイズの監査
- 05危機に関わる利用パターンの検出
- 06性能回帰の課題登録
活用シーン
- 01sobriety.toolsのデプロイ前の変更確認
- 02検索や連絡先表示の遅延調査
- 03危機リソースのオフライン利用確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ curiositech/ some_claude_skills --skill sobriety-tools-guardianインストール後、Claude Code で/sobriety-tools-guardianを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/CRISIS_DETECTION.mdPERFORMANCE_PATTERNS.mdscripts/bundle-analyzer.tscache-health.tscrisis-path-test.tsperf-audit.ts詳細
Sobriety Tools Guardian
使命:sobriety.tools が命を救えるだけの速さを保ちます。危機に直面したフェンタニル依存症の人に残された時間は、数分ではなく数秒です。アプリは瞬時に読み込まれ、オフラインで動作し、助けを求める前に支援を提示しなければなりません。
パフォーマンスが生死を分ける理由
CRISIS TIMELINE:
0-30 seconds: User opens app in distress
30-60 seconds: Looking for sponsor number or meeting
60-120 seconds: Decision point - call someone or use
2+ minutes: If still searching, may give up
EVERY SECOND OF LOAD TIME = LIVES AT RISK
核心となる事実:これはビジネスアプリではありません。パフォーマンスの低下は「UX の悪化」ではなく、危機に直面した人が利用をやめることにつながります。スピナーを見つめているユーザーは、生きるか死ぬかを決めようとしているかもしれません。
技術スタック固有の最適化に関する知識
アーキテクチャ(完全に把握しておくこと)
Next.js 15 (static export) → Cloudflare Pages
↓
Supabase (PostgREST + PostGIS)
↓
Cloudflare Workers:
- meeting-proxy (KV cached, geohash-based)
- meeting-harvester (hourly cron)
- claude-api (AI features)
重要なパフォーマンス経路
1. ミーティング検索(必ず <500ms)
User location → Geohash (3-char ~150km cell)
→ KV cache lookup (edge, ~5ms)
→ Cache HIT: Return immediately
→ Cache MISS: Supabase RPC find_current_meetings
→ PostGIS ST_DWithin query
→ Store in KV, return
ボトルネック:Supabase クエリのコールドスタート。解決策:/warm エンドポイント経由で主要な 30 の都市圏を事前にウォームアップします。
2. スポンサー/連絡先リスト(必ず <200ms)
User opens contacts → Local IndexedDB first
→ Show cached contacts instantly
→ Background sync with Supabase
→ Update UI if changes
アンチパターン:連絡先を表示する前にネットワーク応答を待つこと。危機の際は、古いデータでもすぐに表示します。
3. チェックインフロー(最初の入力まで必ず <100ms)
Open check-in → Pre-rendered form shell
→ Load previous patterns async
→ Submit optimistically
オフラインファーストの要件(絶対厳守)
// Service Worker must cache:
const CRISIS_CRITICAL = [
'/contacts', // Sponsor phone numbers
'/safety-plan', // User's safety plan
'/meetings?saved=true', // Saved meetings list
'/crisis', // Crisis resources page
];
// These MUST work with zero network:
// 1. View sponsor contacts
// 2. View safety plan
// 3. View saved meetings (even if stale)
// 4. Record check-in (sync when online)
危機検知のパターン
ジャーナルの感情分析シグナル
// RED FLAGS (surface help proactively):
const CRISIS_INDICATORS = {
anger_spike: 'HALT angry score jumps 3+ points',
ex_mentions: 'Mentions ex-partner 3+ times in week',
isolation: 'No check-ins for 3+ days after daily streak',
time_distortion: 'Check-ins at unusual hours (2-5am)',
negative_spiral: 'Consecutive declining mood scores',
};
// When detected: Surface sponsor contact, safety plan link
// DO NOT: Be preachy or alarming. Gentle nudge only.
チェックイン分析
-- Detect concerning patterns
SELECT user_id,
AVG(angry_score) as avg_anger,
AVG(angry_score) FILTER (WHERE created_at > NOW() - INTERVAL '3 days') as recent_anger,
COUNT(*) FILTER (WHERE EXTRACT(HOUR FROM created_at) BETWEEN 2 AND 5) as late_night_checkins
FROM daily_checkins
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY user_id
HAVING AVG(angry_score) FILTER (WHERE created_at > NOW() - INTERVAL '3 days') >
AVG(angry_score) + 2;
パフォーマンスの監視とログ記録
追跡する主要な指標
// Client-side (log to analytics)
const PERF_METRICS = {
ttfb: 'Time to First Byte',
fcp: 'First Contentful Paint',
lcp: 'Largest Contentful Paint',
tti: 'Time to Interactive',
// App-specific critical paths
contacts_visible: 'Time until sponsor list renders',
meeting_results: 'Time until first meeting card shows',
checkin_interactive: 'Time until check-in form accepts input',
};
// Log slow paths
if (contactsVisibleTime > 500) {
logPerf('contacts_slow', { duration: contactsVisibleTime, network: navigator.connection?.effectiveType });
}
パフォーマンスのリグレッションを自動検知
# scripts/perf-audit.sh - Run in CI
lighthouse https://sobriety.tools/meetings --output=json --output-path=./perf.json
SCORE=$(jq '.categories.performance.score' perf.json)
if (( $(echo "$SCORE < 0.9" | bc -l) )); then
echo "Performance regression: $SCORE"
# Create GitHub issue automatically
fi
問題の自動検知と起票
バックグラウンドのパフォーマンススキャナー
// Run hourly via Cloudflare Worker cron
async function performanceAudit() {
const checks = [
checkMeetingCacheHealth(),
checkSupabaseQueryTimes(),
checkStaticAssetSizes(),
checkServiceWorkerCoverage(),
];
const issues = await Promise.all(checks);
const problems = issues.flat().filter(i => i.severity === 'high');
for (const problem of problems) {
await createGitHubIssue({
title: `[Auto] Perf: ${problem.title}`,
body: problem.description + '\n\n' + problem.suggestedFix,
labels: ['performance', 'automated'],
});
}
}
よくあるアンチパターン
1. ネットワーク応答を待ってから連絡先を表示する
症状:連絡先ページが取得中にスピナーを表示する 問題:危機に直面したユーザーに、スポンサーの電話番号ではなく読み込み状態が表示される 解決策:
// WRONG
const { data: contacts } = useQuery(['contacts'], fetchContacts);
// RIGHT
const { data: contacts } = useQuery(['contacts'], fetchContacts, {
initialData: () => getCachedContacts(), // IndexedDB
staleTime: Infinity, // Never refetch automatically
});
2. ミーティング検索をキャッシュしない
症状:検索のたびに Supabase にアクセスする 問題:検索のたびに 200~500ms の遅延が発生する 解決策:ジオハッシュベースの KV キャッシュ(meeting-proxy にはすでに実装済み)
3. 大きなバンドルが操作性を妨げる
症状:TTFB が速いにもかかわらず TTI が高い 問題:JavaScript バンドルがメインスレッドをブロックする 解決策:
// Lazy load non-critical features
const JournalAI = dynamic(() => import('./JournalAI'), { ssr: false });
const Charts = dynamic(() => import('./Charts'), { loading: () => <ChartSkeleton /> });
4. チェックイン送信が同期処理になっている
症状:ネットワークリクエスト中、ボタンが無効のままになる 問題:ユーザーが処理に失敗したと思い、アプリを閉じてしまう 解決策:楽観的 UI とバックグラウンド同期キュー
パフォーマンス最適化チェックリスト
デプロイの前に毎回確認
- バンドルサイズの増加が < 5KB
- 重要な経路に新たな同期ネットワーク呼び出しがない
- Lighthouse のパフォーマンススコアが >= 90
- オフラインモードをテスト済み(DevTools でネットワークを無効化)
毎週の監査
- Supabase の低速クエリログを確認する
- KV キャッシュのヒット率を確認する(>80% が目安)
- 実ユーザー指標(RUM)で P95 の読み込み時間を分析する
- 3G の速度制限を設定した接続でテストする
毎月の詳細な調査
- React のレンダーをプロファイリングする(なぜ再レンダーされたのか?)
- サードパーティスクリプトを監査する
- 未使用の依存関係を確認し、削除する
- 実機で危機対応フローをエンドツーエンドでテストする
利用可能なスクリプト
| スクリプト | 目的 |
|---|---|
scripts/perf-audit.ts | Lighthouse とカスタムチェックを実行し、問題を起票する |
scripts/cache-health.ts | KV キャッシュのヒット率と古さを確認する |
scripts/crisis-path-test.ts | 危機対応に不可欠なフローを自動テストする |
scripts/bundle-analyzer.ts | バンドルサイズの経時変化を追跡する |
連携ポイント
meeting-harvester との連携
- 収集後、主要な都市圏のキャッシュをウォームアップする
- 収集所要時間とミーティング件数を監視する
- 収集に失敗したらアラートを出す(データが古いと、ミーティング時間を誤って表示する)
チェックインシステムとの連携
- 危機検知のためにパターンを分析する
- 送信成功率を追跡する
- オフラインキューの深さを監視する
連絡先/スポンサーとの連携
- オフラインで利用できることを確保する
- 表示までの時間を追跡する
- 同期の失敗を監視する
エスカレーションする条件
次の場合は、直ちに GitHub issue を作成してください:
- Lighthouse スコアが 85 未満に低下した
- ミーティング検索の P95 が 1 秒を超えた
- 連絡先ページに 200ms を超える読み込み状態がある
- Service Worker が危機対応ページをキャッシュできない
- 危機が起こりやすい時間帯(夕方/週末)に、ユーザーから「読み込めなかった」と報告があった
これは回復を支援するアプリです。パフォーマンスは機能の一つではありません。誰かが助けを得られるか、誰にも看取られずに亡くなるかを分けるものです。