---
name: perfex-module-basics
description: Fundamentos de desenvolvimento de módulos Perfex CRM — estrutura de pastas, ficheiro init, headers e integração CodeIgniter. Baseado apenas na documentação oficial.
---

# /perfex-module-basics - Estrutura Base Módulos Perfex CRM

Fundamentos para desenvolvimento de módulos Perfex CRM. **Zero assumptions, zero hallucinations** - apenas documentação oficial.

---

## Documentação Base

- [Module Basics](https://help.perfexcrm.com/module-basics/)
- [Introduction to Modules](https://help.perfexcrm.com/introduction-to-perfex-crm-modules/)
- [Module File Headers](https://help.perfexcrm.com/module-file-headers/)

---

## Estrutura de Pastas (Obrigatória)

```
modules/
└── meu_modulo/
    ├── meu_modulo.php      # Init file (OBRIGATÓRIO - mesmo nome da pasta)
    ├── controllers/
    │   └── Meu_modulo.php
    ├── models/
    │   └── Meu_modulo_model.php
    ├── views/
    │   ├── index.php
    │   └── form.php
    ├── libraries/
    ├── helpers/
    ├── language/
    │   └── english/
    │       └── meu_modulo_lang.php
    ├── migrations/
    │   └── 001_version_100.php
    ├── config/
    └── index.html          # SEGURANÇA - prevenir directory listing
```

---

## Init File (Obrigatório)

O ficheiro init é o ponto de entrada do módulo. **DEVE ter o mesmo nome da pasta.**

### Template Mínimo

```php
<?php

defined('BASEPATH') or exit('No direct script access allowed');

/*
Module Name: Meu Módulo
Description: Descrição do módulo
Version: 1.0.0
Requires at least: 2.3.*
Author: Descomplicar
Author URI: https://descomplicar.pt
*/

// Registar hooks de activação/desactivação
register_activation_hook('meu_modulo', 'meu_modulo_activation_hook');
register_deactivation_hook('meu_modulo', 'meu_modulo_deactivation_hook');
register_uninstall_hook('meu_modulo', 'meu_modulo_uninstall_hook');

/**
 * Executado quando o módulo é activado
 */
function meu_modulo_activation_hook()
{
    $CI = &get_instance();

    // Criar tabelas
    if (!$CI->db->table_exists(db_prefix() . 'meu_modulo')) {
        $CI->db->query('CREATE TABLE `' . db_prefix() . 'meu_modulo` (
            `id` INT(11) NOT NULL AUTO_INCREMENT,
            `name` VARCHAR(255) NOT NULL,
            `created_at` DATETIME NOT NULL,
            PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
    }

    // Adicionar opções
    add_option('meu_modulo_version', '1.0.0');
}

/**
 * Executado quando o módulo é desactivado
 */
function meu_modulo_deactivation_hook()
{
    // Limpeza temporária (não apagar dados)
}

/**
 * Executado quando o módulo é removido
 */
function meu_modulo_uninstall_hook()
{
    $CI = &get_instance();

    // Remover tabelas
    $CI->db->query('DROP TABLE IF EXISTS `' . db_prefix() . 'meu_modulo`');

    // Remover opções
    delete_option('meu_modulo_version');
}
```

---

## File Headers (Meta-Informação)

### Headers Obrigatórios

| Header | Descrição |
|--------|-----------|
| `Module Name` | **ÚNICO OBRIGATÓRIO** - Nome do módulo |

### Headers Opcionais (Recomendados)

| Header | Descrição | Exemplo |
|--------|-----------|---------|
| `Description` | Descrição funcional | `CRM integration module` |
| `Version` | Versão semântica | `1.0.0` |
| `Requires at least` | Versão mínima Perfex | `2.3.*` |
| `Author` | Nome do autor | `Descomplicar` |
| `Author URI` | Website do autor | `https://descomplicar.pt` |
| `Module URI` | Página do módulo | `https://...` |

### Exemplo Completo

```php
/*
Module Name: Customer Portal
Description: Extended customer self-service portal
Version: 2.1.0
Requires at least: 2.3.*
Author: Descomplicar
Author URI: https://descomplicar.pt
Module URI: https://descomplicar.pt/modules/customer-portal
*/
```

---

## Aceder ao CodeIgniter

Fora de controllers/models, usar `get_instance()`:

```php
$CI = &get_instance();

// Carregar helper
$CI->load->helper('meu_modulo/meu_helper');

// Carregar library
$CI->load->library('meu_modulo/minha_library');

// Carregar model
$CI->load->model('meu_modulo/meu_modulo_model');

// Aceder à BD
$CI->db->get(db_prefix() . 'meu_modulo');
```

---

## Funções de Módulo Essenciais

### Paths e URLs

```php
// URL do módulo
$url = module_dir_url('meu_modulo');
// Resultado: https://crm.exemplo.pt/modules/meu_modulo/

// Path absoluto
$path = module_dir_path('meu_modulo');
// Resultado: /var/www/html/modules/meu_modulo/

// Path das libraries
$libs_path = module_libs_path('meu_modulo');
// Resultado: /var/www/html/modules/meu_modulo/libraries/
```

### Opções (Persistência)

```php
// Criar opção (não sobrescreve se existir)
add_option('meu_modulo_setting', 'valor', 0);

// Ler opção
$valor = get_option('meu_modulo_setting');

// Actualizar opção (cria se não existir - v2.3.3+)
update_option('meu_modulo_setting', 'novo_valor');

// Apagar opção
delete_option('meu_modulo_setting');
```

### Database Prefix

**SEMPRE usar `db_prefix()` em queries:**

```php
// CORRECTO
$CI->db->get(db_prefix() . 'meu_modulo');
$CI->db->query('SELECT * FROM ' . db_prefix() . 'meu_modulo');

// ERRADO - vai falhar se prefix não for "tbl"
$CI->db->get('tblmeu_modulo');
```

---

## Convenções de Nomenclatura

### Prefixos (OBRIGATÓRIO)

Todas as funções e classes devem ter prefixo único para evitar conflitos:

```php
// CORRECTO
function meu_modulo_get_data() { }
class Meu_modulo_helper { }

// ERRADO - pode conflitar com outros módulos/core
function get_data() { }
class Helper { }
```

### Nomes de Ficheiros

| Tipo | Convenção | Exemplo |
|------|-----------|---------|
| Controller | Primeira letra maiúscula | `Meu_modulo.php` |
| Model | Sufixo `_model` | `Meu_modulo_model.php` |
| Helper | Sufixo `_helper` | `meu_modulo_helper.php` |
| Language | Sufixo `_lang` | `meu_modulo_lang.php` |

---

## Modo de Desenvolvimento

**SEMPRE activar durante desenvolvimento:**

1. Abrir `application/config/config.php`
2. Definir: `$config['development_mode'] = true;`

Isto mostra:
- Erros PHP
- Warnings de depreciação
- Stack traces

---

## Anti-Patterns (NUNCA FAZER)

| Anti-Pattern | Risco | Alternativa |
|--------------|-------|-------------|
| Modificar ficheiros core do Perfex | Quebra em updates | Usar hooks |
| Hardcode database prefix `tbl` | Falha em instalações custom | `db_prefix()` |
| Funções sem prefixo | Conflitos | Prefixar tudo |
| Init file com nome diferente da pasta | Módulo não detectado | Nomes iguais |
| Desenvolver sem development mode | Erros silenciosos | Activar sempre |
| Não incluir index.html nas pastas | Directory listing | Incluir sempre |

---

## Checklist Novo Módulo

```
1. [ ] Pasta em /modules/ com nome único
2. [ ] Init file com mesmo nome da pasta
3. [ ] Header "Module Name" presente
4. [ ] defined('BASEPATH') em todos os ficheiros PHP
5. [ ] index.html em todas as pastas
6. [ ] Funções com prefixo único
7. [ ] db_prefix() em todas as queries
8. [ ] Development mode activado para testes
9. [ ] Hooks de activation/deactivation/uninstall
10. [ ] Testado em ambiente staging
```

---

**Versão:** 1.0.0 | **Autor:** Descomplicar®
**Fonte:** help.perfexcrm.com/module-basics

---

## Healing Log

Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.

```jsonl
{"date":"","issue":"","fix":"","source":"user|auto"}
```

*Adicionar nova linha após cada erro corrigido.*
