O praxis-metadata-starter hoje publica o endpoint
POST /filter/cursor no AbstractCrudController,
mas a implementação padrão do service ainda não materializa keyset
pagination.
Na prática:
BaseCrudService#filterByCursorMapped(...)BaseCrudService ainda fornece um default que lança
UnsupportedOperationException("Cursor pagination not implemented")AbstractCrudController converte esse caso em
501 Not ImplementedIsso explica por que apps consumidores, como o
praxis-api-quickstart, respondem 501 no Render
mesmo quando os demais filtros funcionam.
A solução correta de plataforma é implementar keyset pagination
canônica no praxis-metadata-starter, e não deixar cada app
consumidor reinventar a estratégia por recurso.
O starter já centraliza:
locateoptions/filter/filter/cursor deve seguir a mesma lógica: contrato e
infraestrutura centralizados, com capacidade explícita e governada.
O ecossistema Spring já fornece primitives importantes para uma implementação sólida:
ScrollPositionKeysetScrollPositionWindow<T>WindowIteratorEssas abstrações são a base mais adequada para scroll/keyset no nível
do starter. O contrato público do Praxis pode continuar usando
CursorPage, mas a implementação interna deve se apoiar
nessas primitives.
Na stack atual do starter, o primeiro caminho a testar deve ser o que
o Spring Data JPA já expõe via
JpaSpecificationExecutor#findBy(..., q -> q.scroll(...))
com Specification.
Isso reduz a chance de criar infraestrutura redundante no v1.
Fragments customizados continuam sendo uma opção válida, mas devem
entrar só se a prova de conceito com
JpaSpecificationExecutor mostrar limitação real para o caso
canônico do v1.
O starter já usa auto-configuração para outros recursos. Cursor pagination deve seguir o mesmo padrão, com propriedades de governança e beans internos configuráveis.
O sucesso da implementação depende de restringir o v1 ao caso canônico da plataforma.
after e
beforeNão tentar no v1:
CursorPage como DTO externoO contrato HTTP do Praxis já usa CursorPage. Isso pode
ser preservado.
Internamente, o starter deve converter entre:
Window<E> / ScrollPositionCursorPage<E>Prioridade do v1:
JpaSpecificationExecutor#findBy(..., q -> q.sortBy(...).scroll(...))Specification<E> já gerada pelo
starterAbstractBaseCrudServiceSe essa via não bastar, aí sim criar algo como:
CursorScrollableRepository<E>CursorScrollableRepositoryImpl<E>O starter deve forçar ordenação determinística:
Exemplo:
ORDER BY publicadoEm DESC, id DESC
O Angular não deve conhecer a estrutura interna do cursor.
O starter deve serializar um payload opaco contendo, no mínimo:
Formato sugerido:
Assinatura/HMAC pode entrar depois, se houver necessidade de blindagem adicional.
Nem todo recurso deve expor suporte real a cursor pagination.
Precisamos de um mecanismo canônico, por exemplo:
supportsCursorPagination()CursorSupportModeValores possíveis:
AUTODISABLEDNo v1, AUTO só habilita quando o recurso for compatível
com o contrato seguro.
Specificationafter / beforeWindowWindow<E> para
CursorPage<E>after, before e
sizeO v1 deve formalizar:
praxis.cursor.max-size)Exemplos de propriedades:
praxis.cursor.enabled=true
praxis.cursor.max-size=100
praxis.cursor.default-mode=auto
JpaSpecificationExecutorWindow ->
CursorPagepraxis-api-quickstart/filter/cursor
para recursos inelegíveis depois que a capability estiver maduraafterbeforeSpecification501/filter/cursor com after/filter/cursor com beforeSim, implementar keyset canônico no
praxis-metadata-starter é uma estratégia sólida, desde que
o rollout seja deliberadamente restrito.
A taxa de sucesso é alta se o starter:
O erro seria tentar resolver no v1 “qualquer sort, qualquer join, qualquer projection”. O caminho robusto é um v1 pequeno, determinístico e plataformizado.