feat/shared-model #37

Merged
christian.keller merged 8 commits from feat/shared-model into main 2026-09-01 14:24:11 +00:00
No description provided.
Phase 0 of docs/plans/shared-model.md: MetaEntity and MetaField carry
declaredRestOperations (the annotation) next to restOperations (the
effective value, identical until an exposure narrows it). The memoized
crudEntity()/crudField() parses stay cached, but every model copies the
cached MetaEntity and MetaFields before wiring, so two CrudMetaModels
share no field instance and wiring one no longer rewires the other.
Phase 1 of docs/plans/shared-model.md:

- crudExposure { } DSL in api (de.loosetie.crudular.api.rest): entity
  blocks with create/read/update field whitelists, like = <op>, delete,
  search condition whitelists, searchCustom, plus the extension hooks
  (declare/capture/extension). build() never throws; structural mistakes
  land as ExposureIssues on the value.
- CrudExposure value with merge by union of mentions; CEILING is the
  neutral element and, as the final union, serves everything annotated.
- starter-base collects CrudExposureDeclaration beans, builds each once,
  unions them and hands the value to CrudMetaModel, which resolves
  effective restOperations at construction (ExposureNarrowing).
- Key fields bypass field whitelists and their read is lifted past an
  off annotation; write operations keep the annotation's protection
  (deviation from the plan's letter: lifting writes would have made
  protected key fields patchable, e.g. the ShelfView fixture).
- Links: a reference field without effective read renders neither value
  nor link; a link to an entity without a local item endpoint keeps its
  uri and points at crudular.rest.not-served-path (default /-/not-served,
  421 route mounted; absolute URLs used verbatim, nothing mounted);
  back-links render only when the referencing entity serves SEARCH.
Phase 2 of docs/plans/shared-model.md:

- Every scanned Search binds to its entity by type argument onto
  MetaType.searches; the canonical-name lookup still decides the Primary
  Search unless the exposure names one via searchCustom (registration by
  naming, so the class binds even outside crudular.model.packages).
  DefaultSearch stays the fallback; unbindable classes land on
  MetaModel.unresolvedSearches, mirroring unresolvedDescriptors.
- The repository (SearchConditions), the jOOQ search plan and both
  search verifications now cover every bound search, resolved from the
  instance's class instead of assuming the primary.
- @CrudSearchField gains rest: Boolean = true; false marks a condition
  repository-only (no query parameter, no OpenAPI, no back-link). A
  mixed @CrudSearchOr group counts as rest = false.
- MetaSearchField carries declaredRest and rest; only the Primary
  Search is narrowed by the exposure's search whitelist. queryMap throws
  for a set repository-only condition; the REST parser and OpenAPI read
  fieldsRest.
Phase 3 of docs/plans/shared-model.md: a new built-in verification,
registered like the others in CrudBaseAutoConfiguration (flag
crudular.model.verification.exposure-enabled), graded under fail-on and
advisory by default. ERRORs name mistakes only the DSL can make (grants
applying to nothing or exceeding the ceiling, key fields in field lists,
republished build issues, conditions of a non-conventional class);
pre-existing code caps at WARNING (stray searches on unresolvedSearches,
mixed @CrudSearchOr rest groups, unrenderable back-links, served
conditions on unserved fields); the not-served-link surface and a custom
Primary Search report as INFO.
Phase 4 of docs/plans/shared-model.md:

- docs/howto/user/shared model exposure.md: the DSL from the consumer's
  side, beans and profiles, application searches and searchCustom,
  rest = false, descriptors and exposure, links to entities not served
  here (crudular.rest.not-served-path), what is served, and the
  adoption checklist.
- ADR-0004 amended with the reversal table (no scope axis, application
  searches allowed, Kotlin DSL instead of properties, not-served href
  instead of unchanged links).
- sample/spring-simple: exposure bean with searchCustom<AppSampleSearch>
  as a working example; the sample's kotlin plugin overrides its parent
  config, so it now pins jvmTarget 21 (needed to inline the api's
  reified builders).
- IDE reformat of the files this feature touched.

CONTEXT.md (gitignored, local) reworded per the plan: Scope and Closure
removed, Exposure reworded, Primary Search added.
refactor(exposure): code-review fixes over the shared-model branch
All checks were successful
/ release (pull_request) Successful in 3m2s
8f502d2f0b
Standards axis: shared anyItemOn() on CrudRestOperations replaces the
duplicated item-endpoint check in HalBuilder and ExposureVerification;
for-loops replace terminal forEach in queryMap and the REST search
parser; guard exits, braces, member order and import cleanups; private
helpers documented with comments instead of KDoc; expression bodies of
new fixtures break after '='.

Spec axis: a searchCustom class with an unresolvable type argument is
now the ERROR the Phase 3 table asks for (was INFO); the invented
extension-collision issue is dropped - two beans carrying one wrapper
extension are the documented pattern (security-by-exposure plan), so
the bag merges first-wins and value merging stays the wrapper concern's
business; protocol-relative not-served-path counts as absolute; the
vacuous ceiling-equality test now asserts effective == declared modulo
the key read lift; new test pins that an unmentioned entity stays
usable through CrudRepository.
style(exposure): trim comments on the branch's changed files
All checks were successful
/ release (pull_request) Successful in 3m9s
e49d2d14ef
Comments dropped where the naming already says it (fixtures, private
helpers, one-line properties); the ones kept are cut to the constraint
they carry: public-API KDoc down to the contract, the key-field
write-protection note, the merge and not-served rules. 226 -> 132
added comment lines.
docs(adr): fold the exposure amendment into ADR-0004, add MIGRATION-2.0.0
All checks were successful
/ release (pull_request) Successful in 3m16s
9790fd907e
ADR-0004 now describes only the current state - no amendment banner, no
reversal table, no references to earlier versions: every consumer
registers the whole model, the exposure DSL grants within the annotation
ceiling, per-application searches with one Primary Search, not-served
links, and the current verification table. Consumer-facing behaviour
changes move to MIGRATION-2.0.0.md at the root (not-served links,
dropped links/back-links, key-field read lift, stray searches now
verified, queryMap throw, recompile note for direct meta construction).
christian.keller deleted branch feat/shared-model 2026-09-01 14:24:12 +00:00
christian.keller referenced this pull request from a commit 2026-09-01 14:24:12 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
DenktMit-OSS/lt-crudular!37
No description provided.