feat: adiciona 12 plugins Descomplicar ao marketplace
Plugins: automacao, crm-ops, design-media, dev-tools, gestao, infraestrutura, marketing, negocio, perfex-dev, project-manager, wordpress + hello-plugin (existente). Totais: 83 skills, 44 agents, 12 datasets.json Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
426
perfex-dev/skills/perfex-migrations/SKILL.md
Normal file
426
perfex-dev/skills/perfex-migrations/SKILL.md
Normal file
@@ -0,0 +1,426 @@
|
||||
---
|
||||
name: perfex-migrations
|
||||
description: Perfex CRM module migrations and upgrades. Version management, migration files, database updates. Based on official documentation only. Use when user mentions "perfex migration", "module upgrade", "version perfex", "database migration".
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.0.0
|
||||
quality_score: 70
|
||||
user_invocable: true
|
||||
desk_task: null
|
||||
---
|
||||
|
||||
# /perfex-migrations - Migrations Perfex CRM
|
||||
|
||||
Sistema de migrações e upgrades de módulos. **Zero assumptions, zero hallucinations** - apenas documentação oficial.
|
||||
|
||||
---
|
||||
|
||||
## Documentação Base
|
||||
|
||||
- [Preparing Module Upgrade](https://help.perfexcrm.com/preparing-module-upgrade/)
|
||||
- [Module Basics](https://help.perfexcrm.com/module-basics/)
|
||||
|
||||
---
|
||||
|
||||
## Como Funciona
|
||||
|
||||
O Perfex CRM compara:
|
||||
- **Versão no init file** (header `Version:`)
|
||||
- **Versão na base de dados** (tabela `tblmodules`)
|
||||
|
||||
Se forem diferentes → Sistema mostra "Database upgrade required".
|
||||
|
||||
---
|
||||
|
||||
## Estrutura de Migrations
|
||||
|
||||
```
|
||||
modules/meu_modulo/
|
||||
├── meu_modulo.php # Init file com Version: X.Y.Z
|
||||
└── migrations/
|
||||
├── 001_version_100.php # v1.0.0 → v1.0.1
|
||||
├── 002_version_101.php # v1.0.1 → v1.0.2
|
||||
├── 100_version_100.php # v1.0.0 inicial (alternativa)
|
||||
├── 110_version_110.php # v1.1.0
|
||||
└── 200_version_200.php # v2.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Formato do Ficheiro
|
||||
|
||||
### Nomenclatura (CRÍTICO)
|
||||
|
||||
O Perfex usa **Sequential Migration** (não Timestamp).
|
||||
|
||||
```
|
||||
NNN_version_NNN.php
|
||||
│ │ │
|
||||
│ │ └── Versão sem pontos (110 = 1.1.0)
|
||||
│ └── Literal "version"
|
||||
└── Número sequencial (3 dígitos, sem gaps)
|
||||
```
|
||||
|
||||
**Exemplos:**
|
||||
|
||||
| Versão | Ficheiro |
|
||||
|--------|----------|
|
||||
| 1.0.0 | `001_version_100.php` ou `100_version_100.php` |
|
||||
| 1.0.1 | `002_version_101.php` ou `101_version_101.php` |
|
||||
| 1.1.0 | `003_version_110.php` ou `110_version_110.php` |
|
||||
| 2.0.0 | `004_version_200.php` ou `200_version_200.php` |
|
||||
|
||||
**Convenção recomendada:** Usar versão como prefixo (100, 110, 200...).
|
||||
|
||||
---
|
||||
|
||||
## Template Migration
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_110 extends App_module_migration
|
||||
{
|
||||
/**
|
||||
* Executado durante upgrade
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// Alterações de base de dados aqui
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Notas Importantes
|
||||
|
||||
1. **Classe:** `Migration_Version_NNN` (NNN = versão sem pontos)
|
||||
2. **Extends:** `App_module_migration`
|
||||
3. **Método:** Apenas `up()` - não há `down()` (downgrades não suportados)
|
||||
4. **Pode ser vazio:** Se não houver alterações de BD, deixar `up()` vazio
|
||||
|
||||
---
|
||||
|
||||
## Exemplos de Migrations
|
||||
|
||||
### Adicionar Coluna
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_110 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
// Adicionar coluna se não existir
|
||||
if (!$CI->db->field_exists('new_column', db_prefix() . 'meu_modulo')) {
|
||||
$CI->db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo`
|
||||
ADD COLUMN `new_column` VARCHAR(255) DEFAULT NULL AFTER `name`');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Criar Nova Tabela
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_120 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
if (!$CI->db->table_exists(db_prefix() . 'meu_modulo_items')) {
|
||||
$CI->db->query('
|
||||
CREATE TABLE `' . db_prefix() . 'meu_modulo_items` (
|
||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`parent_id` INT(11) UNSIGNED NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`quantity` INT(11) NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parent_id` (`parent_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';
|
||||
');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Modificar Coluna
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_130 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
// Alterar tipo de coluna
|
||||
$CI->db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo`
|
||||
MODIFY COLUMN `amount` DECIMAL(15,2) NOT NULL DEFAULT 0.00');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adicionar Índice
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_140 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
// Verificar se índice existe (evitar erro)
|
||||
$indexes = $CI->db->query('SHOW INDEX FROM `' . db_prefix() . 'meu_modulo`
|
||||
WHERE Key_name = "idx_status"')->result();
|
||||
|
||||
if (count($indexes) == 0) {
|
||||
$CI->db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo`
|
||||
ADD INDEX `idx_status` (`status`)');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Migração de Dados
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_150 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
// Migrar dados existentes
|
||||
$CI->db->query('UPDATE `' . db_prefix() . 'meu_modulo`
|
||||
SET `status` = "active"
|
||||
WHERE `status` = "1"');
|
||||
|
||||
$CI->db->query('UPDATE `' . db_prefix() . 'meu_modulo`
|
||||
SET `status` = "inactive"
|
||||
WHERE `status` = "0"');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adicionar Opção
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_160 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// Adicionar nova opção (add_option não sobrescreve)
|
||||
add_option('meu_modulo_new_feature', '1');
|
||||
add_option('meu_modulo_default_status', 'pending');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Migration Vazia (Só actualiza versão)
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_170 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// Sem alterações de BD nesta versão
|
||||
// O Perfex apenas actualiza o número da versão
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sincronizar Activation Hook
|
||||
|
||||
**CRÍTICO:** O activation hook deve SEMPRE conter o schema mais recente.
|
||||
|
||||
```php
|
||||
// modules/meu_modulo/meu_modulo.php
|
||||
|
||||
function meu_modulo_activation_hook()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
// Schema completo e actualizado (v1.7.0)
|
||||
if (!$CI->db->table_exists(db_prefix() . 'meu_modulo')) {
|
||||
$CI->db->query('
|
||||
CREATE TABLE `' . db_prefix() . 'meu_modulo` (
|
||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`client_id` INT(11) UNSIGNED NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`new_column` VARCHAR(255) DEFAULT NULL, -- Adicionado v1.1.0
|
||||
`description` TEXT,
|
||||
`amount` DECIMAL(15,2) NOT NULL DEFAULT 0.00, -- Modificado v1.3.0
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT "pending",
|
||||
`created_at` DATETIME NOT NULL,
|
||||
`updated_at` DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `client_id` (`client_id`),
|
||||
KEY `idx_status` (`status`) -- Adicionado v1.4.0
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';
|
||||
');
|
||||
}
|
||||
|
||||
// Tabela items (adicionada v1.2.0)
|
||||
if (!$CI->db->table_exists(db_prefix() . 'meu_modulo_items')) {
|
||||
$CI->db->query('
|
||||
CREATE TABLE `' . db_prefix() . 'meu_modulo_items` (
|
||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`parent_id` INT(11) UNSIGNED NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`quantity` INT(11) NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parent_id` (`parent_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';
|
||||
');
|
||||
}
|
||||
|
||||
// Opções (versão mais recente)
|
||||
add_option('meu_modulo_version', '1.7.0');
|
||||
add_option('meu_modulo_new_feature', '1'); // v1.6.0
|
||||
add_option('meu_modulo_default_status', 'pending'); // v1.6.0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow de Release
|
||||
|
||||
### 1. Desenvolver Alterações
|
||||
|
||||
```php
|
||||
// Exemplo: Adicionar campo "priority" na v1.8.0
|
||||
```
|
||||
|
||||
### 2. Criar Migration
|
||||
|
||||
```php
|
||||
// migrations/180_version_180.php
|
||||
|
||||
<?php
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_Version_180 extends App_module_migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
if (!$CI->db->field_exists('priority', db_prefix() . 'meu_modulo')) {
|
||||
$CI->db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo`
|
||||
ADD COLUMN `priority` TINYINT(1) NOT NULL DEFAULT 0 AFTER `status`');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Actualizar Activation Hook
|
||||
|
||||
```php
|
||||
// Adicionar campo ao CREATE TABLE no activation hook
|
||||
`priority` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
```
|
||||
|
||||
### 4. Actualizar Versão no Header
|
||||
|
||||
```php
|
||||
/*
|
||||
Module Name: Meu Módulo
|
||||
Version: 1.8.0 <!-- ACTUALIZAR -->
|
||||
Requires at least: 2.3.*
|
||||
*/
|
||||
```
|
||||
|
||||
### 5. Testar
|
||||
|
||||
1. Instalação limpa (activation hook)
|
||||
2. Upgrade de versão anterior (migration)
|
||||
|
||||
---
|
||||
|
||||
## Verificações de Segurança em Migrations
|
||||
|
||||
```php
|
||||
public function up()
|
||||
{
|
||||
$CI = &get_instance();
|
||||
|
||||
// Verificar se tabela existe antes de ALTER
|
||||
if (!$CI->db->table_exists(db_prefix() . 'meu_modulo')) {
|
||||
return; // Tabela não existe, nada a fazer
|
||||
}
|
||||
|
||||
// Verificar se coluna existe antes de ADD
|
||||
if ($CI->db->field_exists('new_column', db_prefix() . 'meu_modulo')) {
|
||||
return; // Coluna já existe
|
||||
}
|
||||
|
||||
// Seguro para executar
|
||||
$CI->db->query('ALTER TABLE ...');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns (NUNCA FAZER)
|
||||
|
||||
| Anti-Pattern | Risco | Alternativa |
|
||||
|--------------|-------|-------------|
|
||||
| Gaps na sequência (001, 003) | Migrations saltadas | Sequência contínua |
|
||||
| Não actualizar activation hook | Instalações novas incompletas | Sincronizar sempre |
|
||||
| ALTER sem verificar existência | Erro se já existe | `field_exists()` |
|
||||
| DROP sem backup | Dados perdidos | Backup ou soft delete |
|
||||
| Hardcode prefix "tbl" | Falha em instalações custom | `db_prefix()` |
|
||||
|
||||
---
|
||||
|
||||
## Checklist Migrations
|
||||
|
||||
```
|
||||
1. [ ] Ficheiro com nome correcto (NNN_version_NNN.php)
|
||||
2. [ ] Classe com nome correcto (Migration_Version_NNN)
|
||||
3. [ ] Extends App_module_migration
|
||||
4. [ ] Verificações de existência antes de ALTER
|
||||
5. [ ] db_prefix() em todas as queries
|
||||
6. [ ] Activation hook actualizado com schema completo
|
||||
7. [ ] Header Version actualizado
|
||||
8. [ ] Testado: instalação limpa
|
||||
9. [ ] Testado: upgrade de versão anterior
|
||||
10. [ ] Sem gaps na sequência de migrations
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Versão:** 1.0.0 | **Autor:** Descomplicar®
|
||||
**Fonte:** help.perfexcrm.com/preparing-module-upgrade
|
||||
Reference in New Issue
Block a user