Files
claude-plugins/perfex-dev/skills/perfex-migrations/SKILL.md
Emanuel Almeida 6b3a6f2698 feat: refactor 30+ skills to Anthropic progressive disclosure pattern
- All SKILL.md files now <500 lines (avg reduction 69%)
- Detailed content extracted to references/ subdirectories
- Frontmatter standardised: only name + description (Anthropic standard)
- New skills: brand-guidelines, spec-coauthor, report-templates, skill-creator
- Design skills: anti-slop guidelines, premium-proposals reference
- Removed non-standard frontmatter fields (triggers, version, author, category)

Plugins affected: infraestrutura, marketing, dev-tools, crm-ops, gestao,
core-tools, negocio, perfex-dev, wordpress, design-media

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:05:03 +00:00

10 KiB

name, description
name description
perfex-migrations Migrações e upgrades de módulos Perfex CRM — gestão de versões, ficheiros de migração e actualizações de base de dados. Baseado apenas na documentação oficial.

/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