- Completely redesigned Cost Center create/edit modal with elegant wizard-style UI - Added preview card, visual settings section, keyword tags with auto-assign badge - Added missing i18n translations for costCenters (namePlaceholder, descPlaceholder, etc.) - Documented modal design pattern in copilot-instructions.md for future reference - Pattern includes: colors, structure, labels, cards, tags, switch components
6.6 KiB
GitHub Copilot Instructions
🚨 REGRA CRÍTICA DE DEPLOY
NUNCA envie arquivos manualmente com scp/rsync para o servidor.
Deploy Obrigatório
Sempre que precisar enviar código para produção, USE OS SCRIPTS:
# Para mudanças no BACKEND (PHP/Laravel)
cd /workspaces/webmoney/backend && ./deploy.sh
# Para mudanças no FRONTEND (React/JS)
cd /workspaces/webmoney/frontend && ./deploy.sh
Por que usar os scripts?
Os scripts de deploy:
-
Backend (deploy.sh):
- Sincroniza arquivos com rsync
- Instala dependências com composer
- Executa migrações
- Limpa e regenera cache
- Reinicia PHP-FPM
- Ajusta permissões
-
Frontend (deploy.sh):
- Faz build do React (npm run build)
- Envia para /var/www/webmoney/frontend/dist (não /frontend!)
- Verifica se deploy funcionou
Proibições
❌ scp arquivo root@213.165.93.60:/var/www/webmoney/...
❌ rsync arquivo root@213.165.93.60:/var/www/webmoney/...
❌ Copiar arquivos individuais manualmente
Workflow
- Editar código
cd backend && ./deploy.shoucd frontend && ./deploy.sh- Testar em https://webmoney.cnxifly.com
- Se OK:
VERSION++(incrementar versão)- Atualizar
CHANGELOG.md(documentar mudanças) - Atualizar
README.md(sempre que necessário - novas features, requisitos, comandos, etc.)
- Commit e push
📝 Quando atualizar README.md
- Nova funcionalidade importante
- Mudança de requisitos (versão PHP, Node, etc.)
- Novos endpoints de API
- Alteração de variáveis de ambiente
- Novos comandos artisan
- Mudança na estrutura do projeto
🚫 Regras de UI/UX
NUNCA use alert(), confirm() ou prompt() do navegador.
Sempre usar componentes modais ou toast:
- Para erros:
toast.error('mensagem') - Para sucesso:
toast.success('mensagem') - Para confirmação: Usar
<ConfirmModal />component - Para formulários: Criar modal customizado
// ❌ PROIBIDO
alert('Erro!');
confirm('Tem certeza?');
// ✅ CORRETO
import { useToast } from '../components/Toast';
import { ConfirmModal } from '../components/Modal';
const toast = useToast();
toast.error('Erro!');
toast.success('Sucesso!');
Estrutura do Servidor
/var/www/webmoney/
├── backend/ # Laravel (Nginx → PHP-FPM)
└── frontend/
└── dist/ # React build (Nginx root)
Credenciais
- Servidor: root@213.165.93.60 (senha: Master9354)
- Banco: webmoney / M@ster9354
- Usuário WebMoney: marco@cnxifly.com / M@ster9354
🔑 Acesso SSH - SEMPRE usar sshpass
OBRIGATÓRIO: Sempre usar sshpass para comandos SSH/SCP/RSYNC.
# SSH para executar comandos
sshpass -p 'Master9354' ssh -o StrictHostKeyChecking=no root@213.165.93.60 "comando"
# Ver logs do Laravel
sshpass -p 'Master9354' ssh -o StrictHostKeyChecking=no root@213.165.93.60 "tail -50 /var/www/webmoney/backend/storage/logs/laravel.log"
# Executar tinker
sshpass -p 'Master9354' ssh -o StrictHostKeyChecking=no root@213.165.93.60 "cd /var/www/webmoney/backend && php artisan tinker --execute='codigo'"
# MySQL
sshpass -p 'Master9354' ssh -o StrictHostKeyChecking=no root@213.165.93.60 "mysql -u webmoney -p'M@ster9354' webmoney -e 'QUERY'"
❌ NUNCA usar ssh root@213.165.93.60 sem sshpass (vai travar esperando senha)
🎨 Padrão Visual de Modais
TODOS os modais de formulário devem seguir este padrão elegante:
Estrutura Base
<div className="modal show d-block" style={{ backgroundColor: 'rgba(0,0,0,0.8)' }}>
<div className="modal-dialog modal-dialog-centered modal-lg">
<div className="modal-content border-0" style={{ background: '#1e293b', maxHeight: '90vh' }}>
{/* Header sem borda */}
<div className="modal-header border-0 pb-0">
<div>
<h5 className="modal-title text-white mb-1">
<i className="bi bi-icon me-2 text-primary"></i>
Título
</h5>
<p className="text-slate-400 mb-0 small">Subtítulo</p>
</div>
<button className="btn-close btn-close-white" onClick={onClose}></button>
</div>
{/* Body com scroll */}
<div className="modal-body pt-3" style={{ maxHeight: '65vh', overflowY: 'auto' }}>
{/* Preview Card - SEMPRE no topo */}
<div className="mb-4 p-3 rounded-3" style={{ background: '#0f172a' }}>
{/* Preview visual do item sendo criado/editado */}
</div>
{/* Campos em cards com background #0f172a */}
{/* Labels com ícones coloridos */}
{/* Badges "Opcional" quando necessário */}
</div>
{/* Footer sem borda */}
<div className="modal-footer border-0">
<button className="btn btn-outline-secondary px-4">Cancelar</button>
<button className="btn btn-primary px-4">Salvar</button>
</div>
</div>
</div>
</div>
Cores do Sistema
- Background modal:
#1e293b - Background campos/cards:
#0f172a - Texto principal:
text-white - Texto secundário:
text-slate-400 - Texto desabilitado:
text-slate-500
Labels com Ícones
<label className="form-label text-white fw-medium mb-2">
<i className="bi bi-type me-2 text-primary"></i>
Nome *
</label>
Badge Opcional
<span className="badge bg-secondary ms-2" style={{ fontSize: '0.65rem' }}>
{t('common.optional')}
</span>
Seleção Visual com Cards
Para seleções (categorias, ícones), usar cards clicáveis:
<div
onClick={() => handleSelect(item)}
className="p-2 rounded text-center"
style={{
background: isSelected ? 'rgba(59, 130, 246, 0.15)' : '#0f172a',
cursor: 'pointer',
border: isSelected ? '2px solid #3b82f6' : '2px solid transparent'
}}
>
<i className={`bi ${icon} d-block mb-1`} style={{ color }}></i>
<small className="text-white">{label}</small>
</div>
Seção de Keywords/Tags
<div className="p-3 rounded" style={{ background: '#0f172a' }}>
<div className="input-group mb-2">
<input className="form-control bg-dark text-white border-0" />
<button className="btn btn-primary px-3">
<i className="bi bi-plus-lg"></i>
</button>
</div>
<div className="d-flex flex-wrap gap-2">
{/* Tags com cor do item */}
</div>
</div>
Switch de Status
<div className="form-check form-switch">
<input type="checkbox" className="form-check-input" role="switch" />
<label className="form-check-label text-white">
<i className={`bi ${isActive ? 'bi-check-circle text-success' : 'bi-x-circle text-secondary'} me-2`}></i>
{isActive ? 'Activo' : 'Inactivo'}
</label>
</div>
Documentação
Consulte .DIRETRIZES_DESENVOLVIMENTO_v5 para regras completas.