Members
Status: 🟢 Estável (mirror leve) Code: backend/app/modules/members UI: frontend/src/app/(admin)/[slug]/admin/members + frontend/src/app/(member) Última revisão deste doc: 2026-05-13 por Felipe + Claude Dependências fortes: crm (sync lifecycle), identity (end_user_id)
1. Identidade
O que faz (uma frase)
Define membros (alunos/clientes ativos do tenant), programas (cursos/produtos) e enrollments (matrículas) — gate de acesso à área restrita do aluno + sync automático com CRM lifecycle.
Por que existe (negócio)
CRM tem todos contatos (lead/customer/vendor). Members tem só quem tem acesso ativo ao produto. Separação importante porque:
- Acesso à área
/clubeexigemembers_memberativo (não basta ser CrmContact). - Plano (basic/pro) determina features.
- Status (active/paused/canceled) afeta cobrança e dunning.
Status atual
Estável. Mirror leve de Members v1 legacy (32 tabelas) — agora 3 tabelas enxutas no Suite.
2. Cases de uso reais
Case 1: Cliente compra acesso
Hotmart webhook → CRM cria/atualiza contato → Members create_member → _sync_crm_lifecycle() atualiza crm_contact.lifecycle_stage=customer.
Case 2: Cliente cancela
UI admin → PATCH /members/{id} {status: canceled} → Members atualiza → CRM lifecycle volta pra subscriber (perde acesso).
3. Oportunidades de negócio
- Member portal whitelabel: vender área do aluno como tema customizável.
- Multi-program access: member com múltiplos enrollments → cobrança bundle.
- Engagement-driven pricing: plan dinâmico baseado em engagement (intelligence).
4. Arquitetura interna
Arquivos
models.py— 3 tabelas.routes.py— 9 endpoints.service.py— CRUD +_sync_crm_lifecycle.
Tasks
Sem Celery próprio.
5. Tabelas (3)
members_member
| Coluna | Notas |
|---|---|
tenant_id | |
legacy_id | Members v1 backfill |
end_user_id | Identity Service |
email / full_name / preferred_name | |
plan | basic/pro/etc. |
status | active / paused / canceled |
avatar_url / bio / profession / birth_date / interests (JSONB) | |
crm_contact_id | Backref sync |
churn_risk_score | Cache |
joined_at / last_active_at |
UNIQUE (tenant_id, email), (tenant_id, legacy_id). Índice (tenant_id, status).
members_program
| Coluna | Notas |
|---|---|
slug / title / description / cover_url | |
is_active |
UNIQUE (tenant_id, slug).
members_enrollment
| Coluna | Notas |
|---|---|
member_id / program_id | FK CASCADE |
status | active / completed / paused |
enrolled_at / completed_at |
UNIQUE (member_id, program_id).
Relacionamentos cross-módulo
| Direção | Outro módulo | Como |
|---|---|---|
| ↘ Escreve | crm_contact | _sync_crm_lifecycle em create/patch (status→lifecycle_stage). Fire-and-recover. |
| ↗ Lê | identity | end_user_id mapeia ao Identity Service (não validado no Suite) |
6. API / Endpoints (9)
| Método | Rota | O que faz |
|---|---|---|
| GET | /members?q=&status=&limit&offset | Lista paginada com search |
| POST | /members | Criar (trigger CRM sync) |
| GET | /members/stats | Contagem por status |
| GET | /members/{id} | Detalhe |
| PATCH | /members/{id} | Atualizar (status change → CRM sync) |
| POST | /members/{id}/enrollments | Matricular |
| DELETE | /members/{id}/enrollments/{program_id} | Desmatricular |
| GET | /programs | Listar ativos |
| POST | /programs | Criar |
7. Configuração
Sem env vars próprias. Reutiliza MANDIR_DEFAULT_TENANT_ID.
8. Operações + Troubleshooting
Sintoma: CRM lifecycle não muda quando member muda status
Causa: _sync_crm_lifecycle é fire-and-recover (não bloqueia).
Diagnóstico: logs members.crm_sync.error.
Fix: rerun manual via API.
9. Limitações e débitos técnicos
| # | Item |
|---|---|
| 1 | CRM sync best-effort — falhas não retornam erro |
| 2 | Sem validação de pré-requisitos em enrollment |
| 3 | Hard-delete — sem deleted_at |
| 4 | end_user_id não validado contra Identity |
10. Histórico
Em prod desde absorção do Members legacy (2026-05-04).