# Database Lifecycle Hooks (https://v1.s3.dimah.dev/docs/db/lifecycle-hooks)

The [`db()`](https://v1.s3.dimah.dev/docs/db/setup) plugin automatically attaches guards and
synchronization actions across upload, download, and delete flows.

## Access and scope validation [#access-and-scope-validation]

Route membership is still the server `keyPrefix` check (`INVALID_KEY`). These
plugin guards do not compare the stored `route` column to the request route.
They look up the row by `(bucket, key)` and compare **scope**.

Before an operation runs, `@dimah-s3/db` resolves the active session scope
through `resolveScope(request, context)`. `context` carries the `operation`,
the `route`, and the object `key` the endpoint already validated (see
[scope context](https://v1.s3.dimah.dev/docs/db/setup#scope-context)):

| Situation                                   | Response Status      | Error Code         |
| ------------------------------------------- | -------------------- | ------------------ |
| `resolveScope` returns `null`               | **401 Unauthorized** | `UNAUTHORIZED`     |
| Target key belongs to another scope         | **403 Forbidden**    | `FORBIDDEN`        |
| Target object row not found or soft-deleted | **404 Not Found**    | `OBJECT_NOT_FOUND` |

---

## Lifecycle behavior by operation [#lifecycle-behavior-by-operation]

- **Upload** — Upserts a `pending` row on presign / multipart init.
- **Upload confirmation** — Verifies `pending` state (or refreshes an
  already-active overwrite), records verified `contentLength` from
  `HeadObject`, and returns the `active` row.
- **Download** — Enforces that the object has `status: "active"` and matches the caller's scope.
- **Delete** — Runs S3 `DeleteObjectCommand`, then updates row status to `"deleted"` (soft delete) or removes it (hard delete). A `pending` row whose object never landed is cleaned up too, so it stops counting toward quota. A pending multipart upload is aborted by its `uploadId` first.

## Frequently asked questions [#frequently-asked-questions]

<Accordions>

<Accordion title="How do my route guards interact with the database plugin?">

Your route-level `guard` runs first during route resolution. After that, the
database plugin's operation guard verifies scope and ownership before your
operation-specific `upload.guard`, `download.guard`, or `delete.guard`. See the
standard [plugin hook order](https://v1.s3.dimah.dev/docs/server/plugins#hook-execution-order).

</Accordion>

</Accordions>
