mcpField
G
grove-account-deletion

grove-account-deletion

github.com/autumnsgroveデータ・データベース667 回インストール5 日前に更新
リポジトリ

grove-account-deletion について

Grove の運用担当者向けに、テナントと関連データの削除手順を示すスキルです。事前確認やサブスクリプションの確認、データベースと R2 の削除検証を重視します。

主な機能

  1. 01テナントの特定と確認
  2. 02テナントと関連レコードの削除
  3. 03R2 メディアオブジェクトの削除
  4. 04削除結果の検証
  5. 05サブスクリプションと複数テナントの確認

活用シーン

  1. 01デモやテストアカウントの削除
  2. 02テナント削除依頼への対応
  3. 03テナントの残存データの整理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/autumnsgrove/lattice --skill grove-account-deletion

インストール後、Claude Code で/grove-account-deletionを入力して読み込まれたか確認します。

詳細

Grove アカウントの削除

wrangler CLI コマンドを使用して、Grove プラットフォームからテナントアカウントと関連するすべてのデータを安全に削除します。

実行するタイミング

  • ユーザーが「Alice のアカウントを削除して」や「Alice はもう使いません」のようなことを言った場合
  • テストアカウントを削除したいと言った場合
  • ウォークスルーやデモの後片付けを依頼された場合
  • /grove-account-deletion を明示的に呼び出した場合
  • 「そのアカウントを消し去って」や「データを全部消して」と言った場合

手順

Identify → Verify → Snapshot → Delete Tenant → Clean Orphans → Purge R2 → Verify
Step 1: テナントを特定する

ユーザーからユーザー名(サブドメイン)、メールアドレス、または表示名が指定されます。次のコマンドで検索します。

# By username/subdomain (most common)
npx wrangler d1 execute grove-engine-db --remote --command="SELECT id, subdomain, display_name, email, plan, created_at FROM tenants WHERE subdomain = 'USERNAME';"

# By email (if username unknown)
npx wrangler d1 execute grove-engine-db --remote --command="SELECT id, subdomain, display_name, email, plan, created_at FROM tenants WHERE email = 'EMAIL';"

# By display name (fuzzy match)
npx wrangler d1 execute grove-engine-db --remote --command="SELECT id, subdomain, display_name, email, plan, created_at FROM tenants WHERE display_name LIKE '%NAME%';"

これらのコマンドはプロジェクトルート(/Users/mini/Documents/Projects/Lattice)から実行してください。

Step 2: ユーザーに確認する

何かを削除する前に、見つかった情報をユーザーに示し、明示的な確認を求めてください。

Found tenant:
  ID:       abc-123-def
  Username: alice
  Name:     Alice Wonderland
  Email:    [email protected]
  Plan:     seedling
  Created:  2026-01-24

This will permanently delete:
  - All blog posts and pages
  - All media files (R2 storage)
  - All sessions and settings
  - Commerce data (orders, products, customers)
  - Curio configurations (timeline, journey, gallery)
  - Onboarding and billing records

Proceed with deletion?

この確認手順を絶対に省略しないでください。 テストアカウントの場合も同様です。

Step 3: 削除前のスナップショット(任意ですが推奨)

テストアカウント以外の場合、削除対象の件数を手早く記録します。

npx wrangler d1 execute grove-engine-db --remote --command="
  SELECT
    (SELECT COUNT(*) FROM posts WHERE tenant_id = 'TENANT_ID') as posts,
    (SELECT COUNT(*) FROM pages WHERE tenant_id = 'TENANT_ID') as pages,
    (SELECT COUNT(*) FROM media WHERE tenant_id = 'TENANT_ID') as media_files,
    (SELECT COUNT(*) FROM sessions WHERE tenant_id = 'TENANT_ID') as sessions;
"
Step 4: テナントを削除する(CASCADE により 29 個のテーブルを処理)

この DELETE を実行すると、次のテーブルにも削除が連鎖します:posts、pages、media records、tenant_settings、sessions、products、product_variants、customers、orders、order_line_items、subscriptions、connect_accounts、platform_billing、refunds、discount_codes、post_views、timeline_curio_config、timeline_summaries、timeline_activity、timeline_ai_usage、journey_curio_config、journey_snapshots、journey_summaries、journey_jobs、gallery_curio_config、gallery_images、gallery_tags、gallery_collections、git_dashboard_config。

npx wrangler d1 execute grove-engine-db --remote --command="DELETE FROM tenants WHERE id = 'TENANT_ID';"
Step 5: 孤立レコードをクリーンアップする

次のテーブルは tenants からの CASCADE 削除に含まれないため、手動でクリーンアップする必要があります。

# Remove onboarding record (linked by username, not FK)
npx wrangler d1 execute grove-engine-db --remote --command="DELETE FROM user_onboarding WHERE username = 'USERNAME';"

# Remove email verification codes for that user (cascades from user_onboarding via FK, but verify)
npx wrangler d1 execute grove-engine-db --remote --command="DELETE FROM email_verification_codes WHERE user_id IN (SELECT id FROM user_onboarding WHERE username = 'USERNAME');"

レガシーの users テーブルをクリーンアップします。

npx wrangler d1 execute grove-engine-db --remote --command="DELETE FROM users WHERE LOWER(email) = LOWER('USER_EMAIL') AND tenant_id = 'TENANT_ID';"
Step 5b: Heartwood の認証レコードをクリーンアップする

重要: これを行わないと、Heartwood の ba_user レコードが残るため、ユーザーは再登録時に「おかえりなさい」というメッセージを目にします。

