# Changelog

## [1.0.6] - 2026-06-22

### Correção crítica (login retornava HTTP 500)
- **`Call to undefined function validateJsonInput()`**: essa função é definida em `core/services/Validator.php`, mas o autoload do `bootstrap.php` só é acionado por referência a uma *classe* — funções globais soltas nunca o disparam. Como `validateJsonInput()` é chamada antes de qualquer uso da classe `Validator`, o arquivo nunca era carregado e a função ficava indefinida, gerando erro fatal (HTTP 500) em todos os endpoints que validam entrada JSON (login, registro, etc.). Corrigido carregando `Validator.php` explicitamente no `bootstrap.php`. Auditado: nenhuma outra função global tem o mesmo problema (todas as demais já vivem no próprio bootstrap).

## [1.0.5] - 2026-06-22

### Correções de bugs (respostas vazias / "Unexpected end of JSON input" no login)
- **Parser do `.env` reescrito**: o uso de `parse_ini_file()` falhava silenciosamente quando algum valor continha caracteres especiais não-quotados (`#`, `;`, `=`, aspas, espaços) — comuns em senhas de banco e chaves JWT geradas aleatoriamente. Isso podia derrubar todo o carregamento e fazer a API responder vazio. Agora o `.env` é lido com um parser manual robusto, e o instalador (`envWrite`) passou a envolver valores especiais em aspas. Round-trip validado para todos os casos problemáticos.
- **Handler global de exceções não capturadas** (`set_exception_handler`): exceções lançadas fora de um bloco `try` (ex: no construtor de um serviço) agora retornam um JSON de erro em vez de uma resposta vazia.
- **Instanciação de serviços movida para dentro do `try`** em `auth.php` — uma falha ao construir `AuthManager`/`RateLimiter` agora é tratada corretamente em vez de quebrar a resposta.
- O `login.html` passou a ler a resposta como texto antes de parsear: se vier vazia ou em formato inesperado, mostra uma mensagem legível com o status HTTP em vez do críptico "Unexpected end of JSON input".

### Robustez
- `Logger` e `CacheManager` agora criam suas pastas e fazem operações de disco de forma silenciosa (`@`), nunca emitindo warnings que poderiam vazar na resposta e quebrar o JSON (essas classes são instanciadas no topo dos endpoints, fora de try).
- `bootstrap.php` garante que a pasta de logs exista e seja gravável antes de configurar o destino de log.
- Checagem de erro de conexão cURL adicionada aos providers restantes (Pexels, Unsplash e geração de imagem DALL-E), completando a cobertura.

### Segurança
- **3 vulnerabilidades de mass-assignment** corrigidas (Content, Site, ImageSettings): um PUT podia incluir `user_id`/`site_id` no corpo e reatribuir a posse do recurso a outro usuário/site. Agora apenas campos editáveis explícitos são aceitos.
- `cron.php` só pode ser executado via linha de comando (CLI), nunca via navegador.
- `setup.php` bloqueia a reexecução de qualquer etapa do instalador depois que a plataforma já foi instalada.
- Adicionado `storage/.htaccess` bloqueando acesso web direto a logs, cache e uploads internos.

### Correção de bug lógico (quota de imagens)
- O reset de quota de imagens (automático e manual) atualizava apenas a data do próximo reset, mas **não avançava a janela de contagem** (`period_start`/`period_end`). Resultado: após o primeiro ciclo, a contagem de uso ficava congelada no período antigo e a quota nunca zerava de fato. Agora o reset move a janela corretamente.

## [1.0.4] - 2026-06-21

### Segurança
- **Vazamento de detalhes internos em erros 500**: 8 das 9 APIs devolviam `$e->getMessage()` ao cliente em erros inesperados, expondo mensagens do MySQL, estrutura de tabelas e caminhos de arquivos (útil para um atacante mapear o sistema). Todas passaram a usar um tratador central (`handleApiException`) que registra o erro real no log e devolve apenas uma mensagem genérica ao cliente (com `APP_DEBUG=1`, inclui detalhe só para depuração local).
- **Instalador reexecutável**: depois de instalada, qualquer etapa do instalador podia ser chamada de novo via POST direto ao `setup.php` (reconfigurar banco, criar outro admin). Agora o `setup.php` bloqueia globalmente qualquer ação se o arquivo `.installed` existir.

### Robustez
- `GeminiProvider` e `OpenAIProvider` (geração de texto) não verificavam erro de conexão do cURL — falhas de rede viravam uma mensagem confusa "HTTP 0". Agora detectam e reportam o erro de conexão explicitamente, como o `ClaudeProvider` já fazia.

## [1.0.3] - 2026-06-21

### Correção crítica (quebrava login e qualquer atualização de dados)
- **`id` sempre nulo em registros carregados do banco**: o ORM interno descartava silenciosamente o campo `id` ao montar objetos a partir de resultados de SELECT, porque `id` nunca está (corretamente) listado em `$fillable` de nenhum model — e o carregamento usava o mesmo filtro de mass-assignment do `fill()`. Isso fazia `$user->id`, `$content->id`, `$site->id` etc. sempre virem `null` depois de qualquer `find()`/`where()`, quebrando login (o cadastro do admin funcionava, mas buscar esse usuário de volta no login não), updates (viravam INSERTs duplicados em vez de atualizar) e relacionamentos. Corrigido com um novo método `Model::hydrate()`, usado apenas internamente pelo `QueryBuilder` para reconstruir objetos a partir de linhas reais do banco (aceitando todas as colunas), mantendo `fill()` restrito a dados de entrada do usuário — sem abrir brecha de mass-assignment do `id` via API.
- Como efeito colateral, `created_at`/`updated_at` também eram descartados na maioria dos models; agora vêm corretos.

