01. Resumo para Leigos

O StarHosting é um painel de gerenciamento de hospedagem web.

Em palavras simples: é uma "central de comando" onde um administrador pode criar e gerenciar sites para clientes, cobrando por planos diferentes.

Domínio: starhosting.com.br

Onde roda: Oracle Cloud Free Tier (servidor virtual gratuito da Oracle)

IP do servidor: 137.131.229.136

Fonte: config.php, linha 6-7

02. Analogia: O que é hospedagem?

Analogia para uma criança de 10 anos

Imagina assim:

O que é um servidor?

Um servidor (Server) é um computador ligado 24 horas por dia, 7 dias por semana, que guarda os arquivos do seu site e os mostra quando alguém visita seu endereço na internet.

O que é um domínio?

Um domínio (Domain) é o endereço que você digita no navegador. Exemplo: starhosting.com.br. É como o CEP da sua casa, mas na internet.

O que é uma hospedagem?

Hospedagem (Hosting) é o serviço de "alugar um pedacinho de servidor" para guardar os arquivos do seu site. Sem hospedagem, seu site não aparece na internet.

03. Por que o StarHosting existe?

Analogia

Imagina que você quer vender bolos. Você precisa de um local (servidor), de um endereço (domínio), e de alguém que cuide da loja (painel). O StarHosting é a "loja de bolos" digital: ele cuida de tudo para que você só precise criar o bolo (site) e vender.

Problemas que o StarHosting resolve

Problema sem o StarHostingSolução com o StarHosting
Configurar Nginx manualmente para cada site Criação automatizada — basta digitar o domínio e clicar "Criar"
Instalar e configurar SSL para cada site HTTPS automático via Let's Encrypt wildcard
Gerenciar permissões de arquivos manualmente Permissões corrigidas com um botão ("Corrigir Tudo")
Saber quanto cada cliente pode usar Limites automáticos por tier (sites, disco, PHP, SQLite)
Cobrar de cada cliente individualmente 3 planos prontos: Basic R$9,90 / Premium R$19,90 / Business R$39,90
Cliente não sabe alterar seu site Painel do cliente com upload, templates e editor

Quem se beneficia?

Fluxo completo de uma venda

[Parceiro] [Admin] [Sistema] [Cliente] │ │ │ │ │ traz cliente │ │ │ │ ──────────────>│ │ │ │ │ cria cliente │ │ │ │ ─────────────────>│ │ │ │ │ envia email │ │ │ │ ─────────────────>│ │ │ │ │ │ │ cria site │ │ │ │ ─────────────────>│ │ │ │ │ configura Nginx │ │ │ │ configura SSL │ │ │ │ cria index.html │ │ │ │ │ │ │ │ acesso ao painel │ │ │ │ ─────────────────>│ │ │ │ │ │ │ │ cliente edita │ │ │ │ faz upload │ │ │ │ aplica template │ │ │ │ │

04. Quem usa o sistema?

O sistema tem 3 tipos de usuários (chamados de roles ou níveis):

Role Nome em português O que é Exemplo do mundo real
admin Administrador O dono do sistema. Controla tudo. O dono da imobiliária
parceiro Parceiro / Coordenador Pessoa que traz clientes e gerencia seus sites. O corretor de imóveis
cliente Cliente Pessoa que tem o site e gerencia seus arquivos. O morador do prédio

Fonte: db.php, tabela "usuarios", campo "nivel" (linhas 17-27)

05. O que cada pessoa faz no sistema?

admin Administrador

URLs de acesso:

parceiro Parceiro / Coordenador

URLs de acesso:

cliente Cliente

URLs de acesso:

06. Diagrama de Componentes

┌─────────────────────────────────────────────────────────────────────────┐ │ INTERNET │ │ │ │ [Usuário no Navegador] ──── https://starhosting.com.br ──────┐ │ │ [Celular/PWA] ──────── https://ai.ckvm.duckdns.org ──────┐ │ │ └─────────────────────────────────────────────────────────────┼──┼───────┘ │ │ ┌─────────────────────────────────────────────────────────────┼──┼───────┐ │ SERVIDOR (Oracle Cloud ARM) │ │ │ │ IP: 137.131.229.136 │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────┐ ┌────────────────────────┘ │ │ │ │ NGINX │ │ │ │ │ │ (Servidor Web / Proxy) │ │ ┌─────────────────────────┐ │ │ │ │ │ │ │ FASTAPI (Python) │ │ │ │ │ - Escuta porta 443 (HTTPS) │ │ │ - Escuta porta 8080 │ │ │ │ │ - Redireciona 80 → 443 │ │ │ - API de IA │ │ │ │ │ - Bloqueia arquivos │ │ │ │ │ │ │ │ internos │ │ └────────────┬─────────────┘ │ │ │ │ - Proxy reverso para │ │ │ │ │ │ │ FastAPI (ai.*) │ │ │ │ │ │ └──────────┬──────────────────┘ │ │ │ │ │ │ │ │ │ │ │ ▼ │ ▼ │ │ │ ┌─────────────────────┐ │ ┌─────────────────────────┐ │ │ │ │ PHP-FPM │ │ │ OLLAMA │ │ │ │ │ (Processador PHP) │ │ │ (Motor de IA Local) │ │ │ │ │ │ │ │ │ │ │ │ │ - Roda código PHP │ │ │ - Modelo: Qwen2.5-VL │ │ │ │ │ - Gerencia sessões │ │ │ - 3B parâmetros │ │ │ │ │ - Acessa banco │ │ │ - ~5GB RAM │ │ │ │ └──────────┬───────────┘ │ │ - 2 threads │ │ │ │ │ │ └─────────────────────────┘ │ │ │ ▼ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ SQLITE │ │ │ │ │ │ (Banco de Dados) │ │ │ │ │ │ │ │ │ │ │ │ - 1 arquivo .db │ │ │ │ │ │ - 5 tabelas │ │ │ │ │ │ - Sem servidor │ │ │ │ │ │ separado │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ LET'S ENCRYPT │ │ │ │ │ │ (Certificado SSL) │ │ │ │ │ │ │ │ │ │ │ │ - Wildcard: *.star- │ │ │ │ │ │ hosting.com.br │ │ │ │ │ │ - Auto-renovação │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ └────────────────────────────────────┴────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────┘

O que acontece quando você visita um site?

  1. Você digita starhosting.com.br no navegador.
  2. O DNS (Domain Name System) traduz o endereço para o IP 137.131.229.136.
  3. O Nginx recebe a requisição na porta 443 (HTTPS).
  4. Se for uma página PHP (como /admin), o Nginx envia para o PHP-FPM.
  5. O PHP-FPM executa o código, acessa o SQLite, e devolve o HTML.
  6. O navegador mostra a página para você.

07. Tecnologias Utilizadas

Camada Tecnologia Para que serve
Servidor Web Nginx (pronuncia "engine-x") Recebe pedidos da internet e mostra páginas. É o "porteiro" do servidor.
Processamento PHP-FPM (pronuncia "PHP FastCGI Process Manager") Executa o código PHP. É o "cozinheiro" que prepara as páginas.
Banco de Dados SQLite3 Guarda informações (usuários, sites, logs). É o "caderninho" do sistema.
Backend PHP 8.x (sem framework) Linguagem do sistema. Código puro, sem bibliotecas complexas.
API de IA FastAPI (Python) + Ollama Executa modelos de inteligência artificial para análise de imagens.
Modelo de IA Qwen2.5-VL 3B (3.8B params, Q4_K_M) Modelo de visão computacional. Analisa imagens e detecta objetos.
Email PHPMailer + Brevo SMTP Envia emails transacionais (confirmação, notificação).
SSL/TLS Let's Encrypt (wildcard) Criptografa a comunicação (HTTPS). Certificado para todos os subdomínios.
DNS Cloudflare DNS Traduz domínios em IPs. Cache DNS global.
Servidor Oracle Cloud Free Tier (ARM) 4 OCPUs ARM (Neoverse-N1), 23GB RAM, Ubuntu 24.04.

Fonte: CHANGELOG.md (linhas 1-50), config.php, main.py

08. Estrutura de Diretórios

/var/www/ ├── gerenciador/ # ← O painel principal (PHP) │ ├── .env # ← Credenciais (NUNCA exponha!) │ ├── .env.example # ← Modelo de .env │ ├── CHANGELOG.md # ← Histórico de alterações │ ├── STARHOSTING_OQueE.html # ← Este documento │ ├── database.db # ← Banco de dados SQLite │ ├── php/ # ← Código-fonte PHP │ │ ├── config.php # ← Configurações globais │ │ ├── db.php # ← Conexão com banco │ │ ├── auth.php # ← Autenticação │ │ ├── functions.php # ← Funções auxiliares │ │ ├── login.php # ← Página de login │ │ ├── logout.php # ← Logout │ │ ├── admin/ # ← Painel do Admin │ │ │ ├── index.php # ← Dashboard │ │ │ ├── clientes.php # ← Gerenciar clientes │ │ │ ├── coordenadores.php # ← Gerenciar parceiros │ │ │ ├── sites.php # ← Gerenciar sites + Ferramentas │ │ │ ├── logs.php # ← Logs de atividade │ │ │ ├── api/ │ │ │ │ └── tools.php # ← API de ferramentas (JSON) │ │ │ └── site/ │ │ │ └── dominio.php # ← Configurar domínio │ │ ├── painel/ # ← Painel do Parceiro │ │ │ ├── index.php │ │ │ ├── clientes.php │ │ │ ├── sites.php │ │ │ └── site/ │ │ │ └── dominio.php │ │ ├── parceiro/ # ← Cópia do painel (atalho) │ │ ├── cliente/ # ← Painel do Cliente │ │ │ ├── index.php │ │ │ ├── site.php │ │ │ ├── upload.php │ │ │ ├── delete.php │ │ │ ├── template.php │ │ │ ├── editar.php │ │ │ ├── notificacoes.php │ │ │ ├── logs.php │ │ │ └── site/ │ │ │ └── dominio.php │ │ ├── api/ │ │ │ ├── notificacoes.php # ← Badge de notificações │ │ │ └── stats.php # ← Estatísticas do dashboard │ │ ├── functions/ │ │ │ └── email.php # ← PHPMailer + Brevo │ │ ├── static/ # ← CSS, JS (cache 30 dias) │ │ └── pwa/ # ← Service Worker, manifest │ ├── templates/ # ← Templates de sites │ │ ├── restaurante/ │ │ ├── loja/ │ │ ├── portfolio/ │ │ ├── escritorio/ │ │ └── saude/ │ ├── tests/ # ← Testes automatizados │ │ ├── run_all.sh │ │ ├── api/ │ │ │ ├── endpoints_test.sh │ │ │ ├── tools_noauth_test.sh │ │ │ └── tools_auth_test.sh │ │ ├── helpers/ │ │ │ └── auth.sh │ │ ├── .env │ │ ├── MANUAL_TESTS.md │ │ ├── RELATORIO_VALIDACAO.md │ │ ├── RELATORIO_VALIDACAO_HONESTO.md │ │ └── AUDITORIA_PROTOCOLO_VERDADE.md │ └── vendor/ # ← Dependências PHP (Composer) │ └── phpmailer/ │ ├── sites/ # ← Sites dos clientes │ ├── site1/ │ │ ├── index.html │ │ └── ... │ ├── site2/ │ └── ... │ ├── ai-api/ # ← API de IA (FastAPI) │ ├── main.py # ← Ponto de entrada FastAPI │ ├── config.py # ← Configurações Ollama │ ├── requirements.txt │ ├── api/ │ │ └── models/ │ │ ├── imagem.py │ │ ├── inventario.py │ │ └── chat.py │ ├── services/ │ │ └── ollama.py │ └── utils/ │ ├── auth.py │ └── database.py │ ├── main/ # ← Página estática (landing page) │ └── index.html │ ├── run_tests.sh # ← Executa todos os testes └── corrigir_tudo.sh # ← Script original de correção

