{
  "id": "traits-e-helpers",
  "title": "Traits e helpers",
  "description": "Comportamentos reutilizáveis e formatações compartilhadas no código do James.",
  "type": "development",
  "status": "observed",
  "visibility": "public",
  "tags": [
    "desenvolvimento",
    "php",
    "convenções"
  ],
  "related": [
    "arquitetura",
    "contribuicao",
    "contatos"
  ],
  "sourceRefs": [
    "https://github.com/james-suite/james/tree/master/app/Traits",
    "https://github.com/james-suite/james/tree/master/app/Helpers",
    "https://github.com/james-suite/james/blob/master/resources/views/components/markdown.blade.php"
  ],
  "authors": [],
  "updated": null,
  "diagram": null,
  "body": "No desenvolvimento do James, adotamos o uso extensivo de **Traits** e **Helpers** para manter os modelos e controllers limpos, reaproveitando lógicas e padronizando formatações.\n\n## Traits\n\nAs Traits injetam comportamentos padronizados em modelos e controllers Eloquent que as implementam.\n\n### `Searchable`\n**Local:** `app/Traits/Searchable.php`\n\nEsta trait adiciona o escopo estático `search($term)` aos modelos. Ela busca em tempo real por um termo específico cruzando colunas normais (via `ILIKE`) e também colunas dinâmicas `JSONB`, extraindo valores aninhados usando `jsonpath`.\nIsso permite que, por exemplo, o módulo de Contatos encontre facilmente um registro digitando apenas parte do número de telefone armazenado num array dinâmico.\n\n### `HasInitials`\n**Local:** `app/Traits/HasInitials.php`\n\nAdiciona o método `getInitials()` ao modelo que extrai e formata as iniciais baseadas na propriedade `name`. Muito útil para renderizar avatares genéricos (fallback) quando o usuário ou contato não possui uma foto (ex: \"Arthur Willers\" → \"AW\", \"João\" → \"J\").\n\n### `HandlesAttachments`\n**Local:** `app/Traits/HandlesAttachments.php`\n\nPadroniza a sincronização de arquivos anexos (adicionando novos uploads e expurgando arquivos marcados para remoção) via Spatie MediaLibrary:\n- `syncAttachments(Model $model, array $data, string $collection = 'attachments'): void`\n\n---\n\n## Helpers\n\nClasses com métodos estáticos utilitários e funções globais associadas para uso direto no backend e nas views Blade.\n\n### `DateHelper`\n**Local:** `app/Helpers/DateHelper.php`\n\nCentraliza a formatação de datas e horas usando a biblioteca `Carbon`, garantindo a aplicação do timezone configurado (`America/Sao_Paulo`):\n\n* `formatDate($date)` / `DateHelper::format($date)`: Formato longo por extenso (Ex: `17 de Junho de 2026`).\n* `formatShort($date)` / `DateHelper::formatShort($date)`: Formato numérico curto (Ex: `17/06/2026`).\n* `formatDateTime($date)` / `DateHelper::formatDateTime($date)`: Formato com data e hora (Ex: `17/06/2026 às 15:42`).\n* `formatRelative($date)` / `DateHelper::formatRelative($date)`: Formato amigável e relativo ao momento atual (Ex: `há 2 horas`, `em 3 dias`).\n* `formatMonthYear($date)` / `DateHelper::formatMonthYear($date)`: Mês e ano abreviado (Ex: `06/2026`).\n* `formatMonthYearFull($date)` / `DateHelper::formatMonthYearFull($date)`: Mês por extenso e ano em TitleCase (Ex: `Junho 2026`).\n\n### `CurrencyHelper`\n**Local:** `app/Helpers/CurrencyHelper.php`\n\nCentraliza a formatação monetária utilizando a classe `Number::currency()` nativa do Laravel:\n\n* `formatCurrency($value, $currency = '', $locale = null)` / `CurrencyHelper::format($value, ...)`: Converte valores numéricos em strings formatadas no padrão da moeda local (Ex: `formatCurrency(1250.50)` → `R$ 1.250,50`).\n\n---\n\n## Componente de Markdown Seguro\n\n### `<x-markdown>`\n**Local:** `resources/views/components/markdown.blade.php`\n\nRenderiza conteúdo em Markdown informado por usuários, como as notas de contatos e grupos, usando a configuração segura do CommonMark. Links inseguros não são permitidos e links para domínios externos são abertos em uma nova janela. Links do próprio domínio configurado para a aplicação continuam no mesmo contexto.\n\nUse o componente em vez de renderizar `markdown()` diretamente em uma view:\n\n```blade\n<x-markdown :content=\"$contact->notes\" />\n```",
  "sections": [
    {
      "id": "traits",
      "level": 2,
      "title": "Traits",
      "text": "As Traits injetam comportamentos padronizados em modelos e controllers Eloquent que as implementam.",
      "line": 3
    },
    {
      "id": "searchable",
      "level": 3,
      "title": "Searchable",
      "text": "**Local:** `app/Traits/Searchable.php`  Esta trait adiciona o escopo estático `search($term)` aos modelos. Ela busca em tempo real por um termo específico cruzando colunas normais (via `ILIKE`) e também colunas dinâmicas `JSONB`, extraindo valores aninhados usando `jsonpath`. Isso permite que, por exemplo, o módulo de Contatos encontre facilmente um registro digitando apenas parte do número de telefone armazenado num array dinâmico.",
      "line": 7
    },
    {
      "id": "hasinitials",
      "level": 3,
      "title": "HasInitials",
      "text": "**Local:** `app/Traits/HasInitials.php`  Adiciona o método `getInitials()` ao modelo que extrai e formata as iniciais baseadas na propriedade `name`. Muito útil para renderizar avatares genéricos (fallback) quando o usuário ou contato não possui uma foto (ex: \"Arthur Willers\" → \"AW\", \"João\" → \"J\").",
      "line": 13
    },
    {
      "id": "handlesattachments",
      "level": 3,
      "title": "HandlesAttachments",
      "text": "**Local:** `app/Traits/HandlesAttachments.php`  Padroniza a sincronização de arquivos anexos (adicionando novos uploads e expurgando arquivos marcados para remoção) via Spatie MediaLibrary: - `syncAttachments(Model $model, array $data, string $collection = 'attachments'): void`  ---",
      "line": 18
    },
    {
      "id": "helpers",
      "level": 2,
      "title": "Helpers",
      "text": "Classes com métodos estáticos utilitários e funções globais associadas para uso direto no backend e nas views Blade.",
      "line": 26
    },
    {
      "id": "datehelper",
      "level": 3,
      "title": "DateHelper",
      "text": "**Local:** `app/Helpers/DateHelper.php`  Centraliza a formatação de datas e horas usando a biblioteca `Carbon`, garantindo a aplicação do timezone configurado (`America/Sao_Paulo`):  * `formatDate($date)` / `DateHelper::format($date)`: Formato longo por extenso (Ex: `17 de Junho de 2026`). * `formatShort($date)` / `DateHelper::formatShort($date)`: Formato numérico curto (Ex: `17/06/2026`). * `formatDateTime($date)` / `DateHelper::formatDateTime($date)`: Formato com data e hora (Ex: `17/06/2026 às 15:42`). * `formatRelative($date)` / `DateHelper::formatRelative($date)`: Formato amigável e relativo ao momento atual (Ex: `há 2 horas`, `em 3 dias`). * `formatMonthYear($date)` / `DateHelper::formatMonthYear($date)`: Mês e ano abreviado (Ex: `06/2026`). * `formatMonthYearFull($date)` / `DateHelper::formatMonthYearFull($date)`: Mês por extenso e ano em TitleCase (Ex: `Junho 2026`).",
      "line": 30
    },
    {
      "id": "currencyhelper",
      "level": 3,
      "title": "CurrencyHelper",
      "text": "**Local:** `app/Helpers/CurrencyHelper.php`  Centraliza a formatação monetária utilizando a classe `Number::currency()` nativa do Laravel:  * `formatCurrency($value, $currency = '', $locale = null)` / `CurrencyHelper::format($value, ...)`: Converte valores numéricos em strings formatadas no padrão da moeda local (Ex: `formatCurrency(1250.50)` → `R$ 1.250,50`).  ---",
      "line": 42
    },
    {
      "id": "componente-de-markdown-seguro",
      "level": 2,
      "title": "Componente de Markdown Seguro",
      "text": "",
      "line": 51
    },
    {
      "id": "x-markdown",
      "level": 3,
      "title": "<x-markdown>",
      "text": "**Local:** `resources/views/components/markdown.blade.php`  Renderiza conteúdo em Markdown informado por usuários, como as notas de contatos e grupos, usando a configuração segura do CommonMark. Links inseguros não são permitidos e links para domínios externos são abertos em uma nova janela. Links do próprio domínio configurado para a aplicação continuam no mesmo contexto.  Use o componente em vez de renderizar `markdown()` diretamente em uma view:",
      "line": 53
    }
  ],
  "sourcePath": "content/traits-e-helpers.md",
  "visuals": [],
  "apiVersion": 1
}
