Files
claude-plugins/perfex-dev/skills/perfex-migrations/SKILL.md
Emanuel Almeida 2cb3210962 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>
2026-02-07 21:41:24 +00:00

11 KiB

name, description, author, version, quality_score, user_invocable, desk_task
name description author version quality_score user_invocable desk_task
perfex-migrations 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". Descomplicar® Crescimento Digital 1.0.0 70 true 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


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

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

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

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

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

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

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

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

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.

// 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

// Exemplo: Adicionar campo "priority" na v1.8.0

2. Criar Migration

// 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

// Adicionar campo ao CREATE TABLE no activation hook
`priority` TINYINT(1) NOT NULL DEFAULT 0,

4. Actualizar Versão no Header

/*
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

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