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?
Imagina assim:
- A internet é como uma enorme cidade cheia de prédios.
- Cada site é um prédio nessa cidade.
- O servidor é o terreno onde o prédio fica construído.
- O domínio é o endereço do prédio (tipo "Rua das Flores, 123").
- O painel StarHosting é como uma imobiliária digital: o dono da imobiliária (Admin) pode construir prédios (criar sites) para seus clientes, cobrando aluguel (planos mensais).
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?
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 StarHosting | Soluçã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?
- Dono do sistema (Admin) — lucra com as assinaturas dos clientes
- Parceiros — ganham comissão por trazer clientes
- Clientes — ganham um site profissional sem saber programar
Fluxo completo de uma venda
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
- Cria e gerencia parceiros e clientes
- Cria sites com criação automatizada (Nginx + SSL)
- Acessa ferramentas de administração do servidor
- Visualiza logs de atividade de todos os usuários
- Corrige permissões e configurações do servidor
URLs de acesso:
- Login:
/admin/login - Dashboard:
/admin/ - Clientes:
/admin/clientes - Parceiros:
/admin/coordenadores - Sites:
/admin/sites - Ferramentas:
/admin/sites(aba Ferramentas) - Logs:
/admin/logs
parceiro Parceiro / Coordenador
- Gerencia seus próprios clientes (cria, edita, desativa)
- Gerencia os sites de seus clientes
- Configura domínios para os sites
URLs de acesso:
- Login:
/login - Dashboard:
/painel/ou/parceiro/ - Clientes:
/painel/clientes - Sites:
/painel/sites
cliente Cliente
- Visualiza seus sites
- Faz upload e deleta arquivos
- Aplica templates nos sites
- Edita informações do site (título, logo, etc.)
- Visualiza suas notificações e logs
URLs de acesso:
- Login:
/login - Dashboard:
/cliente/ - Site:
/cliente/site?id=X - Upload:
/cliente/upload?site_id=X - Template:
/cliente/template?id=X - Editar:
/cliente/editar?id=X
06. Diagrama de Componentes
O que acontece quando você visita um site?
- Você digita
starhosting.com.brno navegador. - O DNS (Domain Name System) traduz o endereço para o IP
137.131.229.136. - O Nginx recebe a requisição na porta 443 (HTTPS).
- Se for uma página PHP (como
/admin), o Nginx envia para o PHP-FPM. - O PHP-FPM executa o código, acessa o SQLite, e devolve o HTML.
- 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. |
| 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
09. Banco de Dados (SQLite)
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)
| Campo | Tipo | O que guarda |
|---|---|---|
id | INTEGER (chave primária) | Número único do usuário |
email | TEXT (único, não nulo) | Email de login |
senha_hash | TEXT (não nulo) | Senha criptografada (bcrypt) |
nome | TEXT (não nulo) | Nome completo |
nivel | TEXT (admin/parceiro/cliente) | Tipo de usuário |
coordenador_id | INTEGER (chave estrangeira) | ID do parceiro dono (para clientes) |
ativo | INTEGER (0 ou 1) | Se a conta está ativa |
criado_em | TIMESTAMP | Data de criação |
Fonte: db.php, linhas 17-27
Tabela: sites (os sites criados)
| Campo | Tipo | O que guarda |
|---|---|---|
id | INTEGER (chave primária) | Número único do site |
dominio | TEXT (único, não nulo) | Endereço do site (ex: meusite.com.br) |
subpasta | TEXT (único, não nulo) | Pasta no servidor (ex: site_abc123) |
tier | TEXT (basic/premium/business) | Plano do site |
cliente_id | INTEGER (chave estrangeira) | ID do cliente dono |
coordenador_id | INTEGER (chave estrangeira) | ID do parceiro |
ssl_ativo | INTEGER (0 ou 1) | Se tem HTTPS ativo |
php_ativo | INTEGER (0 ou 1) | Se PHP está habilitado |
status | TEXT (ativo/suspenso) | Estado do site |
criado_em | TIMESTAMP | Data de criação |
Fonte: db.php, linhas 29-42
Tabela: logs_acao (registro de ações)
| Campo | Tipo | O que guarda |
|---|---|---|
id | INTEGER | Número do log |
usuario_id | INTEGER | Quem fez a ação |
acao | TEXT | O que foi feito (ex: "login", "criar_site") |
detalhes | TEXT | Informações extras |
ip_address | TEXT | IP de onde veio o pedido |
criado_em | TIMESTAMP | Quando aconteceu |
Fonte: db.php, linhas 44-52
Tabela: notificacoes (avisos para o usuário)
| Campo | Tipo | O que guarda |
|---|---|---|
id | INTEGER | Número da notificação |
usuario_id | INTEGER | Para quem é |
titulo | TEXT | Título da mensagem |
mensagem | TEXT | Corpo da mensagem |
lida | INTEGER (0 ou 1) | Se já foi lida |
criado_em | TIMESTAMP | Quando foi criada |
Fonte: db.php, linhas 54-62
Tabela: templates (modelos de site)
| Campo | Tipo | O que guarda |
|---|---|---|
id | INTEGER | Número do template |
nome | TEXT | Nome (ex: "restaurante") |
descricao | TEXT | Breve descrição |
arquivo_zip | TEXT | Arquivo ZIP do template |
preview_url | TEXT | URL de preview |
tier_minimo | TEXT | Tier mínimo necessário (basic/premium/business) |
Fonte: db.php, linhas 64-71
Relacionamento entre tabelas
10. Autenticação e Sessões
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?
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 digitada | O 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ção | Protege 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)
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)
| Template | Descrição | Pasta |
|---|---|---|
| restaurante | Site para restaurantes | /var/www/gerenciador/templates/restaurante/ |
| loja | Site para lojas | /var/www/gerenciador/templates/loja/ |
| portfolio | Site para portfólio | /var/www/gerenciador/templates/portfolio/ |
| escritorio | Site para escritórios | /var/www/gerenciador/templates/escritorio/ |
| saude | Site 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).
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ção | Valor | O que é |
|---|---|---|
| Servidor SMTP | smtp-relay.brevo.com | Endereço do "carteiro digital" |
| Porta | 587 (STARTTLS) | Porta segura para envio |
| Usuário | ad1b03001@smtp-brevo.com | Login no Brevo |
| Senha | xsmtpsib-... | API key (não é senha normal) |
| Email remetente | admin@starhosting.com.br | De quem é o email |
| Email suporte | suporte@starhosting.com.br | Para emails de suporte |
| Email noreply | noreply@starhosting.com.br | Para 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
| Remetente | Uso | |
|---|---|---|
admin | admin@starhosting.com.br | Emails administrativos, boas-vindas |
suporte | suporte@starhosting.com.br | Suporte ao cliente |
noreply | noreply@starhosting.com.br | Notificações automáticas |
Fluxo de envio
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)
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:
manifest.json— arquivo que diz ao celular como instalar o appsw.js(Service Worker) — faz o app funcionar offline- Ícones em diferentes tamanhos para celular
Arquivos do PWA
| Arquivo | O que faz | Configuraçõ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
- Abra
starhosting.com.brno Chrome do celular - Toque no botão "⋮" (três pontos) no canto superior direito
- Toque em "Adicionar à tela inicial"
- Confirme o nome e toque em "Adicionar"
- Pronto! Agora tem um ícone do StarHosting na tela do celular
15. Domínios e SSL
Domínios configurados
| Domínio | Para que serve | DNS |
|---|---|---|
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)
| Propriedade | Valor |
|---|---|
| Tipo | Wildcard (*.starhosting.com.br) |
| Emissor | Let's Encrypt |
| Validade | 28/08/2026 |
| Desafio | DNS-01 via Cloudflare |
| Auto-renovação | Sim (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ínio | Backend | Autenticaçã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
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
| Aspecto | PHP (Sessão) | FastAPI (API Key) |
|---|---|---|
| Onde é armazenado | Cookie no navegador | Header do pedido |
| Expira? | Sim, após inatividade | Não expira |
| Quem usa | Usuários do painel (admin, parceiro, cliente) | Aplicações externas (câmeras, IoT) |
| Como revogar | Deletar sessão no servidor | Mudar a API_KEY no .env |
18. Login/Logout
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étodo | URL | Auth | Roles | O 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
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ível | Redireciona para | O que pode ver |
|---|---|---|
admin | /admin | Painel admin completo: config, clientes, templates, ferramentas |
coordenador | /coord | Gerenciar seus próprios clientes e sites |
cliente | /painel | Ver e gerenciar seus próprios sites |
Fonte: auth.php (login(), logout()), login.php, logout.php
/admin/loginFonte: login.php, logout.php, admin/login.php
19. Painel Admin (HTML)
| Método | URL | Auth | O que faz |
|---|---|---|---|
| GET | /admin/ | Admin | Dashboard: contadores de parceiros, clientes, sites, logs |
| GET | /admin/clientes | Admin | Lista todos os clientes |
| POST | /admin/clientes | Admin | Cria novo cliente |
| GET | /admin/clientes?toggle=X | Admin | Ativa/desativa cliente |
| GET | /admin/coordenadores | Admin | Lista todos os parceiros |
| POST | /admin/coordenadores | Admin | Cria novo parceiro |
| GET | /admin/coordenadores?toggle=X | Admin | Ativa/desativa parceiro |
| GET | /admin/sites | Admin | Lista todos os sites + Ferramentas |
| POST | /admin/sites | Admin | Cria novo site (automatizado) |
| GET | /admin/site/dominio?id=X | Admin | Configura domínio do site |
| POST | /admin/site/dominio?id=X | Admin | Salva configuração de domínio |
| GET | /admin/logs | Admin | Ú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ção | Descrição | Comando usado |
|---|---|---|
fix_perms | Corrige owner/permissoes em /var/www | chown + chmod 2775 |
fix_all | Reparo completo (6 passos) | chown, chmod dirs, chmod files, g+s, nginx -t, restart |
get_server_status | Stats do servidor | stat, free, uptime, ls, systemctl, openssl |
get_nginx_config | Retorna configs Nginx | cat /etc/nginx/sites-available/* |
get_ssl_certs | Lista certs SSL com validade | ls + openssl x509 |
restart_nginx | Testa e reinicia Nginx | nginx -t + systemctl restart |
clear_cache | Reinicia PHP-FPM | systemctl restart php-fpm |
update_system | Atualiza sistema | apt update + apt upgrade |
test_nginx | Testa configuração Nginx | nginx -t |
check_ssl | Verifica SSL dos sites ativos | openssl x509 -checkend |
check_disk | Uso de disco total + top 10 | df -h + du |
check_logs | Últimas 30 linhas do log de erro | tail /var/log/nginx/error.log |
check_status | Status Nginx + PHP-FPM + disco | systemctl is-active + df |
clean_logs | Limpa logs antigos + vacuum journal | journalctl --vacuum-time |
backup_db | Copia database para backup | cp database.db /home/ubuntu/Downloads/ |
list_backups | Lista backups disponíveis | glob('/home/ubuntu/Downloads/database-*.db') |
restore_db?file=X | Restaura database de backup | cp 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ção | Usa sudo? | Para que serve? |
|---|---|---|
runLocal($cmd) | Não | Comandos 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
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ível | Pode acessar? | O que vê |
|---|---|---|
| admin | Sim | TODOS os clientes e sites (pode gerenciar tudo) |
| coordenador (parceiro) | Sim | Apenas SEUS clientes e sites (não vê de outros parceiros) |
| cliente | Não | — |
Endpoints do Painel Parceiro
| Método | URL | Auth | O que faz |
|---|---|---|---|
| GET | /painel/ ou /parceiro/ | Coord/Admin | Dashboard do parceiro (resumo de clientes e sites) |
| GET | /painel/clientes | Coord/Admin | Lista clientes (próprios para parceiro, todos para admin) |
| POST | /painel/clientes | Coord/Admin | Cria cliente (parceiro_id = usuário logado automaticamente) |
| GET | /painel/sites | Coord/Admin | Lista sites do parceiro |
| POST | /painel/sites | Coord/Admin | Cria site para parceiro |
| GET | /painel/site/dominio?id=X | Coord/Admin | Configura domínio do site |
| POST | /painel/site/dominio?id=X | Coord/Admin | Salva 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
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ção | O que acontece |
|---|---|
| Ver seus sites | Lista todos os sites que ele tem |
| Ver detalhes de um site | Mostra informações, arquivos e opções |
| Fazer upload de arquivos | Envia imagens, HTML, CSS para o site |
| Deletar arquivos | Remove arquivos que não precisa mais |
| Aplicar template | Troca o visual do site (restaurante, loja, etc.) |
| Editar conteúdo | Altera textos, cores, logos do site |
| Configurar domínio | Aponta um domínio personalizado para o site |
| Ver notificações | Mensagens do sistema (site criado, etc.) |
| Ver logs | Histórico das últimas 50 ações |
Endpoints do Painel Cliente
| Método | URL | Auth | O que faz |
|---|---|---|---|
| GET | /cliente/ | Login | Lista sites do cliente |
| GET | /cliente/site?id=X | Login+Owner | Detalhes do site + upload |
| POST | /cliente/upload?site_id=X | Login+Owner | Faz upload de arquivo |
| GET | /cliente/delete?site_id=X&arquivo=Y | Login+Owner | Deleta arquivo do site |
| GET | /cliente/template?id=X | Login+Owner | Mostra templates disponíveis |
| POST | /cliente/template?id=X | Login+Owner | Aplica template ao site |
| GET | /cliente/editar?id=X | Login+Owner | Formulário de edição |
| POST | /cliente/editar?id=X | Login+Owner | Salva alterações + regenera site |
| GET | /cliente/site/dominio?id=X | Login | Configura domínio |
| POST | /cliente/site/dominio?id=X | Login | Salva domínio |
| GET | /cliente/notificacoes | Login | Lista notificações (marca como lida) |
| GET | /cliente/logs | Login | Ú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étodo | Endpoint | Auth | Descrição |
|---|---|---|---|
| GET | /health | Nenhuma | Health check (retorna modelo + status) |
| POST | /api/v1/analise | X-API-Key | Análise de imagens (bounding boxes, objetos) |
| POST | /api/v1/inventario | X-API-Key | Contagem de produtos por imagem |
| POST | /api/v1/chat | X-API-Key | Chat 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
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id_sessao | string | Sim | Identificador da sessão (uso interno, não afeta o modelo) |
historico_mensagens | array | Sim | Lista de mensagens (mínimo 1). O modelo recebe TODAS as mensagens. |
historico_mensagens[].role | string | Sim | "user" para mensagens do usuário, "assistant" para respostas da IA |
historico_mensagens[].content | string | Sim | Texto da mensagem |
historico_mensagens[].images | array | Não | Lista de imagens em Base64 (opcional, para chat multimodal) |
num_ctx | integer | Não | Janela 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
| Campo | Tipo | Descrição |
|---|---|---|
status | string | "sucesso" ou "erro" |
id_sessao | string | Mesmo ID enviado no request |
data_resposta | string | Data/hora UTC da resposta (ISO 8601) |
mensagem_resposta | object | Resposta do modelo: role (sempre "assistant") + content (texto) |
performance | object | Mé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
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
| Endpoint | Uso | Entrada | Histó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âmetro | Valor | O que faz |
|---|---|---|
model | qwen2.5vl:3b | Modelo de visão (3.8B parâmetros) |
temperature | 0.0 | Respostas sempre iguais (determinístico) |
num_thread | 2 | 2 threads CPU (otimizado para ARM) |
num_ctx | 8096 | Janela de contexto do modelo |
keep_alive | -1 | Modelo fica carregado permanentemente |
flash_attention | 1 | Acelera 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.
| Imagem | Objetos Detectados | Tempo | Descriçã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
| Imagem | Tempo (s) | Status |
|---|---|---|
| pic01.jpg | 129 | OK |
| pic02.jpg | 246 | OK |
| pic03.jpg | 246 | OK |
| pic04.jpg | 165 | OK |
| pic05.jpg | 148 | OK |
| pic06.jpg | 245 | OK |
| pic07.jpg | 246 | OK |
| pic08.jpg | 124 | OK |
| pic09.jpg | 135 | OK |
| pic10.jpg | 17 | OK |
Tempo médio: ~170 segundos (2 min 50s) por imagem em CPU ARM.
24. Tabela Resumo de Todos os Endpoints
| # | Método | Endpoint | Auth | Roles | Tipo |
|---|---|---|---|---|---|
| 1 | GET/POST | /login | Nenhuma | Público | HTML |
| 2 | GET | /logout | Session | Qualquer | Redirect |
| 3 | GET/POST | /admin/login | Nenhuma | Público | HTML |
| 4 | GET | /admin/ | Admin | admin | HTML |
| 5 | GET/POST | /admin/clientes | Admin | admin | HTML |
| 6 | GET | /admin/clientes?toggle=X | Admin | admin | HTML |
| 7 | GET/POST | /admin/coordenadores | Admin | admin | HTML |
| 8 | GET | /admin/coordenadores?toggle=X | Admin | admin | HTML |
| 9 | GET/POST | /admin/sites | Admin | admin | HTML |
| 10 | GET/POST | /admin/site/dominio?id=X | Admin | admin | HTML |
| 11 | GET | /admin/logs | Admin | admin | HTML |
| 12 | GET | /admin/api/tools.php?action=X | Admin | admin | JSON |
| 13 | GET | /painel/ | Coord/Admin | parceiro, admin | HTML |
| 14 | GET/POST | /painel/clientes | Coord/Admin | parceiro, admin | HTML |
| 15 | GET/POST | /painel/sites | Coord/Admin | parceiro, admin | HTML |
| 16 | GET/POST | /painel/site/dominio?id=X | Coord/Admin | parceiro, admin | HTML |
| 17 | GET | /cliente/ | Login | cliente | HTML |
| 18 | GET | /cliente/site?id=X | Login+Owner | cliente | HTML |
| 19 | POST | /cliente/upload?site_id=X | Login+Owner | cliente | Redirect |
| 20 | GET | /cliente/delete?site_id=X&arquivo=Y | Login+Owner | cliente | Redirect |
| 21 | GET/POST | /cliente/template?id=X | Login+Owner | cliente | HTML |
| 22 | GET/POST | /cliente/editar?id=X | Login+Owner | cliente | HTML |
| 23 | GET/POST | /cliente/site/dominio?id=X | Login | cliente | HTML |
| 24 | GET | /cliente/notificacoes | Login | cliente | HTML |
| 25 | GET | /cliente/logs | Login | cliente | HTML |
| 26 | GET | /api/notificacoes.php | Session | Qualquer logado | JSON |
| 27 | GET | /api/stats.php | Admin | admin | JSON |
| 28 | GET | /health | Nenhuma | Público | JSON |
| 29 | POST | /api/v1/analise | X-API-Key | Interno | JSON |
| 30 | POST | /api/v1/inventario | X-API-Key | Interno | JSON |
| 31 | POST | /api/v1/chat | X-API-Key | Interno | JSON |
25. Como Rodar o Sistema
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ção | Comando |
|---|---|
| O site não carrega | sudo systemctl status nginx |
| Página PHP retorna erro 500 | sudo tail -f /var/log/php8.3-fpm.log |
| API de IA não responde | systemctl status ai-api |
| Disco cheio | df -h + du -sh /var/www/sites/* |
| Servidor lento | free -h + top |
| Certificado SSL expirou | sudo 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
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:
/admin/relatorios→/admin/relatorios.php
Fonte: /etc/nginx/sites-available/starhosting (linhas 47-49)
27. Como Criar uma API Nova
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
- Node.js v24+ (instalado via NVM)
- Arquivo
/var/www/gerenciador/tests/.envcom credenciais
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
| Arquivo | Testes | O que verifica |
|---|---|---|
endpoints_test.sh | 7 | Home (200), Login (200), Admin sem auth (302), 3 arquivos bloqueados (403) |
tools_noauth_test.sh | 3 | GET/POST sem sessão (403), ação inexistente (403) |
tools_auth_test.sh | 8 | Todas 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
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ção | Exemplo | Por quê |
|---|---|---|---|
| Arquivos PHP (páginas) | snake_case, minúsculas | clientes.php, meu_endpoint.php | Nginx e servidores Linux distinguem maiúsculas de minúsculas |
| Funções PHP | camelCase | checkSiteLimit(), getDB() | Padrão PHP (PSR-1) |
| Variáveis PHP | snake_case | $cliente_id, $site_path | Fácil de ler com múltiplas palavras |
| Constantes | UPPER_SNAKE_CASE | DB_PATH, SITES_PATH | Destaca que é valor fixo, não muda |
| Endpoints API | snake_case | /api/v1/meu_endpoint | RESTful, fácil de digitar no navegador |
| Tabelas banco | snake_case, plural | usuarios, logs_acao | Padrão SQL, descreve coleções de dados |
O que NÃO fazer
- ❌ Nunca usar
sedpara editar código — pode quebrar formatação e caracteres especiais - ❌ Nunca expor o arquivo
.env— contém senhas e chaves de API - ❌ Nunca inventar dados — sempre usar fatos verificáveis
- ❌ Nunca usar
sudodesnecessariamente — minimiza riscos de segurança - ❌ Nunca commitar segredos no Git — ficam visíveis para quem clonar o repositório
- ❌ Nunca modificar arquivos fora do escopo declarado — pode quebrar funcionalidade
Protocolo da Verdade (resumo)
- Toda afirmação deve ter fonte verificável (arquivo, linha, comando)
- Se não souber, dizer "Dados insuficientes" — nunca inventar
- Nunca inventar, especular ou assumir
- Mostrar raciocínio passo a passo
- Aceitar feedback negativo como verdade
Fonte: PROTOCOLO_VERDADE.md (249 linhas)
30. Arquivos Importantes
| Arquivo | Descrição | Quando usar |
|---|---|---|
php/config.php | Configurações globais, tiers, helpers | Quando precisa de constantes ou config |
php/db.php | Conexão SQLite, schema, logAcao() | Quando precisa acessar banco de dados |
php/auth.php | login(), logout(), requireLogin(), etc. | Quando precisa proteger páginas |
php/functions.php | Funções de negócio (createSite, paginate, etc.) | Quando precisa de lógica reutilizável |
php/admin/api/tools.php | API de ferramentas do servidor | Quando precisa executar ações admin |
.env | Credenciais (SENHA, SMTP, etc.) | NUNCA expor, apenas referência |
/etc/nginx/sites-available/starhosting | Config Nginx do painel | Quando precisa alterar comportamento do servidor |
ai-api/main.py | Ponto de entrada FastAPI | Quando precisa alterar endpoints de IA |
ai-api/config.py | Configurações Ollama | Quando precisa alterar modelo ou parâmetros |
CHANGELOG.md | Histórico completo do sistema | Quando precisa ver o que mudou |
31. Comandos Úteis
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
| Prioridade | Item | Status |
|---|---|---|
| Alta | Email via Brevo (verificação de domínio) | Pendente |
| Alta | Cloudflare Email Routing (admin@, suporte@, noreply@) | Pendente |
| Média | Templates Premium/Business | Pendente |
| Média | Integração de templates no fluxo de criação | Pendente |
| Média | Documentação da API (Swagger/README) | Pendente |
| Baixa | Script automatizado de criação de site | Pendente |
| Baixa | Configurar OpenCode com Qwen3:8b + MiMo V2.5 Free | Pendente |
| Média | API Pública — instalar dependências (php-redis, firebase/php-jwt) | Pendente |
| Média | API Pública — criar tabela api_clients | Pendente |
| Média | API Pública — implementar auth + rate limit + endpoints | Pendente |
Fonte: CHANGELOG.md (linhas 210-240)
33. API Pública (Planejada)
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).
Por que não expor as APIs internas?
| Problema de expor diretamente | Soluçã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 | JWT com expiração curta (15min) + refresh tokens|
| Sem log de auditoria — impossível rastrear uso | Toda chamada logada: client_id, endpoint, IP, timestamp |
Arquitetura
Decisões de Arquitetura
| Componente | Escolha | Por quê (padrão de mercado) |
|---|---|---|
| Algoritmo de Rate Limit | Token Bucket | Padrão AWS/Google/Stripe — permite rajadas + taxa sustentada |
| Storage do Rate Limit | Redis | Já instalado e rodando, operações atômicas, TTL automático |
| Autenticação | JWT (firebase/php-jwt) | 460M+ installs, padrão da indústria, suporta HS256 |
| Banco de dados | SQLite (já temos) | Econômico, suficiente para volume de clientes |
| Secret key | Auto-gerado (32 bytes hex) | Cliente nunca escolhe — sistema gera, mostra uma vez, armazena hash |
| Scopes por plano | Definidos na criação | Segue 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étodo | Endpoint | Descrição | Scopes |
|---|---|---|---|
| POST | /api/public/v1/auth/token | Gera JWT (client_id + secret) | público |
| GET | /api/public/v1/status | Status do sistema | read |
| GET | /api/public/v1/sites | Lista sites do cliente | read |
| GET | /api/public/v1/sites/{id} | Detalhes de um site | read |
| POST | /api/public/v1/ai/analise | Envia imagem para análise | analyze |
| POST | /api/public/v1/ai/chat | Chat com IA | analyze |
Segurança (padrão de mercado)
- HTTPS obrigatório — já temos via Cloudflare
- Rate limit headers —
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset - HTTP 429 — com header
Retry-Afterquando excede - JWT expira em 15 min — refresh token para sessões longas
- Secret nunca mais mostrado — após criação, só hash no banco
- Log de auditoria — toda chamada registrada
- CORS configurado — only origins permitidos
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
| Arquivo | Função |
|---|---|
/var/www/gerenciador/php/api/index.php | Router principal |
/var/www/gerenciador/php/api/auth.php | Geração e validação de JWT |
/var/www/gerenciador/php/api/ratelimit.php | Token Bucket com Redis |
/var/www/gerenciador/php/api/middleware.php | Pipeline: auth → rate limit → scope |
/var/www/gerenciador/php/api/endpoints/ | Endpoints específicos (status, sites, ai) |
/etc/nginx/sites-available/api | Config Nginx para /api/public/ |
34. Chat API Interna (Implementada)
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.
O que a Chat API faz
| Funcionalidade | Descrição |
|---|---|
| Receber mensagens | Cliente envia mensagem, IA responde |
| Manter contexto | IA lembra das últimas 30 mensagens |
| Detectar confusão | Se cliente diz "como assim", "não entendi", usa 100 msgs em vez de 30 |
| Compactação automática | A cada 30 msgs ou 2 horas sem atividade |
| Compactação manual | Endpoint para forçar compactação |
| Gerenciar contexto | Loja pode atualizar contexto (produtos, preços, etc.) |
| Histórico completo | Todas as mensagens salvas no SQLite |
Arquitetura
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étodo | Endpoint | Descrição |
|---|---|---|
| POST | /api/chat/send.php | Envia mensagem e recebe resposta da IA |
| POST | /api/chat/contexto.php | Atualiza contexto da loja |
| POST | /api/chat/compact.php | Força compactação manual |
| GET | /api/chat/history.php | Retorna 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
| Tipo | Gatilho | O que faz |
|---|---|---|
| Automática | 30+ mensagens OU 2+ horas sem atividade | Resume msgs antigas, mantém últimas 10 |
| Manual | POST /api/chat/compact.php | Loja força compactação quando quiser |
| Expandida | Confusã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:
- "não entendi", "como assim", "pode repetir"
- "o que?", "pode explicar", "confuso"
- "como?", "que?", "de novo"
Arquivos
| Arquivo | Função | Linhas |
|---|---|---|
api/chat/config.php | Configurações (limites, API key, sinais) | ~66 |
api/chat/db.php | CRUD de sessões no SQLite | ~85 |
api/chat/ollama.php | Chamada à AI API | ~85 |
api/chat/compactador.php | Detecção + compactação | ~95 |
api/chat/send.php | Endpoint principal | ~95 |
api/chat/contexto.php | Atualização de contexto | ~70 |
api/chat/compact.php | Compactação manual | ~50 |
api/chat/history.php | Histórico da sessão | ~45 |
Fonte: /var/www/gerenciador/php/api/chat/ (640 linhas totais)
Apêndice A. Credenciais e Configurações
| Item | Valor | Fonte |
|---|---|---|
| IP do servidor | 137.131.229.136 | config.php, linha 6 |
| URL base | https://starhosting.com.br | config.php, linha 7 |
| Admin email | admin@starhosting.com.br | .env, linha 2 |
| Admin senha | Windows@98 | .env, linha 4 |
| Secret key (sessões) | 59fee5ec... (64 hex chars) | .env, linha 1 |
| SMTP host | smtp-relay.brevo.com | .env, linha 7 |
| SMTP user | ad1b03001@smtp-brevo.com | .env, linha 9 |
| SMTP pass | xsmtpsib-... (API key) | .env, linha 10 |
| AI API key (interna) | 2c33bb2a... (64 hex chars) | CHANGELOG.md |
| Cloudflare Zone ID | 6eb5cee90c8f644ab42dd32150cd73ff | CHANGELOG.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
- Ancoragem Factual Absoluta — Toda afirmação deve ser baseada em fontes verificáveis. Proibido inventar, especular ou assumir.
- 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.
- Anti-Arrogância — Eliminar vieses pessoais e sycophancy (concordância injustificada). Correto factual > soar útil.
- Anti-Dados Mock — Proibido usar dados fictícios, returns hardcoded, ou placeholders em funções complexas.
Correção de Erros do Usuário
- Anti-Gaslighting Algorítmico — NUNCA assumir que o sistema está correto e que o usuário ou seu software está errado.
- Blacklist Anti-Looping — Se uma abordagem falhar 2 vezes, registrar na "Blacklist Registry" e NUNCA mais tentar.
- Blacklist Comportamental (v2.5) — Aplica-se a padrões comportamentais: Helpfulness Bias, Scope Creep, Premature Action.
Gatekeeper de Compactação de Contexto
- NUNCA invocar
/compactno meio de um processo lógico complexo. - Compactar APENAS no final de um ciclo completo.
Escopo e Disciplina de Edição (v2.5)
- Declaração Obrigatória de Escopo — ANTES de qualquer edição, declarar: Escopo, Exclusões, Intenção.
- Execução de Limite de Edição — NUNCA modificar arquivo fora do escopo declarado.
- 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
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ês | Tradução | O que é | Exemplo |
|---|---|---|---|
| Server | Servidor | Computador ligado 24h que guarda e mostra sites | O StarHosting roda num servidor Oracle Cloud |
| Domain | Domínio | Endereço do site na internet | starhosting.com.br |
| Hosting | Hospedagem | Serviço de alugar espaço em servidor | StarHosting é um serviço de hospedagem |
| SSL/TLS | Certificado de Segurança | CRIPTOGRAFA a comunicação (HTTPS) | starhosting.com.br tem SSL válido até 28/08/2026 |
| DNS | Domain Name System | Traduz domínio em IP | Cloudflare DNS traduz starhosting.com.br → 137.131.229.136 |
| HTTPS | HTTP Seguro | HTTP com criptografia SSL | Todo acesso ao StarHosting é via HTTPS |
| Nginx | Motor-X (servidor web) | Software que recebe pedidos e mostra páginas | Nginx serve os sites criados no StarHosting |
| PHP-FPM | PHP FastCGI Process Manager | Executa código PHP | PHP-FPM processa as páginas do painel |
| SQLite | Banco de dados leve | Banco em arquivo único, sem servidor | database.db guarda todos os dados do StarHosting |
| API | Application Programming Interface | Forma de programas se comunicarem | /api/v1/analise recebe imagem e retorna análise |
| JSON | JavaScript Object Notation | Formato de dados (chave: valor) | {"ok": true, "dados": {"status": "ativo"}} |
| CRUD | Create, Read, Update, Delete | 4 operações básicas de banco de dados | Criar site, ver site, editar site, deletar site |
| Session | Sessão | Dados do usuário logado no servidor | $_SESSION['user_id'] = 1 |
| Cookie | Biscoito (navegador) | Arquivo pequeño no navegador que identifica o usuário | PHPSESSID identifica quem está logado |
| Token | Chave/Código | Código único que prova que você é quem diz ser | API Key do FastAPI: x-api-key: 2c33bb... |
| Bcrypt | Algoritmo de hash | Transforma senha em código ilegível | password_hash($senha, PASSWORD_BCRYPT) |
| PWA | Progressive Web App | Site que vira app de celular | StarHosting é PWA — funciona offline |
| Service Worker | Trabalhador de serviço | Script que faz PWA funcionar offline | sw.js cacheia páginas para funcionar sem internet |
| FastAPI | API Rápida (Python) | Framework Python para criar APIs | A API de IA usa FastAPI (main.py) |
| Ollama | Motor de IA Local | Roda modelos de IA no servidor | Ollama roda qwen2.5vl:3b no servidor |
| LLM | Large Language Model | Modelo de linguagem | Qwen é um LLM que gera texto |
| VLM | Vision Language Model | Modelo de IA que "enxerga" imagens | qwen2.5vl:3b analisa imagens de câmeras |
| Base64 | Codificação Base64 | Transforma binário (imagem) em texto | Imagem vira string para enviar na API |
| Bounding Box | Caixa delimitadora | Retângulo que marca onde um objeto está na imagem | [0.1, 0.2, 0.3, 0.4] = x1, y1, x2, y2 |
| Endpoint | Ponto de extremidade | URL que responde a pedidos HTTP | /api/v1/analise é um endpoint |
| Middleware | Software intermediário | Código que roda entre o pedido e a resposta | FastAPI usa middleware para autenticação |
| Wildcard | Curinga | Certificado que vale para TODOS os subdomínios | *.starhosting.com.br cobre api., admin., etc. |
| Daemon | Demônio (serviço em background) | Programa que roda sem interface visual | Ollama roda como daemon (ollama.service) |
| Cron | Agendador de tarefas | Executa comandos em horários definidos | certbot renova SSL automaticamente via cron |
| symlink | Link simbólico | Atalho que aponta para outro arquivo/pasta | site_xyz em sites-available → sites-enabled |
| root | Raiz (Nginx) | Pasta onde o Nginx procura os arquivos | root /var/www/gerenciador/php |
| server_name | Nome do servidor | Domínio que o Nginx responde | server_name starhosting.com.br *.starhosting.com.br |
| location | Localização | Bloco que define como tratar URLs | location /admin/ { ... } |
| try_files | Tentar arquivos | Procura o arquivo na ordem especificada | try_files $uri $uri.php =404 |
| return 301 | Redirecionar permanentemente | Move o usuário para outra URL | return 301 https://starhosting.com.br$request_uri |
Apêndice D. Histórico deste Documento
| Data | Versão | Alteração | Autor |
|---|---|---|---|
| 03/06/2026 | 1.0 | Criação inicial do documento | StarHosting AI |
StarHosting — Documentação Completa v1.2
Última atualização: 03/06/2026
starhosting.com.br









