webmoney/.github/copilot-instructions.md

7.4 KiB

Copilot Instructions

🔄 REPOSITÓRIO GIT - GITEA (Self-Hosted)

IMPORTANTE: O repositório principal é o Gitea no nosso servidor, NÃO o GitHub.

Configuração do Repositório

# Repositório principal (Gitea)
git remote -v
# gitea   https://git.cnxifly.com/marco/webmoney.git

# URL Web
https://git.cnxifly.com/marco/webmoney

# Credenciais Gitea
Usuário: marco
Senha:   M@ster9354

Comandos Git

# Push para Gitea (SEMPRE usar este)
git push gitea main

# Pull do Gitea
git pull gitea main

# Commit padrão
git add -A && git commit -m "descrição" && git push gitea main

Proibições Git

  • NUNCA usar git push origin (GitHub foi descontinuado)
  • NUNCA criar repositórios no GitHub para este projeto

🚨 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:

  1. 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
  2. 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

  1. Editar código
  2. cd backend && ./deploy.sh ou cd frontend && ./deploy.sh
  3. Testar em https://webmoney.cnxifly.com
  4. Se OK:
    • VERSION++ (incrementar versão)
    • Atualizar CHANGELOG.md (documentar mudanças)
    • Atualizar README.md (sempre que necessário - novas features, requisitos, comandos, etc.)
  5. Commit e push para Gitea:
    git add -A && git commit -m "descrição" && git push gitea main
    

📝 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

🔑 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.