# Lifecycle Management

Most resources in Apiera follow a lifecycle with explicit state transitions rather than direct status updates. You
cannot set a resource's status to an arbitrary value. Instead, you invoke a specific transition (e.g. "publish",
"deactivate") and the system validates whether that transition is allowed from the current state.

## Why explicit transitions?

- **Business rules are enforced consistently.** A product cannot be published unless it meets validation requirements.
Direct status updates would bypass these checks.
- **Events are meaningful.** Each transition fires a specific webhook event (e.g. `product.published`), giving
integrations clear signals about what happened.
- **Invalid states are impossible.** The state machine prevents transitions that don't make sense (e.g. removing an
already removed product).


## Lifecycle patterns

Resources follow one of two lifecycle patterns depending on their intent.

### Publication lifecycle

Used by **output-oriented** resources that are intended to be pushed out of the system (to storefronts, feeds,
integrations, etc.): **Product**, **Asset**, **Attribute**, **Category**, **Tag**, **Brand**.

Publishing signals that a resource is ready for external consumption. Unpublishing pulls it back.


```
         +----------+
         |  Draft   |
         +----+-----+
              |
         publish / remove
              |
    +---------v----------+
    |     Published      |
    +--+-----+-------+---+
       |     |       |
   draft  unpublish  archive / remove
       |     |       |
       |  +--v-----------+       +----------+
       |  |  Unpublished |------>| Archived |  (Product and Asset only)
       |  +--+-----------+       +-----+----+
       |     |                         |
       +-----+    unarchive / remove   |
              |                        |
              +-------+--------+-------+
                      |
                      v
                 +---------+
                 | Removed |
                 +----+----+
                      |
                   restore
                      |
                      v
              (returns to
               Unpublished)
```

**Products and Assets** have the full set of states including Archived. **Attributes, Categories, Tags, and Brands**
use the same pattern but without the Archived state.

**Transitions:**

| Transition | Description |
|  --- | --- |
| `publish` | Make the resource visible. May require validation (e.g. products need a family). |
| `unpublish` | Remove from active use while preserving all data. |
| `draft` | Return to draft for further editing. |
| `archive` | Mark as historical. Excluded from standard queries. (Product and Asset only.) |
| `unarchive` | Restore from archive. (Product and Asset only.) |
| `remove` | Soft-delete. See [Soft Deletion](/concepts/soft-deletion). |
| `restore` | Recover from removal. |


### Activation lifecycle

Used by **operational** resources that stay within the system and support the resources that get pushed out:
**Product Family**, **Locale**, **Channel**, **TypeGroup**, **InputType**, **Collection**.

Activation signals that a resource is ready for use internally. Deactivation disables it without removing it.


```
         +----------+
         |  Draft   |
         +----+-----+
              |
        activate / deactivate / remove
              |
    +---------v----------+
    |       Active       |
    +--+--------+--------+
       |        |
    draft    deactivate / remove
       |        |
       |  +-----v------+
       |  |  Inactive   |
       |  +--+----------+
       |     |
       +-----+  activate / remove
              |
              v
         +---------+
         | Removed |
         +----+----+
              |
           restore
              |
              v
         (returns to
          Inactive)
```

**Transitions:**

| Transition | Description |
|  --- | --- |
| `activate` | Enable the resource for use. |
| `deactivate` | Disable without removing. |
| `remove` | Soft-delete. |
| `restore` | Recover from removal. |


## Invoking transitions

Transitions are invoked via the lifecycle action endpoint on each resource:


```bash
curl -X PATCH https://api.apiera.io/v1/products/{uuid}/actions/lifecycle \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{ "transition": "publish" }'
```

## Transition validation

Some transitions enforce validation rules before they succeed:

- **Product publish** requires the product to have a family assigned. If validation fails, the API returns a
`422 Unprocessable Entity` with an error code describing what's missing.


Invalid transitions (e.g. trying to publish a removed product) return a `409 Conflict` with an
`INVALID_TRANSITION` error code.

## Default query filtering

Resources in certain states are excluded from standard list queries by default:

| State | Behavior |
|  --- | --- |
| **Removed** | Excluded by default. Use `isRemoved[eq]=true` to include. |
| **Archived** | Excluded by default (Product only). Use `isArchived[eq]=true` to include. |
| **All other states** | Included in standard queries. |


This means your integration sees only active resources unless it explicitly requests removed or archived ones.