Skip to content

feat(intent): read-only mode for personal surfaces (personalReadOnly) - #6369

Merged
delchev merged 2 commits into
masterfrom
feat/intent-personal-readonly
Jul 22, 2026
Merged

feat(intent): read-only mode for personal surfaces (personalReadOnly)#6369
delchev merged 2 commits into
masterfrom
feat/intent-personal-readonly

Conversation

@delchev

@delchev delchev commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Closes #6367.

What

Adds a read-only mode to the personal (my) surface. A personal owner relation may now declare personalReadOnly: true alongside personal: true:

  • the generated <Entity>MyController serves the scoped reads (getAll / get / count) but its create/update/delete return 403 FORBIDDEN;
  • the my pages drop New / Edit / Delete;
  • identity scoping, sensitive: stripping and the application-personal-perspectives registration are unchanged;
  • the regular (power) controller is unaffected — the back office still writes these records.

Why

A writable personal surface is wrong for records the owner may see but never author — a leave-balance/entitlement account (creating one on the my surface is a self-grant) or a payslip. Without this flag such surfaces are either unsafe or a hand-written controller + bespoke page.

Chain

RelationIntent.personalReadOnlyEdmIntentGenerator emits relationshipPersonalReadOnlyparameterUtils.js sets e.personalReadOnly (+ composition-child inheritance) → EntityMyController.java.template guards the write methods → my-list-view / my-form-view drop the buttons.

Test

IntentEmissionCoverageIT gains a Balance entity (owned by Person, personalReadOnly: true) with:

  • emission asserts: the my controller contains the 403 refusal and HttpStatus.FORBIDDEN, does not emit repository.save, and the my list view has no New button;
  • a runtime assert (outermost layer): GET /balance/BalanceMyController200, POST403.

Green locally (Tests run: 1, Failures: 0).

Note

403 FORBIDDEN (not 405) is used for the write refusal: the rs SDK's ControllerInvoker honors a handler-thrown ResponseStatusException status, and 403 is already the surface's convention (the "no identity mapped" case). A handler-thrown 405 was observed to surface as 400.

delchev and others added 2 commits July 22, 2026 09:47
A personal relation may declare personalReadOnly: true alongside personal:
true - the generated <Entity>MyController then serves only the scoped reads
and its create/update/delete return 405, and the my pages drop New/Edit/
Delete. For owner-owned reference records the person may SEE but never author
(a leave-balance account, a payslip) - closes the self-grant hole where a
writable personal surface let the owner create their own entitlement. The
regular (power) controller is unaffected.

Chain: RelationIntent.personalReadOnly -> EdmIntentGenerator emits
relationshipPersonalReadOnly -> parameterUtils sets e.personalReadOnly
(+ composition-child inheritance) -> EntityMyController.java.template guards
the writes -> my-list-view/my-form-view drop the buttons. Guide + IT
(IntentEmissionCoverageIT: Balance entity, emission asserts + runtime GET 200
/ POST 405) extended per the engine-intent keyword contract.

Addresses #6367.
…; 405 mapped to 400) + IT posts PascalCase body

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@delchev
delchev merged commit bbfe0e2 into master Jul 22, 2026
10 checks passed
@delchev
delchev deleted the feat/intent-personal-readonly branch July 22, 2026 08:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intent: read-only mode for personal (and partner) surfaces — see-only 'My' records

1 participant