# `ExScim.Lifecycle.Adapter`
[🔗](https://github.com/ExScim/ex_scim/blob/main/lib/ex_scim/lifecycle/adapter.ex#L1)

Behaviour for lifecycle hooks around SCIM operations.

Implement this behaviour to run custom logic before or after SCIM operations.
All callbacks are optional. Unimplemented callbacks are no-ops.

## Configuration

    config :ex_scim, lifecycle_adapter: MyApp.ScimLifecycle

## Before hooks

Fire after validation/mapping/metadata, immediately before storage.
Can modify domain data or reject the operation by returning `{:error, term()}`.

## After hooks

Fire after successful storage + SCIM response mapping. Observe-only (return `:ok`).

## Error hook

Fires when an operation fails. Observe-only.

## Example

    defmodule MyApp.ScimLifecycle do
      use ExScim.Lifecycle.Adapter

      @impl true
      def before_create(:user, data, _caller) do
        if some_business_rule_violated?(data) do
          {:error, {:forbidden, "Business rule violated"}}
        else
          {:ok, data}
        end
      end

      @impl true
      def after_create(:user, scim_response, _caller) do
        MyApp.Notifications.send_welcome(scim_response["id"])
        :ok
      end
    end

# `caller`

```elixir
@type caller() :: ExScim.Scope.t()
```

The authenticated caller scope for the current request.

# `operation`

```elixir
@type operation() :: :create | :replace | :patch | :delete | :get
```

The SCIM operation type that triggered the hook.

# `resource_data`

```elixir
@type resource_data() :: term()
```

The domain-level resource data (struct or map) being processed.

# `resource_id`

```elixir
@type resource_id() :: binary()
```

The unique identifier of the resource.

# `resource_type`

```elixir
@type resource_type() :: :user | :group
```

The type of resource being operated on: `:user` or `:group`.

# `scim_response`

```elixir
@type scim_response() :: map()
```

The SCIM JSON response map after mapping from the domain struct.

# `after_create`
*optional* 

```elixir
@callback after_create(resource_type(), scim_response(), caller()) :: :ok
```

Fires after a resource is successfully created. Observe-only.

# `after_delete`
*optional* 

```elixir
@callback after_delete(resource_type(), resource_id(), caller()) :: :ok
```

Fires after a resource is successfully deleted. Observe-only.

# `after_get`
*optional* 

```elixir
@callback after_get(resource_type(), scim_response(), caller()) :: :ok
```

Fires after a resource is successfully retrieved. Observe-only.

# `after_patch`
*optional* 

```elixir
@callback after_patch(resource_type(), scim_response(), caller()) :: :ok
```

Fires after a resource is successfully patched. Observe-only.

# `after_replace`
*optional* 

```elixir
@callback after_replace(resource_type(), scim_response(), caller()) :: :ok
```

Fires after a resource is successfully replaced. Observe-only.

# `before_create`
*optional* 

```elixir
@callback before_create(resource_type(), resource_data(), caller()) ::
  {:ok, resource_data()} | {:error, term()}
```

Fires before a resource is created. Return `{:ok, data}` to proceed or `{:error, reason}` to reject.

# `before_delete`
*optional* 

```elixir
@callback before_delete(resource_type(), resource_id(), caller()) ::
  :ok | {:error, term()}
```

Fires before a resource is deleted. Return `:ok` to proceed or `{:error, reason}` to reject.

# `before_get`
*optional* 

```elixir
@callback before_get(resource_type(), resource_id(), caller()) :: :ok | {:error, term()}
```

Fires before a resource is retrieved. Return `:ok` to proceed or `{:error, reason}` to reject.

# `before_patch`
*optional* 

```elixir
@callback before_patch(resource_type(), resource_id(), resource_data(), caller()) ::
  {:ok, resource_data()} | {:error, term()}
```

Fires before a resource is patched. Return `{:ok, data}` to proceed or `{:error, reason}` to reject.

# `before_replace`
*optional* 

```elixir
@callback before_replace(resource_type(), resource_id(), resource_data(), caller()) ::
  {:ok, resource_data()} | {:error, term()}
```

Fires before a resource is replaced (PUT). Return `{:ok, data}` to proceed or `{:error, reason}` to reject.

# `on_error`
*optional* 

```elixir
@callback on_error(operation(), resource_type(), term(), caller()) :: :ok
```

Fires when an operation fails. Observe-only; intended for logging or metrics.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