09. Banco de Dados (SQLite)

Analogia

SQLite é como um caderno de anotações. Tudo fica guardado em um único arquivo (database.db), não precisa de um servidor separado. É leve, rápido e perfeito para sistemas pequenos.

Tabela: usuarios (quem usa o sistema)

CampoTipoO que guarda
idINTEGER (chave primária)Número único do usuário
emailTEXT (único, não nulo)Email de login
senha_hashTEXT (não nulo)Senha criptografada (bcrypt)
nomeTEXT (não nulo)Nome completo
nivelTEXT (admin/parceiro/cliente)Tipo de usuário
coordenador_idINTEGER (chave estrangeira)ID do parceiro dono (para clientes)
ativoINTEGER (0 ou 1)Se a conta está ativa
criado_emTIMESTAMPData de criação

Fonte: db.php, linhas 17-27

Tabela: sites (os sites criados)

CampoTipoO que guarda
idINTEGER (chave primária)Número único do site
dominioTEXT (único, não nulo)Endereço do site (ex: meusite.com.br)
subpastaTEXT (único, não nulo)Pasta no servidor (ex: site_abc123)
tierTEXT (basic/premium/business)Plano do site
cliente_idINTEGER (chave estrangeira)ID do cliente dono
coordenador_idINTEGER (chave estrangeira)ID do parceiro
ssl_ativoINTEGER (0 ou 1)Se tem HTTPS ativo
php_ativoINTEGER (0 ou 1)Se PHP está habilitado
statusTEXT (ativo/suspenso)Estado do site
criado_emTIMESTAMPData de criação

Fonte: db.php, linhas 29-42

Tabela: logs_acao (registro de ações)

CampoTipoO que guarda
idINTEGERNúmero do log
usuario_idINTEGERQuem fez a ação
acaoTEXTO que foi feito (ex: "login", "criar_site")
detalhesTEXTInformações extras
ip_addressTEXTIP de onde veio o pedido
criado_emTIMESTAMPQuando aconteceu

Fonte: db.php, linhas 44-52

Tabela: notificacoes (avisos para o usuário)

CampoTipoO que guarda
idINTEGERNúmero da notificação
usuario_idINTEGERPara quem é
tituloTEXTTítulo da mensagem
mensagemTEXTCorpo da mensagem
lidaINTEGER (0 ou 1)Se já foi lida
criado_emTIMESTAMPQuando foi criada

Fonte: db.php, linhas 54-62

Tabela: templates (modelos de site)

CampoTipoO que guarda
idINTEGERNúmero do template
nomeTEXTNome (ex: "restaurante")
descricaoTEXTBreve descrição
arquivo_zipTEXTArquivo ZIP do template
preview_urlTEXTURL de preview
tier_minimoTEXTTier mínimo necessário (basic/premium/business)

Fonte: db.php, linhas 64-71

Relacionamento entre tabelas

┌──────────────┐ ┌──────────────┐ │ usuarios │ │ sites │ ├──────────────┤ ├──────────────┤ │ id (PK) │◄────────│ cliente_id │ ← 1 cliente tem N sites │ email │ │ coordenador_id│ ← 1 parceiro tem N sites │ senha_hash │ │ dominio │ │ nome │ │ tier │ │ nivel │ │ ssl_ativo │ │ coordenador_id│←─┐ │ status │ │ ativo │ │ └──────────────┘ └──────────────┘ │ │ │ └───────────┘ ← 1 parceiro tem N clientes ┌──────────────┐ ┌──────────────┐ │ usuarios │ │ logs_acao │ ├──────────────┤ ├──────────────┤ │ id (PK) │◄────────│ usuario_id │ ← 1 usuário tem N logs └──────────────┘ └──────────────┘ ┌──────────────┐ ┌──────────────┐ │ usuarios │ │ notificacoes │ ├──────────────┤ ├──────────────┤ │ id (PK) │◄────────│ usuario_id │ ← 1 usuário tem N notificações └──────────────┘ └──────────────┘

10. Autenticação e Sessões

Analogia

Autenticação é como mostrar sua identidade na porta de um prédio. Quando você faz login, o sistema verifica se seu email e senha estão corretos. Se estiverem, ele dá um "crachá" (session) que prova que você é quem diz ser.

Como funciona o fluxo de login?

[Usuário] [Servidor] [Banco] │ │ │ │ 1. Digita email + senha │ │ │ ──────────────────────────>│ │ │ │ 2. Busca usuário por email │ │ │ ────────────────────────────>│ │ │ │ │ │ 3. Retorna: id, senha_hash │ │ │ <────────────────────────────│ │ │ │ │ │ 4. Compara senha digitada │ │ │ com senha_hash (bcrypt) │ │ │ │ │ 5. Se OK: cria sessão │ │ │ redireciona para │ │ │ /admin ou /painel │ │ │ <──────────────────────────│ │ │ │ │

O que é bcrypt?

BCrypt é um algoritmo de criptografia que transforma sua senha em uma sequência de caracteres que NINGUÉM consegue decifrar. Mesmo se alguém roubar o banco de dados, não vai conseguir ver sua senha.

Exemplo:

Senha digitadaO que fica salvo no banco
Windows@98$2y$10$... (80 caracteres ilegíveis)

Código PHP que faz isso:

// Auth.php - Função login()
function login($email, $senha) {
    $db = getDB();
    $stmt = $db->prepare('SELECT * FROM usuarios WHERE email = :email AND ativo = 1');
    $stmt->bindValue(':email', $email, SQLITE3_TEXT);
    $result = $stmt->execute();
    $user = $result->fetchArray(SQLITE3_ASSOC);
    
    // password_verify() compara a senha digitada com o hash salvo
    if ($user && password_verify($senha, $user['senha_hash'])) {
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['user_nome'] = $user['nome'];
        $_SESSION['user_email'] = $user['email'];
        $_SESSION['user_nivel'] = $user['nivel'];
        $_SESSION['user_coordenador_id'] = $user['coordenador_id'];
        return $user['nivel']; // Retorna "admin", "parceiro" ou "cliente"
    }
    return false; // Senha errada ou usuário inativo
}

Fonte: auth.php, linhas 4-23

Como o sistema protege as páginas?

Existem 3 funções de proteção:

FunçãoProtege para quem?O que faz?
requireLogin() Qualquer usuário logado Se não estiver logado, redireciona para /login
requireAdmin() Apenas admins Se não for admin, redireciona para /login
requireCoordOrAdmin() Parceiros + admins Se não for nenhum dos dois, redireciona para /login

Fonte: auth.php, linhas 38-65

11. Sistema de Tiers (Planos)

Analogia

Tiers são como planos de celular: o plano básico dá para pouca coisa, o plano premium dá para mais, e o plano business dá para tudo. Cada plano tem limites diferentes.

Recurso Basic R$9,90/mês Premium R$19,90/mês Business R$39,90/mês
Sites 1 3 5
Espaço em disco 512 MB 2 GB (2048 MB) 10 GB (10240 MB)
PHP ❌ Não ✅ Sim ✅ Sim
SQLite ❌ Não ✅ Sim ✅ Sim
WordPress ❌ Não ❌ Não ✅ Sim

Fonte: config.php, linhas 19-23

Como o código valida os limites?

// functions.php - Verificar limite de sites
function checkSiteLimit($cliente_id, $tier) {
    $config = getConfig();
    $limit = $config['tier_limits'][$tier]['sites'] ?? 0;
    $db = getDB();
    $current = (int)$db->querySingle(
        "SELECT COUNT(*) FROM sites WHERE cliente_id = $cliente_id"
    );
    return $current < $limit; // true se pode criar mais
}

// functions.php - Verificar espaço em disco
function checkDiskLimit($cliente_id, $tier) {
    $config = getConfig();
    $limit_mb = $config['tier_limits'][$tier]['disco_mb'] ?? 0;
    $used_mb = calculateDiskUsage($cliente_id);
    return $used_mb < $limit_mb;
}

Fonte: functions.php, linhas 179-211

12. Templates de Sites

Templates são modelos prontos de site. Quando um cliente cria um site, ele pode escolher um template e o sistema gera o HTML automaticamente.

Templates disponíveis (Tier Basic)

TemplateDescriçãoPasta
restauranteSite para restaurantes/var/www/gerenciador/templates/restaurante/
lojaSite para lojas/var/www/gerenciador/templates/loja/
portfolioSite para portfólio/var/www/gerenciador/templates/portfolio/
escritorioSite para escritórios/var/www/gerenciador/templates/escritorio/
saudeSite para clínicas/saúde/var/www/gerenciador/templates/saude/

Fonte: CHANGELOG.md (linhas 44-50)

13. Sistema de Email

O sistema usa PHPMailer para enviar emails via Brevo SMTP (antigo Sendinblue).

Analogia

Enviar email é como mandar uma carta. Você escreve (conteúdo HTML), coloca no envelope (destinatário), e o carteiro (SMTP) entrega. O Brevo é o carteiro digital do StarHosting.

Configuração SMTP

ConfiguraçãoValorO que é
Servidor SMTPsmtp-relay.brevo.comEndereço do "carteiro digital"
Porta587 (STARTTLS)Porta segura para envio
Usuárioad1b03001@smtp-brevo.comLogin no Brevo
Senhaxsmtpsib-...API key (não é senha normal)
Email remetenteadmin@starhosting.com.brDe quem é o email
Email suportesuporte@starhosting.com.brPara emails de suporte
Email noreplynoreply@starhosting.com.brPara emails automáticos

