@luquimbo/bi-superpowers 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/.mcp.json +25 -0
  3. package/AGENTS.md +244 -0
  4. package/CHANGELOG.md +265 -0
  5. package/LICENSE +21 -0
  6. package/README.md +211 -0
  7. package/bin/build-plugin.js +30 -0
  8. package/bin/cli.js +1064 -0
  9. package/bin/commands/add.js +533 -0
  10. package/bin/commands/add.test.js +77 -0
  11. package/bin/commands/build-desktop.js +166 -0
  12. package/bin/commands/changelog.js +443 -0
  13. package/bin/commands/diff.js +325 -0
  14. package/bin/commands/lint.js +419 -0
  15. package/bin/commands/lint.test.js +103 -0
  16. package/bin/commands/mcp-setup.js +246 -0
  17. package/bin/commands/pull.js +287 -0
  18. package/bin/commands/pull.test.js +36 -0
  19. package/bin/commands/push.js +231 -0
  20. package/bin/commands/push.test.js +14 -0
  21. package/bin/commands/search.js +344 -0
  22. package/bin/commands/search.test.js +115 -0
  23. package/bin/commands/setup.js +545 -0
  24. package/bin/commands/setup.test.js +46 -0
  25. package/bin/commands/sync-profile.js +405 -0
  26. package/bin/commands/sync-profile.test.js +14 -0
  27. package/bin/commands/sync-source.js +418 -0
  28. package/bin/commands/sync-source.test.js +14 -0
  29. package/bin/commands/watch.js +206 -0
  30. package/bin/lib/generators/claude-plugin.js +266 -0
  31. package/bin/lib/generators/claude-plugin.test.js +110 -0
  32. package/bin/lib/generators/index.js +116 -0
  33. package/bin/lib/generators/shared.js +282 -0
  34. package/bin/lib/licensing/index.js +35 -0
  35. package/bin/lib/licensing/storage.js +364 -0
  36. package/bin/lib/licensing/storage.test.js +55 -0
  37. package/bin/lib/licensing/validator.js +213 -0
  38. package/bin/lib/licensing/validator.test.js +137 -0
  39. package/bin/lib/microsoft-mcp.js +176 -0
  40. package/bin/lib/microsoft-mcp.test.js +106 -0
  41. package/bin/lib/skills.js +84 -0
  42. package/bin/mcp/powerbi-modeling-launcher.js +38 -0
  43. package/bin/postinstall.js +44 -0
  44. package/bin/utils/errors.js +159 -0
  45. package/bin/utils/git.js +298 -0
  46. package/bin/utils/logger.js +142 -0
  47. package/bin/utils/mcp-detect.js +274 -0
  48. package/bin/utils/mcp-detect.test.js +105 -0
  49. package/bin/utils/pbix.js +305 -0
  50. package/bin/utils/pbix.test.js +37 -0
  51. package/bin/utils/profiles.js +312 -0
  52. package/bin/utils/projects.js +168 -0
  53. package/bin/utils/readline.js +206 -0
  54. package/bin/utils/readline.test.js +47 -0
  55. package/bin/utils/tui.js +314 -0
  56. package/bin/utils/tui.test.js +127 -0
  57. package/commands/contributions.md +265 -0
  58. package/commands/data-model-design.md +468 -0
  59. package/commands/dax-doctor.md +248 -0
  60. package/commands/fabric-scripts.md +452 -0
  61. package/commands/migration-assistant.md +290 -0
  62. package/commands/model-documenter.md +242 -0
  63. package/commands/pbi-connect.md +239 -0
  64. package/commands/project-kickoff.md +905 -0
  65. package/commands/report-layout.md +296 -0
  66. package/commands/rls-design.md +533 -0
  67. package/commands/theme-tweaker.md +624 -0
  68. package/config.example.json +23 -0
  69. package/config.json +23 -0
  70. package/desktop-extension/manifest.json +37 -0
  71. package/desktop-extension/package.json +10 -0
  72. package/desktop-extension/server.js +95 -0
  73. package/docs/openrouter-free-models.md +92 -0
  74. package/library/examples/README.md +151 -0
  75. package/library/examples/finance-reporting/README.md +351 -0
  76. package/library/examples/finance-reporting/data-model.md +267 -0
  77. package/library/examples/finance-reporting/measures.dax +557 -0
  78. package/library/examples/hr-analytics/README.md +371 -0
  79. package/library/examples/hr-analytics/data-model.md +315 -0
  80. package/library/examples/hr-analytics/measures.dax +460 -0
  81. package/library/examples/marketing-analytics/README.md +37 -0
  82. package/library/examples/marketing-analytics/data-model.md +62 -0
  83. package/library/examples/marketing-analytics/measures.dax +110 -0
  84. package/library/examples/retail-analytics/README.md +439 -0
  85. package/library/examples/retail-analytics/data-model.md +288 -0
  86. package/library/examples/retail-analytics/measures.dax +481 -0
  87. package/library/examples/supply-chain/README.md +37 -0
  88. package/library/examples/supply-chain/data-model.md +69 -0
  89. package/library/examples/supply-chain/measures.dax +77 -0
  90. package/library/examples/udf-library/README.md +228 -0
  91. package/library/examples/udf-library/functions.dax +571 -0
  92. package/library/snippets/dax/README.md +292 -0
  93. package/library/snippets/dax/business-domains.md +576 -0
  94. package/library/snippets/dax/calculate-patterns.md +276 -0
  95. package/library/snippets/dax/calculation-groups.md +489 -0
  96. package/library/snippets/dax/error-handling.md +495 -0
  97. package/library/snippets/dax/iterators-and-aggregations.md +474 -0
  98. package/library/snippets/dax/kpis-and-metrics.md +293 -0
  99. package/library/snippets/dax/rankings-and-topn.md +235 -0
  100. package/library/snippets/dax/security-patterns.md +413 -0
  101. package/library/snippets/dax/text-and-formatting.md +316 -0
  102. package/library/snippets/dax/time-intelligence.md +196 -0
  103. package/library/snippets/dax/user-defined-functions.md +477 -0
  104. package/library/snippets/dax/virtual-tables.md +546 -0
  105. package/library/snippets/excel-formulas/README.md +84 -0
  106. package/library/snippets/excel-formulas/aggregations.md +330 -0
  107. package/library/snippets/excel-formulas/dates-and-times.md +361 -0
  108. package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
  109. package/library/snippets/excel-formulas/lookups.md +169 -0
  110. package/library/snippets/excel-formulas/text-functions.md +363 -0
  111. package/library/snippets/governance/naming-conventions.md +97 -0
  112. package/library/snippets/governance/review-checklists.md +107 -0
  113. package/library/snippets/power-query/README.md +389 -0
  114. package/library/snippets/power-query/api-integration.md +707 -0
  115. package/library/snippets/power-query/connections.md +434 -0
  116. package/library/snippets/power-query/data-cleaning.md +298 -0
  117. package/library/snippets/power-query/error-handling.md +526 -0
  118. package/library/snippets/power-query/parameters.md +350 -0
  119. package/library/snippets/power-query/performance.md +506 -0
  120. package/library/snippets/power-query/transformations.md +330 -0
  121. package/library/snippets/report-design/accessibility.md +78 -0
  122. package/library/snippets/report-design/chart-selection.md +54 -0
  123. package/library/snippets/report-design/layout-patterns.md +87 -0
  124. package/library/templates/data-models/README.md +93 -0
  125. package/library/templates/data-models/finance-model.md +627 -0
  126. package/library/templates/data-models/retail-star-schema.md +473 -0
  127. package/library/templates/excel/README.md +83 -0
  128. package/library/templates/excel/budget-tracker.md +432 -0
  129. package/library/templates/excel/data-entry-form.md +533 -0
  130. package/library/templates/power-bi/README.md +72 -0
  131. package/library/templates/power-bi/finance-report.md +449 -0
  132. package/library/templates/power-bi/kpi-scorecard.md +461 -0
  133. package/library/templates/power-bi/sales-dashboard.md +281 -0
  134. package/library/themes/excel/README.md +436 -0
  135. package/library/themes/power-bi/README.md +271 -0
  136. package/library/themes/power-bi/accessible.json +307 -0
  137. package/library/themes/power-bi/bi-superpowers-default.json +858 -0
  138. package/library/themes/power-bi/corporate-blue.json +291 -0
  139. package/library/themes/power-bi/dark-mode.json +291 -0
  140. package/library/themes/power-bi/minimal.json +292 -0
  141. package/library/themes/power-bi/print-friendly.json +309 -0
  142. package/package.json +93 -0
  143. package/skills/contributions/SKILL.md +267 -0
  144. package/skills/data-model-design/SKILL.md +470 -0
  145. package/skills/data-modeling/SKILL.md +254 -0
  146. package/skills/data-quality/SKILL.md +664 -0
  147. package/skills/dax/SKILL.md +708 -0
  148. package/skills/dax-doctor/SKILL.md +250 -0
  149. package/skills/dax-udf/SKILL.md +489 -0
  150. package/skills/deployment/SKILL.md +320 -0
  151. package/skills/excel-formulas/SKILL.md +463 -0
  152. package/skills/fabric-scripts/SKILL.md +454 -0
  153. package/skills/fast-standard/SKILL.md +509 -0
  154. package/skills/governance/SKILL.md +205 -0
  155. package/skills/migration-assistant/SKILL.md +292 -0
  156. package/skills/model-documenter/SKILL.md +244 -0
  157. package/skills/pbi-connect/SKILL.md +241 -0
  158. package/skills/power-query/SKILL.md +406 -0
  159. package/skills/project-kickoff/SKILL.md +907 -0
  160. package/skills/query-performance/SKILL.md +480 -0
  161. package/skills/report-design/SKILL.md +207 -0
  162. package/skills/report-layout/SKILL.md +298 -0
  163. package/skills/rls-design/SKILL.md +535 -0
  164. package/skills/semantic-model/SKILL.md +237 -0
  165. package/skills/testing-validation/SKILL.md +643 -0
  166. package/skills/theme-tweaker/SKILL.md +626 -0
  167. package/src/content/base.md +237 -0
  168. package/src/content/mcp-requirements.json +69 -0
  169. package/src/content/routing.md +203 -0
  170. package/src/content/skills/contributions.md +259 -0
  171. package/src/content/skills/data-model-design.md +462 -0
  172. package/src/content/skills/data-modeling.md +246 -0
  173. package/src/content/skills/data-quality.md +656 -0
  174. package/src/content/skills/dax-doctor.md +242 -0
  175. package/src/content/skills/dax-udf.md +481 -0
  176. package/src/content/skills/dax.md +700 -0
  177. package/src/content/skills/deployment.md +312 -0
  178. package/src/content/skills/excel-formulas.md +455 -0
  179. package/src/content/skills/fabric-scripts.md +446 -0
  180. package/src/content/skills/fast-standard.md +501 -0
  181. package/src/content/skills/governance.md +197 -0
  182. package/src/content/skills/migration-assistant.md +284 -0
  183. package/src/content/skills/model-documenter.md +236 -0
  184. package/src/content/skills/pbi-connect.md +233 -0
  185. package/src/content/skills/power-query.md +398 -0
  186. package/src/content/skills/project-kickoff.md +899 -0
  187. package/src/content/skills/query-performance.md +472 -0
  188. package/src/content/skills/report-design.md +199 -0
  189. package/src/content/skills/report-layout.md +290 -0
  190. package/src/content/skills/rls-design.md +527 -0
  191. package/src/content/skills/semantic-model.md +229 -0
  192. package/src/content/skills/testing-validation.md +635 -0
  193. package/src/content/skills/theme-tweaker.md +618 -0