# Check if user has other tenants first
npx wrangler d1 execute grove-engine-db --remote --command="SELECT id, subdomain FROM tenants WHERE email = 'USER_EMAIL';"

# If no other tenants exist, clean Heartwood auth records:
# Delete sessions
npx wrangler d1 execute groveauth --remote --command="DELETE FROM ba_session WHERE user_id IN (SELECT id FROM ba_user WHERE email = 'USER_EMAIL');"

# Delete OAuth account linkages (Google, etc.)
npx wrangler d1 execute groveauth --remote --command="DELETE FROM ba_account WHERE user_id IN (SELECT id FROM ba_user WHERE email = 'USER_EMAIL');"

# Delete verification records
npx wrangler d1 execute groveauth --remote --command="DELETE FROM ba_verification WHERE identifier = 'USER_EMAIL';"

# Delete the auth user record
npx wrangler d1 execute groveauth --remote --command="DELETE FROM ba_user WHERE email = 'USER_EMAIL';"
Step 6: R2 メディアを削除する(メディアが存在する場合)

R2 のキーは {tenant_id}/{filename} の形式です。D1 の media テーブルのレコードはすでに削除されています(CASCADE)が、実際の R2 オブジェクトは残っています。

# List objects with tenant prefix
npx wrangler r2 object list grove-media --prefix="TENANT_ID/" --remote

# Delete each object (wrangler doesn't support bulk delete, so iterate)
# For a small number of files:
npx wrangler r2 object delete grove-media --remote "TENANT_ID/filename1.webp"
npx wrangler r2 object delete grove-media --remote "TENANT_ID/filename2.webp"

ファイルが多数ある場合は、削除スクリプトを生成します。

# List all keys, then delete in a loop
npx wrangler r2 object list grove-media --prefix="TENANT_ID/" --remote 2>/dev/null | jq -r '.[] .key' | while read key; do
  echo "Deleting: $key"
  npx wrangler r2 object delete grove-media --remote "$key"
done

削除前のスナップショットでメディアファイルが 0 件だった場合は、この手順を省略してください。

Step 7: 削除後の確認

テナントが完全に削除されたことを確認します。

# Verify tenant deleted
npx wrangler d1 execute grove-engine-db --remote --command="SELECT COUNT(*) as remaining FROM tenants WHERE subdomain = 'USERNAME';"

# Verify cascade worked (spot-check a few tables)
npx wrangler d1 execute grove-engine-db --remote --command="
  SELECT
    (SELECT COUNT(*) FROM posts WHERE tenant_id = 'TENANT_ID') as posts,
    (SELECT COUNT(*) FROM media WHERE tenant_id = 'TENANT_ID') as media,
    (SELECT COUNT(*) FROM sessions WHERE tenant_id = 'TENANT_ID') as sessions;
"

# Verify onboarding cleaned
npx wrangler d1 execute grove-engine-db --remote --command="SELECT COUNT(*) as remaining FROM user_onboarding WHERE username = 'USERNAME';"
Step 8: 報告

ユーザーに分かりやすく要約して報告します。

Tenant "alice" (Alice Wonderland) has been fully deleted.

Cleaned up:
  - Tenant record + 29 cascaded tables
  - Onboarding record
  - 3 R2 media files
  - Email verification codes

The subdomain "alice.grove.place" is now available for reuse.

安全ルール

  1. 削除前に必ず確認する - ユーザーが確信しているように見えても、まずテナントの詳細を示してください
  2. ID だけで削除しない - 確認のため、必ずサブドメインやメールアドレスなど、人が読める識別子に照合してください
  3. 有効なサブスクリプションを確認する - platform_billing.status = 'active' または LemonSqueezy のサブスクリプションがある場合は警告してください
  4. テストアカウントも通常のアカウントです - 同じ手順、同じ確認、同じ検証を行ってください
  5. R2 のデータは復元できません - R2 オブジェクトを削除すると、元に戻せません。キーを保持していた D1 の media レコードはすでに CASCADE で削除されているため、保存内容を追跡できなくなる前に R2 をクリーンアップしてください

クイックモード(テストアカウント)

ユーザーが明示的に「テストアカウント」と呼ぶアカウント、または現在のセッション中に作成されたアカウントの場合:

  • ユーザー名またはメールアドレスは引き続き確認する
  • 削除前のスナップショットは省略する
  • メディアがアップロードされていない場合は R2 のクリーンアップを省略する
  • 削除が完了したことは引き続き検証する

例外的なケース

ユーザーが複数のテナントを持っている

1 つのメールアドレスで複数のサブドメインを所有できます。指定されたテナントだけを削除してください。他のテナントには触れないでください。

テナントが見つからない

サブドメインまたはメールアドレスに一致するテナントがない場合は、ユーザーに伝えてください。推測で判断しないでください。

Heartwood のセッションクリーンアップ

Heartwood のセッションは D1 ではなく KV に保存されます。D1 の sessions テーブルは、レガシーまたはローカルのセッション用です。Heartwood のセッションは自然に期限切れになります(TTL は 24h)。緊急対応を指定された場合を除き、手動でのクリーンアップは不要です。

LemonSqueezy のサブスクリプションが有効な場合

user_onboarding.lemonsqueezy_subscription_id が設定されている場合は、LemonSqueezy のダッシュボードでサブスクリプションを別途解約する必要があることをユーザーに伝えてください。D1 の削除では、外部の課金は解約されません。


環境

すべてのコマンドはプロジェクトのルートから実行します:/Users/mini/Documents/Projects/Lattice

データベース:grove-engine-db(D1) メディアバケット:grove-media(R2)


きれいに削除することは、優しい別れです。孤児を残さないでください。

コメント