npm package: @hed-hog/address
Description: Módulo para gerenciamento de endereços no HedHog. Fornece endpoints para criar, listar, atualizar e deletar endereços, com suporte a múltiplos tipos de endereço e controle de endereço primário por tipo.
Latest version: 0.0.303

# @hed-hog/address

Módulo para gerenciamento de endereços no HedHog. Fornece endpoints para criar, listar, atualizar e deletar endereços, com suporte a múltiplos tipos de endereço e controle de endereço primário por tipo.

---

## 1. Visão geral do módulo

Este módulo gerencia informações de endereços, permitindo operações CRUD (criar, ler, atualizar, deletar) com suporte a múltiplos tipos de endereço (residencial, comercial, correspondência, etc.). Possui controle para garantir que apenas um endereço por tipo seja marcado como primário. Suporta busca, paginação, ordenação e filtros nos endpoints.

---

## 2. Escopo e responsabilidades

- Gerenciar dados de endereços com validação e consistência.
- Controlar endereço primário único por tipo.
- Suportar operações RESTful autenticadas.
- Fornecer respostas paginadas e filtradas.
- Garantir mensagens localizadas conforme idioma da requisição.
- Integrar com sistema de roles para autorização.

---

## 3. Endpoints

### 3.1 Listar Endereços

- **Método:** GET  
- **Path:** `/address`  
- **Autenticação:** Requerida (`@Role()`)  
- **Descrição:** Retorna lista paginada de endereços com busca, ordenação e seleção de campos.  
- **Query Parameters:**

| Parâmetro   | Tipo            | Obrigatório | Descrição                                                                                   |
|-------------|-----------------|-------------|---------------------------------------------------------------------------------------------|
| `page`      | number          | Não         | Número da página (padrão: 1)                                                               |
| `pageSize`  | number          | Não         | Quantidade de itens por página (padrão: 10)                                                |
| `search`    | string          | Não         | Busca por texto (procura em id, tipo, país, estado, cidade, CEP, linha1 e linha2)          |
| `sortField` | string          | Não         | Campo para ordenação (padrão: id)                                                          |
| `sortOrder` | `asc` \| `desc` | Não         | Ordem de classificação (padrão: desc)                                                      |
| `fields`    | string          | Não         | Campos a retornar, separados por vírgula                                                   |

- **Resposta de Sucesso (200 OK):**

```json
{
  "data": [
    {
      "id": 1,
      "address_type": "residential",
      "country_code": "BR",
      "state": "SP",
      "city": "São Paulo",
      "postal_code": "01234-567",
      "line1": "Rua A, 123",
      "line2": "Apartamento 101",
      "is_primary": true,
      "created_at": "2025-01-10T14:30:00Z",
      "updated_at": "2025-01-10T14:30:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "pageSize": 10,
    "total": 1,
    "pageCount": 1,
    "hasNextPage": false,
    "hasPreviousPage": false
  }
}
```

- **Erros Comuns:** Nenhum específico além dos padrões de autenticação/autorização.

---

### 3.2 Obter Endereço por ID

- **Método:** GET  
- **Path:** `/address/:id`  
- **Autenticação:** Requerida (`@Role()`)  
- **Descrição:** Retorna detalhes de um endereço pelo seu ID.  
- **Path Parameters:**

| Parâmetro | Tipo   | Descrição            |
|-----------|--------|----------------------|
| `id`      | number | ID único do endereço  |

- **Resposta de Sucesso (200 OK):**

```json
{
  "id": 1,
  "address_type": "residential",
  "country_code": "BR",
  "state": "SP",
  "city": "São Paulo",
  "postal_code": "01234-567",
  "line1": "Rua A, 123",
  "line2": "Apartamento 101",
  "is_primary": true,
  "created_at": "2025-01-10T14:30:00Z",
  "updated_at": "2025-01-10T14:30:00Z"
}
```

