@@ -68,6 +68,9 @@ export const SITE_MAP: Record<string, PageRoleConfig> = {
6868 { role : "CanDeleteEntitlementRequestsAtAnyBank" } ,
6969 ] ,
7070 } ,
71+ "/rbac/groups" : {
72+ required : [ { role : "CanGetGroupsAtAllBanks" } ] ,
73+ } ,
7174 "/rbac/groups/create" : {
7275 required : [ { role : "CanCreateGroupAtAllBanks" } ] ,
7376 } ,
@@ -132,6 +135,12 @@ export const SITE_MAP: Record<string, PageRoleConfig> = {
132135 required : [ { role : "CanManageFeaturedApiCollections" } ] ,
133136 } ,
134137
138+ // ── Products ────────────────────────────────────────────
139+ "/products/bootstrap" : {
140+ required : [ { role : "CanUpdateApiProduct" , bankScoped : true } ] ,
141+ optional : [ { role : "CanDeleteApiProduct" , bankScoped : true } ] ,
142+ } ,
143+
135144 // ── Banks ─────────────────────────────────────────────
136145 "/banks/create" : {
137146 required : [ { role : "CanCreateBank" } ] ,
@@ -152,6 +161,12 @@ export const SITE_MAP: Record<string, PageRoleConfig> = {
152161 } ,
153162
154163 // ── Metrics ───────────────────────────────────────────
164+ "/metrics" : {
165+ required : [ { role : "CanReadMetrics" } ] ,
166+ } ,
167+ "/aggregate-metrics" : {
168+ required : [ { role : "CanReadAggregateMetrics" } ] ,
169+ } ,
155170 "/connector-traces" : {
156171 required : [ { role : "CanGetConnectorTrace" } ] ,
157172 } ,
@@ -248,6 +263,30 @@ export const SITE_MAP: Record<string, PageRoleConfig> = {
248263 } ,
249264} ;
250265
266+ /**
267+ * Validate that no SITE_MAP page mixes bankScoped and non-bankScoped roles
268+ * in its required list. Mixing scopes would show confusing role widgets
269+ * (some saying "System-wide" and others "Bank-level") on the same page.
270+ * Logs a warning at startup for any violations.
271+ */
272+ export function validateSiteMapScopes ( ) : void {
273+ for ( const [ route , config ] of Object . entries ( SITE_MAP ) ) {
274+ const roles = config . required ;
275+ if ( roles . length < 2 ) continue ;
276+
277+ const hasBankScoped = roles . some ( ( r ) => r . bankScoped ) ;
278+ const hasSystemScoped = roles . some ( ( r ) => ! r . bankScoped ) ;
279+
280+ if ( hasBankScoped && hasSystemScoped ) {
281+ logger . warn (
282+ `SITE_MAP "${ route } " mixes bankScoped and system-wide roles in its required list: ` +
283+ roles . map ( ( r ) => `${ r . role } ${ r . bankScoped ? " (bankScoped)" : "" } ` ) . join ( ", " ) +
284+ `. This will show confusing role widgets. Separate into distinct pages or unify the scope.` ,
285+ ) ;
286+ }
287+ }
288+ }
289+
251290/**
252291 * Look up page roles by route ID (stripping /(protected) prefix if present)
253292 */
0 commit comments