Transformar o plano de keyset pagination do starter em um backlog técnico executável, arquivo por arquivo, para o v1 canônico da plataforma.
Este backlog assume as decisões do documento CURSOR-PAGINATION-KEYSET-PLAN.md:
praxis-metadata-starterCursorPage como DTO externoafter e beforeSpecificationCursorPageInfraestrutura mínima no starter:
Implementação JPA real no starter:
Window -> CursorPageJpaSpecificationExecutorController/documentação/testes consumidores:
praxis-api-quickstartsrc/main/java/org/praxisplatform/uischema/dto/CursorPage.javaObjetivo: - revisar o DTO externo para garantir compatibilidade com
Window<T>
Tarefas: - confirmar se o shape atual é suficiente para
next, prev e size - decidir se
precisa de metadados adicionais no v1 - preservar backward compatibility
do contrato HTTP
Critério de aceite: - CursorPage continua sendo o DTO
externo único do starter para cursor
src/main/java/org/praxisplatform/uischema/service/cursor/CursorSupportMode.javaObjetivo: - definir capability explícita por recurso
Tarefas: - criar enum inicial com pelo menos: - AUTO -
DISABLED
Critério de aceite: - existe um contrato claro para dizer se o recurso suporta cursor
src/main/java/org/praxisplatform/uischema/service/cursor/CursorEligibility.javaObjetivo: - encapsular a avaliação de elegibilidade do v1
Tarefas: - modelar regras mínimas: - ID simples - sort estável baseado em campos escalares - sem coleções/nested sorts - sem depender de joins complexos como chave do cursor - expor utilitário/serviço reutilizável
Critério de aceite: - o starter consegue decidir, de forma centralizada, se um recurso é elegível
src/main/java/org/praxisplatform/uischema/service/cursor/CursorTokenCodec.javaObjetivo: - serializar/deserializar o cursor opaco
Tarefas: - modelar payload interno do cursor - usar JSON + base64url
- suportar direção (after/before)
Critério de aceite: - cursor opaco gerado e lido sem expor diretamente a estrutura ao frontend
src/main/java/org/praxisplatform/uischema/service/cursor/CursorSortNormalizer.javaObjetivo: - transformar Sort em sort cursor-safe
Tarefas: - definir a fonte canônica do sort do v1: -
sort explícito somente quando cursor-safe - fallback para
getDefaultSort() - resolução consistente de aliases/campos
de FilterDTO para property path JPA - anexar ID como
tie-breaker - rejeitar sort inelegível
Critério de aceite: - todo fluxo de cursor passa por um sort estável e determinístico
src/main/java/org/praxisplatform/uischema/service/cursor/CursorProperties.javaObjetivo: - centralizar configuração do v1
Tarefas: - modelar propriedades como: - enabled -
maxSize - defaultMode -
publishEndpointStrategy ou semântica equivalente, se
necessário - decidir explicitamente se o binding será via
@ConfigurationProperties ou se o v1 ficará alinhado ao
padrão atual do starter com @Value
Critério de aceite: - configurações de cursor ficam governadas via Spring Boot properties
src/main/java/org/praxisplatform/uischema/repository/base/BaseCrudRepository.javaObjetivo: - confirmar se o contrato atual do repositório base já é suficiente para o v1
Tarefas: - validar o uso de
JpaSpecificationExecutor#findBy(..., q -> q.scroll(...))
com Specification - só introduzir fragmento custom se
houver limitação real da stack atual para o caso canônico do v1
Critério de aceite: - o backlog do v1 não cria infraestrutura redundante no repositório base
src/main/java/org/praxisplatform/uischema/repository/base/CursorScrollableRepository.javaObjetivo: - existir apenas como fallback arquitetural, não como premissa obrigatória
Tarefas: - criar somente se a prova de conceito com
JpaSpecificationExecutor mostrar limitação concreta - se
existir, declarar método de scroll keyset com: -
Specification<E> - Sort -
ScrollPosition/KeysetScrollPosition -
limit
Critério de aceite: - o fragmento só entra quando simplificar de fato a plataforma
src/main/java/org/praxisplatform/uischema/repository/base/CursorScrollableRepositoryImpl.javaObjetivo: - implementar execução keyset real apenas se a via nativa do Spring Data não bastar para o v1
Tarefas: - encapsular a limitação encontrada na prova de conceito -
manter o mesmo contrato de elegibilidade e sort normalizado do v1 -
suportar after e before
Critério de aceite: - a implementação adicional reduz complexidade total; não a aumenta sem ganho
src/main/java/org/praxisplatform/uischema/service/base/BaseCrudService.javaObjetivo: - substituir o default puramente não implementado por capability governada
Tarefas: - adicionar API canônica de suporte a cursor - decidir
comportamento de supportsCursorPagination() - integrar
CursorSupportMode - distinguir claramente: - recurso
globalmente desabilitado - recurso habilitado mas inelegível no v1 -
recurso elegível e operacional
Critério de aceite: - a ausência de suporte deixa de ser implícita e passa a ser governada
src/main/java/org/praxisplatform/uischema/service/base/AbstractBaseCrudService.javaObjetivo: - fornecer implementação padrão reutilizável de
filterByCursor(...)
Tarefas: - implementar a primeira versão usando preferencialmente
JpaSpecificationExecutor#findBy(..., q -> q.sortBy(...).scroll(...))
- reaproveitar GenericSpecificationsBuilder para produzir
Specification e o mapping de sort já existente, sem
duplicar semântica em outra camada - adaptar
Window<E> para CursorPage<E> -
aplicar CursorSortNormalizer
Critério de aceite: - recursos elegíveis passam a suportar cursor sem override manual por app
src/main/java/org/praxisplatform/uischema/service/base/AbstractReadOnlyService.javaObjetivo: - herdar a implementação padrão sem duplicação
Tarefas: - validar que recursos read-only elegíveis também entram no fluxo
Critério de aceite: - read-only e CRUD simples compartilham a mesma infraestrutura cursorável
src/main/java/org/praxisplatform/uischema/controller/base/AbstractCrudController.javaObjetivo: - alinhar a publicação de /filter/cursor com
suporte real
Tarefas: - revisar comportamento de 501 - no v1, manter
o endpoint publicado e governar suporte real por capability e
documentação, evitando tentar despublicação dinâmica por recurso nesta
fase - manter validação de size
Critério de aceite: - a superfície publicada não promete mais suporte inexistente sem governança
src/main/java/org/praxisplatform/uischema/controller/base/AbstractReadOnlyController.javaObjetivo: - garantir consistência com o controller base read-only
Tarefas: - revisar herança e documentação do endpoint de cursor
Critério de aceite: - mesma semântica entre controllers CRUD e read-only
src/main/java/org/praxisplatform/uischema/configuration/OpenApiUiSchemaAutoConfiguration.javaObjetivo: - registrar beans necessários do v1
Tarefas: - registrar CursorProperties - registrar
codec/normalizer/serviços auxiliares - expor beans com
@ConditionalOnMissingBean quando fizer sentido - evitar
mexer no agregador sem necessidade; preferir encaixar o v1 na
auto-configuração já existente do starter
Critério de aceite: - apps consumidores recebem a infraestrutura cursorável automaticamente
src/main/java/org/praxisplatform/uischema/configuration/PraxisMetadataAutoConfiguration.javaObjetivo: - revisar se o módulo agregador precisa importar algo explicitamente
Tarefas: - confirmar apenas que a auto-configuração cursorável continua no caminho de inicialização; não abrir refactor do agregador sem necessidade concreta
Critério de aceite: - o starter sobe com a capability sem wiring manual no app consumidor
README.mdObjetivo: - ajustar narrativa pública sobre paginação por cursor
Tarefas: - deixar explícito que keyset é suportado apenas em recursos elegíveis no v1
Critério de aceite: - o README não promete cursor universal se o v1 for governado por elegibilidade
docs/technical/CURSOR-PAGINATION-KEYSET-PLAN.mdObjetivo: - manter o plano estratégico alinhado ao que foi implementado
Tarefas: - atualizar status do rollout conforme cada lote avançar
Critério de aceite: - o documento continua sendo o norte técnico de arquitetura
docs/technical/CURSOR-PAGINATION-KEYSET-V1.mdObjetivo: - documentar a implementação efetiva do v1 depois que sair do papel
Tarefas: - descrever: - capability - restrições - propriedades - exemplos de uso
Critério de aceite: - existe uma doc operacional do v1, não só um plano
src/test/java/org/praxisplatform/uischema/service/cursor/CursorTokenCodecTest.javaObjetivo: - cobrir encode/decode do cursor opaco
src/test/java/org/praxisplatform/uischema/service/cursor/CursorSortNormalizerTest.javaObjetivo: - cobrir sort estável, tie-break por ID e rejeição de sort inelegível
src/test/java/org/praxisplatform/uischema/service/cursor/CursorJpaKeysetIntegrationTest.javaObjetivo: - validar keyset real com JPA/H2 pela via escolhida no v1
Observação: - se o v1 ficar na via nativa de
JpaSpecificationExecutor, o teste cobre essa integração -
se um fragmento custom for introduzido depois, ele ganha teste
dedicado
Cenários mínimos: - asc - desc - empate por ID - after -
before - filtro + sort
src/test/java/org/praxisplatform/uischema/controller/base/...Objetivo: - validar 501 apenas para recurso
explicitamente inelegível - validar 200 em recurso elegível
real
praxis-api-quickstart/src/test/java/...Objetivo: - provar integração real sem mock do service
Recursos candidatos iniciais: - um CRUD simples com sort canônico já
estável, por exemplo Cargo, Departamento ou
Equipe - um read-only simples com sort escalar e baixo
acoplamento relacional - deixar MencoesMidia,
VwRankingReputacao e Missao para rodada
posterior, se continuarem elegíveis após a prova do v1
Critério de aceite: - pelo menos um recurso CRUD e um recurso
read-only passam em /filter/cursor no app consumidor
real
JpaSpecificationExecutor#findBy(...).scroll(...)O v1 só deve ser considerado pronto quando:
/filter/cursor real/filter/cursor realafter, before, asc,
desc e empate por IDnullsComeçar pelo lote de infraestrutura mínima:
CursorSupportModeCursorEligibilityCursorTokenCodecCursorSortNormalizerCursorPropertiesNa sequência imediata, provar o caminho mais curto com a stack atual:
JpaSpecificationExecutor#findBy(..., q -> q.sortBy(...).scroll(...))Window -> CursorPageSó depois disso decidir se existe motivo real para abrir um fragmento custom de repositório no v1.