Flaubert CMS — Content Manager AI
Plataforma SaaS que gera conteúdo com IA, faz auditoria SEO/GEO/AEO, gerencia imagens e publica em sites WordPress remotamente via REST API — sem instalar plugin obrigatório no site gerenciado. Arquitetura em monorepo: frontend React (SPA) desacoplado de um backend PHP 8.2 que expõe a API e serve o build do front.
Documento gerado a partir da leitura do código-fonte atual. Descreve o comportamento em produção — não altera nada.
1 Visão geral
Duas aplicações independentes no mesmo repositório, comunicando por HTTP através de um proxy.
frontend/
SPA em React 19 (Vite + TanStack Router/Start), UI shadcn/Radix + Tailwind v4. Gerado/versionado via Lovable. Roda local com Bun (bun run dev) e vai para produção como build estático.
backend/
API e CMS em PHP 8.2 (/api/v1/*). ORM próprio, JWT, fila assíncrona, integrações com IA, WordPress, Google e Alexa. Hospedado em cPanel/LiteSpeed.
Como front e back conversam
O PHP não envia cabeçalhos CORS, então o navegador não chama a API diretamente. O front expõe uma rota-proxy server-side (src/routes/api/proxy/$.ts) que roda no mesmo domínio e repassa tudo para o PHP:
O cliente HTTP central do front (src/lib/api.ts) sempre aponta para /api/proxy, anexa o JWT do localStorage e trata refresh automático em 401. Cabeçalhos de proxy/CDN (X-Forwarded-For, CF-*) são removidos no repasse.
cms.flaubert.dev.br o próprio .htaccess do backend serve o index.html do SPA para qualquer rota que não seja arquivo real, pasta real, /api/ ou /aprovacao/. Ou seja, o mesmo domínio entrega o app React e a API.2 Stack tecnológica
| Camada | Tecnologia |
|---|---|
| Frontend framework | React 19, TanStack Router + TanStack Start, TanStack Query |
| Build / runtime | Vite 8, Bun, Nitro (Worker/Cloudflare), TypeScript 5.8 |
| UI | shadcn/ui sobre Radix UI, Tailwind CSS v4, lucide-react, recharts, sonner, react-hook-form + zod |
| Backend | PHP 8.2 (LiteSpeed/lsphp), ORM próprio (PDO), sem framework externo |
| Banco | MySQL / MariaDB (utf8mb4), schema em backend/database/ |
| Autenticação | JWT próprio (access + refresh), suporte a 2FA (TOTP), blacklist de tokens |
| Assíncrono | Fila de jobs em tabela jobs, worker via cron.php (CLI) ou inline |
| IA (texto) | Claude (Anthropic), Gemini (Google), OpenAI |
| Imagens | OpenAI gpt-image-1 (IA), Pexels e Unsplash (stock), upload manual, processamento com GD |
| Integrações | WordPress REST API + Application Passwords, Google Search Console/Indexing API, Alexa Proactive Events, e-mail (SMTP), WhatsApp |
| MCP | Servidor Node/Express expondo ferramentas ao Claude Desktop |
3 Estrutura de pastas
Projeto CMS/
├── README.md Monorepo (instruções de deploy)
├── Plano-de-Acao-SaaS.md Plano de virar SaaS multi-tenant
├── Alexa-Integracao-Guia.md
├── Google-Search-Console-Guia.md
│
├── frontend/ SPA React (Vite + TanStack)
│ ├── src/
│ │ ├── routes/ 1 arquivo = 1 tela (dashboard, editor, sites…)
│ │ │ └── api/proxy/$.ts Proxy server-side → PHP
│ │ ├── components/ AdminShell, AppSidebar, Topbar, AuthGuard…
│ │ │ └── ui/ 46 componentes shadcn/ui
│ │ ├── lib/ api.ts, auth.ts, api-types.ts, utils.ts
│ │ └── hooks/
│ ├── package.json vite.config.ts .env (API_BASE_URL)
│
└── backend/ API + CMS em PHP 8.2
├── .htaccess Roteamento (SPA + API + /aprovacao)
├── .env.example Modelo de configuração
├── cron.php Worker da fila (CLI) + limpezas
├── api/v1/ 19 endpoints REST
├── core/
│ ├── bootstrap.php Carrega .env, autoload, handlers de erro
│ ├── Database.php ContentService.php
│ ├── auth/ AuthManager, RoleManager
│ ├── middleware/ Auth, Permission, MiddlewareStack
│ ├── models/ ORM (Model, QueryBuilder) + 20 models
│ ├── providers/adapters/ Claude, Gemini, OpenAI, Pexels, Unsplash
│ ├── queue/ Queue, Job + 5 jobs
│ └── services/ ~18 serviços (regra de negócio)
├── database/ schema.sql + migrations
├── admin/ Sobras (dicas-conteudo.html, esta doc, css/js)
├── mcp-server/ Servidor MCP (Node/Express)
├── wordpress-mu-plugin/ cms-faq-rest-bridge.php (instalar no WP)
├── install/ Instalador web (wizard)
└── storage/ uploads/ Logs, cache, mídia temporária
editor.html, historico.html etc.) foram migradas para o SPA React. Em backend/admin/ restam apenas arquivos utilitários (dicas-conteudo.html, footer.js, sidebar.js, shell.css) — e agora este documentacao.html.4 Núcleo do backend (bootstrap e ORM)
bootstrap.php
Ponto de entrada de todo endpoint (require_once core/bootstrap.php). Responsável por:
- Sessão: só inicia se ainda não houver sessão ativa (evita warning em inclusão aninhada).
- Parser de
.envmanual: não usaparse_ini_file()(falhava com#,;,=, aspas em senhas/chaves). Faz parse linha a linha e remove aspas envolventes. - Controle de erros:
display_errorsfica OFF por padrão (um warning no corpo quebra o JSON do front). Erros vão parastorage/logs/php-errors.log.APP_DEBUG=1liga a exibição só em dev. - Handlers globais:
set_exception_handlerdevolve JSON de erro genérico em vez de resposta vazia. - Autoload de classes do
core/e carga explícita doValidator.php(funções globais soltas não disparam o autoload).
ORM próprio
Sem Eloquent/Doctrine. core/models/Model.php + QueryBuilder.php implementam um mini-ORM sobre PDO:
fill()respeita$fillable(proteção contra mass-assignment na entrada de usuário).hydrate()reconstrói objetos a partir de linhas reais do banco aceitando todas as colunas (inclusiveid,created_at) — sem abrir brecha via API.- Dirty tracking:
update()só grava os campos realmente alterados. - Helpers
where(),whereNull(),whereNotNull(),first(),get(). Database.phpnormaliza booleanos para1/0(comEMULATE_PREPARES=false,true/falseviravam string vazia).
Roteamento
Cada arquivo em api/v1/ é um roteador simples: lê REQUEST_METHOD + REQUEST_URI e casa a rota com preg_match/strpos, respondendo com json_response(). Autenticação via getAuthenticatedUser(); erros centralizados em handleApiException() (loga o real, devolve mensagem genérica).
5 Autenticação e papéis
JWT próprio com access token + refresh token, 2FA opcional (TOTP) e blacklist de tokens revogados.
- Login devolve
token+refresh_token; o front guarda nolocalStoragee renova em 401 viaauth/refresh. - Logout adiciona o token à
token_blacklist; ocron.phplimpa tokens expirados diariamente. - Recuperação de senha:
auth/password/forgoteauth/password/reset.
Papéis (RoleManager)
| Papel | Permissões |
|---|---|
admin | * — acesso total, incl. configurações, usuários, chaves de API, limpeza de histórico. |
gerente | * — igual ao admin na prática (evita 403 em criar/editar/publicar). Distinção histórica: não limpa histórico. |
editor | posts.create, posts.edit, posts.publish, posts.delete, sites.view, sites.create |
redator | posts.create, posts.edit (não publica nem exclui) |
Verificação por RoleManager::can($role, $permission). Endpoints sensíveis (usuários, publicação) também revalidam papel. Recursos são checados por dono (helpers findContentForUser / findSiteForUser) para evitar IDOR.
6 Endpoints da API (/api/v1)
19 arquivos de rota. Abaixo, o mapa completo por recurso.
Autenticação — auth.php
| POST | /auth/login | Login (e-mail + senha, 2FA se ativo) |
| POST | /auth/register | Registro |
| POST | /auth/refresh | Renova access token |
| POST | /auth/logout | Revoga token (blacklist) |
| POST | /auth/password/forgot · /reset | Recuperação de senha |
| POST GET | /auth/users | Admin cria / lista usuários (qualquer papel) |
| PUT DEL | /auth/users/{id} | Edita / remove usuário |
Posts / conteúdo — posts.php
| GET | /posts | Lista (filtro ?status=, exclui soft-deleted) |
| POST | /posts | Cria conteúdo |
| GET PUT DEL | /posts/{id} | Lê / atualiza / exclui (soft delete) |
| GET | /posts/{id}/versions | Versões do post |
| POST | /posts/{id}/revert/{version} | Reverte para versão |
| POST | /posts/{id}/restore | Restaura da lixeira |
| POST | /posts/{id}/publish · /schedule | Publica / agenda |
| POST | /posts/{id}/request-approval | Envia para aprovação do cliente |
| POST | /posts/check-grammar | Correção ortográfica (LanguageTool) |
| POST | /posts/generate-faq | Gera FAQ (perguntas/respostas) via IA |
| POST | /posts/generate-seo-title · /generate-meta-description | Gera título SEO / meta description via IA |
| GET | /posts/history · /history/years | Histórico de publicações e anos p/ filtro |
Sites — sites.php
| GET POST | /sites | Lista / cria site |
| GET PUT DEL | /sites/{id} | Lê / atualiza / remove |
| POST | /sites/test-connection | Testa credenciais WordPress |
| GET | /sites/{id}/categories · /authors | Categorias e autores do WP (cache 1h) |
| GET | /sites/{id}/faq-capability · /approval-capability | Detecta recursos do site |
Publicação, mídia e fila
| POST | /publish/now · /publish/schedule | Publica agora / agenda |
| GET | /media?content_id= | Imagem destacada do post |
| POST | /media/upload | Upload manual de imagem |
| PUT DEL | /media/{id} | Atualiza alt/title/caption (local + WP) / exclui |
| POST GET | /queue/jobs · /queue/jobs/{id} | Enfileira / consulta status de job |
IA, imagens e limites
| POST | /ai-images (via job) | Gera/processa imagem para conteúdo |
| GET | /ai-images/can-generate | Verifica se ainda há cota |
| GET | /ai-images/limits/dashboard · /dashboard-countdown | Painel de limites + contagem regressiva de reset |
| POST PUT | /ai-images/limits · /limits/{id} | Cria / edita cota de imagens |
| POST | /ai-images/limits/{id}/reset | Reset manual da cota |
| POST | /ai-images/alerts/{id}/acknowledge | Marca alerta como lido |
| GET | /tokens/summary · /dashboard · /usage · /check | Consumo/custo de tokens de IA |
| GET PUT | /image-settings?site_id= | Config de imagem por site |
| POST | /ai-test · /alexa-test | Testa conexão IA / envio Alexa |
Configurações, relatórios e observabilidade
| GET PUT | /settings/ai-defaults | Provider padrão de texto/imagem |
| GET PUT | /settings/api-keys | Status mascarado / atualização de chaves |
| GET PUT | /settings/notifications | SMTP / WhatsApp |
| GET PUT DEL | /settings/theme | Cores personalizadas (claro/escuro) |
| POST | /settings/test-email | Envia e-mail de teste (SMTP salvo) |
| GET | /report | Relatório mensal |
| GET | /history | Histórico/eventos |
| GET POST | /backup | Exporta / importa backup |
| GET POST DEL | /branding · /branding/{logo|favicon} | Logo / favicon / marca |
| GET PATCH POST | /logs · /logs/channels · /logs/{id} · /logs/clear-all | Log central (resolver/limpar entradas) |
Google Search Console — google.php
| GET | /google/connect?site_id= · /callback | Fluxo OAuth do cliente |
| GET | /google/status?site_id= | Estado da conexão |
| POST | /google/test · /disconnect | Valida credenciais / desconecta |
| POST | /google/detect-sitemap · /reindex | Detecta sitemap / pede reindexação |
| PUT | /google/sitemap | Define o sitemap |
| GET | /google/performance?content_id=&days= | Desempenho da URL no GSC |
Aprovação pública — approval-public.php
| GET | /aprovacao/{token} | Página de confirmação (sem login, renderizada em PHP) |
| POST | /aprovacao/{token} | Cliente aprova / pede ajustes / rejeita |
7 Serviços (regra de negócio)
A lógica vive em core/services/; os endpoints são finos e delegam para cá.
| Serviço | Responsabilidade |
|---|---|
ContentService | CRUD de conteúdo, versionamento, geração de alternativa por IA, histórico, requisitos mínimos, status de aprovação, parse de FAQ da IA, validação SEO. |
PublishService | Publica/agenda no WordPress; publishDue() publica agendados vencidos (chamado pelo cron), disparando o gancho de indexação. |
SiteManager | Cria sites, testa conexão WP, busca categorias/autores (cache), detecta capacidade de FAQ. |
SEOService | Auditoria estilo Yoast: título, meta description, densidade de palavra-chave (normaliza acentos), H1/H2, regras por canal. |
ImageService | Processa imagem com GD (redimensiona, libera memória no finally), envia ao WordPress, atualiza metadados da mídia no WP. |
ImageGenerationService | Orquestra geração de imagem para um conteúdo (provider + limites + salvamento). |
ApprovalService | Canais disponíveis, solicita aprovação, processa resposta do cliente, invalida pendências, notifica expiração. |
NotificationService | Envio de e-mail (SMTP ou mail() nativo) e WhatsApp. |
AlexaNotificationService | Eventos proativos na Alexa (aprovado/ajustes/rejeitado) via API oficial. |
GoogleSearchConsoleService | OAuth por site, reenvio de sitemap, pedido de indexação, desempenho de URL, detecção de sitemap. |
TokenService | Estima custo, registra consumo, resumo (hoje/mês/total), verifica disponibilidade, consome cota. |
QuotaManager / AiImageLimiter | Cotas de imagens IA (diária/semanal/mensal/custom), uso, alertas, reset com avanço de janela, histórico. |
SettingsService | Ordem de fallback de providers de texto, provider de imagem, chaves de API (mascaradas), notificações, tema. |
RateLimiter | Limite por identificador/janela; IP só usa cabeçalho de proxy se TRUSTED_PROXY=1. |
Validator | Validação/sanitização de entrada (e-mail, URL, HTML). |
8 Provedores de IA e imagem
Padrão adapter em core/providers/adapters/, orquestrados por ProviderManager com ordem de fallback configurável.
ClaudeProvider
Anthropic — geração de texto.
GeminiProvider
Google — texto.
OpenAIProvider
Texto + imagem (gpt-image-1, retorna base64).
PexelsProvider
Imagens de banco (stock).
UnsplashProvider
Imagens de banco (stock).
Todos verificam erro de conexão cURL explicitamente (evita o confuso "HTTP 0"). Consumo é registrado em token_usage / ai_image_usage com custo estimado. O provider padrão de texto e de imagem é definido em /settings/ai-defaults.
gpt-image-1, que devolve base64 em vez de URL — exigindo salvar arquivo temporário local antes do upload).9 Fila de jobs e cron
Trabalho pesado (gerar conteúdo, imagem, publicar, validar SEO) roda de forma assíncrona na tabela jobs.
Jobs disponíveis
GenerateContentJob
Gera o texto do post via IA.
GenerateImageJob
Gera/processa a imagem.
GenerateFaqJob
Gera FAQ via IA.
PublishJob
Publica no WordPress.
SeoValidationJob
Roda auditoria SEO.
Worker (cron.php)
- Só roda via CLI (bloqueia acesso por navegador). Configurar
* * * * *a cada minuto. - Processa até 10 jobs por execução; lock atômico (
UPDATE ... WHERE status='pending') evita processamento duplicado. - Recupera jobs travados em "processing" por 3+ minutos (
recoverStalled()). - Publica agendados vencidos via
PublishService— mas se há aprovação pendente, marca o post comoexpirede avisa o redator (segurança: não publica sem aprovação). - Limpezas periódicas: remove tokens expirados da blacklist.
- Ambientes sem cron: existe um worker inline como fallback.
10 Modelo de dados
MySQL/MariaDB, utf8mb4. Schema completo em backend/database/schema.sql; alterações incrementais em migrate_*.sql.
| Tabela | Descrição |
|---|---|
users | Usuários. Papel (admin/gerente/editor/redator), plano (basic/pro/agency), 2FA. |
sites | Sites WordPress gerenciados (URL, credenciais WP, e-mail/WhatsApp do cliente, sitemap, aprovação padrão). |
site_credentials | Credenciais extras por site (FTP, cPanel etc.). |
contents | Conteúdo/posts: título, seo_title, corpo, meta, focus_keyword, categorias/autor WP, faq_data, status, agendamento, soft delete, flags de aprovação do cliente. |
content_approvals | Envios de aprovação: token UUID único, status, canal, IP de resposta, comentário. |
content_versions | Histórico de versões (título/corpo) por post. |
content_events | Linha do tempo (criado, aprovação, publicado, falha…). Usada pelo Histórico. |
media | Imagens: URL, wp_media_id, alt/title/caption/description, origem, slug. |
token_usage / token_quotas | Consumo e cotas de tokens de IA (texto) por usuário/provider/modelo. |
ai_generated_images | Registro de cada imagem gerada por IA (prompt, custo, tempo). |
ai_image_quotas / _usage / _alerts | Sistema de limites de imagem IA: cotas (diária/semanal/mensal/custom), uso, alertas. |
quota_reset_history | Auditoria de resets de cota. |
image_settings | Config de imagem por (usuário, site): fonte, provider, dimensões, templates de prompt. |
jobs | Fila assíncrona (tipo, payload, status, tentativas, resultado). |
seo_validation_results | Resultados de auditoria SEO (score, status, issues, sugestões). |
audit_logs | Auditoria de ações (quem, o quê, IP, resultado). |
system_logs | Log técnico central (warning/error/critical) por canal (IA, WP, fila, GSC…). |
token_blacklist | Tokens JWT revogados (logout), limpos pelo cron. |
site_google_connections | OAuth do Google do cliente por site (access/refresh token, propriedade GSC). |
11 Integração WordPress
Publicação remota via REST API + Application Passwords. O plugin no site é opcional (só necessário para FAQ Schema e para contornar bloqueios de segurança).
- Publicação:
PublishServicecria/atualiza o post via/wp-json/wp/v2/posts, enviando categorias, autor e a imagem destacada. - Categorias/autores: buscados via REST com cache de 1h, reutilizando as credenciais já salvas do site.
- Mídia: imagem enviada para a biblioteca do WP; metadados (alt/title/caption) sincronizados.
mu-plugin: cms-faq-rest-bridge.php
Instalar em wp-content/mu-plugins/ no site gerenciado. Faz duas coisas, de forma puramente aditiva (não edita plugins existentes):
- Expõe as 9 metas
_mseo_faq_*do plugin "FAQ Schema" na REST API (comauth_callbackexigindoedit_poste a mesma sanitização do plugin), gerandoFAQPageSchema.org. - Cria a rota
/wp-json/cms-faq/v1/authors, contornando bloqueios do Wordfence/iThemes Security ao endpoint padrão/wp/v2/users. Também expõe/statuspara a plataforma detectar o plugin.
12 Fluxo de aprovação do cliente
O cliente aprova o conteúdo por um link sem login, recebido por e-mail ou WhatsApp.
- A rota
/aprovacao/é PHP renderizado no servidor, fora do SPA (o.htaccessa exclui do React) — por isso funciona sem login. - Cada envio gera um token único; envios antigos ficam
superseded. O IP e o comentário do cliente são registrados para auditoria. - Se um post agendado tem aprovação pendente na hora de publicar, o cron o marca
expirede avisa o redator — nunca publica sem aprovação. - Canais dependem do que o site tem cadastrado (e-mail e/ou WhatsApp).
13 Google Search Console
Ao publicar/aprovar, o CMS avisa o Google. Conexão OAuth é por site (o cliente é o dono da propriedade).
- Reenvio de sitemap via Search Console API — funciona e ajuda o Google a descobrir URLs novas mais rápido.
- Pedido de indexação via Indexing API — a API é oficialmente só para
JobPosting/BroadcastEvent; para blog comum o Google ignora. Conte com o reenvio de sitemap como ganho real. - Botão manual "Reindexar no Google" e consulta de desempenho da URL (
/google/performance). - Credenciais OAuth criadas uma vez para a plataforma; cada cliente conecta a própria conta. Detecção automática de sitemap disponível.
Detalhes de configuração em Google-Search-Console-Guia.md.
14 Integração Alexa
Notificações proativas na Alexa usando a API oficial de Proactive Events da Amazon — sem AWS Lambda, tudo roda no servidor.
- Eventos cobertos: cliente aprovou, pediu ajustes, rejeitou uma publicação.
- Serviço dedicado
AlexaNotificationService(isConfigured(),sendProactiveEvent(),notifyApproval()). Arquitetura modular: novo evento = novo método. - Endpoint de teste:
POST /api/v1/alexa-test.
Passo a passo em Alexa-Integracao-Guia.md.
15 MCP Server
Servidor Node/Express (backend/mcp-server/) que expõe a plataforma como ferramentas para o Claude Desktop.
- Configuração por ambiente:
PLATFORM_API_URL,PLATFORM_API_KEY,MCP_PORT(padrão 3000). - Ferramentas expostas incluem
generate-content(gera post por site/tópico/keyword, com opção de auto-publicar) esearch-and-process-image, entre outras. - Chama a mesma API
/api/v1— é um cliente, não um caminho paralelo.
16 Frontend (SPA React)
TanStack Router com roteamento por arquivo: cada src/routes/*.tsx é uma tela. Layout comum em AdminShell (sidebar + topbar), proteção por AuthGuard.
| Rota | Tela |
|---|---|
/ (index) | Login (redireciona ao dashboard se já logado) |
/dashboard | Painel principal (posts, atalhos) |
/editor | Editor de conteúdo: SEO/GEO/AEO em tempo real, categorias, FAQ, imagem, aprovação |
/sites | Gerência de sites WordPress |
/historico | Histórico de publicações (timeline, filtros, status, quem excluiu) |
/imagens | Configurações de imagem por site |
/limites-ia | Limites e consumo de IA/imagens |
/relatorios | Relatório mensal (imprimível) |
/logs | Log central técnico |
/usuarios | Gestão de usuários e papéis |
/configuracoes | Chaves de IA, notificações, tema, branding, backup |
/forgot-password | Recuperação de senha |
Camada de dados
lib/api.ts— cliente HTTP único (proxy + JWT + refresh +HttpError).lib/auth.ts— sessão/token nolocalStorage.lib/api-types.ts— tipos TypeScript espelhando as respostas do PHP.- TanStack Query para cache/estado de servidor; react-hook-form + zod nos formulários; sonner para toasts.
17 Configuração (.env)
Segredos só no .env do backend (fora do git). Modelo em backend/.env.example.
| Grupo | Chaves |
|---|---|
| Banco | DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD |
| IA (texto) | ANTHROPIC_API_KEY, GOOGLE_API_KEY, OPENAI_API_KEY |
| Imagens stock | UNSPLASH_API_KEY, PEXELS_API_KEY |
| App | APP_URL, JWT_SECRET, APP_DEBUG (0 em prod), TRUSTED_PROXY |
| Cache | CACHE_DRIVER (file/redis/memcached) + hosts/portas |
| Notificações | SMTP_*, MAIL_FROM*, MAIL_USE_NATIVE, WHATSAPP_API_URL/TOKEN |
No frontend, frontend/.env define API_BASE_URL (destino do proxy; padrão https://cms.flaubert.dev.br).
APP_DEBUG=1 em produção (vaza detalhes internos) nem comite .env, build (dist/, assets/ gerado) ou node_modules/.18 Deploy
cd frontend && bun install && bun run build- Enviar
backend/+ o build do frontend (index.html+assets/) para a raiz do servidor. - Configurar
backend/.enva partir debackend/.env.example. - Banco: manter o existente; aplicar migrations de
backend/database/na ordem indicada. - Cron: agendar
php /caminho/cron.phpa cada minuto.
Servidor de produção: cPanel + LiteSpeed (lsphp ea-php82) em cms.flaubert.dev.br. O .htaccess cuida do roteamento: arquivo real → arquivo; /api/ → PHP; /aprovacao/ → PHP público; resto → index.html do SPA. Também bloqueia acesso web direto a .env, core/, database/, storage/.
19 Segurança (correções consolidadas)
Endurecimentos aplicados ao longo das versões (ver backend/CHANGELOG.md e ALTERACOES.md).
- IDOR: posts, mídia e publicação verificam o dono antes de operar.
- Mass-assignment: PUT não pode reatribuir
user_id/site_id; só campos editáveis explícitos. - Vazamento de senha WP:
wp_passwordoculto nas respostas da API. - Erros 500: tratador central loga o real e devolve mensagem genérica (não expõe MySQL/paths).
- Rate limiter à prova de spoofing: só confia em cabeçalho de proxy com
TRUSTED_PROXY=1. - Instalador: bloqueado após instalado (
.installed);cron.phpesetup.phpprotegidos. - Cabeçalhos:
X-Content-Type-Options,X-Frame-Options,X-XSS-Protection;storage/.htaccessbloqueia acesso direto. - Fila: lock atômico evita processamento duplicado; recuperação de jobs travados.
20 Roadmap SaaS
Direção definida em Plano-de-Acao-SaaS.md: transformar em SaaS multi-tenant escalável sem afetar clientes atuais.
Os 4 desacoplamentos
- Cloudflare na frente de tudo (troca de origem invisível ao cliente).
- Mídia em object storage (Cloudflare R2 / Backblaze B2) — a mídia nunca se move.
- Banco portátil (dump/import; depois banco gerenciado).
- App stateless (JWT + config em
.env) — já em grande parte atendido.
Multi-tenant (principal item da Fase 0)
- Tabela
organizations;organization_idemusers,sites,contents,media, settings, uso/limites. - Toda query filtrada pela organização (escopo global); settings por organização.
- Papel
adminvira admin da organização; acima, um super-admin. - BYOK (cada cliente com sua chave de IA) + limites por tenant.
Fases seguintes: cobrança recorrente (Asaas/Mercado Pago/Iugu/Vindi com Pix/boleto), travar recursos por plano, e por fim migração para VPS/infra dedicada quando o volume justificar.
Esta documentação reflete o estado atual do código lido em backend/ e frontend/. Para mudanças de comportamento, atualizar também as fontes citadas (CHANGELOG, ALTERACOES e os guias na raiz).