Modelo de Persistência¶
O MIDDAG adota um modelo de persistência orientado por famílias arquiteturais, com repository como fronteira oficial de acesso a dados.
Esse desenho existe para sustentar flexibilidade de produto sem espalhar schema, SQL e detalhes de hidratação pelo restante do framework.
Premissa estrutural¶
No local_middag, a base de persistência do produto é fixa. O framework e as extensions internas devem operar sobre as famílias oficiais do schema, e não criar novas tabelas de domínio para cada nova capacidade.
Se essa premissa se mostrar inviável no futuro, isso deve ser tratado como mudança profunda de arquitetura e exigirá novo ADR.
A unidade central: item¶
item é a unidade canônica de persistência flexível do MIDDAG.
Ele cumpre papel equivalente ao post no ecossistema WordPress: um registro-base tipado, capaz de representar diferentes objetos de negócio sem exigir uma nova tabela para cada capacidade do produto.
No MIDDAG:
TYPEdefine o tipo lógico do registro;- a tabela principal guarda atributos estruturais recorrentes;
- a tabela de metadata absorve extensibilidade útil;
- o model hidratado define o comportamento de domínio correspondente.
Essa abordagem já foi validada em ecossistemas amplos como WordPress e plugins como WooCommerce. O objetivo aqui não é copiar WordPress literalmente, e sim aplicar a mesma vantagem estrutural: flexibilidade com camada estável de persistência.
As quatro famílias de persistência¶
1. Current state¶
middag_itemsmiddag_itemmeta
Representam o estado operacional atual do framework.
Use essa família quando o objetivo for:
- persistir o estado corrente de uma entidade do produto;
- suportar múltiplos tipos de item no mesmo modelo base;
- permitir extensibilidade sem migração frequente.
2. Revision history¶
middag_item_revisionmiddag_item_revision_meta
Representam histórico imutável de um item.
Use essa família quando o objetivo for:
- registrar versões sucessivas de um item;
- reconstruir estado anterior;
- preservar histórico estrutural separado do estado atual.
3. Audit trail¶
middag_audit_logmiddag_audit_diffmiddag_audit_snapshot
Representam fatos auditáveis derivados de signals e outras ocorrências despachadas pelo framework.
Use essa família quando o objetivo for:
- rastrear o que aconteceu;
- registrar contexto, ator e origem;
- guardar diff ou snapshot observável de mudanças.
4. Job governance¶
middag_jobmiddag_job_attempt
Representam a governança persistida de trabalho assíncrono e observável.
Use essa família quando o objetivo for:
- registrar intenção e status de execução;
- controlar tentativas e deduplicação;
- manter rastreabilidade operacional sem substituir o runtime do Moodle.
O schema oficial atual¶
Estas são as tabelas oficiais do produto no estado arquitetural atual:
middag_itemsmiddag_itemmetamiddag_item_revisionmiddag_item_revision_metamiddag_audit_logmiddag_audit_diffmiddag_audit_snapshotmiddag_jobmiddag_job_attempt
Tabelas invioláveis
Dentro do local_middag, esse conjunto é tratado como base fixa da arquitetura atual. Core e extensions internas não devem introduzir novas tabelas de domínio locais como alternativa casual ao modelo. Se isso precisar mudar, será uma mudança profunda e exigirá novo ADR.
Modelo híbrido¶
O MIDDAG usa um modelo híbrido:
- colunas reais para dados estruturais recorrentes;
- metadata para extensibilidade;
- repositories para esconder joins, hidratação, serialização e transações.
Isso evita dois extremos ruins:
- criar tabela nova para cada tipo de item;
- jogar toda a modelagem em metadata e perder estrutura.
Como cada camada deve aplicar¶
Os exemplos abaixo são educacionais. Eles mostram a direção arquitetural esperada.
Framework¶
O framework trabalha sobre repositories e tipos de item, sem vazar nome de tabela.
<?php
namespace local_middag\framework\application\service\catalog;
use local_middag\framework\contract\repository\item_repository_interface;
final class catalog_item_service
{
public function __construct(
private item_repository_interface $item_repository,
) {}
public function find_item(int $item_id): object|null
{
return $this->item_repository->find_by_id($item_id);
}
}
Extension do ecossistema¶
A extension reutiliza o modelo item e pode especializar comportamento por TYPE, sem criar tabela própria dentro do local_middag.
<?php
namespace local_middag\extensions\ecommerce\service;
use local_middag\framework\contract\repository\item_repository_interface;
final class store_item_service
{
public function __construct(
private item_repository_interface $item_repository,
) {}
public function find_store(int $item_id): object|null
{
return $this->item_repository->find_by_id($item_id);
}
}
Direção esperada
Mesmo quando a extension representa um conceito próprio, como loja, pedido ou catálogo, a direção é modelar isso sobre item e famílias complementares do framework, não abrir nova tabela da extension.
Plugin terceiro¶
O plugin terceiro pode escolher entre aderir ao modelo do MIDDAG ou manter schema próprio.
Aderindo ao modelo do MIDDAG
<?php
use local_middag\framework\contract\repository\item_repository_interface;
use local_middag\middag;
middag::init();
$item_repository = middag::get(item_repository_interface::class);
$item = $item_repository->find_by_id(42);
Mantendo tabela própria
Liberdade de terceiros
Plugins terceiros podem ter tabelas próprias, mas essa liberdade não altera a regra do ecossistema interno do local_middag. O core e as extensions internas continuam presos às famílias oficiais do framework.
O que não fazer¶
- Não tratar nomes de tabela como API pública do framework.
- Não acessar tabelas do core diretamente em services, controllers ou extensions.
- Não criar novas tabelas de domínio dentro do core ou das extensions internas do
local_middag. - Não usar metadata para esconder campos essenciais que deveriam ser estruturais.
Quando algo não couber no modelo¶
Se uma necessidade importante não couber bem em item e nas famílias complementares, isso não deve virar escolha local de implementação.
O caminho correto é:
- reconhecer a limitação como questão arquitetural;
- validar se o problema é real e recorrente;
- tratar a mudança como decisão explícita em novo ADR.