Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"metadata": {
"description": "Claude skills for Dynamicweb 10 — organized by task domain, bundled by role.",
"version": "3.8.1"
"version": "3.8.2"
},
"plugins": [
{
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
All notable changes to the Dynamicweb Skills plugin are recorded here. The
`version` field in `.claude-plugin/marketplace.json` tracks these entries.

## [3.8.2]

### Changed
- **Group-scoped page/paragraph gates work — via the deny+grant pair; 3.8.1's role-string-only rule
was a misdiagnosis.** Further live verification on the same 10.26.x host: a **bare** group-id
grant does not gate because highest-wins resolution lets the inherited broad
`AuthenticatedFrontend` grant override it — which is what previously read as "group gating is
non-functional". The working shape (verified at page AND paragraph level): an explicit
`AuthenticatedFrontend → None` deny **plus** a `<group id> → Read` grant on the same entity.
Also live-verifies the `PermissionName='Paragraph'` row shape (previously hedged), with the
deny+grant pair written via the paragraph's Permissions panel or direct SQL + security-cache
flush. Rewrote the §15 role-string rule in
`dw-demo-base/references/foundational/users-permissions.md` around the pair (including the
two-step hide-a-subtree recipe, whose step-2 group grants are effective exactly because of the
step-1 deny), the restrict-a-page recipe in `dw-users-permissions/SKILL.md` (the broad-role deny
named as load-bearing), and the `dw10-canonical-surfaces.md` routing row.

## [3.8.1]

### Changed
Expand Down
30 changes: 18 additions & 12 deletions skills/dw-demo-base/references/foundational/users-permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -636,12 +636,15 @@ rows on that build, and `AccessElementPermission` (which also exists) stays empt
modelling-time / render-time split this ref opens with is **semantic, not physical** — same table,
different `PermissionName`, key shape, and enforcement points.

**Gate the storefront by role string.** Rows scoped to the frontend role strings `Anonymous` /
`AuthenticatedFrontend` gate correctly; rows scoped to an `AccessUser` group id failed to gate the
frontend on a 10.26.x build. Design storefront gates on the role strings, keep group-scoped
visibility on the surfaces that natively support it (Assortments, DC groups —
[`commerce-b2b.md`](commerce-b2b.md)), and validate any group-scoped page gate on the target build
before a demo depends on it.
**Group-scoped gates need the deny+grant pair.** Rows scoped to the frontend role strings
`Anonymous` / `AuthenticatedFrontend` gate correctly on their own. A **bare** group-id grant does
NOT gate — highest-wins resolution lets the inherited broad `AuthenticatedFrontend` grant override
it, which reads as "group gating is non-functional" if that's the only shape tested. The working
shape (verified live on 10.26.x, page AND paragraph level): an explicit
`AuthenticatedFrontend → None` deny **plus** a `<group id> → Read` grant **on the same entity** —
i.e. exactly the two-step recipe under "Frontend resolution" below. For visibility that should
follow commerce data rather than CMS permissions, prefer the surfaces that natively scope by group
(Assortments, DC groups — [`commerce-b2b.md`](commerce-b2b.md)).

### Enforcement points

Expand Down Expand Up @@ -673,11 +676,14 @@ as "blank homepage", not "please sign in".
`Page.PermissionType = 0` keeps a page inheriting rather than carrying its own rows).
2. No template edits needed. Nav, redirect, and child-render all self-filter.

### How to hide a single paragraph from a role
### How to hide a single paragraph from a persona

Use the paragraph's own Permissions panel — same entity-store mechanics; the frontend renderer's
`Content.cs:398` returns empty content for users without a read grant. (Only the `PermissionName='Page'`
row shape is live-verified; drive paragraph gates through the panel rather than hand-writing rows.)
Same entity-store mechanics with `PermissionName='Paragraph'` and the paragraph id as
`PermissionKey` (live-verified on 10.26.x): write the deny+grant pair —
`('AuthenticatedFrontend', '<paragraphId>', 'Paragraph', <None>)` plus
`('<groupId>', '<paragraphId>', 'Paragraph', <Read>)` — via the paragraph's Permissions panel or
direct SQL + security-cache flush. The frontend renderer's `Content.cs:398` returns empty content
for users without a read grant.

### Frontend resolution takes the HIGHEST level across a user's identities

Expand All @@ -687,8 +693,8 @@ is ignored. Resolution takes the **highest** level across all of a user's identi
grants `Read`. To hide a subtree from one persona while keeping it for others:

1. Deny the broad role on the subtree root (e.g. `AuthenticatedFrontend → None`).
2. Grant the personas that *should* keep it → `Read` — and per the role-string rule above, verify a
group-scoped grant actually gates on the target build before relying on it.
2. Grant the personas that *should* keep it → `Read` (group-id grants work here — the explicit
deny in step 1 is what makes them effective; a group grant without it is silently overridden).

The excluded persona then resolves to `None` (section drops from all nav templates, direct URLs 302);
others keep it; children inherit the root. (When a CSR-type user **impersonates** a customer the
Expand Down
2 changes: 1 addition & 1 deletion skills/dw-demo-swift/references/dw10-canonical-surfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
| Surface you're about to hand-roll | Use instead — owned by | Candidate |
|---|---|---|
| Read user / user groups (`Pageview.User`, `Pageview.User.GetGroups()`) | `dw-render-viewmodels` | [`render-viewmodels.md`](../../dw-demo-base/references/foundational/render-viewmodels.md) "User identity / groups" |
| Gate a Page/Paragraph by role (the permission entity store — `UnifiedPermission` rows keyed `PermissionName='Page'`, NOT the legacy `*Permission` columns) | `dw-users-permissions` | [`users-permissions.md`](../../dw-demo-base/references/foundational/users-permissions.md) §15 |
| Gate a Page/Paragraph by role or group (the permission entity store — `UnifiedPermission` rows keyed `PermissionName='Page'`/`'Paragraph'`; group gates need the broad-role deny pair; NOT the legacy `*Permission` columns) | `dw-users-permissions` | [`users-permissions.md`](../../dw-demo-base/references/foundational/users-permissions.md) §15 |
| Read prices (`Services.Prices`, custom `PriceProvider`) | `dw-commerce-catalog` | [`commerce-catalog.md`](../../dw-demo-base/references/foundational/commerce-catalog.md) §2.12 |
| Read customer orders (`Services.Orders.GetCustomerOrdersByType` / `GetOrdersBySearch`) | `dw-commerce-orders` | [`commerce-orders.md`](../../dw-demo-base/references/foundational/commerce-orders.md) "canonical order read surface" |
| Get product / friendly URLs; `AddStylesheet`/`AddScript` hoisting; cross-cutting redirects (`Page.Loaded` subscriber); per-category behavior; product-field arrays | `dw-render-razor` | [`render-razor.md`](../../dw-demo-base/references/foundational/render-razor.md) §1 |
Expand Down
7 changes: 4 additions & 3 deletions skills/dw-users-permissions/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,10 @@ Default: Anonymous users have Read on all pages.

To restrict a page or branch:
1. Set **Anonymous users (frontend) → None** on the page
2. Grant **Read** to **Authenticated users (frontend)** — role grants gate reliably. Verify a
group-scoped page grant actually gates on the target build before relying on it (group-scoped
rows failed to gate the frontend on a 10.26.x install; role-string rows gated correctly).
2. Grant **Read** to **Authenticated users (frontend)** — or, to restrict to specific groups, set
**Authenticated users (frontend) → None** and grant **Read** to the target groups. The explicit
broad-role deny is load-bearing: a bare group grant is silently overridden by the inherited
Authenticated-users grant (highest wins) and does not gate.

A denied anonymous visitor is auto-redirected to the first page in the website that carries the
UserAuthentication app — keep that page active and un-restricted.
Expand Down
Loading