1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

この記事では、クラウドストレージサービスである Amazon S3 (Simple Storage Service)の操作と、Webアプリケーションにおけるデータ削除のビジネスロジックを組み合わせた活用事例を紹介します。

【今回活用したS3および関連操作】

  • ファイルパスの収集: 削除対象のデータベースレコードから、関連するS3上のファイルパスを抽出
  • 複数ファイルの削除(S3一括削除): 収集したファイルパスの配列を使用し、AWS SDKで実装した関数を利用して、S3上の関連画像を一括削除
  • エラー耐性の確保: S3からのファイル削除が失敗しても、データベースレコードの削除は継続し、データ不整合を防ぐ
  • 権限確認とログ記録: 処理実行前に管理者権限を確認し、削除操作の追跡可能なログを記録

1. S3ファイル削除の実際の活用場面

// 削除関数をインポート
import { deleteFilesFromS3 } from "~/utils/s3.server"

2. 削除処理の発生条件

// 削除処理の判定
if (intent === "delete") {
    // 管理者がスーパーユーザーであることを確認
    if (!isSuperAdmin) {
        throw new Response("削除権限がありません。", { status: 403 })
    }

処理内容:

  • フォームでintent="delete"が送信された時
  • スーパーユーザー権限を持つ管理者のみが削除可能

3. 削除前の画像ファイル情報取得

// 削除前に関連する画像ファイルを取得
const userRecordWithImages = await db.userRecord.findUnique({
    where: { kyufuUniqueCode: params.recordId },
    include: {
        bankAccountInfo: {
            select: {
                copyImageUrl: true,     // 口座コピー画像1
                copyImageUrl2: true,    // 口座コピー画像2
            },
        },
    },
})

処理内容:

  • データベースから削除対象レコードを取得
  • includeで関連する銀行口座情報も取得
  • 削除前に画像URLを収集するため

4. 削除対象ファイルの収集

// S3から削除する画像ファイルのパスを収集
const s3FilesToDelete: string[] = []

// 本人確認画像のURL
if (userRecordWithImages.personalIdentificationImageUrl) {
    s3FilesToDelete.push(userRecordWithImages.personalIdentificationImageUrl)
}
if (userRecordWithImages.personalIdentificationImageUrl2) {
    s3FilesToDelete.push(userRecordWithImages.personalIdentificationImageUrl2)
}

// 口座関連の画像URL
userRecordWithImages.bankAccountInfo.forEach(account => {
    if (account.copyImageUrl) {
        s3FilesToDelete.push(account.copyImageUrl)
    }
    if (account.copyImageUrl2) {
        s3FilesToDelete.push(account.copyImageUrl2)
    }
})

処理内容:

  • 本人確認画像: personalIdentificationImageUrlpersonalIdentificationImageUrl2
  • 口座関連画像: 各口座のcopyImageUrlcopyImageUrl2
  • 存在する画像URLのみを配列に追加
  • 最大で住民1人につき:本人確認画像2枚

5. 実際のS3削除処理の実行

// S3から関連する画像ファイルを削除
if (s3FilesToDelete.length > 0) {
    try {
        await deleteFilesFromS3(s3FilesToDelete)  // ← ここでS3削除関数を呼び出し
    } catch (s3Error) {
        console.error("S3からの画像削除中にエラーが発生しました:", s3Error)
        // S3の削除に失敗してもデータベースの削除は続行
    }
}

処理内容:

  • 削除対象ファイルがある場合のみ実行
  • deleteFilesFromS3関数に配列を渡して一括削除
  • 重要: S3削除でエラーが発生してもデータベース削除は継続

6. データベース削除とログ記録

// 削除前にログデータを作成
const logData = JSON.stringify({
    adminUserId: await getAdminUserName(adminUserId),
    action: "deleteUserRecord",
    parameters: {
        recordId: await getHouseholdNumberFromKyufuUniqueCode(params.recordId || ""),
    },
})

// レコードの削除
await db.userRecord.delete({
    where: { kyufuUniqueCode: params.recordId },
})

// 削除操作ログの記録
await createLog(adminUserId, logData)

処理内容:

  • データベースからレコードを削除
  • 操作ログを記録(誰がいつ何を削除したか)

7. 削除処理の全体的な流れ

// 実際の処理順序
1. 権限確認スーパーユーザーのみ
2. 削除対象レコードの取得
3. 関連画像ファイルのパス収集
4. ログデータの準備
5. S3から画像ファイルの削除エラーが発生しても継続
6. データベースからレコードの削除
7. 操作ログの記録
8. 管理画面一覧にリダイレクト

8. エラーハンドリング

// 全体のエラーハンドリング
} catch (error) {
    console.error("レコード削除時のエラー:", error)
    return json({ error: "レコード削除中にエラーが発生しました。" }, { status: 500 })
}

処理内容:

  • 削除処理全体でエラーが発生した場合
  • エラーログを出力し、ユーザーにエラーメッセージを表示

9. 実際の利用例

// 削除対象のファイル
s3FilesToDelete = [
    "uuid1-identification1.jpg",    // 本人確認画像1
    "uuid2-identification2.jpg",    // 本人確認画像2
    "uuid3-bank-copy1.jpg",         // 口座コピー画像1
    "uuid4-bank-copy2.jpg",         // 口座コピー画像2
]

// 一括削除実行
await deleteFilesFromS3(s3FilesToDelete)

重要なポイント

  1. データ整合性: データベース削除前にS3ファイルを削除
  2. エラー耐性: S3削除失敗でもデータベース削除は継続
  3. 権限管理: スーパーユーザーのみが削除可能
  4. ログ管理: 削除操作の記録を残す
  5. 一括処理: 関連する全ての画像を一度に削除
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?