c2f-payment-gateways
Skill5 starsChanged 2 months agoMITView on GitHub
LEIA ANTES de implementar, integrar ou testar gateways de pagamento (Stripe, PayPal, etc.) no Conn2Flow (\"integra o checkout\", \"configura o gateway\", \"testa o pagamento\"). Se não ler: preço no frontend é adulterável, webhook sem idempotência duplica cobranças, SDK pesado carrega sem necessidade, e testes exigem credenciais reais.
- Reads credentials
- Sends data out
Files
Gateways de Pagamento Seguros (c2f-payment-gateways)
⚡ Gatilho Obrigatório
- TRIGGER: Pedido para implementar, configurar, testar ou auditar integração com gateways de pagamento (Stripe, PayPal, PagSeguro, etc.); criar endpoints de checkout; processar webhooks de pagamento; adicionar métodos de pagamento ao e-commerce.
- SKIP APENAS SE: Edição de módulos sem relação com transações financeiras ou páginas de produto sem checkout.
- CONSEQUÊNCIA DE IGNORAR: Preços adulteráveis pelo cliente, cobranças duplicadas por webhooks reenviados, vazamento de credenciais em logs, SDKs pesados carregados desnecessariamente e testes impossíveis sem chaves de produção.
1. Autoridade Estrita do Servidor
O preço unitário, a moeda, descontos e taxas são definidos e validados exclusivamente no backend. O cliente frontend trafega apenas identificadores e quantidades.
1.1 Proibição de Preço no Frontend
// ❌ ERRADO — preço vindo do frontend é adulterável
$preco = $_POST['preco'];
$gateway->criarCobranca($preco);
// ✅ CORRETO — preço lido do banco no backend
$produto = banco_select_registro('products', "WHERE id = '$produto_id'");
$preco = (float) $produto['preco'];
$gateway->criarCobranca($preco);1.2 Validação Dupla (Frontend + Backend)
- O frontend pode exibir preços para UX, mas toda transação financeira deve recalcular valores no servidor a partir da fonte de dados canônica (banco de dados).
- Descontos, cupons e frete devem ser validados no backend antes de criar a intenção de pagamento no gateway.
2. Tokens de Pedido Criptográficos HMAC
O acesso público a um pedido (ex: página de confirmação, link por e-mail) é protegido por HMAC com salt único por pedido.
2.1 Geração do Token
// Gerar salt único por pedido
$salt = bin2hex(random_bytes(16));
banco_update_campo('salt', $salt);
banco_update_executar('orders', "WHERE numero = '$numero_pedido'");
// Gerar token HMAC para URL pública
$token = hash_hmac('sha256', $numero_pedido . '|' . $salt, OPENSSL_PASSWORD);
$url_publica = "/pedido/$numero_pedido?token=$token";2.2 Validação do Token
function validar_token_pedido($numero, $token_recebido) {
$pedido = banco_select_registro('orders', "WHERE numero = '$numero'");
$token_esperado = hash_hmac('sha256', $numero . '|' . $pedido['salt'], OPENSSL_PASSWORD);
return hash_equals($token_esperado, $token_recebido);
}[!IMPORTANT] O salt é o único segredo armazenado no banco. A constante
OPENSSL_PASSWORDé a chave HMAC do ambiente e NUNCA deve ser exposta ao frontend. Usehash_equals()para comparação timing-safe.
3. Prova de Posse em Verificações de Estado
O estado do pagamento é lido diretamente da API oficial do gateway com prova de posse obrigatória.
3.1 Tripla Verificação
Ao verificar o estado de um pagamento (ex: após retorno do checkout, webhook, polling), o sistema DEVE confirmar:
- Identificador do pedido nos metadados: O campo
metadata.order_id(Stripe) oucustom_id(PayPal) corresponde ao pedido interno. - Valor cobrado: O
amountretornado pelo gateway corresponde exatamente ao valor calculado no backend. - Moeda: O
currencyretornado corresponde à moeda do pedido.
// ✅ Prova de posse completa
function verificar_pagamento_gateway($payment_intent_id, $pedido) {
$pi = $stripe->paymentIntents->retrieve($payment_intent_id);
// 1. Prova de posse: metadados
if ($pi->metadata->order_id !== $pedido['id']) {
throw new Exception('Payment intent não pertence a este pedido');
}
// 2. Prova de posse: valor
if ($pi->amount !== (int)($pedido['total'] * 100)) {
throw new Exception('Valor divergente');
}
// 3. Prova de posse: moeda
if ($pi->currency !== strtolower($pedido['moeda'])) {
throw new Exception('Moeda divergente');
}
return $pi->status === 'succeeded';
}[!CAUTION] NUNCA confie apenas no
payment_intent_idouorder_iddo retorno do checkout. Um atacante pode substituir o ID por um pagamento legítimo de valor inferior. A tripla verificação é obrigatória.
4. Captura Mandatória no Backend
Para gateways que operam em duas fases (autorização + captura), como PayPal, a captura financeira efetiva deve ocorrer exclusivamente no servidor.
4.1 Padrão PayPal: Autorizar no Cliente, Capturar no Servidor
// Frontend — PayPal SDK (apenas AUTORIZA)
paypal.Buttons({
createOrder: (data, actions) => {
return fetch('/api/paypal/create-order', { method: 'POST' })
.then(res => res.json())
.then(data => data.order_id);
},
onApprove: (data, actions) => {
// ❌ ERRADO: actions.order.capture() captura no frontend
// ✅ CORRETO: enviar para backend capturar
return fetch('/api/paypal/capture-order', {
method: 'POST',
body: JSON.stringify({ order_id: data.orderID })
});
}
}).render('#paypal-button-container');// Backend — captura com prova de posse
function capturar_ordem_paypal($order_id, $pedido) {
$response = $paypal->captureOrder($order_id);
// Validar prova de posse (§3) antes de atualizar o pedido
validar_prova_de_posse($response, $pedido);
atualizar_status_pedido($pedido['id'], 'pago');
}5. Webhooks Minimalistas e Idempotentes
O webhook atua primariamente como sinalizador, não como processador de regras de negócio.
5.1 Fluxo do Webhook
- Receber o evento do gateway.
- Validar a assinatura (Stripe:
Webhook::constructEvent(); PayPal: verificar certificado). - Identificar o pedido interno via metadados do evento.
- Disparar ressincronização via API oficial do gateway (§3 — Prova de Posse).
- Registrar o evento com
gateway_event_idpara idempotência.
5.2 Idempotência Absoluta
function processar_webhook($event_id, $pedido_id) {
// Verificar idempotência
$existente = banco_select_registro('gateway_events',
"WHERE gateway_event_id = '$event_id'");
if ($existente) {
return; // Evento já processado — ignorar silenciosamente
}
// Registrar evento ANTES de processar
banco_insert_registro('gateway_events', [
'gateway_event_id' => $event_id,
'pedido_id' => $pedido_id,
'processado_em' => date('Y-m-d H:i:s')
]);
// Ressincronizar via API oficial (prova de posse)
verificar_e_atualizar_pagamento($pedido_id);
}[!WARNING] O webhook não deve conter lógica de negócio complexa. Ele sinaliza que algo mudou; a lógica de atualização usa a API oficial do gateway para obter o estado real com prova de posse.
5.3 Endpoint Público e Seguro
O endpoint de webhook utiliza o padrão <modulo>.ajax.public.php (ver c2f-gestor-functions §11) para receber requisições sem autenticação de sessão, mas obrigatoriamente valida a assinatura criptográfica do gateway.
6. Carregamento Condicional de SDKs
SDKs de terceiros pesados (Stripe.js ~40 KB, PayPal SDK ~200 KB) só devem ser carregados quando o pedido selecionar aquele método de pagamento.
6.1 Carregamento Sob Demanda
// ✅ CORRETO — carregar SDK apenas quando necessário
function carregarGatewaySDK(gateway) {
if (gateway === 'stripe' && !window.Stripe) {
return carregarScript('https://js.stripe.com/v3/');
}
if (gateway === 'paypal' && !window.paypal) {
return carregarScript(`https://www.paypal.com/sdk/js?client-id=${clientId}`);
}
return Promise.resolve();
}
// Ao selecionar método de pagamento
seletorGateway.addEventListener('change', async (e) => {
await carregarGatewaySDK(e.target.value);
inicializarFormularioPagamento(e.target.value);
});6.2 Auditoria de Tráfego de Rede
- Em testes E2E (Playwright), interceptar requisições de rede via
page.on('request')para certificar que SDKs de gateways não selecionados não estão sendo carregados. - Classes CSS dos containers de gateway não selecionado devem receber
hiddenpara evitar renderização do iframe.
7. Gateway Padrão (Fallback Seguro)
Na ausência de seleção explícita pelo comprador, o sistema assume o gateway padrão do lojista.
7.1 Configuração do Fallback
// Determinar gateway do pedido
$gateway = $pedido['gateway'] ?? $config_loja['gateway_padrao'] ?? 'stripe';
// Validar que o gateway é suportado
$gateways_ativos = ['stripe', 'paypal']; // Do JSON de configuração
if (!in_array($gateway, $gateways_ativos)) {
throw new Exception("Gateway '$gateway' não está configurado");
}7.2 Regra de Prioridade
- Gateway explícito selecionado pelo comprador no checkout.
- Gateway padrão configurado pelo lojista no painel administrativo.
- Primeiro gateway ativo na lista de gateways configurados.
[!NOTE] O fallback seguro garante que nenhum pedido fique sem gateway atribuído, mesmo que o frontend não envie a seleção.
8. Testes Unitários sem Credenciais
A estratégia de testes de checkout é baseada em dublês/mocks das funções da biblioteca do gateway.
8.1 Padrão de Dublê (Test Double)
// Biblioteca do gateway com injeção de dependência
class GatewayStripe {
private $client;
public function __construct($client = null) {
$this->client = $client ?? new \Stripe\StripeClient(STRIPE_SECRET_KEY);
}
public function criarIntencao($valor, $moeda, $metadata) {
return $this->client->paymentIntents->create([
'amount' => $valor,
'currency' => $moeda,
'metadata' => $metadata
]);
}
}
// No teste — sem credenciais reais
class GatewayStripeTest extends TestCase {
public function testCriarIntencao() {
$mock = $this->createMock(\Stripe\StripeClient::class);
// Configurar mock para retornar resposta simulada
$gateway = new GatewayStripe($mock);
$resultado = $gateway->criarIntencao(1000, 'brl', ['order_id' => '123']);
$this->assertNotNull($resultado);
}
}8.2 Testes E2E com Cartões de Teste
- Stripe: usar cartões de teste (
4242 4242 4242 4242) no modo de teste. - PayPal: usar contas sandbox do PayPal Developer.
- Proibição Absoluta: Credenciais de produção NUNCA devem constar em arquivos de teste, variáveis de ambiente de CI, ou logs de execução.
8.3 Simulação de Webhooks
# Stripe CLI — enviar webhook de teste localmente
stripe trigger payment_intent.succeeded --override payment_intent:metadata.order_id=pedido-123
# Teste manual — POST direto no endpoint
curl -X POST https://meusite.com/ecommerce/ecommerce.ajax.public.php \
-H "Content-Type: application/json" \
-d '{"type":"payment_intent.succeeded","data":{"object":{"id":"pi_test","metadata":{"order_id":"123"}}}}'[!CAUTION] Em ambientes de produção, sempre valide a assinatura do webhook (
Stripe-Signatureheader). Testes comcurldireto devem ser restritos a ambientes de desenvolvimento/staging.
In this repository102 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- cli/CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- .cursor/rules/sdd.mdcCursor rule
- c2f-database-testingSkill
- c2f-gd-image-safetySkill
- c2f-json-resources-syncSkill
- c2f-mdd-indexing-and-handoffsSkill
- c2f-mysql-utf8-emoji-encodingSkill
- c2f-tailwind-css-architectureSkill
- c2f-tailwind-module-migrationSkill
- c2f-widget-developmentSkill
- c2f-agent-visual-inspectionSkill
- c2f-ai-featuresSkill
- c2f-architect-masterSkill
- c2f-database-operationsSkill
- c2f-database-testingSkill
- c2f-dev-scriptsSkill
- c2f-docker-environmentSkill
- c2f-documentation-governanceSkill
- c2f-documentationSkill
- c2f-environment-configurationSkill
- c2f-executor-agentSkill
- c2f-gd-image-safetySkill
- c2f-gestor-functionsSkill
- c2f-global-variablesSkill
- c2f-hooks-systemSkill
- c2f-html-css-pages-and-componentsSkill
- c2f-interface-v2-architectureSkill
- c2f-javascript-ajaxSkill
- c2f-json-resources-syncSkill
- c2f-mdd-indexing-and-handoffsSkill
- c2f-modelo-templatesSkill
- c2f-module-crud-scaffoldingSkill
- c2f-module-visual-assetsSkill
- c2f-multilingual-systemSkill
- c2f-mysql-utf8-emoji-encodingSkill
- c2f-plugin-architectureSkill
- c2f-preview-modals-systemSkill
- c2f-project-pipeline-and-tasksSkill
- c2f-projects-systemSkill
- c2f-resources-systemSkill
- c2f-reviewer-agentSkill
- c2f-shell-and-windows-trapsSkill
- c2f-system-tasksSkill
- c2f-tailwind-css-architectureSkill
- c2f-tailwind-module-migrationSkill
- c2f-variables-systemSkill
- c2f-widget-developmentSkill
- continue-mdd-batchSkill
- mdd-memory-gardeningSkill
- mdd-workflowSkill
- project-validationSkill
- raise-spec-changeSkill
- review-current-batchSkill
- start-mdd-sliceSkill
- c2f-agent-visual-inspectionSkill
- c2f-ai-featuresSkill
- c2f-architect-masterSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

