Summary#
app.Classifications maps each data-sensitivity level to the set of [Role] members permitted to read fields
marked at that level. A level is a DataClass value — PII, Financial, Secret, and so on — and each
Classification pairs one level with a Roles = [ … ] list. A field annotated [Classification(DataClass.PII)] is
then readable only by a principal holding one of the roles listed for PII; to everyone else the field is masked. The
list is declared inside the bare app = new() { … } config object.
enum DataClass { PII, Financial }
app = new() {
Name = "Orders",
Classifications = [
new Classification(DataClass.PII) { Roles = [Role.Staff, Role.Admin] },
new Classification(DataClass.Financial) { Roles = [Role.Admin] },
],
};Signature#
[Role] enum Role { Staff, Admin } // the [Role] enum must be declared
enum DataClass { PII, Financial } // …and the level vocabulary is an enum too
app = new() {
Name = "Orders",
Classifications = [ // one entry per data-sensitivity level
new Classification(DataClass.PII) { // the level this entry governs
Roles = [Role.Staff, Role.Admin], // roles allowed to read fields at this level
},
new Classification(DataClass.Financial) { Roles = [Role.Admin] },
],
};Classifications is a list — an app may map several independent DataClass levels, each to its own set of roles.
Description#
Each Classification has:
DataClass.<Level>— the constructor argument names the sensitivity level this entry governs (PII,Financial,Secret, …). One entry per level. The level vocabulary is an enum the app declares — it need not be calledDataClass, and naming a member no enum declares is a compile error, exactly as it is in the[Classification]attribute.Roles— a list of[Role]enum members. A principal must hold one of these roles to read a field marked at this level. A principal holding none of them sees the field masked.
A field opts into a level with the [Classification] attribute — [Classification(DataClass.<Level>)] on the
member. The classification declared here is what that attribute resolves against: it decides which roles can read the
field. Because Roles references [Role]
members, the [Role] enum must be declared in the app — a role name that doesn't resolve is a compile error that
names the roles you do define.
The whole list lives inside the bare app = new() { Name = "…", Classifications = [ … ] } config object alongside the
app's other configuration.
Includes — a kit's personal level, onto one of yours#
Includes = [Osysharp.Conversations.Personal.Content] on one of your classifications maps a PACKAGE's personal level onto
it: that kit's fields at that level are read by whoever this classification clears (its Roles, or Open). A kit
announces the levels it uses in its package.osy (personal Content;); one you map to nothing is read through each
row's own security, so most apps write nothing at all. See [[security-personal-data#kit-levels]].
Open — a Personal level read through the row's own security#
new Classification(Personal.Content) { Open = true } maps a core Personal level to whoever may read the row
instead of to roles: the data stays personal for privacy (kept out of the audit trail, restrictable), and a person
reading their own row — a customer in a chat widget, who holds no role — is not masked from it. It is refused on any
other level, and beside Roles (the two would contradict each other). See personal data (Classification(Personal.X)).
Examples#
An app that classifies PII fields as readable by staff or admins, and Financial fields as admin-only. The [Role]
enum is declared because Roles references its members:
[Role] enum Role { Staff, Admin }
[Principal] entity User { [Unique, MaxLength(200)] string Email; }
[RoleGrant] entity RoleGrant { [Required] User Member; [Required] Role Role; } // who holds which role
enum DataClass { PII, Financial }
app = new() {
Name = "Orders",
Classifications = [
new Classification(DataClass.PII) { Roles = [Role.Staff, Role.Admin] },
new Classification(DataClass.Financial) { Roles = [Role.Admin] },
],
};See also#
- role grants (and the first admin) — declaring the
[Role]enum whose members appear inRoles - security { } — entity-level read/write gates that compose with field classifications
- principal predicates (IsAuthenticated / IsAnonymous / IsTheApp) and open reads — the principal whose roles are checked against a field's classification