MemberJunction / MemberJunction/MJ
Field-Level Security: no UI can enable it — `EnableFieldLevelSecurity` is not exposed on the Entity form
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
## Summary
Field-level security is gated entirely on `Entity.EnableFieldLevelSecurity`. Every enforcement point in the feature tests that boolean first and short-circuits when it is off, and reconciliation/snapshot initialization is triggered by the flag going from off to on. **There is no way to set it in the product.**
## Detail
The *generated* Entity form does render the field:
`packages/Angular/Explorer/core-entity-forms/src/lib/generated/Entities/MJEntity/mjentity.form.component.html`
...but `MJ: Entities` has a **custom** form registered, which wins by ClassFactory priority and does not expose it:
`packages/Angular/Explorer/core-entity-forms/src/lib/custom/Entities/entity-form.component.{ts,html}`
That form surfaces `TrackRecordChanges`, `AllowCaching` and the other entity-level configuration, but has no control for `EnableFieldLevelSecurity`.
Consequence: an administrator following the Field-Level Security guide reaches "turn the flag on" with nothing to click. Every manual verification pass during development had to flip it through the entity layer from the browser console.
## Why direct SQL is not an acceptable workaround
Enabling the flag is not a plain column write. `MJEntityEntityServer.Save()` wraps two things in one entity transaction — persisting the flag, then running `ReconcileFieldPermissions` to snapshot the entity's existing entity-level permissions into per-field rows. On an FLS-enabled entity **a field with no permission rows is denied**, so committing the flag without the snapshot locks every user out of every field on that entity until something else reconciles.
So the fix has to go through the entity layer, not the table.
## Proposed fix
Add the flag to the custom Entity form's configuration section, alongside `TrackRecordChanges` / `AllowCaching`. Worth considering as part of the same change:
- a confirmation step explaining that enabling writes snapshot rows and disabling retains them;
- surfacing the resulting `MJ: Entity Field Permissions` rows for the entity, since there is currently no administrative surface for those either.
## References
- Guide: `guides/FIELD_LEVEL_SECURITY_GUIDE.md` §1.1 (configuration model) and §5 (operational notes)
- Flag semantics: `packages/MJCore/src/generic/entityInfo.ts` (`EntityInfo.EnableFieldLevelSecurity`)
- Snapshot-on-enable: `packages/MJCoreEntitiesServer/src/custom/MJEntityEntityServer.server.ts`
Contributor guide
Research direction
Start with packages/Angular/Explorer/core-entity-forms/src/lib/custom/Entities/entity-form.component.ts and entity-form.component.html, comparing the custom form with the generated form. Read packages/MJCoreEntitiesServer/src/custom/MJEntityEntityServer.server.ts and the Field-Level Security guide to understand the enable-time snapshot behavior. Done means administrators can enable the flag through the custom Entity form without bypassing the entity layer.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- frontend, security
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 76/100