- **Erros Possíveis:**

  - **404 Not Found:** Endereço com ID especificado não encontrado.

---

### 3.3 Criar Novo Endereço

- **Método:** POST  
- **Path:** `/address`  
- **Autenticação:** Requerida (`@Role()`)  
- **Descrição:** Cria um novo endereço. Se `is_primary=true`, remove o status primário de outros endereços do mesmo tipo.  
- **Request Body:**

| Campo          | Tipo    | Obrigatório | Descrição                                                                                   |
|----------------|---------|-------------|---------------------------------------------------------------------------------------------|
| `address_type` | enum    | Sim         | Tipo do endereço. Valores: `residential`, `commercial`, `correspondence`, `alternative`, `work`, `billing`, `shipping` |
| `country_code` | string  | Sim         | Código do país (ex: "BR", "US", "ES")                                                      |
| `state`        | string  | Sim         | Nome do estado/província (ex: "SP", "RJ")                                                  |
| `city`         | string  | Sim         | Nome da cidade                                                                             |
| `postal_code`  | string  | Sim         | CEP/código postal                                                                          |
| `line1`        | string  | Sim         | Linha de endereço principal (rua, número, etc)                                            |
| `line2`        | string  | Não         | Linha de endereço complementar (apartamento, complemento, etc)                            |
| `is_primary`   | boolean | Não         | Define como endereço primário do tipo (padrão: false)                                     |

- **Exemplo de Requisição:**

```bash
POST /address
Content-Type: application/json

{
  "address_type": "residential",
  "country_code": "BR",
  "state": "SP",
  "city": "São Paulo",
  "postal_code": "01234-567",
  "line1": "Rua A, 123",
  "line2": "Apartamento 101",
  "is_primary": true
}
```

- **Resposta de Sucesso (201 Created):**

```json
{
  "id": 1,
  "address_type": "residential",
  "country_code": "BR",
  "state": "SP",
  "city": "São Paulo",
  "postal_code": "01234-567",
  "line1": "Rua A, 123",
  "line2": "Apartamento 101",
  "is_primary": true,
  "created_at": "2025-01-10T14:30:00Z",
  "updated_at": "2025-01-10T14:30:00Z"
}
```

- **Erros Possíveis:**

  - **400 Bad Request:** Validação de dados falhou ou erro ao criar endereço.

---

### 3.4 Atualizar Endereço

- **Método:** PATCH  
- **Path:** `/address/:id`  
- **Autenticação:** Requerida (`@Role()`)  
- **Descrição:** Atualiza parcialmente um endereço existente. Ajusta o status primário conforme tipo e flag `is_primary`.  
- **Path Parameters:**

| Parâmetro | Tipo   | Descrição                  |
|-----------|--------|----------------------------|
| `id`      | number | ID do endereço a atualizar |

- **Request Body:** (todos opcionais)

| Campo          | Tipo    | Descrição                      |
|----------------|---------|--------------------------------|
| `address_type` | enum    | Novo tipo do endereço          |
| `country_code` | string  | Novo código do país            |
| `state`        | string  | Novo estado/província          |
| `city`         | string  | Nova cidade                   |
| `postal_code`  | string  | Novo CEP/código postal        |
| `line1`        | string  | Nova linha de endereço principal |
| `line2`        | string  | Nova linha de endereço complementar |
| `is_primary`   | boolean | Novo status de primário       |

- **Exemplo de Requisição:**

```bash
PATCH /address/1
Content-Type: application/json

{
  "city": "Rio de Janeiro",
  "state": "RJ",
  "is_primary": false
}
```

- **Resposta de Sucesso (200 OK):**

```json
{
  "id": 1,
  "address_type": "residential",
  "country_code": "BR",
  "state": "RJ",
  "city": "Rio de Janeiro",
  "postal_code": "01234-567",
  "line1": "Rua A, 123",
  "line2": "Apartamento 101",
  "is_primary": false,
  "created_at": "2025-01-10T14:30:00Z",
  "updated_at": "2025-01-11T10:15:00Z"
}
```

