# Manual do 1MZ For Artists

> **Versão deste manual:** 1.5.149
> **Cobertura:** funcionalidades até 1.5.148
> **Idioma:** Português (Moçambique)
> **Audiência:** administradores, suporte, equipa 1MZ Records, e developers futuros

---

## Índice

### Parte I — Operacional (para admins/suporte)

1. [Visão geral do sistema](#1-visão-geral-do-sistema)
2. [Estrutura do menu admin](#2-estrutura-do-menu-admin)
3. [Operações diárias](#3-operações-diárias)
4. [Aprovar depósitos](#4-aprovar-depósitos)
5. [Aprovar levantamentos](#5-aprovar-levantamentos)
6. [Importar royalties (CSV)](#6-importar-royalties-csv)
7. [Aprovar releases](#7-aprovar-releases)
8. [Pedidos de splits](#8-pedidos-de-splits)
9. [Pedidos de lojas (DSPs)](#9-pedidos-de-lojas-dsps)
10. [Centro de Notificações](#10-centro-de-notificações)
11. [Sistema de Referrals](#11-sistema-de-referrals)
12. [Gestão de artista (perfil)](#12-gestão-de-artista-perfil)
13. [Diagnósticos](#13-diagnósticos)
14. [Pré-Deploy & Hardening](#14-pré-deploy--hardening)
15. [FAQs operacionais](#15-faqs-operacionais)
16. [Troubleshooting comum](#16-troubleshooting-comum)

### Parte II — Técnico (para developers)

17. [Arquitectura: as 2 contas (MT vs USD)](#17-arquitectura-as-2-contas-mt-vs-usd)
18. [Schema da base de dados](#18-schema-da-base-de-dados)
19. [Cron jobs](#19-cron-jobs)
20. [Hooks e filtros disponíveis](#20-hooks-e-filtros-disponíveis)
21. [Markers em transações (auditoria)](#21-markers-em-transações-auditoria)
22. [Estrutura do código (ficheiros)](#22-estrutura-do-código-ficheiros)
23. [Convenções e padrões](#23-convenções-e-padrões)
24. [Comandos SQL úteis](#24-comandos-sql-úteis)

---

# Parte I — Operacional

## 1. Visão geral do sistema

O **1MZ For Artists** é uma plataforma WordPress para distribuição musical e gestão de royalties em Moçambique. Os artistas têm contas com **dois saldos separados**:

- **Conta Principal** em **Meticais (MT)** — para vendas, comissões, e operações locais
- **Conta de Distribuição** em **Dólares (USD)** — exclusivamente para royalties internacionais

Esta separação é o **invariante mais importante do sistema**. Qualquer operação financeira respeita esta divisão.

### Fluxo típico de um artista

```
1. Cria conta → faz primeiro depósito (activação)
2. Compra plano VIP (mensal/anual)
3. Submete música(s) — aprovação pelo admin → distribuição para DSPs
4. Royalties chegam (USD) → admin importa CSV trimestralmente
5. Levantamento — escolhe MT (Conta Principal) ou USD→MT (Distribuição)
```

---

## 2. Estrutura do menu admin

```
1MZ Manager
├── 📊 Visão Geral (analytics)
├── 🎵 Música (Site)             ← submissões para o blog
├── 📹 Vídeos (Redes)             ← submissões para social
├── Pacotes VIP                   ← planos disponíveis
├── 💬 Projetos & Chat
├── 👥 Artistas & Saldos          ← gestão de cada artista
├── 🌍 Distribuição               ← TODA a distribuição (sub-tabs):
│   ├── 📊 Visão Geral
│   ├── 🎵 Lançamentos
│   ├── ⚡ Fila de Aprovação
│   ├── 🔒 Serviços Exclusivos
│   ├── 💿 Catálogo de Faixas
│   ├── 🤝 Splits
│   ├── 📩 Pedidos Splits
│   ├── 🏪 Pedidos Lojas          ← novo 1.5.144
│   ├── 📚 Catálogo Lojas         ← novo 1.5.144
│   ├── 📥 Importar Royalties
│   ├── 💰 Royalties
│   ├── ⚠️ Não Reclamados
│   ├── 🔍 Matches a Rever
│   ├── 🔗 Mapeamentos ISRC
│   ├── 🩺 Diagnóstico
│   ├── 📋 Auditoria
│   └── ⚙ Configurações
├── 💰 Depósitos                  ← aprovar / rejeitar
├── 💸 Levantamentos              ← aprovar / rejeitar
├── 🎟️ Cupões
└── 🛡 Pré-Deploy                 ← novo 1.5.148 (snapshots, health, deploy log)
```

---

## 3. Operações diárias

Esta é a tua **checklist matinal** sugerida (5-10 minutos):

| Tarefa | Onde | O que verificar |
|---|---|---|
| **1. Health check** | 🛡 Pré-Deploy → Health Dashboard | Tudo verde? Sem erros nas últimas 24h? |
| **2. Depósitos** | 💰 Depósitos | Aprovar pendentes (verificar comprovativo) |
| **3. Levantamentos** | 💸 Levantamentos | Aprovar pendentes (verificar saldo + processar pagamento) |
| **4. Aprovar releases** | 🌍 Distribuição → ⚡ Fila de Aprovação | Submissões novas |
| **5. Pedidos** | 🌍 → 📩 Pedidos Splits + 🏪 Pedidos Lojas | Decidir cada um |
| **6. Notificações** | (nada — automático) | — |

### Operações semanais

- **Backup**: 🛡 Pré-Deploy → 📸 **Criar Snapshot** (antes de qualquer update)
- **Diagnósticos**: 🌍 Distribuição → 🩺 Diagnóstico (verificar discrepâncias)
- **Auditoria**: 🌍 → 📋 Auditoria (logs de mudanças importantes)

### Operações mensais

- **Importar royalties**: 🌍 → 📥 Importar Royalties (CSV trimestral dos DSPs)
- **Match Review**: 🌍 → 🔍 Matches a Rever (resolver releases não-mapeadas)

---

## 4. Aprovar depósitos

**Caminho:** `1MZ Manager → 💰 Depósitos`

### Fluxo

1. Artista cria pedido de depósito (M-Pesa, eMola, etc.) — sobe comprovativo
2. Aparece na lista como `pendente`
3. **Verificar o comprovativo** — abrir imagem e confirmar:
   - Valor bate com o pedido
   - Número M-Pesa do remetente bate (idealmente)
   - Não é duplicado de pedido anterior
4. Carregar **Aprovar** → wallet do artista é creditada em MT

### Casos especiais

- **Primeiro depósito** = depósito de activação. Se aprovar:
  - O artista pode comprar plano VIP
  - Sistema cria notificação `welcome` + dispara `rmbz_first_deposit_approved`
  - Sistema de referrals valida 1ª das 2 condições da comissão
- Se **não aprovar em 24h** após criação, sistema apaga conta + depósito (cron `rmbz_first_deposit_cleanup_extended`)

### Reverter um depósito aprovado

Se aprovaste por engano, vai a:
**👥 Artistas & Saldos → [artista] → 📥 Pedidos de Depósito → ↩ Reverter**

Reverter faz: apaga registo + remove transação +amount do extrato + ajusta saldo (debita).

> ⚠ Pode criar saldo negativo se o artista já gastou. Confirma antes.

---

## 5. Aprovar levantamentos

**Caminho:** `1MZ Manager → 💸 Levantamentos`

### Fluxo

1. Artista cria pedido — saldo é DEBITADO logo (anti-double-spend)
2. Aparece como `pendente`
3. Admin processa pagamento manualmente (M-Pesa, banco, etc.)
4. Carrega **Aprovar** → estado fica `aprovado`, processed_date guardado

### Se rejeitar

- Saldo é **automaticamente devolvido** (cria transação `withdrawal_rejected` no extrato)
- Artista recebe notificação

### Origem do saldo: MT vs USD

O artista pode escolher de qual conta levanta:
- **Wallet MT** — saída directa, sem conversão
- **USD (royalties)** — antes do levantamento, sistema converte USD→MT via `rmbz_secure_transfer_usd_to_mt` (câmbio configurado)

---

## 6. Importar royalties (CSV)

**Caminho:** `1MZ Manager → 🌍 Distribuição → 📥 Importar Royalties`

### Fluxo

1. **Download CSV** dos DSPs (Spotify, Apple Music, etc.) — formato standardizado
2. **Upload no admin** — sistema processa em background, marca como `pending_approval`
3. **Match Review** (se necessário) — para releases não auto-mapeados, escolher manualmente
4. **Aprovar Import** — créditos USD são aplicados nas wallets de distribuição
5. Sistema envia notificação `royalties_credited` a cada artista creditado

### Reverter um import

**Caminho:** `🌍 → 💰 Royalties → tab Imports → Reverter`

Faz cascata:
- Marca ledger entries como `reverted_at`
- Apaga daily_stats
- Marca `withdrawal_rejected_revert` ledger entries para refunds (se houver)
- CSV original fica em `/uploads/rmbz_imports_archive/` (configurável)

### Re-importar (apanhar linhas desmarcadas)

**Caminho:** `🌍 → 🔍 Importações Adicionais` — útil quando após match review aparecem novos releases que devem ser cobertos por um import passado.

---

## 7. Aprovar releases

**Caminho:** `1MZ Manager → 🌍 Distribuição → ⚡ Fila de Aprovação`

### Estados de uma release

```
incomplete → pendente → aprovado → live (distribuído)
                ↓
             returned (devolvido para correcções)
                ↓
             pendente (após resubmit)
```

### Quando aprovar

- Verificar metadados (título, ISRC, covers)
- Confirmar splits (se aplicável)
- Verificar serviços exclusivos requeridos
- **Aprovar** → status `aprovado` (preparar para distribuição)
- Marcar como **Live** quando chega às lojas

### Quando devolver

Se há problemas (cover mau, metadados errados, etc.):
- **Devolver com problemas** — marcar checkboxes dos problemas + nota
- Status fica `returned` com `return_deadline` (default 7 dias)
- Artista recebe notificação `release_returned` + email
- Artista corrige + resubmit → volta para `pendente`

---

## 8. Pedidos de splits

**Caminho:** `🌍 Distribuição → 📩 Pedidos Splits`

### Como funciona

Splits são divisões de royalties entre artistas/colaboradores. Há **3 fases**:

1. **Fase 1**: artista define splits ANTES da release ir live (pode editar livremente)
2. **Fase 2**: release está live → admin precisa de aprovar mudanças (caso a caso)
3. **Fase 3**: artista pede mudanças oficialmente, admin aprova ou rejeita

### Aprovar/rejeitar pedido

1. Listar pendentes nesta tab
2. Ver "current splits snapshot" vs "proposed splits"
3. Aprovar → splits aplicados imediatamente
4. Rejeitar → opcional adicionar `admin_note` explicativa

---

## 9. Pedidos de lojas (DSPs)

**Caminho:** `🌍 Distribuição → 🏪 Pedidos Lojas` (e `📚 Catálogo Lojas`)

### Como funciona (artista)

Para releases LIVE, o artista pode pedir adicionar/remover lojas via botão **"🏪 Adicionar / Remover Lojas"** no single-view do release.

### Regras de cobrança

- **1ª alteração** ao longo da vida do release = **grátis**
- Subsequentes:
  - Só **adições** → cobra `rmbz_store_change_fee_subsequent` (default 100 MT)
  - Só **remoções** → sempre grátis
- Custo é debitado na hora da aprovação pelo admin (não na submissão)

### Catálogo de lojas (admin)

- 24 DSPs built-in (Spotify, Apple Music, etc.) auto-importadas no install
- Podes **adicionar lojas custom** (Anghami se aparece nova região)
- Podes **desactivar** built-in (deixar de oferecer aos artistas)
- Podes **apagar** custom (built-in não é apagável, só desactivável)

---

## 10. Centro de Notificações

**Caminho:** `1MZ Manager → 🌍 Distribuição → ⚙ Configurações → tab E-mails 📧`

### O que é

Sistema centralizado de comunicação automática com os artistas. Cada evento dispara uma notificação:
- 📧 **Email** para o telemóvel (gateway SMS-to-email ou email registado)
- 🔔 **Sino no painel** com badge de não-lidos

### Templates editáveis (11 actuais)

| Key | Quando dispara |
|---|---|
| `welcome` | Conta criada |
| `deposit_approved` | Depósito aprovado |
| `deposit_rejected` | Depósito rejeitado |
| `vip_purchased` | Comprou plano VIP |
| `vip_expiring` | VIP a expirar (7 dias antes) |
| `vip_expired` | VIP expirou (cron diário) |
| `referral_pending` | Link de referral usado, aguarda 2ª condição |
| `referral_completed` | Referral completou ambas condições, comissão paga |
| `royalties_credited` | Royalties USD creditados após import |
| `release_returned` | Release devolvido para correcções |
| `release_live` | Release passou para live nas lojas |
| `store_change_approved` | Pedido de alteração de lojas aprovado |
| `store_change_rejected` | Pedido de alteração de lojas rejeitado |

### Variáveis disponíveis

Cada template tem placeholders `{nome_artista}`, `{titulo_release}`, `{valor}`, etc. — ver tab para a lista completa de variáveis por template.

---

## 11. Sistema de Referrals

**Caminho:** `1MZ Manager → 🌍 Distribuição → ⚙ Configurações → tab Referrals 🤝`

### Como funciona

Cada artista tem um **código de referral** único. Quando convida outro artista:

1. Convidado regista-se com o código
2. Cria o referral com status `pending`
3. **2 condições** têm de ser cumpridas para a comissão ser paga:
   - **Condição A**: convidado faz primeiro depósito aprovado
   - **Condição B**: convidado compra plano VIP
4. Quando ambas cumpridas → comissão automática para o convidador

### Tipos de comissão

- **MT (saldo)** — credita X MT na wallet do convidador
- **Dias VIP** — adiciona X dias ao plano VIP do convidador

### Anti-fraude built-in

- ❌ Auto-referral (próprio telemóvel) bloqueado
- ❌ Telemóveis na blacklist bloqueados
- ❌ Utilizador `is_banned = 1` não pode usar nem ser usado
- ✅ Validação ao vivo no input (antes de submeter)
- ✅ Aviso explícito antes de submeter convite inválido

---

## 12. Gestão de artista (perfil)

**Caminho:** `1MZ Manager → 👥 Artistas & Saldos → [artista]`

### Painéis disponíveis

- **🔧 Acções administrativas**: ajustar saldo, banir, redefinir PIN, enviar pop-up directo
- **📥 Pedidos de Depósito**: lista todos · botões 🔴 Excluir (só registo) e 🟠 Reverter (registo + extrato + saldo)
- **💸 Pedidos de Levantamento**: idem
- **📊 Histórico financeiro**: extrato completo paginado (15/página, AJAX)
- **🎵 Releases**: todos os releases deste artista
- **🤝 Referrals**: árvore de quem convidou e quem foi convidado

### Acção C7: Limpar Tudo vs Reverter Tudo

Disponível em ambos os painéis (Depósitos e Levantamentos):

| Botão | O que faz |
|---|---|
| 🔴 **Limpar Tudo** | Apaga apenas os registos. Saldo e Extrato **intactos**. |
| 🟠 **Reverter Tudo** | Apaga registos + reverte transações no Extrato + ajusta saldo. |

> ⚠ Reverter Tudo de Depósitos pode criar **saldo negativo** se o artista já gastou. Sistema permite saldo negativo.

---

## 13. Diagnósticos

**Caminho:** `🌍 Distribuição → 🩺 Diagnóstico`

### As 5 secções

1. **Imports problemáticos** — CSVs com erros de processamento
2. **Releases sem ledger** — músicas live mas sem royalties registados (bug?)
3. **Holdings stuck** — splits parados em pending_approval há muito
4. **Match Review backlog** — releases não auto-mapeadas (necessita acção manual)
5. **🩺 Wallet MT contaminada** — wallets afectadas pelo bug pre-1.5.110 (USD-tratado-como-MT)

### Secção 5 em detalhe

Em **1.5.147** ganhou ferramenta completa de inspecção e correção:
- Lista wallets afectadas com `net_wrong` (lixo a corrigir)
- Botão **🔍 Inspeccionar e Debitar** abre painel rico:
  - Composição por categoria (imports vs match vs revert)
  - Markers únicos vs duplicados (red flag se rácio > 5)
  - Distribuição por mês
  - Histórico de transações afectadas (paginado, 100/página)
  - Histórico de correções já aplicadas (com botão ↩ Anular)
  - **Painel de débito** com 3 quick-presets (Tudo / Seguro / Metade) + preview live AJAX

### Workflow sugerido

```
1. Identificar wallet com problema
2. 🔍 Inspeccionar e Debitar
3. Ler composição, markers, distribuição
4. Começar com preset 🛡 Seguro (nunca cria saldo negativo)
5. Confirmar no preview live
6. Escrever nota explicativa
7. Aplicar débito
8. Se errado: ↩ Anular da secção "Correções aplicadas"
```

---

## 14. Pré-Deploy & Hardening

**Caminho:** `1MZ Manager → 🛡 Pré-Deploy`

### 3 ferramentas em 1

#### 💾 Snapshots da BD

- **📸 Criar Snapshot Agora** → dump SQL completo das tabelas `rmbz_*`
- Guardado em `/uploads/rmbz_predeploy_snapshots/` (protegido por `.htaccess`)
- Lista snapshots existentes com download/apagar
- **Restauro é manual** (deliberadamente) via phpMyAdmin

#### 📊 Health Dashboard (10 verificações)

| Check | Que avalia |
|---|---|
| PHP version | >= 7.4 |
| Memory limit | >= 256 MB recomendado |
| Upload max | >= 32 MB recomendado para CSVs |
| Disco livre | em /uploads |
| Tabelas rmbz_* | quantidade |
| Tabelas críticas | 8 obrigatórias presentes |
| Cron jobs | rmbz_unlock_funds_hook, etc. |
| WP_DEBUG_LOG | activo? |
| Erros 24h | parsing de wp-content/debug.log |
| Última actividade | last deposit_request |

Resumo no fundo: "X OK · Y warn · Z fail · pronto/não-pronto para deploy".

#### 📜 Deploy Log

- Tabela `rmbz_deploy_log` regista cada versão instalada (auto)
- Botão **⭐ Marcar estável** para identificar versões conhecidas como funcionais
- Snapshot fica ligado ao deploy quando criado logo após upgrade

### Workflow de deploy seguro

```
1. ✓ Health Dashboard sem fails
2. 📸 Criar Snapshot
3. Instalar nova versão do plugin
4. ✓ Health Dashboard continua sem fails
5. Testar funcionalidades críticas durante 24-48h
6. Se OK → ⭐ Marcar estável
   Se problema → restaurar snapshot via phpMyAdmin + reinstalar versão estável anterior
```

---

## 15. FAQs operacionais

### "Um artista diz que não recebeu dinheiro de royalties"

1. Verifica **🌍 Distribuição → 💰 Royalties → tab Imports** — o último import foi aprovado?
2. Vai a **👥 Artistas & Saldos → [esse artista] → tab Distribuição** — vê total earnings em USD
3. Se não aparece nada, vai a **🔍 Matches a Rever** — pode ser que a release não foi auto-mapeada

### "O artista não consegue levantar"

1. Vê o saldo dele em **👥 Artistas & Saldos → [artista]**
2. Verifica se está acima do `RMBZ_MIN_WITHDRAWAL` (definido em código, default 100 MT)
3. Se tem saldo USD mas não MT, ele tem que usar a opção "Levantamento Inteligente" (escolher origem USD)
4. Se o artista está `is_banned = 1`, levantamentos estão bloqueados

### "Aprovei um depósito por engano"

Vai a **👥 Artistas & Saldos → [esse artista] → 📥 Pedidos de Depósito → ↩ Reverter** (só aparece em depósitos `aprovado`).

### "O sistema diz que tenho wallets contaminadas — devo executar correção?"

**Não imediatamente.** Vai a **🌍 → 🩺 Diagnóstico → Secção 5** e:
1. Clica **🔍 Inspeccionar e Debitar** na primeira wallet
2. Lê a composição (imports / matches / reverts)
3. Vê se os markers únicos / total faz sentido (rácio < 5x)
4. Começa com preset **🛡 Seguro** (nunca cria negativo)
5. Confirma no preview live antes de aplicar

### "Onde estão os snapshots dos updates passados?"

`/wp-content/uploads/rmbz_predeploy_snapshots/`

Pasta protegida por `.htaccess`, acessível via admin → 🛡 Pré-Deploy → lista de snapshots.

### "Cron parece não correr"

1. Verifica se WordPress cron está activo (`DISABLE_WP_CRON` em wp-config.php?)
2. Vai a **🛡 Pré-Deploy** → Health Dashboard → "Cron jobs essenciais"
3. Se algum em falta: re-activar o plugin força re-registo

---

## 16. Troubleshooting comum

### Sintoma: páginas admin demoram a carregar

1. Verifica `Health Dashboard → Memory limit` (sobe para 256MB+)
2. Verifica se `debug.log` está enorme (>50MB) — apaga e reinicia
3. Verifica se há queries N+1 (chamar com `?debug=1` se desenvolveste página custom)

### Sintoma: artista não recebe email de notificação

1. Vai a **🌍 Distribuição → ⚙ Configurações → tab E-mails 📧** — template está editado/correcto?
2. Verifica logs em tabela `rmbz_email_logs`
3. Verifica gateway de email (SMTP plugin tipo WP Mail SMTP funciona?)
4. Verifica se utilizador tem `is_banned = 1` — sistema pode silenciar

### Sintoma: backdrop de modal não cobre tela toda

(Resolvido na 1.5.146) — se voltar a acontecer noutra modal nova:
- Verifica se a modal tem `position:fixed` em ancestral com `transform`/`filter`/`will-change`
- Solução: mover modal para `<body>` via JS no carregamento

### Sintoma: ZIP de update não dá para upload

- Tamanho > `upload_max_filesize` no PHP — sobe para 32MB+
- Tamanho > `post_max_size` no PHP — sobe igual
- Servidor com proxy/reverse-proxy (Cloudflare) com limite — sobe lá

### Sintoma: schemas em falta após upgrade

- Vai a **🌍 → 🩺 Diagnóstico** — vê secção "Schema Health Check"
- Botão "Correr installers em falta" força re-execução

---

# Parte II — Técnico

## 17. Arquitectura: as 2 contas (MT vs USD)

**Este é o invariante mais importante do sistema.** Qualquer código que toca dinheiro tem de respeitar esta separação.

### Conta Principal (MT)

- Tabela: `rmbz_wallets.balance` (decimal)
- Moeda: **Meticais (MT)**
- Operações: vendas (Site/Redes), comissões, depósitos, levantamentos, compras de plano VIP
- Function helper: `rmbz_update_wallet_balance($tel, $amount, $type, $project_id, $details, $is_unlocked, $unlock_date)`

### Conta de Distribuição (USD)

- Tabela: `rmbz_distro_stats.total_earnings` (decimal)
- Moeda: **Dólares Americanos (USD)**
- Operações: royalties (vindos do CSV de DSPs), splits
- Recalculo: `rmbz_recalc_artist_stats($telemovel)` (soma do ledger USD)

### Como passar de USD → MT

**ÚNICA forma autorizada:** `rmbz_secure_transfer_usd_to_mt($tel, $usd_amount)`

Esta função:
1. Valida que existe saldo USD suficiente
2. Aplica câmbio actual (`get_option('rmbz_exchange_rate', 63.50)`)
3. Debita USD da Conta de Distribuição
4. Credita MT equivalente na Conta Principal
5. Regista ambas as transações com markers ligados

**NUNCA** escrever directamente USD na wallet MT (foi o bug fix da 1.5.110).

---

## 18. Schema da base de dados

### Tabelas principais (~20 tabelas, prefixo `rmbz_`)

| Tabela | O que guarda |
|---|---|
| `rmbz_wallets` | Saldos MT por artista (1 row por telemóvel) |
| `rmbz_wallet_transactions` | Extrato MT (todas as movimentações) |
| `rmbz_subscriptions` | Planos VIP activos/históricos |
| `rmbz_deposit_requests` | Pedidos de depósito |
| `rmbz_withdrawal_requests` | Pedidos de levantamento |
| `rmbz_distro_releases` | Releases (lançamentos musicais) |
| `rmbz_distro_release_platforms` | DSPs seleccionados por release (`dsp_list` JSON) |
| `rmbz_distro_release_tracks` | Tracks de cada release |
| `rmbz_distro_stats` | Total earnings USD por artista |
| `rmbz_distro_ledger` | Ledger USD (cada linha de royalty) |
| `rmbz_distro_daily_stats` | Stats diários por release/track/país/store |
| `rmbz_distro_unclaimed` | Royalties não-mapeadas (esperam match review) |
| `rmbz_distro_import_logs` | Histórico de imports CSV |
| `rmbz_distro_holdings` | Splits a colaboradores externos |
| `rmbz_split_change_requests` | Pedidos de alteração de splits |
| `rmbz_store_change_requests` | Pedidos de alteração de lojas (1.5.144) |
| `rmbz_dsp_catalog` | Catálogo de DSPs (built-in + custom) (1.5.144) |
| `rmbz_email_logs` | Logs de envio de emails |
| `rmbz_referrals` | Sistema de referrals |
| `rmbz_deploy_log` | Histórico de versões instaladas (1.5.148) |

### Convenções de campos comuns

- **`user_telemovel`** (varchar 20) — chave para identificar artista (NÃO email, NÃO username)
- **`amount`** (decimal 10,2) — sempre signed (negativo = débito, positivo = crédito)
- **`details`** (text) — descrição livre + markers `[type:id]` para auditoria
- **`type`** (varchar 50) — tipo da transação (ver markers abaixo)
- **`transaction_date`** (datetime) — sempre via `current_time('mysql')`

---

## 19. Cron jobs

### Crons registados pelo plugin

| Hook | Frequência | O que faz |
|---|---|---|
| `rmbz_unlock_funds_hook` | diário | Desbloqueia fundos com `unlock_date` passada + dispara notificação `vip_expired` |
| `rmbz_first_deposit_cleanup_extended` | hourly | Apaga contas + depósitos não aprovados em 24h após criação |
| `rmbz_imports_archive_purge` | weekly | Apaga CSVs arquivados após `rmbz_imports_archive_retention_days` (default 730) |

### Ver crons activos

```php
// Em wp-content/mu-plugins/cron-debug.php ou via wp-cli:
wp cron event list
```

Ou no admin: 🛡 Pré-Deploy → Health Dashboard → "Cron jobs essenciais".

---

## 20. Hooks e filtros disponíveis

### Action hooks (do_action)

| Hook | Args | Quando dispara |
|---|---|---|
| `rmbz_first_deposit_approved` | `$user_tel, $amount` | Primeiro depósito aprovado de um utilizador |
| `rmbz_distro_status_changed` | `$release_id, $old, $new` | Qualquer mudança de status de release |
| `rmbz_distro_release_returned` | `$release_id, $problems[], $note` | Release devolvido para correcções |
| `rmbz_distro_after_single_view` | `$release_id, $user_tel` | Após render do single-view (1.5.144) |
| `rmbz_unlock_funds_hook` | — | Cron diário (também usado como bus pra outras tasks) |

### Funções públicas para integrar

| Função | Onde |
|---|---|
| `rmbz_notify($user_tel, $key, $vars)` | Disparar notificação (email + sino) |
| `rmbz_update_wallet_balance(...)` | Mexer saldo MT |
| `rmbz_secure_transfer_usd_to_mt(...)` | USD → MT (única forma) |
| `rmbz_recalc_artist_stats($tel)` | Recalcular total_earnings USD |
| `rmbz_distro_dsp_catalog($only_active=true)` | Catálogo de DSPs (BD-driven desde 1.5.144) |

---

## 21. Markers em transações (auditoria)

Os campos `details` em `rmbz_wallet_transactions` e `rmbz_distro_ledger` usam **markers** para tornar transações rastreáveis:

| Marker | Significado |
|---|---|
| `[royalty_import:HASH]` | Crédito de royalty vindo de import CSV (HASH = file_hash) |
| `[match_review:ID]` | Crédito vindo de match review approval |
| `[revert:HASH]` | Débito de revert de import |
| `[mtfix:TIMESTAMP]` | Correção 1.5.110 (USD-tratado-como-MT) |
| `[undo:TX_ID]` | Anulação de uma correção mtfix (1.5.147) |
| `[withdrawal_rejected_revert:ID]` | Refund por rejeição de levantamento |

### Procurar transações com SQL

```sql
-- Todos os créditos de import errados (pre-1.5.110 bug):
SELECT * FROM wp_rmbz_wallet_transactions
WHERE type = 'royalty_payout'
  AND (details LIKE '%[royalty_import:%' OR details LIKE '%[match_review:%');

-- Correções já aplicadas a um artista:
SELECT * FROM wp_rmbz_wallet_transactions
WHERE user_telemovel = '+258XXXXXXXX'
  AND type = 'mt_fix_correction'
  AND details LIKE '%[mtfix:%';
```

---

## 22. Estrutura do código (ficheiros)

### Top-level

```
1mz-for-artists.php          ← header WP + carregamento via rmbz_carregar_ficheiro()
MANUAL.md                     ← este manual (1.5.149)
includes/
├── *.php                     ← módulos centrais (wallet, notif, cron, etc.)
└── admin/
    ├── *.php                 ← páginas admin
    ├── distribution/
    │   └── distribution-*.php
    └── royalties/
        └── royalties-*.php
```

### Módulos centrais (`includes/*.php`)

| Ficheiro | Responsabilidade |
|---|---|
| `wallet-functions.php` | API da wallet MT |
| `notifications-center.php` | Centro de notificações + 11 templates |
| `notifications-distro-bridge.php` | Listeners para os 4 hooks (1.5.145) |
| `referral-system.php` | Sistema de referrals |
| `first-deposit-gate.php` | Gate do primeiro depósito (activação) |
| `cron-jobs.php` | Registo dos crons |
| `email-manager.php` | Gateway de email + templates antigos |
| `form-handler.php` | Handlers de forms públicos |
| `my-account-page.php` | Página principal do artista |
| `shortcodes.php` | Shortcodes públicos |

### Distribuição (`includes/distribution/*.php`)

| Ficheiro | Responsabilidade |
|---|---|
| `distribution-platforms.php` | DSPs (catálogo, territories, exclusives) |
| `distribution-wizard.php` | Wizard 4-step de criação de release |
| `distribution-single-view.php` | View detalhada de uma release |
| `distribution-list-view.php` | Lista de releases do artista |
| `distribution-splits.php` | Splits backend |
| `distribution-splits-frontend.php` | Modal de splits |
| `distribution-splits-phases.php` | Fase 3 (pedidos de change) |
| `distribution-store-requests.php` | Pedidos de lojas + catálogo DB (1.5.144) |
| `distribution-licensing.php` | Licenciamento + SOMAS |
| `distribution-return-workflow.php` | Devolver releases ao artista |

### Admin (`includes/admin/*.php`)

| Ficheiro | Responsabilidade |
|---|---|
| `admin-menus.php` | Registo de menus |
| `admin-distribution-controller.php` | Router das tabs de distribuição |
| `admin-handlers.php` | Handlers de aprovação de depósitos/levantamentos |
| `admin-user-profile.php` | Perfil do artista (ver/editar) |
| `import-diagnostics.php` | Página Diagnósticos (5 secções) |
| `wallet-mt-cleanup.php` | Backend de cleanup (1.5.110+) + tools 1.5.147 |
| `predeploy-hardening.php` | Snapshots + Health + Deploy Log (1.5.148) |
| `admin-withdrawal-guard.php` | Validações pré-aprovação de levantamentos |

---

## 23. Convenções e padrões

### Nomenclatura

- **Funções**: `rmbz_<modulo>_<acao>()` (ex: `rmbz_store_create_request`)
- **Tabelas**: prefixo `{$wpdb->prefix}rmbz_<nome>` (ex: `wp_rmbz_wallets`)
- **Options**: `rmbz_<feature>_<setting>` (ex: `rmbz_store_change_fee_subsequent`)
- **Hooks**: `rmbz_<modulo>_<evento>` (ex: `rmbz_distro_release_returned`)
- **Cron hooks**: `rmbz_<task>_hook` (ex: `rmbz_unlock_funds_hook`)
- **Markers**: `[<tipo>:<id>]` em campos `details` (ex: `[mtfix:1714672800]`)

### Padrões importantes

#### Lock por wallet (anti-race)

Operações financeiras serializam por carteira:
```php
$lock_name = 'rmbz_wallet_' . md5((string) $tel);
$got = (int) $wpdb->get_var( $wpdb->prepare("SELECT GET_LOCK(%s, 5)", $lock_name) );
if ( ! $got ) return [ 'success' => false, 'message' => 'Sistema ocupado' ];
try {
    // ...operação...
    $wpdb->query( $wpdb->prepare("SELECT RELEASE_LOCK(%s)", $lock_name) );
} catch ( Exception $e ) {
    $wpdb->query( $wpdb->prepare("SELECT RELEASE_LOCK(%s)", $lock_name) );
    return [ 'success' => false, 'message' => $e->getMessage() ];
}
```

#### WordPress escapa `&` em `<script>`

Em JavaScript inline, **NUNCA** usar `&&`. WordPress (com algumas configs) escapa `&` para `&amp;` dentro de `<script>` blocks que estão em PHP, partindo o JS.

✅ Correcto:
```js
if (a) { if (b) { doStuff(); } }
```

❌ Quebra:
```js
if (a && b) { doStuff(); }
```

(Bug descoberto na 1.5.119, padrão depois.)

#### Idempotência em listeners de notificação

Listeners verificam que o evento ainda não foi notificado antes de disparar. Usam:
- Flag em `extra_data` (`vip_expired_notified` = `end_date` do contrato)
- Hook natural one-shot (`rmbz_distro_release_returned` só dispara na transição)
- Filtros explícitos no listener (ex: `release_live` só se old != live)

#### `current_time('mysql')` vs `current_time('mysql', 1)`

- `current_time('mysql')` — hora local do servidor
- `current_time('mysql', 1)` — UTC (recomendado para timestamps internos)

Convenção do plugin: usar **UTC** para `request_date` em pedidos, e **local** para `transaction_date` em extrato.

---

## 24. Comandos SQL úteis

### Saúde geral

```sql
-- Total de wallets activas
SELECT COUNT(*) FROM wp_rmbz_wallets;

-- Saldo total no sistema (MT)
SELECT SUM(balance) FROM wp_rmbz_wallets;

-- Total earnings em USD (todos os artistas)
SELECT SUM(total_earnings) FROM wp_rmbz_distro_stats;

-- Discrepância entre wallet e ledger (debug)
SELECT user_telemovel,
       (SELECT balance FROM wp_rmbz_wallets w WHERE w.user_telemovel = t.user_telemovel) as wallet_balance,
       SUM(amount) as ledger_sum
FROM wp_rmbz_wallet_transactions t
GROUP BY user_telemovel
HAVING ABS(wallet_balance - ledger_sum) > 0.01;
```

### Pedidos pendentes

```sql
-- Depósitos pendentes
SELECT * FROM wp_rmbz_deposit_requests WHERE status = 'pendente' ORDER BY request_date;

-- Levantamentos pendentes
SELECT * FROM wp_rmbz_withdrawal_requests WHERE status = 'pendente' ORDER BY request_date;

-- Pedidos de splits pendentes
SELECT * FROM wp_rmbz_split_change_requests WHERE status = 'pending';

-- Pedidos de lojas pendentes
SELECT * FROM wp_rmbz_store_change_requests WHERE status = 'pending';
```

### Wallet contaminada (pre-1.5.110)

```sql
-- Listar wallets com lixo a corrigir
SELECT user_telemovel,
       SUM(CASE WHEN type = 'royalty_payout' AND
                ( details LIKE '%[royalty_import:%' OR details LIKE '%[match_review:%' )
                THEN amount ELSE 0 END) as wrong_credits,
       SUM(CASE WHEN type = 'mt_fix_correction' THEN amount ELSE 0 END) as already_fixed,
       COUNT(*) as tx_count
FROM wp_rmbz_wallet_transactions
WHERE details LIKE '%[royalty_import:%'
   OR details LIKE '%[match_review:%'
   OR details LIKE '%[revert:%'
   OR details LIKE '%[mtfix:%'
GROUP BY user_telemovel
HAVING (wrong_credits + already_fixed) > 0.01
ORDER BY ABS(wrong_credits) DESC;
```

### Audit / Diagnóstico

```sql
-- Histórico de versões instaladas
SELECT * FROM wp_rmbz_deploy_log ORDER BY id DESC;

-- Última versão estável
SELECT * FROM wp_rmbz_deploy_log WHERE is_stable = 1 ORDER BY id DESC LIMIT 1;

-- Imports recentes
SELECT id, file_name, file_hash, status, approval_status, approved_at, approved_by
FROM wp_rmbz_distro_import_logs
ORDER BY id DESC LIMIT 10;
```

---

## Apêndice A — Glossário

| Termo | Significado |
|---|---|
| **DSP** | Digital Service Provider — Spotify, Apple Music, etc. |
| **ISRC** | International Standard Recording Code — identificador único de gravação |
| **Royalty** | Pagamento por uso de obra (streams, downloads) |
| **Match Review** | Processo de mapear royalties não-identificadas a releases |
| **Holding** | Reserva de royalties para colaborador externo (split) |
| **Takedown** | Pedido de remoção de uma release das lojas |
| **MT** | Metical (moeda de Moçambique) |
| **VIP** | Plano de subscrição activa do artista |
| **SOMAS** | Sociedade Moçambicana de Autores |

---

## Apêndice B — Versões e changelog

Para changelog completo ver header de `1mz-for-artists.php` (entradas `== X.Y.Z (DATA) == ...`).

Resumo das marcas mais importantes:

| Versão | Marco |
|---|---|
| 1.5.110 | **Bug fix crítico**: USD-tratado-como-MT em `approve_import` / `match_review` / `revert_import` |
| 1.5.111 | Diagnostics Section 5 + `wallet-mt-cleanup.php` |
| 1.5.117 | Sistema de Splits (3 fases) |
| 1.5.131 | First Deposit Gate (activação) |
| 1.5.138 | Centro de Notificações com 11 templates editáveis |
| 1.5.144 | Sistema de Pedidos de Lojas + Catálogo Gerido |
| 1.5.145 | Conexão dos 4 templates pendentes |
| 1.5.147 | Wallet MT Cleanup melhorado (preview, parcial, undo, paginação) |
| 1.5.148 | Hardening Pré-Produção (snapshots, health, deploy log) |
| 1.5.149 | Manual + página admin "📖 Manual" |

---

*Manual escrito em 2026-05. Mantido sincronizado com o plugin. Para discrepâncias entre manual e código, **o código é a fonte de verdade**.*