### Correção de robustez (erros do PHP vazando nas respostas JSON)
- `display_errors` estava ligado, fazendo qualquer warning/notice do PHP ser impresso no meio da resposta da API, quebrando o parsing de JSON no frontend (erro "Unexpected non-whitespace character after JSON..."). Agora fica desligado por padrão; ative com `APP_DEBUG=1` no `.env` apenas para depuração local. Erros continuam sendo logados em `storage/logs/php-errors.log` independente disso.
- `session_start()` agora só é chamado se ainda não houver sessão ativa, evitando warning em cenários de inclusão aninhada do `bootstrap.php`.
- Adicionado handler de erro fatal que devolve um JSON de erro genérico em vez de despejar HTML, caso algo inesperado aconteça.

## [1.0.2] - 2026-06-21

### Correção de roteamento (instalação em subdomínio cPanel)
- `login.html` estava dentro de `public/`, enquanto `admin/` e `install/` ficavam na raiz do pacote — essa mistura quebrava os links/redirects quando o Document Root do (sub)domínio aponta para a raiz do pacote (cenário comum em subdomínios cPanel). `login.html` foi movido para a raiz e o roteador (`public/index.php`) foi reescrito para detectar automaticamente o prefixo de URL e servir tudo corretamente, com ou sem `/public/` na URL, em domínio raiz ou subpasta.

## [1.0.1] - 2026-06-21

### Correções de segurança
- **IDOR corrigido**: endpoints de posts, mídia e publicação agora verificam se o recurso pertence ao usuário autenticado antes de operar (helpers `findContentForUser` / `findSiteForUser`). Antes, um usuário podia acessar/editar/publicar/deletar conteúdo de outros trocando o ID na URL.
- **Vazamento de senha do WordPress**: o model `Site` agora oculta `wp_password` nas respostas da API (antes a senha criptografada era enviada ao frontend em toda listagem).
- **Rate limiter à prova de spoofing**: o IP do cliente só usa cabeçalhos de proxy (X-Forwarded-For, CF-Connecting-IP) quando `TRUSTED_PROXY=1` está configurado; caso contrário usa apenas `REMOTE_ADDR`.

### Correções de bugs
- **Booleanos no MySQL**: com `PDO::ATTR_EMULATE_PREPARES => false`, valores `true`/`false` eram gravados como string vazia em vez de `1`/`0`. Corrigido centralmente em `Database`. Isso restaura o funcionamento do dashboard de limites (`is_active`) e da deduplicação de alertas (`acknowledged`).
- **Posts agendados nunca publicavam**: adicionado `PublishService::publishDueScheduled()`, chamado pelo cron, que publica conteúdos cujo horário agendado já chegou.
- **`update()` reescrevia todos os campos**: implementado rastreamento de campos modificados (dirty tracking); agora o UPDATE só altera os campos realmente mudados, sem tocar em `created_at`/`updated_at` indevidamente.
- **Processamento duplicado de jobs**: adicionado lock atômico no `Queue` (`UPDATE ... WHERE status='pending'`) para evitar que execuções sobrepostas do cron processem o mesmo job duas vezes.
- **Filtro `?status=` ignorado** na listagem de posts: agora aplicado corretamente.
- **`where('coluna', null)`** deslocava o operador: corrigido usando `func_num_args()` em vez de checar se o valor é null.
- **Content-Type com sufixo** (`image/jpeg; charset=binary`) era rejeitado: agora extrai apenas o MIME base.
- **Vazamento de memória GD**: `processWithGD` agora libera os recursos de imagem mesmo em caso de erro (bloco `finally`).
- **Erro de cURL no upload** ao WordPress agora é detectado e reportado explicitamente.
- **Blacklist de tokens** crescia indefinidamente: o cron agora remove tokens expirados diariamente.

## [1.0.0] - 2026-06-19

### Adicionado
- Sistema completo de gestão de conteúdo com IA
- Integração com provedores de IA: Claude (Anthropic), Gemini (Google), OpenAI
- Geração e processamento de imagens (IA, stock, upload manual)
- Publicação automática e agendada no WordPress via REST API
- Dashboard administrativo interativo (Alpine.js)
- Editor de conteúdo com validação SEO em tempo real e versionamento
- Sistema de quotas e limites de imagens IA (diário/semanal/mensal/customizado)
- Alertas automáticos de limite com contagem regressiva de reset
- MCP Server para integração com Claude Desktop
- Sistema de fila de jobs assíncrono com retry automático
- Autenticação JWT própria com suporte a 2FA (TOTP)
- Sistema de roles (admin, editor, redator)
- Instalador web com wizard de 5 passos
- Auditoria SEO estilo Yoast (título, meta description, densidade de palavra-chave, H1/H2)