- **Erros Possíveis:**

  - **400 Bad Request:** Validação de dados falhou ou erro ao atualizar.
  - **404 Not Found:** Endereço com ID especificado não encontrado.

---

### 3.5 Deletar Endereço(s)

- **Método:** DELETE  
- **Path:** `/address`  
- **Autenticação:** Requerida (`@Role()`)  
- **Descrição:** Deleta um ou múltiplos endereços por seus IDs.  
- **Request Body:**

| Campo | Tipo       | Obrigatório | Descrição                     |
|-------|------------|-------------|-------------------------------|
| `ids` | number[]   | Sim         | Array com IDs dos endereços a deletar |

- **Exemplo de Requisição:**

```bash
DELETE /address
Content-Type: application/json

{
  "ids": [1, 2, 3]
}
```

- **Resposta de Sucesso (200 OK):**

```json
{
  "count": 3
}
```

- **Erros Possíveis:**

  - **400 Bad Request:** Campo `ids` não fornecido ou vazio.
  - **404 Not Found:** Um ou mais IDs especificados não encontrados.

---

## 4. Regras de autenticação e autorização

- Todos os endpoints requerem autenticação via JWT no header:

  ```
  Authorization: Bearer <seu_token_jwt>
  ```

- A autorização é baseada em roles/funções, protegida pelo decorator `@Role()`.
- O usuário deve estar autenticado e possuir permissão para acessar a rota, conforme tabela `route` no banco.
- Roles autorizadas para acesso aos endpoints:

  - `admin`
  - `admin-address` (Administrador de Endereços)

---

## 5. Estruturas de request/response

### CreateDTO (Criar Endereço)

| Campo          | Tipo    | Obrigatório | Descrição                      |
|----------------|---------|-------------|--------------------------------|
| `address_type` | enum    | Sim         | Tipo do endereço (ver seção Tipos de Endereço) |
| `country_code` | string  | Sim         | Código do país (ex: "BR")      |
| `state`        | string  | Sim         | Estado/província               |
| `city`         | string  | Sim         | Cidade                        |
| `postal_code`  | string  | Sim         | CEP/código postal             |
| `line1`        | string  | Sim         | Linha principal do endereço   |
| `line2`        | string  | Não         | Linha complementar            |
| `is_primary`   | boolean | Não         | Endereço primário do tipo (default: false) |

### UpdateDTO (Atualizar Endereço)

- Todos os campos do CreateDTO são opcionais para atualização parcial.

### DeleteDTO (Deletar Endereços)

| Campo | Tipo     | Obrigatório | Descrição                     |
|-------|----------|-------------|-------------------------------|
| `ids` | number[] | Sim         | IDs dos endereços a deletar   |

### Respostas

- Listagem: objeto com `data` (array de endereços) e `meta` (paginação).
- Obter, criar e atualizar: objeto com dados do endereço.
- Deletar: objeto com `count` de registros deletados.

---

## 6. Erros comuns

| Código | Descrição                                            |
|--------|-----------------------------------------------------|
| 400    | Dados inválidos, campo obrigatório ausente ou erro na validação. |
| 404    | Endereço(s) não encontrado(s) para o(s) ID(s) informado(s). |
| 401/403| Falha na autenticação ou autorização (não documentado diretamente, mas implícito). |

Mensagens de erro são localizadas conforme header `Accept-Language`.

---

## 7. Banco de dados (tabelas YAML)

### Tabela: `address`

- **Finalidade:** Armazenar informações de endereços com múltiplos tipos e controle de endereço primário.

