Skip to content

REF-202-03: Parent-Child Hierarchy

ADR: ADR-202 — Entitlement: Agregador CentralEscopo: Campo parent_entitlement_id, profundidade, materialized path, créditos compartilhados, expiração independente, desvinculação, hooks


1. Estrutura

AspectoDetalhe
Campoparent_entitlement_id (FK nullable para Entitlement)
Quem pode ser paiQualquer entitlement. Caso principal: SVC (contrato-âncora), ENV (agrupa PLGs)
ProfundidadeDefault: 3 níveis. Configurável via POLICY.
ValidaçãoDetecção de ciclos (anti-loop) obrigatória. Rejeição se profundidade excede limite.
PersistênciaMaterialized path (/SVC-001/ENV-002/PLG-003) para queries eficientes

2. Exemplo Multinível

Organization: Cliente X

└── SVC-2026040001 (Gestão de Projetos — contrato-âncora, nível 1)
    ├── ENV-2026040002 (Moodle produção, nível 2)
    │   └── PLG-2026040003 (Licença Connector, nível 3 — máximo default)
    ├── ENV-2026040004 (Moodle homologação, nível 2)
    │   └── PLG-2026040003 (mesma licença, ativada em 2 ENVs, nível 3)
    └── SVC-2026040005 (Projeto custom pontual, nível 2, lifecycle: project)

3. Materialized Path

Stored em meta do entitlement para queries eficientes sem recursive CTEs em wp_posts.

Entitlementmaterialized_pathNível
SVC-2026040001/SVC-20260400011
ENV-2026040002/SVC-2026040001/ENV-20260400022
PLG-2026040003/SVC-2026040001/ENV-2026040002/PLG-20260400033

Queries:

  • "Todos os filhos de SVC-001" → WHERE materialized_path LIKE '/SVC-2026040001/%'
  • "Profundidade de PLG-003" → contar separadores no path

Manutenção: Path recalculado quando entitlement é vinculado/desvinculado.


4. Créditos Compartilhados

RegraDescrição
Flag por filhouse_parent_credits (boolean, default: true)
Quando trueServiceRequests do filho consomem CreditBalance do pai (SVC)
Quando falseFilho precisa de créditos/billing próprio
Sem CreditBalance no paiFlag ignorada — SR do filho é billing avulso

Reserva e Consumo

EtapaComportamento
Abertura de SRCréditos estimados reservados (soft-lock)
Conclusão de SRCréditos reais consumidos (débito efetivo). Diferença ajustada.
Cancelamento de SRReserva liberada integralmente
Limite excedidoBloqueio se consumo ultrapassa limite configurável (CreditPolicy)
FIFOCréditos mais antigos consumidos primeiro

5. Expiração Independente

RegraComportamento
Cada entitlement tem sua expiraçãoPai expira dez/2026, filho PLG pode expirar mar/2027
Pai expira ou cancelaFilhos são desvinculados (parent_entitlement_id = null), NÃO expirados
Filho com lifecycle próprioContinua ativo (ex: PLG com Stripe subscription ativa)
Filho sem lifecycle próprioFica órfão — notificação ao admin
Materialized pathRecalculado nos filhos desvinculados

6. Operações

OperaçãoQuemValidação
Vincular filhoAdmin / AutoProfundidade ≤ max, sem ciclos, mesma org
Desvincular filhoAdminSempre permitido. Path recalculado.
Mover filho (troca pai)AdminProfundidade nova ≤ max, sem ciclos, mesma org
Auto-vincular (order)SistemaSVC no order → demais items viram filhos

7. Hooks

HookParâmetrosQuando
middag_entitlement_orphaned$child, $former_parentPai expirou/cancelou, filho desvinculado
middag_entitlement_linked$child, $parentFilho vinculado a pai
middag_entitlement_unlinked$child, $former_parentFilho desvinculado de pai