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