| Coluna         | Tipo       | Nulável | Default           | Descrição                                      |
|----------------|------------|---------|-------------------|------------------------------------------------|
| `id`           | INT (PK)   | Não     | auto-increment    | Identificador único do endereço                 |
| `address_type` | ENUM       | Não     | -                 | Tipo do endereço (valores definidos abaixo)    |
| `country_code` | VARCHAR    | Não     | -                 | Código do país (ISO 3166-1 alpha-2)             |
| `state`        | VARCHAR    | Não     | -                 | Estado ou província                              |
| `city`         | VARCHAR    | Não     | -                 | Cidade                                          |
| `postal_code`  | VARCHAR    | Não     | -                 | CEP ou código postal                             |
| `line1`        | VARCHAR    | Não     | -                 | Linha principal do endereço                      |
| `line2`        | VARCHAR    | Sim     | NULL              | Linha complementar                              |
| `is_primary`   | BOOLEAN    | Não     | false             | Indica se é o endereço primário do tipo        |
| `created_at`   | TIMESTAMP  | Não     | CURRENT_TIMESTAMP | Data e hora de criação                           |
| `updated_at`   | TIMESTAMP  | Não     | CURRENT_TIMESTAMP | Data e hora da última atualização                |

#### Índices

| Nome                     | Colunas               | Único | Condição           | Propósito                                               |
|--------------------------|-----------------------|-------|--------------------|--------------------------------------------------------|
| `idx_address_type_primary` | `address_type`, `is_primary` | Sim   | `is_primary = true` | Garante apenas um endereço primário por tipo           |

#### Enum `address_type` valores possíveis:

- `residential`
- `commercial`
- `correspondence`
- `alternative`
- `work`
- `billing`
- `shipping`

---

## 8. Regras de negócio relevantes

- **Endereço primário único por tipo:**  
  Ao criar ou atualizar um endereço com `is_primary=true`, o sistema automaticamente remove a flag `is_primary` de outros endereços do mesmo tipo, garantindo unicidade.

- **Busca:**  
  O parâmetro `search` realiza busca case-insensitive em múltiplos campos: `id` (se numérico), `address_type`, `country_code`, `state`, `city`, `postal_code`, `line1`, `line2`.

- **Localização:**  
  Mensagens de erro e validação são localizadas conforme o header `Accept-Language`.

- **Autorização:**  
  Acesso restrito a usuários autenticados com roles específicas, conforme tabela `route` e `role`.

---

## 9. Guia rápido de uso (exemplos)

### Listar endereços com busca e paginação

```bash
GET /address?page=1&pageSize=10&search=residential&sortField=city&sortOrder=asc
Authorization: Bearer <token>
```

### Obter endereço por ID

```bash
GET /address/1
Authorization: Bearer <token>
```

### Criar novo endereço

```bash
POST /address
Content-Type: application/json
Authorization: Bearer <token>

{
  "address_type": "residential",
  "country_code": "BR",
  "state": "SP",
  "city": "São Paulo",
  "postal_code": "01234-567",
  "line1": "Rua A, 123",
  "line2": "Apartamento 101",
  "is_primary": true
}
```

### Atualizar endereço parcialmente

```bash
PATCH /address/1
Content-Type: application/json
Authorization: Bearer <token>

{
  "city": "Rio de Janeiro",
  "state": "RJ",
  "is_primary": false
}
```

### Deletar múltiplos endereços

```bash
DELETE /address
Content-Type: application/json
Authorization: Bearer <token>

{
  "ids": [1, 2, 3]
}
```

---

## Tipos de Endereço

| Valor           | Descrição                      |
|-----------------|--------------------------------|
| `residential`   | Endereço residencial/doméstico |
| `commercial`    | Endereço comercial/empresarial |
| `correspondence`| Endereço para correspondência  |
| `alternative`   | Endereço alternativo/secundário|
| `work`          | Endereço de trabalho/empresa   |
| `billing`       | Endereço para faturamento      |
| `shipping`      | Endereço para entrega/despacho |

---

## Licença

Parte do projeto HedHog Lab v2.