Fonte: .env, linhas 6-12

Como enviar um email (código PHP)

// Importar a função
require_once __DIR__ . '/functions/email.php';

// Enviar email simples
sendEmail(
    'cliente@email.com',           // Destinatário
    'Bem-vindo ao StarHosting',    // Assunto
    '<h1>Olá!</h1><p>Seu site foi criado.</p>',  // Corpo HTML
    'admin'                        // Remetente (admin/suporte/noreply)
);

// Enviar email de suporte
sendEmail(
    'cliente@email.com',
    'Seu ticket foi respondido',
    '<p>Sua solicitação foi atendida.</p>',
    'suporte'
);

Remetentes disponíveis

RemetenteEmailUso
adminadmin@starhosting.com.brEmails administrativos, boas-vindas
suportesuporte@starhosting.com.brSuporte ao cliente
noreplynoreply@starhosting.com.brNotificações automáticas

Fluxo de envio

[Código PHP] [PHPMailer] [Brevo SMTP] [Destinatário] │ │ │ │ │ sendEmail() │ │ │ │ ──────────────────>│ │ │ │ │ Conecta SMTP │ │ │ │ porta 587 │ │ │ │ ────────────────────>│ │ │ │ │ │ │ │ Envia email │ │ │ │ ────────────────────>│ │ │ │ │ Entrega email │ │ │ │ ──────────────────>│ │ │ │ │

Arquivo de configuração

A função sendEmail() está em:

/var/www/gerenciador/php/functions/email.php

Fonte: functions/email.php (60 linhas)

14. PWA (App Instalável)

Analogia

PWA (Progressive Web App) é como transformar um site em um aplicativo de celular. Você abre o site uma vez, instala ele, e depois aparece como um ícone no celular, igual um app normal.

O StarHosting tem suporte a PWA com:

Arquivos do PWA

ArquivoO que fazConfigurações importantes
pwa/manifest.json Configura o "app" — nome, ícone, cores name: "StarHosting", display: "standalone", theme_color: "#10b981"
pwa/sw.js Service Worker — cacheia páginas para offline Salva páginas principais no cache, depois serve do cache primeiro

Como funciona o Service Worker

// Quando instala, salva páginas principais no cache
self.addEventListener('install', e => {
  e.waitUntil(
    caches.open('starhosting-v1').then(cache => {
      return cache.addAll([
        '/painel',          // Página do painel
        '/admin',           // Página do admin
        '/static/style.css' // CSS do sistema
      ]);
    })
  );
});

// Quando visita uma página, primeiro tenta cache
self.addEventListener('fetch', e => {
  e.respondWith(
    caches.match(e.request).then(resp => {
      return resp || fetch(e.request);  // Cache ou rede
    })
  );
});

Fonte: pwa/sw.js (69 linhas)

Como instalar no celular

  1. Abra starhosting.com.br no Chrome do celular
  2. Toque no botão "⋮" (três pontos) no canto superior direito
  3. Toque em "Adicionar à tela inicial"
  4. Confirme o nome e toque em "Adicionar"
  5. Pronto! Agora tem um ícone do StarHosting na tela do celular

15. Domínios e SSL

Domínios configurados

DomínioPara que serveDNS
starhosting.com.br Painel principal (domínio primário) Cloudflare
www.starhosting.com.br Alias do painel (301 redirect) Cloudflare
ckvm.duckdns.org Redireciona para starhosting.com.br (exceto api/ai) DuckDNS
api.ckvm.duckdns.org Endpoints de API (mantido por compatibilidade) DuckDNS
ai.ckvm.duckdns.org API de IA (FastAPI + Ollama) DuckDNS

Fonte: CHANGELOG.md (linhas 34-38)

SSL (Certificado de Segurança)

PropriedadeValor
TipoWildcard (*.starhosting.com.br)
EmissorLet's Encrypt
Validade28/08/2026
DesafioDNS-01 via Cloudflare
Auto-renovaçãoSim (certbot + cron)

Fonte: config.php (linhas 10-11), /etc/nginx/sites-available/starhosting (linhas 13-14)

Segurança do Nginx

O Nginx bloqueia acesso a arquivos internos:

# Bloquear arquivos internos
location ~ ^/(config|functions|auth|db)\.php$ { deny all; }
location ~ ^/includes/ { deny all; }
location ~ /\. { deny all; }                    # Arquivos ocultos
location ~ \.(db|sqlite|env)$ { deny all; }    # Banco e config

Fonte: /etc/nginx/sites-available/starhosting (linhas 38-41)

16. Visão Geral dos Endpoints

O StarHosting tem 3 domínios com 2 backends diferentes:

DomínioBackendAutenticação
starhosting.com.br PHP (Nginx + PHP-FPM) Session (cookie)
ai.ckvm.duckdns.org FastAPI (Python, porta 8080) X-API-Key (header)

Total de endpoints: 44 (27 páginas HTML + 6 JSON PHP + 4 JSON FastAPI + 3 static + 2 debug + 2 auth)

17. Autenticação da API

Analogia

Autenticação é como mostrar um crachá para entrar. Se você é funcionário (usuário logado), o crachá (sessão) está na sua bolsa (cookie). Se é fornecedor (API externa), precisa de uma chave especial (API Key) que só o dono da loja tem.

PHP (starhosting.com.br) — Sessões

Usa sessões PHP (cookies). Quando o usuário faz login, o servidor cria uma sessão e guarda os dados do usuário. O navegador envia o cookie de sessão automaticamente a cada pedido.

// Como funciona internamente:
// 1. Usuário envia email + senha
// 2. Servidor verifica no banco (SQLite)
// 3. Se correto, cria sessão com dados do usuário
// 4. Envia cookie "PHPSESSID" para o navegador
// 5. Navegador envia cookie a cada pedido
// 6. Servidor lê cookie e sabe quem é o usuário

// Exemplo de como verificar login:
if (!isLoggedIn()) {
    // Não está logado → redirecionar para login
    header('Location: /login');
    exit;
}

// Exemplo de como verificar se é admin:
requireAdmin();  // Redireciona se não for admin

Fonte: auth.php (login(), isLoggedIn(), requireAdmin())

FastAPI (ai.ckvm.duckdns.org) — API Key

Usa API Key no header X-API-Key. A chave é validada contra a variável de ambiente INTERNAL_API_KEY.

// Como funciona internamente:
// 1. Cliente envia request com header X-API-Key
// 2. FastAPI lê a variável de ambiente INTERNAL_API_KEY
// 3. Compara as duas chaves
// 4. Se forem iguais, processa o pedido
// 5. Se forem diferentes, retorna erro 401

// Exemplo de chamada com curl:
curl -X POST https://ai.ckvm.duckdns.org/api/v1/analise \
  -H "Content-Type: application/json" \
  -H "X-API-Key: 2c33bb2a66d7e1aa96f262d9d9429edc47e53ca6e167dbc30894c935a93d687" \
  -d '{"id_camera": "cam01", "imagem_base64": "..."}'

Fonte: ai-api/main.py (middleware de autenticação)

Comparação dos dois sistemas

AspectoPHP (Sessão)FastAPI (API Key)
Onde é armazenadoCookie no navegadorHeader do pedido
Expira?Sim, após inatividadeNão expira
Quem usaUsuários do painel (admin, parceiro, cliente)Aplicações externas (câmeras, IoT)
Como revogarDeletar sessão no servidorMudar a API_KEY no .env

18. Login/Logout

Analogia

Login é como entrar na sua casa. Você mostra a chave (email + senha), a porta abre (sessão criada), e agora pode circular pela casa (painel). Logout é trancar a porta e jogar a chave fora.

Endpoints de autenticação

MétodoURLAuthRolesO que faz
GET /login Nenhuma Público Mostra formulário de login
POST /login Nenhuma Público Autentica email+senha, cria sessão
GET /logout Session Qualquer logado Destroi sessão, redireciona para /
GET /admin/login Nenhuma Público Mostra formulário de login admin

Fluxo completo de login

[Navegador] [Servidor PHP] [SQLite DB] │ │ │ │ POST /login │ │ │ email + senha │ │ │ ────────────────────>│ │ │ │ SELECT * FROM │ │ │ usuarios WHERE │ │ │ email = '...' │ │ │ ────────────────────>│ │ │ │ │ │ Retorna usuário │ │ │ <────────────────────│ │ │ │ │ Verifica senha │ │ password_verify() │ │ │ │ Cria sessão: │ │ $_SESSION['user_id'] │ │ $_SESSION['user_nivel'] │ │ │ Cookie: PHPSESSID │ │ <────────────────────│ │ │ │ Redireciona para │ │ /painel ou /admin │ │ <────────────────────│ │ │

Fluxo de logout

// O que acontece quando você clica em "Sair":
// 1. Navegador envia GET /logout
// 2. Servidor destroi a sessão (session_destroy())
// 3. Servidor redireciona para /
// 4. Navegador perde o cookie PHPSESSID
// 5. Usuário não está mais logado

// Código simplificado:
session_start();
session_destroy();           // Destroi a sessão
header('Location: /');       // Redireciona para home
exit;

Onde cada perfil vai após login

NívelRedireciona paraO que pode ver
admin/adminPainel admin completo: config, clientes, templates, ferramentas
coordenador/coordGerenciar seus próprios clientes e sites
cliente/painelVer e gerenciar seus próprios sites

Fonte: auth.php (login(), logout()), login.php, logout.php

POST /admin/login Nenhuma Público Autentica apenas users admin

Fonte: login.php, logout.php, admin/login.php

19. Painel Admin (HTML)

MétodoURLAuthO que faz
GET/admin/AdminDashboard: contadores de parceiros, clientes, sites, logs
GET/admin/clientesAdminLista todos os clientes
POST/admin/clientesAdminCria novo cliente
GET/admin/clientes?toggle=XAdminAtiva/desativa cliente
GET/admin/coordenadoresAdminLista todos os parceiros
POST/admin/coordenadoresAdminCria novo parceiro
GET/admin/coordenadores?toggle=XAdminAtiva/desativa parceiro
GET/admin/sitesAdminLista todos os sites + Ferramentas
POST/admin/sitesAdminCria novo site (automatizado)
GET/admin/site/dominio?id=XAdminConfigura domínio do site
POST/admin/site/dominio?id=XAdminSalva configuração de domínio
GET/admin/logsAdminÚltimos 100 logs de atividade

Fonte: admin/index.php, admin/clientes.php, admin/sites.php, admin/logs.php

20. Admin API JSON (tools.php)