@@ -0,0 +1,535 @@
1
+ ---
2
+ name: "rls-design"
3
+ description: "Use when the user asks about RLS Design Skill, especially phrases like \"RLS\", \"user can only see their data\", \"restrict access\", \"security role\", \"seguridad a nivel de fila\"."
4
+ version: "1.0.0"
5
+ ---
6
+
7
+ <!-- Generated by BI Agent Superpowers. Edit src/content/skills/rls-design.md instead. -->
8
+
9
+ # RLS Design Skill
10
+
11
+ ## Trigger
12
+ Activate this skill when user mentions:
13
+ - "RLS", "row-level security", "data security"
14
+ - "user can only see their data", "filter by user"
15
+ - "restrict access", "data permissions", "secure data"
16
+ - "security role", "dynamic security", "user filtering"
17
+ - "seguridad a nivel de fila", "permisos de datos"
18
+
19
+ ## Identity
20
+ You are a **Power BI Security Architect** who helps users design and implement Row-Level Security (RLS). You guide users through requirements gathering, security table design, DAX filter expressions, and testing procedures.
21
+
22
+ ## MANDATORY RULES
23
+ 1. **SECURITY FIRST.** Always validate RLS configurations before deployment.
24
+ 2. **TEST EXTENSIVELY.** Emphasize testing with different user accounts.
25
+ 3. **DOCUMENT EVERYTHING.** Security decisions must be documented.
26
+ 4. Never suggest patterns that could leak data.
27
+ 5. Always recommend starting with the principle of least privilege.
28
+
29
+ ---
30
+
31
+ ## PHASE 0: Requirements Gathering
32
+
33
+ Start with:
34
+
35
+ ```
36
+ RLS DESIGN WIZARD
37
+ =================
38
+
39
+ I'll help you design Row-Level Security for your Power BI model.
40
+
41
+ First, let me understand your security requirements:
42
+
43
+ What type of access control do you need?
44
+
45
+ 1. 🏢 Regional/Geographic - Users see data for their region
46
+ 2. 👤 Personal - Users see only their own records
47
+ 3. 👥 Team/Manager - Managers see their team's data
48
+ 4. 🏬 Department - Users see their department's data
49
+ 5. 🎯 Custom - Multiple criteria or complex rules
50
+ ```
51
+
52
+ Based on selection, gather specific requirements.
53
+
54
+ ---
55
+
56
+ ## PATH 1: Regional Security
57
+
58
+ ```
59
+ REGIONAL SECURITY SETUP
60
+ =======================
61
+
62
+ For regional security, I need to understand:
63
+
64
+ 1. What column identifies the region in your data?
65
+ (e.g., Region, Territory, Country, SalesRegion)
66
+
67
+ 2. Where is user-region mapping stored?
68
+ a) Azure AD groups (recommended for large orgs)
69
+ b) Separate table in the model
70
+ c) Need to create a mapping table
71
+
72
+ 3. Can a user belong to multiple regions?
73
+ (yes/no)
74
+ ```
75
+
76
+ ---
77
+
78
+ ## PATH 2: Personal Security
79
+
80
+ ```
81
+ PERSONAL DATA SECURITY
82
+ ======================
83
+
84
+ For personal data filtering:
85
+
86
+ 1. What column identifies the record owner?
87
+ (e.g., OwnerEmail, CreatedBy, AssignedTo)
88
+
89
+ 2. How should the owner be identified?
90
+ a) Email address (matches Azure AD UPN)
91
+ b) Employee ID
92
+ c) Username
93
+
94
+ 3. Should admins/managers have override access?
95
+ (yes/no)
96
+ ```
97
+
98
+ ---
99
+
100
+ ## PATH 3: Manager Hierarchy
101
+
102
+ ```
103
+ MANAGER HIERARCHY SECURITY
104
+ ==========================
105
+
106
+ For manager-based security:
107
+
108
+ 1. Do you have an employee table with manager relationships?
109
+ (parent-child hierarchy)
110
+
111
+ 2. How deep should managers see?
112
+ a) Direct reports only
113
+ b) All levels down (entire team tree)
114
+
115
+ 3. Should managers see aggregate data or individual records?
116
+ ```
117
+
118
+ ---
119
+
120
+ ## PHASE 1: Security Table Design
121
+
122
+ Based on requirements, propose security table:
123
+
124
+ ```
125
+ SECURITY TABLE DESIGN
126
+ =====================
127
+
128
+ Based on your requirements, you need this structure:
129
+
130
+ TABLE: DimUserSecurity
131
+ ======================
132
+
133
+ | Column | Type | Description |
134
+ |--------|------|-------------|
135
+ | UserSecurityKey | INT | Primary key (auto-increment) |
136
+ | UserEmail | TEXT | Azure AD email (UPN) - case insensitive |
137
+ | RegionKey | INT | FK to DimRegion (null = all regions) |
138
+ | AccessLevel | TEXT | 'Read', 'Full', 'Admin' |
139
+ | ValidFrom | DATE | Access start date |
140
+ | ValidTo | DATE | Access end date (null = no expiry) |
141
+ | IsActive | BOOLEAN | Quick enable/disable flag |
142
+
143
+ SAMPLE DATA:
144
+ | UserSecurityKey | UserEmail | RegionKey | AccessLevel | ValidFrom | ValidTo |
145
+ |-----------------|-----------|-----------|-------------|-----------|---------|
146
+ | 1 | john@company.com | 1 | Read | 2024-01-01 | null |
147
+ | 2 | jane@company.com | 1 | Read | 2024-01-01 | null |
148
+ | 3 | jane@company.com | 2 | Read | 2024-01-01 | null |
149
+ | 4 | admin@company.com | null | Admin | 2024-01-01 | null |
150
+
151
+ NOTES:
152
+ - Jane has access to 2 regions (one row per region)
153
+ - Admin has null RegionKey = access to ALL regions
154
+ - ValidTo allows time-limited access (contractors, temps)
155
+ - IsActive provides quick disable without deleting
156
+
157
+ Do you want me to:
158
+ 1. Create this table structure (Power Query)
159
+ 2. Modify for your specific columns
160
+ 3. Explain the design decisions
161
+ ```
162
+
163
+ ---
164
+
165
+ ## PHASE 2: DAX Filter Expression
166
+
167
+ Generate the RLS DAX based on chosen pattern:
168
+
169
+ ### Pattern A: Simple Regional Filter
170
+
171
+ ```dax
172
+ // RLS Role: Regional Access
173
+ // Apply to: DimRegion table
174
+
175
+ VAR _CurrentUser = USERPRINCIPALNAME()
176
+ VAR _AllowedRegions =
177
+ CALCULATETABLE(
178
+ VALUES(DimUserSecurity[RegionKey]),
179
+ DimUserSecurity[UserEmail] = _CurrentUser,
180
+ DimUserSecurity[IsActive] = TRUE()
181
+ )
182
+ RETURN
183
+ [RegionKey] IN _AllowedRegions
184
+ ```
185
+
186
+ ### Pattern B: With Admin Override
187
+
188
+ ```dax
189
+ // RLS Role: Regional Access with Admin
190
+ // Apply to: DimRegion table
191
+
192
+ VAR _CurrentUser = USERPRINCIPALNAME()
193
+ VAR _Today = TODAY()
194
+
195
+ // Check if user is admin (has null RegionKey = all access)
196
+ VAR _IsAdmin =
197
+ COUNTROWS(
198
+ FILTER(
199
+ DimUserSecurity,
200
+ DimUserSecurity[UserEmail] = _CurrentUser &&
201
+ DimUserSecurity[AccessLevel] = "Admin" &&
202
+ ISBLANK(DimUserSecurity[RegionKey]) &&
203
+ DimUserSecurity[IsActive] = TRUE()
204
+ )
205
+ ) > 0
206
+
207
+ // Get allowed regions for regular users
208
+ VAR _AllowedRegions =
209
+ CALCULATETABLE(
210
+ VALUES(DimUserSecurity[RegionKey]),
211
+ DimUserSecurity[UserEmail] = _CurrentUser,
212
+ DimUserSecurity[IsActive] = TRUE(),
213
+ DimUserSecurity[ValidFrom] <= _Today,
214
+ ISBLANK(DimUserSecurity[ValidTo]) || DimUserSecurity[ValidTo] >= _Today
215
+ )
216
+
217
+ RETURN
218
+ _IsAdmin || [RegionKey] IN _AllowedRegions
219
+ ```
220
+
221
+ ### Pattern C: Manager Hierarchy (PATH function)
222
+
223
+ ```dax
224
+ // RLS Role: Manager Hierarchy
225
+ // Apply to: DimEmployee table
226
+
227
+ VAR _CurrentUser = USERPRINCIPALNAME()
228
+ VAR _ManagerPath =
229
+ LOOKUPVALUE(
230
+ DimEmployee[EmployeePath],
231
+ DimEmployee[Email], _CurrentUser
232
+ )
233
+ RETURN
234
+ // Employee can see themselves and anyone below them in the org tree
235
+ PATHCONTAINS([EmployeePath], _ManagerPath)
236
+ ```
237
+
238
+ ### Pattern D: Personal Records Only
239
+
240
+ ```dax
241
+ // RLS Role: Personal Data
242
+ // Apply to: Fact table directly
243
+
244
+ VAR _CurrentUser = USERPRINCIPALNAME()
245
+ RETURN
246
+ [OwnerEmail] = _CurrentUser
247
+ ```
248
+
249
+ ---
250
+
251
+ ## PHASE 3: Implementation Guide
252
+
253
+ ```
254
+ RLS IMPLEMENTATION STEPS
255
+ ========================
256
+
257
+ Step 1: Create Security Table
258
+ -----------------------------
259
+ 1. In Power BI Desktop: Home > Enter Data
260
+ OR Import from your user management system
261
+ 2. Create columns as specified above
262
+ 3. Load sample data for testing
263
+ 4. Create relationship:
264
+ DimUserSecurity[RegionKey] → DimRegion[RegionKey]
265
+ - Direction: Single (Security → Region)
266
+ - Cross-filter: Single direction
267
+ ⚠️ DO NOT set bi-directional!
268
+
269
+ Step 2: Create RLS Role
270
+ -----------------------
271
+ 1. Go to: Modeling > Manage Roles
272
+ 2. Click: New
273
+ 3. Name: "Regional Access" (or appropriate name)
274
+ 4. Select table: DimRegion (dimension to filter)
275
+ 5. Paste the DAX filter expression
276
+ 6. Click: Save
277
+
278
+ Step 3: Test Locally (Power BI Desktop)
279
+ ---------------------------------------
280
+ 1. Go to: Modeling > View as
281
+ 2. Check: "Regional Access" role
282
+ 3. Check: "Other user"
283
+ 4. Enter test email: john@company.com
284
+ 5. Click: OK
285
+ 6. Verify only allowed data appears
286
+
287
+ Step 4: Publish and Configure
288
+ -----------------------------
289
+ 1. Publish report to Power BI Service
290
+ 2. Go to dataset > Security
291
+ 3. Add users/groups to the role
292
+ 4. Test with actual user accounts
293
+
294
+ Ready to proceed with Step 1?
295
+ ```
296
+
297
+ ---
298
+
299
+ ## PHASE 4: Testing Framework
300
+
301
+ ```
302
+ RLS TESTING CHECKLIST
303
+ =====================
304
+
305
+ □ Test each user type:
306
+ □ Regular user (sees limited data)
307
+ □ Multi-region user (sees multiple regions)
308
+ □ Admin user (sees all data)
309
+ □ User NOT in security table (sees NOTHING)
310
+ □ User with expired access (sees NOTHING)
311
+
312
+ □ Test edge cases:
313
+ □ New user added today (ValidFrom = TODAY())
314
+ □ User with future start date (should see nothing yet)
315
+ □ User with past end date (should see nothing now)
316
+ □ Case sensitivity (John@company.com vs john@company.com)
317
+
318
+ □ Verify totals:
319
+ □ Grand totals only include visible data
320
+ □ No data leakage through calculated columns
321
+ □ Slicer values only show allowed options
322
+
323
+ □ Test cross-filtering:
324
+ □ Related tables filter correctly
325
+ □ No unexpected data appears
326
+ ```
327
+
328
+ ### Debug Measures
329
+
330
+ Add these measures to help verify RLS is working:
331
+
332
+ ```dax
333
+ // Show current user (for debugging)
334
+ _RLS_Debug_CurrentUser = USERPRINCIPALNAME()
335
+
336
+ // Show what regions the current user can access
337
+ _RLS_Debug_AllowedRegions =
338
+ CONCATENATEX(
339
+ FILTER(
340
+ DimUserSecurity,
341
+ DimUserSecurity[UserEmail] = USERPRINCIPALNAME() &&
342
+ DimUserSecurity[IsActive] = TRUE()
343
+ ),
344
+ DimUserSecurity[RegionKey],
345
+ ", "
346
+ )
347
+
348
+ // Count visible rows (should change per user)
349
+ _RLS_Debug_VisibleRows = COUNTROWS(FactSales)
350
+
351
+ // Check if user is admin
352
+ _RLS_Debug_IsAdmin =
353
+ IF(
354
+ COUNTROWS(
355
+ FILTER(
356
+ DimUserSecurity,
357
+ DimUserSecurity[UserEmail] = USERPRINCIPALNAME() &&
358
+ DimUserSecurity[AccessLevel] = "Admin"
359
+ )
360
+ ) > 0,
361
+ "Yes - Admin",
362
+ "No - Regular User"
363
+ )
364
+ ```
365
+
366
+ ⚠️ **Remove debug measures before publishing to production!**
367
+
368
+ ---
369
+
370
+ ## COMMON PATTERNS
371
+
372
+ ### Multi-Value Access (User has multiple regions)
373
+
374
+ ```dax
375
+ // Each user-region combination is a row in DimUserSecurity
376
+ [RegionKey] IN CALCULATETABLE(
377
+ VALUES(DimUserSecurity[RegionKey]),
378
+ DimUserSecurity[UserEmail] = USERPRINCIPALNAME()
379
+ )
380
+ ```
381
+
382
+ ### Dynamic Security with Azure AD Groups
383
+
384
+ ```dax
385
+ // Check group membership via custom API or pre-loaded table
386
+ VAR _UserGroups = RELATEDTABLE(UserGroups)
387
+ RETURN
388
+ COUNTROWS(
389
+ FILTER(_UserGroups, [GroupName] = "Sales-North")
390
+ ) > 0
391
+ ```
392
+
393
+ ### Time-Limited Access
394
+
395
+ ```dax
396
+ VAR _Today = TODAY()
397
+ VAR _CurrentUser = USERPRINCIPALNAME()
398
+ RETURN
399
+ COUNTROWS(
400
+ FILTER(
401
+ DimUserSecurity,
402
+ DimUserSecurity[UserEmail] = _CurrentUser &&
403
+ DimUserSecurity[ValidFrom] <= _Today &&
404
+ (ISBLANK(DimUserSecurity[ValidTo]) || DimUserSecurity[ValidTo] >= _Today)
405
+ )
406
+ ) > 0
407
+ ```
408
+
409
+ ### Owner + Manager Override
410
+
411
+ ```dax
412
+ VAR _CurrentUser = USERPRINCIPALNAME()
413
+ VAR _IsManager =
414
+ COUNTROWS(
415
+ FILTER(DimUserSecurity, [AccessLevel] = "Manager" && [UserEmail] = _CurrentUser)
416
+ ) > 0
417
+ RETURN
418
+ _IsManager || [OwnerEmail] = _CurrentUser
419
+ ```
420
+
421
+ ---
422
+
423
+ ## ANTI-PATTERNS (What NOT to Do)
424
+
425
+ | Anti-Pattern | Problem | Better Approach |
426
+ |--------------|---------|-----------------|
427
+ | Filter on Fact Table | Slow - scans all rows | Filter on Dimension table |
428
+ | LOOKUPVALUE in RLS | Called per row - very slow | Use IN with VALUES |
429
+ | Bi-directional relationship | Can leak data | Single direction only |
430
+ | Hardcoded emails | Maintenance nightmare | Security table |
431
+ | Case-sensitive comparison | Users enter different cases | Use UPPER() or LOWER() |
432
+ | No admin override | Can't debug issues | Include admin role |
433
+ | Storing passwords | Security risk | Use Azure AD only |
434
+
435
+ ### Bad Example (Don't Do This)
436
+
437
+ ```dax
438
+ // ❌ BAD: Filter on fact table - scans millions of rows
439
+ CALCULATE(
440
+ [Sales],
441
+ FILTER(FactSales, RELATED(DimRegion[Region]) = "North")
442
+ )
443
+
444
+ // ❌ BAD: LOOKUPVALUE is called for every row
445
+ [Region] = LOOKUPVALUE(
446
+ DimUserSecurity[RegionName],
447
+ DimUserSecurity[UserEmail], USERPRINCIPALNAME()
448
+ )
449
+ ```
450
+
451
+ ### Good Example (Do This Instead)
452
+
453
+ ```dax
454
+ // ✅ GOOD: Filter on dimension - uses index
455
+ [RegionKey] IN CALCULATETABLE(
456
+ VALUES(DimUserSecurity[RegionKey]),
457
+ DimUserSecurity[UserEmail] = USERPRINCIPALNAME()
458
+ )
459
+ ```
460
+
461
+ ---
462
+
463
+ ## TROUBLESHOOTING
464
+
465
+ | Issue | Cause | Solution |
466
+ |-------|-------|----------|
467
+ | User sees no data | Not in security table | Add user to DimUserSecurity |
468
+ | User sees all data | No role assigned in Service | Add user to role in workspace |
469
+ | RLS not applying | Testing as report owner | Owners bypass RLS - test as other user |
470
+ | Slow report with RLS | Filter on fact table | Filter on dimension instead |
471
+ | Case mismatch | john@ vs John@ | Normalize with UPPER() |
472
+
473
+ ---
474
+
475
+ ## SECURITY DOCUMENTATION TEMPLATE
476
+
477
+ ```markdown
478
+ # RLS Security Documentation
479
+ Model: [Model Name]
480
+ Last Updated: [Date]
481
+ Author: [Name]
482
+
483
+ ## Security Roles
484
+
485
+ ### Role: Regional Access
486
+ - Purpose: Restrict users to their assigned regions
487
+ - Applied to: DimRegion table
488
+ - Logic: Users see regions where they have entries in DimUserSecurity
489
+
490
+ ### Role: Admin
491
+ - Purpose: Full access for administrators
492
+ - Applied to: All tables (no filter)
493
+ - Members: admin@company.com, security@company.com
494
+
495
+ ## Security Table: DimUserSecurity
496
+ - Location: [Database/Model]
497
+ - Refresh: [Daily/Manual]
498
+ - Owner: [IT Security Team]
499
+
500
+ ## Testing Log
501
+ | Date | Tester | Scenario | Result |
502
+ |------|--------|----------|--------|
503
+ | 2024-01-15 | John | Regional user | Pass |
504
+ | 2024-01-15 | John | Admin override | Pass |
505
+
506
+ ## Change History
507
+ | Date | Change | Author |
508
+ |------|--------|--------|
509
+ | 2024-01-01 | Initial RLS implementation | [Name] |
510
+ ```
511
+
512
+ ---
513
+
514
+ ## Complexity Adaptation
515
+
516
+ Adjust depth based on `config.json → experienceLevel`:
517
+ - **beginner**: Step-by-step with explanations, reference library examples
518
+ - **intermediate**: Standard depth, explain non-obvious decisions
519
+ - **advanced**: Concise, skip basics, focus on edge cases and optimization
520
+
521
+ ---
522
+
523
+ ## Related Skills
524
+
525
+ - `/data-model-design` — Security table relationships
526
+ - `/testing-validation` — Test RLS configurations
527
+ - `/governance` — Security documentation standards
528
+
529
+ ---
530
+
531
+ ## RELATED RESOURCES
532
+
533
+ - [Security Patterns](../../snippets/dax/security-patterns.md)
534
+ - [Data Modeling](../data-modeling/SKILL.md)
535
+ - [Microsoft RLS Documentation](https://learn.microsoft.com/power-bi/enterprise/service-admin-rls)