URL: /admin/api/tools.php?action=X

Método: GET

Auth: Admin (session)

Resposta: JSON

AçãoDescriçãoComando usado
fix_permsCorrige owner/permissoes em /var/wwwchown + chmod 2775
fix_allReparo completo (6 passos)chown, chmod dirs, chmod files, g+s, nginx -t, restart
get_server_statusStats do servidorstat, free, uptime, ls, systemctl, openssl
get_nginx_configRetorna configs Nginxcat /etc/nginx/sites-available/*
get_ssl_certsLista certs SSL com validadels + openssl x509
restart_nginxTesta e reinicia Nginxnginx -t + systemctl restart
clear_cacheReinicia PHP-FPMsystemctl restart php-fpm
update_systemAtualiza sistemaapt update + apt upgrade
test_nginxTesta configuração Nginxnginx -t
check_sslVerifica SSL dos sites ativosopenssl x509 -checkend
check_diskUso de disco total + top 10df -h + du
check_logsÚltimas 30 linhas do log de errotail /var/log/nginx/error.log
check_statusStatus Nginx + PHP-FPM + discosystemctl is-active + df
clean_logsLimpa logs antigos + vacuum journaljournalctl --vacuum-time
backup_dbCopia database para backupcp database.db /home/ubuntu/Downloads/
list_backupsLista backups disponíveisglob('/home/ubuntu/Downloads/database-*.db')
restore_db?file=XRestaura database de backupcp backup → database.db

Fonte: admin/api/tools.php (197 linhas)

Exemplo de resposta JSON (get_server_status)

{
    "ok": true,
    "owner": "ubuntu:www-data",
    "perms": "2775",
    "nginx": "active",
    "php": "active",
    "disk": {
        "total": "193G",
        "used": "21G",
        "percent": "11%"
    },
    "ram": {
        "total": "23Gi",
        "used": "7.1Gi",
        "free": "15Gi"
    },
    "uptime": "2 days, 3:45",
    "ssl_certs": 3,
    "sites": 3
}

Função runLocal() vs run()

FunçãoUsa sudo?Para que serve?
runLocal($cmd)NãoComandos de leitura: stat, free, uptime, ls, wc
run($cmd)Sim (/bin/sudo)Comandos privilegiados: chown, chmod, find, systemctl, nginx, openssl
runBg($cmd)Sim (background)Comandos que demoram: systemctl restart

21. Painel Parceiro

Analogia

Parceiro é como um revendedor. Ele compra o produto do dono da loja (admin) e revende para seus próprios clientes. O parceiro só vê seus clientes, não vê os clientes de outros parceiros.

Quem pode acessar?

NívelPode acessar?O que vê
adminSimTODOS os clientes e sites (pode gerenciar tudo)
coordenador (parceiro)SimApenas SEUS clientes e sites (não vê de outros parceiros)
clienteNão

Endpoints do Painel Parceiro

MétodoURLAuthO que faz
GET/painel/ ou /parceiro/Coord/AdminDashboard do parceiro (resumo de clientes e sites)
GET/painel/clientesCoord/AdminLista clientes (próprios para parceiro, todos para admin)
POST/painel/clientesCoord/AdminCria cliente (parceiro_id = usuário logado automaticamente)
GET/painel/sitesCoord/AdminLista sites do parceiro
POST/painel/sitesCoord/AdminCria site para parceiro
GET/painel/site/dominio?id=XCoord/AdminConfigura domínio do site
POST/painel/site/dominio?id=XCoord/AdminSalva configuração de domínio

Como o parceiro cria um cliente

// Quando o parceiro preenche o formulário e clica "Criar":
// 1. POST /painel/clientes com: nome, email, senha, tier
// 2. Sistema cria o usuário no banco SQLite
// 3. Automaticamente define coordenador_id = ID do parceiro logado
// 4. Envia email de boas-vindas para o novo cliente
// 5. Cliente pode acessar /painel com suas credenciais

// Código simplificado:
requireCoordOrAdmin();
$cliente_id = $_SESSION['user_id'];  // ID do parceiro logado
// ...
$stm->execute([
    $nome, $email, $senha_hash, $tier,
    $cliente_id  // ← Isso vincula o cliente ao parceiro
]);

Fonte: painel/site_create.php, painel/clientes.php

22. Painel Cliente

Analogia

Painel do cliente é como a área do cliente numa loja online. Você compra o produto (site), depois pode ver seus pedidos (sites), trocar a embalagem (template), enviar novos produtos (upload), e tudo mais — tudo sozinho, sem precisar ligar para o vendedor.

O que o cliente pode fazer?

AçãoO que acontece
Ver seus sitesLista todos os sites que ele tem
Ver detalhes de um siteMostra informações, arquivos e opções
Fazer upload de arquivosEnvia imagens, HTML, CSS para o site
Deletar arquivosRemove arquivos que não precisa mais
Aplicar templateTroca o visual do site (restaurante, loja, etc.)
Editar conteúdoAltera textos, cores, logos do site
Configurar domínioAponta um domínio personalizado para o site
Ver notificaçõesMensagens do sistema (site criado, etc.)
Ver logsHistórico das últimas 50 ações

Endpoints do Painel Cliente

MétodoURLAuthO que faz
GET/cliente/LoginLista sites do cliente
GET/cliente/site?id=XLogin+OwnerDetalhes do site + upload
POST/cliente/upload?site_id=XLogin+OwnerFaz upload de arquivo
GET/cliente/delete?site_id=X&arquivo=YLogin+OwnerDeleta arquivo do site
GET/cliente/template?id=XLogin+OwnerMostra templates disponíveis
POST/cliente/template?id=XLogin+OwnerAplica template ao site
GET/cliente/editar?id=XLogin+OwnerFormulário de edição
POST/cliente/editar?id=XLogin+OwnerSalva alterações + regenera site
GET/cliente/site/dominio?id=XLoginConfigura domínio
POST/cliente/site/dominio?id=XLoginSalva domínio
GET/cliente/notificacoesLoginLista notificações (marca como lida)
GET/cliente/logsLoginÚltimos 50 logs do usuário

O que significa "Login+Owner"?

O sistema verifica se o usuário está logado E se o site pertence a ele. Exemplo:

// cliente/site.php
requireLogin();
$site = getSiteById($_GET['id']);
if ($site['cliente_id'] != $_SESSION['user_id']) {
    // Este site NÃO é seu! Acesso negado.
    header('Location: /cliente/');
    exit;
}

Fonte: cliente/site.php, cliente/upload.php

23. API de IA (FastAPI)

Domínio: ai.ckvm.duckdns.org

Backend: FastAPI (Python)

Modelo: Qwen2.5-VL 3B (via Ollama)

MétodoEndpointAuthDescrição
GET/healthNenhumaHealth check (retorna modelo + status)
POST/api/v1/analiseX-API-KeyAnálise de imagens (bounding boxes, objetos)
POST/api/v1/inventarioX-API-KeyContagem de produtos por imagem
POST/api/v1/chatX-API-KeyChat com IA (multimodal com imagens)

Request body: /api/v1/analise

{
    "id_camera": "cam01",          // ID da câmera (obrigatório)
    "imagem_base64": "base64...",  // Imagem em Base64 (obrigatório)
    "formato": "jpeg",             // Formato da imagem (opcional, default: jpeg)
    "prompt_customizado": "..."    // Prompt personalizado (opcional)
}

Response: /api/v1/analise

{
    "status": "sucesso",
    "data_processamento": "2026-06-03T04:00:00",
    "tempo_execucao_segundos": 2.35,
    "total_objetos": 5,
    "resultado": {
        "total_objetos": 5,
        "objetos": [
            {
                "classe": "garrafa",
                "confianca": 0.95,
                "bounding_box": {"x1": 100, "y1": 200, "x2": 300, "y2": 500}
            }
        ]
    }
}

Request body: /api/v1/chat

{
    "id_sessao": "sessao_abc123",           // ID da sessão (qualquer string)
    "historico_mensagens": [                // Lista de mensagens (mínimo 1)
        {
            "role": "user",                 // "user" ou "assistant"
            "content": "Olá!",              // Texto da mensagem
            "images": ["base64..."]         // Opcional: imagens em base64
        }
    ],
    "num_ctx": 32768                        // Opcional: contexto do modelo (default 32768)
}

Campos do Request

CampoTipoObrigatórioDescrição
id_sessaostringSimIdentificador da sessão (uso interno, não afeta o modelo)
historico_mensagensarraySimLista de mensagens (mínimo 1). O modelo recebe TODAS as mensagens.
historico_mensagens[].rolestringSim"user" para mensagens do usuário, "assistant" para respostas da IA
historico_mensagens[].contentstringSimTexto da mensagem
historico_mensagens[].imagesarrayNãoLista de imagens em Base64 (opcional, para chat multimodal)
num_ctxintegerNãoJanela de contexto do modelo (default: 32768). Valores maiores usam mais RAM.

Response: /api/v1/chat

{
    "status": "sucesso",
    "id_sessao": "sessao_abc123",
    "data_resposta": "2026-06-03T07:00:00.123456",
    "mensagem_resposta": {
        "role": "assistant",
        "content": "Olá! Tudo bem sim, e você?"
    },
    "performance": {
        "eval_count": 12,
        "tokens_por_segundo": 7.5
    }
}

Campos do Response

CampoTipoDescrição
statusstring"sucesso" ou "erro"
id_sessaostringMesmo ID enviado no request
data_respostastringData/hora UTC da resposta (ISO 8601)
mensagem_respostaobjectResposta do modelo: role (sempre "assistant") + content (texto)
performanceobjectMétricas: eval_count (tokens gerados) + tokens_por_segundo

Exemplo de chamada (curl)

# Chat simples (texto)
curl -X POST http://localhost:8080/api/v1/chat \
  -H "Content-Type: application/json" \
  -H "X-API-Key: SUA_API_KEY_AQUI" \
  -d '{
    "id_sessao": "minha_sessao",
    "historico_mensagens": [
        {"role": "user", "content": "Olá, tudo bem?"}
    ]
  }'

# Chat com imagem (multimodal)
BASE64=$(base64 -w 0 minha_foto.jpg)
curl -X POST http://localhost:8080/api/v1/chat \
  -H "Content-Type: application/json" \
  -H "X-API-Key: SUA_API_KEY_AQUI" \
  -d "{
    \"id_sessao\": \"minha_sessao\",
    \"historico_mensagens\": [
        {
            \"role\": \"user\",
            \"content\": \"O que tem nesta imagem?\",
            \"images\": [\"$BASE64\"]
        }
    ]
  }"

Como funciona o fluxo

[Cliente] [FastAPI] [Ollama] │ │ │ │ POST /api/v1/chat │ │ │ {historico_mensagens} │ │ │ ──────────────────────────>│ │ │ │ POST /api/chat │ │ │ {model, messages, options}│ │ │ ──────────────────────────>│ │ │ │ │ │ processa todas as │ │ │ mensagens do histórico │ │ │ │ │ │ {response: "resposta"} │ │ │ <──────────────────────────│ │ │ │ │ {mensagem_resposta} │ │ │ <──────────────────────────│ │ │ │ │
Importante: Stateless (sem estado)
O servidor NÃO guarda histórico entre requests. A cada chamada, você deve enviar TODAS as mensagens anteriores. Se enviar apenas a última mensagem, o modelo não vai "lembrar" das anteriores.

Exemplo: Se o usuário já enviou 3 mensagens, o historico_mensagens deve conter as 3 + a nova.

Chat multimodal (com imagens)

O campo images aceita uma lista de strings Base64. Use isso para enviar imagens junto com o texto.

{
    "id_sessao": "analise_foto",
    "historico_mensagens": [
        {
            "role": "user",
            "content": "Analise esta imagem e descreva o que vê",
            "images": ["data:image/jpeg;base64,/9j/4AAQSkZJRg..."]
        }
    ],
    "num_ctx": 32768
}

Diferença entre /api/chat e /api/generate

EndpointUsoEntradaHistórico
/api/v1/chat Chat conversacional Lista de mensagens (historico_mensagens) Sim — modelo recebe todas as mensagens anteriores
/api/v1/analise Análise de imagem Uma imagem + prompt Não — processa apenas a imagem atual
/api/v1/inventario Contagem de produtos Uma imagem + prompt Não — processa apenas a imagem atual

Configuração do modelo (Ollama)

ParâmetroValorO que faz
modelqwen2.5vl:3bModelo de visão (3.8B parâmetros)
temperature0.0Respostas sempre iguais (determinístico)
num_thread22 threads CPU (otimizado para ARM)
num_ctx8096Janela de contexto do modelo
keep_alive-1Modelo fica carregado permanentemente
flash_attention1Acelera processamento (economiza RAM)

Fonte: ai-api/config.py, CHANGELOG.md (linhas 14-24)

Resultados Reais da API de Visão

10 imagens reais processadas pela API em 03/06/2026. Cada imagem foi enviada para o modelo qwen2.5vl:3b via /api/v1/analise.

Nota sobre qualidade: O modelo Qwen2.5-VL 3B (Q4_K_M, CPU ARM) tem limitações de precisão. Bounding boxes podem estar desalinhados. O resultado é um protótipo, não um produto final.
ImagemObjetos DetectadosTempoDescrição
10 carros 129s Cena urbana com múltiplos carros em estacionamento/rua
10+ pessoas 246s Multidão de pedestres em rua movimentada
10+ pessoas 246s Grupo de pessoas em ambiente externo
3 pessoas, 2 motos 165s Pessoas e motocicletas em rua
Pessoas, 2 motos 148s Cena com motocicletas e pedestres
1 carro + objetos 245s Carro em estacionamento com múltiplos objetos
20+ pessoas 246s Grupo grande de pessoas em evento/rua
1 carro 124s Carro isolado em cena
1 pessoa 135s Pessoa em plano próximo
1 supermercado 17s Fachada de supermercado/loja

Exemplo de resposta JSON real (pic08.jpg — 1 carro detectado)

{
    "status": "sucesso",
    "data_processamento": "2026-06-03T06:54:25.755305",
    "tempo_execucao_segundos": 123.58,
    "total_objetos": 0,
    "resultado": {
        "raw_response": "```json\n{\n  \"objetos\": [\n    {\n      \"nome\": \"carro\",\n      \"coordenadas\": [217, 210, 330, 332],\n      \"confianca\": 0.9\n    }\n  ],\n  \"total\": 1\n}\n```"
    }
}

Exemplo de resposta JSON real (pic04.jpg — 3 pessoas + 2 motos)

{
    "status": "sucesso",
    "data_processamento": "2026-06-03T06:41:43.013860",
    "tempo_execucao_segundos": 165.19,
    "resultado": {
        "raw_response": "```json\n{\n  \"objetos\": [\n    {\n      \"nome\": \"pessoa\",\n      \"coordenadas\": [\n        [79, 100, 156, 310],\n        [161, 94, 293, 326],\n        [282, 104, 408, 330]\n      ],\n      \"confianca\": 0.9\n    },\n    {\n      \"nome\": \"motocicleta\",\n      \"coordenadas\": [\n        [156, 154, 294, 328],\n        [282, 159, 408, 330]\n      ],\n      \"confianca\": 0.9\n    }\n  ],\n  \"total\": 2\n}\n```"
    }
}

Resumo dos tempos de processamento

ImagemTempo (s)Status
pic01.jpg129OK
pic02.jpg246OK
pic03.jpg246OK
pic04.jpg165OK
pic05.jpg148OK
pic06.jpg245OK
pic07.jpg246OK
pic08.jpg124OK
pic09.jpg135OK
pic10.jpg17OK

Tempo médio: ~170 segundos (2 min 50s) por imagem em CPU ARM.

24. Tabela Resumo de Todos os Endpoints

#MétodoEndpointAuthRolesTipo
1GET/POST/loginNenhumaPúblicoHTML
2GET/logoutSessionQualquerRedirect
3GET/POST/admin/loginNenhumaPúblicoHTML
4GET/admin/AdminadminHTML
5GET/POST/admin/clientesAdminadminHTML
6GET/admin/clientes?toggle=XAdminadminHTML
7GET/POST/admin/coordenadoresAdminadminHTML
8GET/admin/coordenadores?toggle=XAdminadminHTML
9GET/POST/admin/sitesAdminadminHTML
10GET/POST/admin/site/dominio?id=XAdminadminHTML
11GET/admin/logsAdminadminHTML
12GET/admin/api/tools.php?action=XAdminadminJSON
13GET/painel/Coord/Adminparceiro, adminHTML
14GET/POST/painel/clientesCoord/Adminparceiro, adminHTML
15GET/POST/painel/sitesCoord/Adminparceiro, adminHTML
16GET/POST/painel/site/dominio?id=XCoord/Adminparceiro, adminHTML
17GET/cliente/LoginclienteHTML
18GET/cliente/site?id=XLogin+OwnerclienteHTML
19POST/cliente/upload?site_id=XLogin+OwnerclienteRedirect
20GET/cliente/delete?site_id=X&arquivo=YLogin+OwnerclienteRedirect
21GET/POST/cliente/template?id=XLogin+OwnerclienteHTML
22GET/POST/cliente/editar?id=XLogin+OwnerclienteHTML
23GET/POST/cliente/site/dominio?id=XLoginclienteHTML
24GET/cliente/notificacoesLoginclienteHTML
25GET/cliente/logsLoginclienteHTML
26GET/api/notificacoes.phpSessionQualquer logadoJSON
27GET/api/stats.phpAdminadminJSON
28GET/healthNenhumaPúblicoJSON
29POST/api/v1/analiseX-API-KeyInternoJSON
30POST/api/v1/inventarioX-API-KeyInternoJSON
31POST/api/v1/chatX-API-KeyInternoJSON

25. Como Rodar o Sistema

Analogia

Rodar o sistema é como ligar uma TV. Você precisa verificar se a TV está ligada (status), se tem sinal (configuração), e se o canal está funcionando (serviços). Se algo der errado, você precisa saber qual botão apertar (comando).

Verificar status dos serviços

# Verificar Nginx (servidor web)
sudo systemctl status nginx
# Deve mostrar: Active: active (running)

# Verificar PHP-FPM (executa código PHP)
sudo systemctl status php8.3-fpm
# Deve mostrar: Active: active (running)

# Verificar Ollama (inteligência artificial)
systemctl status ollama
# Deve mostrar: Active: active (running)

# Verificar FastAPI (API de IA)
systemctl status ai-api
# Deve mostrar: Active: active (running)

# Verificar disco (quanto espaço sobrou)
df -h
# Deve mostrar: /dev/sda1  11% used (21G/193G)

# Verificar RAM (quanta memória está usando)
free -h
# Deve mostrar: 7.1Gi/23Gi used

Reiniciar serviços

# Reiniciar Nginx (se o site não carrega)
sudo systemctl restart nginx

# Reiniciar PHP-FPM (se o PHP não executa)
sudo systemctl restart php8.3-fpm

# Reiniciar Ollama (se a IA não responde)
sudo systemctl restart ollama

# Reiniciar FastAPI (se a API de IA não responde)
sudo systemctl restart ai-api

Verificar logs (quando algo dá errado)

# Logs do Nginx (erros de servidor web)
sudo tail -f /var/log/nginx/error.log

# Logs do Nginx (quem acessou o site)
sudo tail -f /var/log/nginx/access.log

# Logs do PHP (erros de código PHP)
sudo tail -f /var/log/php8.3-fpm.log

# Logs do Ollama (erros da IA)
journalctl -u ollama -f

# Logs do FastAPI (erros da API de IA)
journalctl -u ai-api -f

Quando usar cada comando

SituaçãoComando
O site não carregasudo systemctl status nginx
Página PHP retorna erro 500sudo tail -f /var/log/php8.3-fpm.log
API de IA não respondesystemctl status ai-api
Disco cheiodf -h + du -sh /var/www/sites/*
Servidor lentofree -h + top
Certificado SSL expirousudo openssl x509 -enddate -noout -in /etc/letsencrypt/live/starhosting.com.br/fullchain.pem

Fonte: CHANGELOG.md, testes de deploy

26. Como Criar uma Página Nova

Analogia

Criar uma página nova é como criar um documento novo no Word. Você abre um modelo em branco (template base), escreve o que precisa (conteúdo), e salva com um nome (arquivo PHP). Depois, qualquer pessoa pode acessar pelo endereço (URL).

Passo 1: Criar o arquivo PHP

# Exemplo: criar página "relatorios" no painel admin
nano /var/www/gerenciador/php/admin/relatorios.php

Passo 2: Usar o template base

<?php
require_once __DIR__ . '/../../config.php';
require_once __DIR__ . '/../../db.php';
require_once __DIR__ . '/../../auth.php';

requireAdmin(); // Protege para admin apenas

$titulo = "Relatórios";
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= $titulo ?> - StarHosting</title>
    <link rel="stylesheet" href="/static/style.css">
</head>
<body>
    <h1>Relatórios do Sistema</h1>

    <!-- Seu conteúdo aqui -->
    <p>Total de clientes: <?= count(getAllClientes()) ?></p>
    <p>Total de sites: <?= count(getAllSites()) ?></p>

</body>
</html>

Passo 3: Acessar via Nginx

O Nginx já faz rewrite automático — você não precisa digitar .php:

Fonte: /etc/nginx/sites-available/starhosting (linhas 47-49)

27. Como Criar uma API Nova

Analogia

Criar uma API é como criar um interfone. Você liga (faz pedido HTTP), a pessoa do outro lado verifica se você pode (autenticação), faz o que pediu (lógica), e devolve a resposta (JSON).

Passo 1: Criar arquivo PHP que retorna JSON

<?php
// /var/www/gerenciador/php/admin/api/meu_endpoint.php
require_once __DIR__ . '/../../../config.php';
require_once __DIR__ . '/../../../db.php';
require_once __DIR__ . '/../../../auth.php';

// Verificar autenticação
if (!isLoggedIn() || $_SESSION['user_nivel'] !== 'admin') {
    http_response_code(403);
    echo json_encode(['ok' => false, 'msg' => 'Não autorizado']);
    exit;
}

header('Content-Type: application/json');

$action = $_GET['action'] ?? '';

switch ($action) {
    case 'minha_acao':
        // Lógica aqui
        echo json_encode(['ok' => true, 'dados' => '...']);
        break;
    
    default:
        echo json_encode(['ok' => false, 'msg' => 'Ação inválida']);
}
?>

Passo 2: Chamar via JavaScript

fetch('/admin/api/meu_endpoint.php?action=minha_acao')
    .then(r => r.json())
    .then(data => {
        if (data.ok) {
            console.log('Sucesso:', data.dados);
        } else {
            console.error('Erro:', data.msg);
        }
    });

Exemplo completo: API de estatísticas

<?php
// /var/www/gerenciador/php/admin/api/stats.php
require_once __DIR__ . '/../../../config.php';
require_once __DIR__ . '/../../../db.php';
require_once __DIR__ . '/../../../auth.php';

if (!isLoggedIn() || $_SESSION['user_nivel'] !== 'admin') {
    http_response_code(403);
    echo json_encode(['ok' => false, 'msg' => 'Não autorizado']);
    exit;
}

header('Content-Type: application/json');

$db = getDB();

// Contar usuários
$total_users = $db->query("SELECT COUNT(*) FROM usuarios")->fetchColumn();

// Contar sites
$total_sites = $db->query("SELECT COUNT(*) FROM sites")->fetchColumn();

// Contar por tier
$sites_by_tier = $db->query(
    "SELECT tier, COUNT(*) as count FROM sites GROUP BY tier"
)->fetchAll(PDO::FETCH_KEY_PAIR);

echo json_encode([
    'ok' => true,
    'stats' => [
        'total_users' => $total_users,
        'total_sites' => $total_sites,
        'sites_by_tier' => $sites_by_tier
    ]
]);
?>

28. Como Rodar os Testes

Pré-requisitos

Executar todos os testes

# Opção 1: via run_tests.sh (recomendado)
bash /var/www/run_tests.sh

# Opção 2: via pasta tests
cd /var/www/gerenciador/tests
bash run_all.sh

Estrutura dos testes

/var/www/gerenciador/tests/
├── run_all.sh                    # Executa tudo
├── .env                          # Credenciais (protegido por .gitignore)
├── helpers/
│   └── auth.sh                   # Função get_session_cookie()
├── api/
│   ├── endpoints_test.sh         # 7 testes de endpoints gerais
│   ├── tools_noauth_test.sh      # 3 testes sem autenticação
│   └── tools_auth_test.sh        # 8 testes com autenticação
├── MANUAL_TESTS.md               # 10 testes manuais
├── RELATORIO_VALIDACAO.md        # Relatório formal
├── RELATORIO_VALIDACAO_HONESTO.md # Relatório honesto (com problemas conhecidos)
└── AUDITORIA_PROTOCOLO_VERDADE.md # Auditoria do protocolo

Testes disponíveis

ArquivoTestesO que verifica
endpoints_test.sh7Home (200), Login (200), Admin sem auth (302), 3 arquivos bloqueados (403)
tools_noauth_test.sh3GET/POST sem sessão (403), ação inexistente (403)
tools_auth_test.sh8Todas as 16 ações do tools.php com autenticação

Fonte: CHANGELOG.md (linhas 186-200), tests/MANUAL_TESTS.md

29. Boas Práticas e Convenções

Analogia

Boas práticas são como regras de trânsito. Todo mundo segue as mesmas regras para que o sistema funcione sem acidentes. Se alguém faz diferente, dá "acidente" (bug, erro, segurança comprometida).

Convenções de nomenclatura

O quêConvençãoExemploPor quê
Arquivos PHP (páginas)snake_case, minúsculasclientes.php, meu_endpoint.phpNginx e servidores Linux distinguem maiúsculas de minúsculas
Funções PHPcamelCasecheckSiteLimit(), getDB()Padrão PHP (PSR-1)
Variáveis PHPsnake_case$cliente_id, $site_pathFácil de ler com múltiplas palavras
ConstantesUPPER_SNAKE_CASEDB_PATH, SITES_PATHDestaca que é valor fixo, não muda
Endpoints APIsnake_case/api/v1/meu_endpointRESTful, fácil de digitar no navegador
Tabelas bancosnake_case, pluralusuarios, logs_acaoPadrão SQL, descreve coleções de dados

O que NÃO fazer

Protocolo da Verdade (resumo)

Fonte: PROTOCOLO_VERDADE.md (249 linhas)

30. Arquivos Importantes

ArquivoDescriçãoQuando usar
php/config.phpConfigurações globais, tiers, helpersQuando precisa de constantes ou config
php/db.phpConexão SQLite, schema, logAcao()Quando precisa acessar banco de dados
php/auth.phplogin(), logout(), requireLogin(), etc.Quando precisa proteger páginas
php/functions.phpFunções de negócio (createSite, paginate, etc.)Quando precisa de lógica reutilizável
php/admin/api/tools.phpAPI de ferramentas do servidorQuando precisa executar ações admin
.envCredenciais (SENHA, SMTP, etc.)NUNCA expor, apenas referência
/etc/nginx/sites-available/starhostingConfig Nginx do painelQuando precisa alterar comportamento do servidor
ai-api/main.pyPonto de entrada FastAPIQuando precisa alterar endpoints de IA
ai-api/config.pyConfigurações OllamaQuando precisa alterar modelo ou parâmetros
CHANGELOG.mdHistórico completo do sistemaQuando precisa ver o que mudou

31. Comandos Úteis

Analogia

Comandos são como ferramentas numa caixa de ferramentas. Cada ferramenta faz uma coisa específica. Se você usa a ferramenta errada, pode quebrar algo. Se usa a certa, resolve rápido.

Serviços

# Status dos serviços (ver se está rodando)
sudo systemctl status nginx
sudo systemctl status php8.3-fpm
sudo systemctl status ollama
sudo systemctl status ai-api

# Reiniciar serviços (quando algo trava)
sudo systemctl restart nginx
sudo systemctl restart php8.3-fpm
sudo systemctl restart ollama
sudo systemctl restart ai-api

Nginx

# Testar configuração (antes de reiniciar!)
sudo nginx -t
# Deve mostrar: syntax is ok, test is successful

# Reiniciar (depois de testar)
sudo systemctl restart nginx

# Ver config do painel
cat /etc/nginx/sites-available/starhosting

# Ver config de um site específico
cat /etc/nginx/sites-available/site_xyz

SQLite

# Abrir banco de dados
sqlite3 /var/www/gerenciador/database.db

# Comandos úteis no SQLite
.tables                          # Listar tabelas
.schema usuarios                 # Ver estrutura da tabela
SELECT COUNT(*) FROM sites;      # Contar sites
SELECT * FROM usuarios;          # Ver todos os usuários
.quit                            # Sair

Ollama

# Listar modelos instalados
ollama list

# Ver modelos carregados (na memória)
ollama ps

# Puxar modelo (download)
ollama pull qwen2.5vl:3b

# Testar modelo (conversa)
ollama run qwen2.5vl:3b "Olá, tudo bem?"

Logs

# Logs do Nginx (erros e acessos)
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log

# Logs do PHP
sudo tail -f /var/log/php8.3-fpm.log

# Logs do sistema
journalctl -u nginx -f
journalctl -u ollama -f
journalctl -u ai-api -f

Discos

# Uso de disco (quanto espaço sobrou)
df -h

# Tamanho das pastas (onde está ocupando espaço)
du -sh /var/www/sites/*
du -sh /var/www/gerenciador/*

Git

# Ver status das alterações
git status

# Ver últimas 10 alterações
git log --oneline -10

# Criar branch nova
git checkout -b nova-funcionalidade

# Voltar alteração (cuidado!)
git checkout -- arquivo.php

32. Pendências e Próximos Passos

PrioridadeItemStatus
AltaEmail via Brevo (verificação de domínio)Pendente
AltaCloudflare Email Routing (admin@, suporte@, noreply@)Pendente
MédiaTemplates Premium/BusinessPendente
MédiaIntegração de templates no fluxo de criaçãoPendente
MédiaDocumentação da API (Swagger/README)Pendente
BaixaScript automatizado de criação de sitePendente
BaixaConfigurar OpenCode com Qwen3:8b + MiMo V2.5 FreePendente
MédiaAPI Pública — instalar dependências (php-redis, firebase/php-jwt)Pendente
MédiaAPI Pública — criar tabela api_clientsPendente
MédiaAPI Pública — implementar auth + rate limit + endpointsPendente

Fonte: CHANGELOG.md (linhas 210-240)

33. API Pública (Planejada)

Analogia

API pública é como uma porta de entrada para convidados. As APIs internas são a cozinha da casa (só quem mora entra). A API pública é a porta da frente: o convidado mostra o convite (JWT), o segurança verifica (rate limit), e só então pode acessar o que o convite permite (scopes).

Status: Esta seção descreve o plano arquitetural para a API pública. A implementação ocorrerá quando o desenvolvimento iniciar.

Por que não expor as APIs internas?

JWT com expiração curta (15min) + refresh tokens
Problema de expor diretamenteSolução com API Wrapper
tools.php pode reiniciar Nginx, deletar backups — perigoso para clientes Wrapper só expõe ações seguras (listar, consultar status)
API de IA processa qualquer imagem sem limite — custo alto Rate limit por cliente: Basic=100/dia, Premium=500/dia, Business=2000/dia
Sem autenticação robusta — qualquer um pode chamar
Sem log de auditoria — impossível rastrear uso Toda chamada logada: client_id, endpoint, IP, timestamp

Arquitetura

[Cliente externo] [API Gateway] [APIs Internas] │ │ │ │ Authorization: Bearer │ │ │ eyJhbGciOiJIUzI1Ni... │ │ │ ────────────────────────>│ │ │ │ 1. Decodifica JWT │ │ │ 2. Busca client no DB │ │ │ 3. Verifica scopes │ │ │ 4. Rate limit (Redis) │ │ │ 5. Valida input │ │ │ │ │ │ chamada interna │ │ │ (localhost) │ │ │ ────────────────────────>│ │ │ │ │ │ resposta formatada │ │ │ <────────────────────────│ │ │ │ │ JSON response │ │ │ + X-RateLimit-Headers │ │ │ <────────────────────────│ │ │ │ │

Decisões de Arquitetura

ComponenteEscolhaPor quê (padrão de mercado)
Algoritmo de Rate LimitToken BucketPadrão AWS/Google/Stripe — permite rajadas + taxa sustentada
Storage do Rate LimitRedisJá instalado e rodando, operações atômicas, TTL automático
AutenticaçãoJWT (firebase/php-jwt)460M+ installs, padrão da indústria, suporta HS256
Banco de dadosSQLite (já temos)Econômico, suficiente para volume de clientes
Secret keyAuto-gerado (32 bytes hex)Cliente nunca escolhe — sistema gera, mostra uma vez, armazena hash
Scopes por planoDefinidos na criaçãoSegue padrão OAuth2

Tabela api_clients

CREATE TABLE api_clients (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    client_id TEXT UNIQUE NOT NULL,        -- identificador público
    secret_hash TEXT NOT NULL,             -- bcrypt do secret (nunca o secret cru)
    nome TEXT NOT NULL,                    -- nome do cliente/app
    plan TEXT DEFAULT 'basic',             -- basic/premium/business
    scopes TEXT DEFAULT '["read"]',        -- JSON: ["read","write","analyze"]
    rate_limit INTEGER DEFAULT 100,        -- req/dia
    ativo INTEGER DEFAULT 1,               -- 0=desativado, 1=ativo
    ultimo_acesso DATETIME,
    criado_em DATETIME DEFAULT CURRENT_TIMESTAMP
);

Dependências a instalar

# 1. Extensão PHP para Redis
sudo apt install php-redis -y
sudo systemctl restart php8.3-fpm

# 2. Biblioteca JWT via Composer
cd /var/www/gerenciador/php
composer require firebase/php-jwt

Custo: ~2MB de disco, 0 serviços novos (Redis já roda)

Endpoints planejados

MétodoEndpointDescriçãoScopes
POST/api/public/v1/auth/tokenGera JWT (client_id + secret)público
GET/api/public/v1/statusStatus do sistemaread
GET/api/public/v1/sitesLista sites do clienteread
GET/api/public/v1/sites/{id}Detalhes de um siteread
POST/api/public/v1/ai/analiseEnvia imagem para análiseanalyze
POST/api/public/v1/ai/chatChat com IAanalyze

Segurança (padrão de mercado)

Exemplos de Uso

1. Autenticar — obter JWT

# Passo 1: Gerar token (client_id + secret)
curl -X POST https://starhosting.com.br/api/public/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "meu_app_001",
    "secret": "a1b2c3d4e5f6..."
  }'

# Resposta:
{
  "ok": true,
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_in": 900,
  "plan": "basic",
  "scopes": ["read"]
}

2. Consultar status do sistema

# Passo 2: Usar o JWT para acessar endpoints
curl https://starhosting.com.br/api/public/v1/status \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

# Resposta:
{
  "ok": true,
  "status": {
    "nginx": "active",
    "php": "active",
    "disk_percent": 11,
    "ram_used": "7.1Gi",
    "sites": 3
  }
}

3. Listar sites do cliente

curl https://starhosting.com.br/api/public/v1/sites \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

# Resposta:
{
  "ok": true,
  "sites": [
    {
      "id": 1,
      "dominio": "minhalojja.com.br",
      "tier": "basic",
      "status": "ativo",
      "ssl_ativo": true
    }
  ],
  "total": 1,
  "limite": 1
}

4. Enviar imagem para análise (IA)

# Enviar imagem em base64 para análise
curl -X POST https://starhosting.com.br/api/public/v1/ai/analise \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "imagem_base64": "data:image/jpeg;base64,/9j/4AAQ...",
    "id_camera": "cam01"
  }'

# Resposta:
{
  "ok": true,
  "resultado": {
    "total_objetos": 5,
    "objetos": [...]
  },
  "tempo_execucao": 2.5
}

5. Chat com IA

curl -X POST https://starhosting.com.br/api/public/v1/ai/chat \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "mensagem": "Olá, qual é o status do meu site?",
    "id_sessao": "sessao_abc123"
  }'

# Resposta:
{
  "ok": true,
  "resposta": "Seu site minhaloja.com.br está ativo e funcionando normalmente.",
  "id_sessao": "sessao_abc123"
}

6. Quando o rate limit excede

# Se o cliente fizer muitas requisições, recebe 429:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1717430400
Retry-After: 3600

{
  "ok": false,
  "error": "rate_limit_exceeded",
  "message": "Limite diário atencido. Tente novamente amanhã.",
  "retry_after": 3600
}

7. Exemplo em JavaScript (fetch)

// Autenticar
const authRes = await fetch('/api/public/v1/auth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    client_id: 'meu_app_001',
    secret: 'a1b2c3d4e5f6...'
  })
});
const { token } = await authRes.json();

// Usar o token
const sitesRes = await fetch('/api/public/v1/sites', {
  headers: { 'Authorization': `Bearer ${token}` }
});
const sites = await sitesRes.json();
console.log(sites);

8. Exemplo em PHP (cURL)

<?php
// Autenticar
$ch = curl_init('https://starhosting.com.br/api/public/v1/auth/token');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'client_id' => 'meu_app_001',
        'secret' => 'a1b2c3d4e5f6...'
    ]),
    CURLOPT_RETURNTRANSFER => true
]);
$data = json_decode(curl_exec($ch), true);
$token = $data['token'];

// Usar o token
$ch = curl_init('https://starhosting.com.br/api/public/v1/sites');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],
    CURLOPT_RETURNTRANSFER => true
]);
$sites = json_decode(curl_exec($ch), true);
print_r($sites);
?>

Arquivos a criar

ArquivoFunção
/var/www/gerenciador/php/api/index.phpRouter principal
/var/www/gerenciador/php/api/auth.phpGeração e validação de JWT
/var/www/gerenciador/php/api/ratelimit.phpToken Bucket com Redis
/var/www/gerenciador/php/api/middleware.phpPipeline: auth → rate limit → scope
/var/www/gerenciador/php/api/endpoints/Endpoints específicos (status, sites, ai)
/etc/nginx/sites-available/apiConfig Nginx para /api/public/

34. Chat API Interna (Implementada)

Analogia

Chat API é como um atendente de loja virtual. O cliente manda mensagem, o atendente (IA) responde. Se o cliente fica confuso, o atendente consulta o histórico completo para entender o que aconteceu antes.

Status: Implementada e funcional. Pronta para uso.

O que a Chat API faz

FuncionalidadeDescrição
Receber mensagensCliente envia mensagem, IA responde
Manter contextoIA lembra das últimas 30 mensagens
Detectar confusãoSe cliente diz "como assim", "não entendi", usa 100 msgs em vez de 30
Compactação automáticaA cada 30 msgs ou 2 horas sem atividade
Compactação manualEndpoint para forçar compactação
Gerenciar contextoLoja pode atualizar contexto (produtos, preços, etc.)
Histórico completoTodas as mensagens salvas no SQLite

Arquitetura

[Loja Online (PHP)] │ │ POST /api/chat/send.php │ {mensagem, user_id, contexto_loja} │ ▼ ┌─────────────────────────────────────┐ │ Chat API (PHP) │ │ /var/www/gerenciador/php/api/chat/ │ │ │ │ 1. Valida API Key (timestamp*dia) │ │ 2. Busca/cria sessão │ │ 3. Detecta confusão (keywords) │ │ 4. Prepara histórico (30 ou 100) │ │ 5. Envia para AI API │ │ 6. Salva resposta │ │ 7. Retorna para a loja │ └──────────────┬──────────────────────┘ │ │ POST http://127.0.0.1:8080/api/v1/chat │ Header: X-API-Key: ▼ ┌─────────────────────────────────────┐ │ AI API (FastAPI + Ollama) │ │ qwen2.5vl:3b │ └─────────────────────────────────────┘

Autenticação

A API usa autenticação por API Key dinâmica. A chave é gerada a cada minuto:

// Como gerar a chave:
$timestamp = time();        // ex: 1780492821
$dia = (int)date('d');       // ex: 3
$valor = $timestamp * $dia;  // ex: 5341478463
$key = base64_encode($valor); // ex: "NTM0MTQ3ODQ2Mw=="

// Validar:
// 1. Decodifica base64 → obtém valor
// 2. Divide por dia → obtém timestamp
// 3. Verifica se timestamp está dentro de 24h

Endpoints

MétodoEndpointDescrição
POST/api/chat/send.phpEnvia mensagem e recebe resposta da IA
POST/api/chat/contexto.phpAtualiza contexto da loja
POST/api/chat/compact.phpForça compactação manual
GET/api/chat/history.phpRetorna histórico da sessão

Exemplos de Uso (curl)

1. Gerar API Key válida

# Gerar chave via PHP
php -r '
$timestamp = time();
$dia = (int)date("d");
$valor = $timestamp * $dia;
echo base64_encode((string)$valor);
'
# Saída: NTM0MTQ3ODQ2Mw==

2. Criar sessão e enviar primeira mensagem

curl -X POST https://api.starhosting.com.br/send.php \
  -H "Content-Type: application/json" \
  -H "X-API-Key: NTM0MTQ3ODQ2Mw==" \
  -d '{
    "mensagem": "Olá, qual o prazo de entrega?",
    "user_id": "cliente_123",
    "loja_id": "lojaX",
    "contexto_loja": "Loja de roupas. Produtos: camisetas, calças."
  }'

# Resposta:
{
  "ok": true,
  "resposta": "Olá! O prazo de entrega é de 3 a 5 dias úteis.",
  "session_id": "lojaX_cliente_123",
  "tokens_usados": 45
}

3. Enviar segunda mensagem (mantém contexto)

curl -X POST https://api.starhosting.com.br/send.php \
  -H "Content-Type: application/json" \
  -H "X-API-Key: NTM0MTQ3ODQ2Mw==" \
  -d '{
    "mensagem": "E tem frete grátis?",
    "user_id": "cliente_123",
    "loja_id": "lojaX"
  }'

# IA lembra que falou de entrega → responde sobre frete

4. Atualizar contexto (mantém histórico)

curl -X POST https://api.starhosting.com.br/contexto.php \
  -H "Content-Type: application/json" \
  -H "X-API-Key: NTM0MTQ3ODQ2Mw==" \
  -d '{
    "session_id": "lojaX_cliente_123",
    "contexto_loja": "Loja de roupas. PROMOÇÃO: frete grátis acima de R$99.",
    "force_new_session": false
  }'

# Resposta:
{
  "ok": true,
  "compactado": false,
  "msg": "Contexto atualizado, histórico mantido"
}

5. Forçar nova sessão (zerar histórico)

curl -X POST https://api.starhosting.com.br/contexto.php \
  -H "Content-Type: application/json" \
  -H "X-API-Key: NTM0MTQ3ODQ2Mw==" \
  -d '{
    "session_id": "lojaX_cliente_123",
    "contexto_loja": "Loja de eletrônicos agora.",
    "force_new_session": true
  }'

# Resposta:
{
  "ok": true,
  "compactado": true,
  "historico_zerado": true,
  "msg": "Contexto atualizado e histórico zerado"
}

6. Usuário confuso → histórico expandido

curl -X POST https://api.starhosting.com.br/send.php \
  -H "Content-Type: application/json" \
  -H "X-API-Key: NTM0MTQ3ODQ2Mw==" \
  -d '{
    "mensagem": "Como assim? Não entendi",
    "user_id": "cliente_123",
    "loja_id": "lojaX"
  }'

# Bot detecta "como assim" + "não entendi" → usa 100 msgs em vez de 30

7. Forçar compactação manual

curl -X POST https://api.starhosting.com.br/compact.php \
  -H "Content-Type: application/json" \
  -H "X-API-Key: NTM0MTQ3ODQ2Mw==" \
  -d '{"session_id": "lojaX_cliente_123"}'

# Resposta:
{
  "ok": true,
  "compactado": true,
  "mensagens_removidas": 25,
  "resumo": "Cliente perguntou sobre prazo de entrega e frete grátis para São Paulo."
}

8. Ver histórico completo

curl "https://api.starhosting.com.br/history.php?session_id=lojaX_cliente_123" \
  -H "X-API-Key: NTM0MTQ3ODQ2Mw=="

# Resposta:
{
  "ok": true,
  "session_id": "lojaX_cliente_123",
  "loja_id": "lojaX",
  "contexto_loja": "Loja de roupas...",
  "total_mensagens": 8,
  "historico": [...]
}

Compactação

TipoGatilhoO que faz
Automática30+ mensagens OU 2+ horas sem atividadeResume msgs antigas, mantém últimas 10
ManualPOST /api/chat/compact.phpLoja força compactação quando quiser
ExpandidaConfusão detectada ("como assim", etc.)Usa 100 msgs em vez de 30

Sinais de Confusão

Quando a mensagem contém algum destes termos, o bot usa 100 mensagens em vez de 30:

Arquivos

ArquivoFunçãoLinhas
api/chat/config.phpConfigurações (limites, API key, sinais)~66
api/chat/db.phpCRUD de sessões no SQLite~85
api/chat/ollama.phpChamada à AI API~85
api/chat/compactador.phpDetecção + compactação~95
api/chat/send.phpEndpoint principal~95
api/chat/contexto.phpAtualização de contexto~70
api/chat/compact.phpCompactação manual~50
api/chat/history.phpHistórico da sessão~45

Fonte: /var/www/gerenciador/php/api/chat/ (640 linhas totais)

Apêndice A. Credenciais e Configurações

ATENÇÃO: Esta seção contém dados sensíveis. Não exponha este conteúdo em repositórios públicos.
ItemValorFonte
IP do servidor137.131.229.136config.php, linha 6
URL basehttps://starhosting.com.brconfig.php, linha 7
Admin emailadmin@starhosting.com.br.env, linha 2
Admin senhaWindows@98.env, linha 4
Secret key (sessões)59fee5ec... (64 hex chars).env, linha 1
SMTP hostsmtp-relay.brevo.com.env, linha 7
SMTP userad1b03001@smtp-brevo.com.env, linha 9
SMTP passxsmtpsib-... (API key).env, linha 10
AI API key (interna)2c33bb2a... (64 hex chars)CHANGELOG.md
Cloudflare Zone ID6eb5cee90c8f644ab42dd32150cd73ffCHANGELOG.md

Apêndice B. Protocolo da Verdade (v2.5)

O Protocolo da Verdade é um conjunto de regras que governa como o sistema (e suas IAs) devem processar informações. Versão: v2.5.

Princípios Fundamentais

  1. Ancoragem Factual Absoluta — Toda afirmação deve ser baseada em fontes verificáveis. Proibido inventar, especular ou assumir.
  2. Transparência de Evidências — Toda alegação técnica deve ter sua fonte oficial. Citações mortas ou alucinadas são violação crítica.
  3. Anti-Arrogância — Eliminar vieses pessoais e sycophancy (concordância injustificada). Correto factual > soar útil.
  4. Anti-Dados Mock — Proibido usar dados fictícios, returns hardcoded, ou placeholders em funções complexas.

Correção de Erros do Usuário

  1. Anti-Gaslighting Algorítmico — NUNCA assumir que o sistema está correto e que o usuário ou seu software está errado.
  2. Blacklist Anti-Looping — Se uma abordagem falhar 2 vezes, registrar na "Blacklist Registry" e NUNCA mais tentar.
  3. Blacklist Comportamental (v2.5) — Aplica-se a padrões comportamentais: Helpfulness Bias, Scope Creep, Premature Action.

Gatekeeper de Compactação de Contexto

Escopo e Disciplina de Edição (v2.5)

  1. Declaração Obrigatória de Escopo — ANTES de qualquer edição, declarar: Escopo, Exclusões, Intenção.
  2. Execução de Limite de Edição — NUNCA modificar arquivo fora do escopo declarado.
  3. Auto-Verificação Periódica — A cada 3-4 execuções de ferramentas, pausar e verificar: "Estou dentro do escopo?"

Apêndice C. Glossário

Analogia

Glossário é como um dicionário técnico. Sempre que encontrar uma palavra estranha, venha aqui procurar. Cada termo tem uma explicação simples e um exemplo para entender fácil.

Termo em InglêsTraduçãoO que éExemplo
ServerServidorComputador ligado 24h que guarda e mostra sitesO StarHosting roda num servidor Oracle Cloud
DomainDomínioEndereço do site na internetstarhosting.com.br
HostingHospedagemServiço de alugar espaço em servidorStarHosting é um serviço de hospedagem
SSL/TLSCertificado de SegurançaCRIPTOGRAFA a comunicação (HTTPS)starhosting.com.br tem SSL válido até 28/08/2026
DNSDomain Name SystemTraduz domínio em IPCloudflare DNS traduz starhosting.com.br → 137.131.229.136
HTTPSHTTP SeguroHTTP com criptografia SSLTodo acesso ao StarHosting é via HTTPS
NginxMotor-X (servidor web)Software que recebe pedidos e mostra páginasNginx serve os sites criados no StarHosting
PHP-FPMPHP FastCGI Process ManagerExecuta código PHPPHP-FPM processa as páginas do painel
SQLiteBanco de dados leveBanco em arquivo único, sem servidordatabase.db guarda todos os dados do StarHosting
APIApplication Programming InterfaceForma de programas se comunicarem/api/v1/analise recebe imagem e retorna análise
JSONJavaScript Object NotationFormato de dados (chave: valor){"ok": true, "dados": {"status": "ativo"}}
CRUDCreate, Read, Update, Delete4 operações básicas de banco de dadosCriar site, ver site, editar site, deletar site
SessionSessãoDados do usuário logado no servidor$_SESSION['user_id'] = 1
CookieBiscoito (navegador)Arquivo pequeño no navegador que identifica o usuárioPHPSESSID identifica quem está logado
TokenChave/CódigoCódigo único que prova que você é quem diz serAPI Key do FastAPI: x-api-key: 2c33bb...
BcryptAlgoritmo de hashTransforma senha em código ilegívelpassword_hash($senha, PASSWORD_BCRYPT)
PWAProgressive Web AppSite que vira app de celularStarHosting é PWA — funciona offline
Service WorkerTrabalhador de serviçoScript que faz PWA funcionar offlinesw.js cacheia páginas para funcionar sem internet
FastAPIAPI Rápida (Python)Framework Python para criar APIsA API de IA usa FastAPI (main.py)
OllamaMotor de IA LocalRoda modelos de IA no servidorOllama roda qwen2.5vl:3b no servidor
LLMLarge Language ModelModelo de linguagemQwen é um LLM que gera texto
VLMVision Language ModelModelo de IA que "enxerga" imagensqwen2.5vl:3b analisa imagens de câmeras
Base64Codificação Base64Transforma binário (imagem) em textoImagem vira string para enviar na API
Bounding BoxCaixa delimitadoraRetângulo que marca onde um objeto está na imagem[0.1, 0.2, 0.3, 0.4] = x1, y1, x2, y2
EndpointPonto de extremidadeURL que responde a pedidos HTTP/api/v1/analise é um endpoint
MiddlewareSoftware intermediárioCódigo que roda entre o pedido e a respostaFastAPI usa middleware para autenticação
WildcardCuringaCertificado que vale para TODOS os subdomínios*.starhosting.com.br cobre api., admin., etc.
DaemonDemônio (serviço em background)Programa que roda sem interface visualOllama roda como daemon (ollama.service)
CronAgendador de tarefasExecuta comandos em horários definidoscertbot renova SSL automaticamente via cron
symlinkLink simbólicoAtalho que aponta para outro arquivo/pastasite_xyz em sites-available → sites-enabled
rootRaiz (Nginx)Pasta onde o Nginx procura os arquivosroot /var/www/gerenciador/php
server_nameNome do servidorDomínio que o Nginx respondeserver_name starhosting.com.br *.starhosting.com.br
locationLocalizaçãoBloco que define como tratar URLslocation /admin/ { ... }
try_filesTentar arquivosProcura o arquivo na ordem especificadatry_files $uri $uri.php =404
return 301Redirecionar permanentementeMove o usuário para outra URLreturn 301 https://starhosting.com.br$request_uri

Apêndice D. Histórico deste Documento

DataVersãoAlteraçãoAutor
03/06/20261.0Criação inicial do documentoStarHosting AI
Nota: Este documento deve ser atualizado sempre que o sistema receber mudanças significativas. Mantenha a seção "Histórico" atualizada com cada alteração.



StarHosting — Documentação Completa v1.2
Última atualização: 03/06/2026
starhosting.com.br