@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,371 @@
1
+ # HR Analytics - Complete Example
2
+
3
+ A comprehensive HR analytics solution for workforce planning, turnover analysis, and employee metrics.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ This example demonstrates building a complete HR analytics solution using:
10
+
11
+ - **Employee-centric data model** with demographics, positions, and history
12
+ - **DAX measures** for headcount, turnover, tenure, and diversity metrics
13
+ - **Time-based analysis** for trend tracking and forecasting
14
+ - **Organizational hierarchy** support for drill-down reporting
15
+
16
+ ---
17
+
18
+ ## Business Requirements
19
+
20
+ ### Stakeholders
21
+ - CHRO: Workforce strategy and executive metrics
22
+ - HR Business Partners: Department-level insights
23
+ - Talent Acquisition: Hiring pipeline and time-to-fill
24
+ - Compensation Team: Pay equity and benchmarking
25
+ - People Analytics: Deep-dive analysis
26
+
27
+ ### Key Questions
28
+ 1. What is our current headcount and how is it trending?
29
+ 2. What's our turnover rate and what's driving attrition?
30
+ 3. How diverse is our workforce across levels?
31
+ 4. What's our average tenure and where are the risks?
32
+ 5. How effective is our recruiting pipeline?
33
+
34
+ ---
35
+
36
+ ## Data Model
37
+
38
+ ### Star Schema Design
39
+
40
+ ```
41
+ ┌─────────────────┐
42
+ │ DimDate │
43
+ │─────────────────│
44
+ │ DateKey (PK) │
45
+ │ Date │
46
+ │ Year │
47
+ │ Month │
48
+ │ Quarter │
49
+ └────────┬────────┘
50
+
51
+ ┌─────────────────┐ │ ┌─────────────────┐
52
+ │ DimEmployee │ │ │ DimDepartment │
53
+ │─────────────────│ │ │─────────────────│
54
+ │ EmployeeKey(PK) │ │ │ DepartmentKey │
55
+ │ EmployeeID │ │ │ DepartmentName │
56
+ │ FirstName │ │ │ Division │
57
+ │ LastName │ │ │ CostCenter │
58
+ │ Gender │ │ │ Manager │
59
+ │ Ethnicity │ │ └────────┬────────┘
60
+ │ BirthDate │ │ │
61
+ │ HireDate │ │ │
62
+ │ TermDate │ ┌────┴─────────────────┐ │
63
+ │ IsActive │ │ FactEmployeeSnap │ │
64
+ └────────┬────────┘ │──────────────────────│ │
65
+ │ │ SnapshotKey (PK) │ │
66
+ └─────────────>│ DateKey (FK) │<┘
67
+ │ EmployeeKey (FK) │
68
+ │ DepartmentKey (FK) │
69
+ │ JobKey (FK) │
70
+ │ LocationKey (FK) │
71
+ │ Salary │
72
+ │ Bonus │
73
+ │ PerformanceRating │
74
+ │ EngagementScore │
75
+ └──────────┬───────────┘
76
+
77
+ ┌──────────────┴──────────────┐
78
+ │ │
79
+ ┌────────┴────────┐ ┌───────┴────────┐
80
+ │ DimJob │ │ DimLocation │
81
+ │─────────────────│ │────────────────│
82
+ │ JobKey (PK) │ │ LocationKey │
83
+ │ JobTitle │ │ LocationName │
84
+ │ JobFamily │ │ City │
85
+ │ JobLevel │ │ State │
86
+ │ IsManagement │ │ Country │
87
+ │ PayGrade │ │ Region │
88
+ └─────────────────┘ └────────────────┘
89
+ ```
90
+
91
+ ### Key Design Decisions
92
+
93
+ 1. **Snapshot Fact Table** - Monthly snapshots capture point-in-time state
94
+ 2. **Employee Dimension** - Contains hire/term dates for tenure calculations
95
+ 3. **Slowly Changing Dimensions** - Track job and department changes over time
96
+ 4. **Separate Job Dimension** - Enables job family and level analysis
97
+
98
+ ---
99
+
100
+ ## Key Measures
101
+
102
+ ### Headcount Metrics
103
+
104
+ ```dax
105
+ // Current active headcount
106
+ Headcount =
107
+ CALCULATE(
108
+ DISTINCTCOUNT(FactEmployeeSnap[EmployeeKey]),
109
+ DimEmployee[IsActive] = TRUE()
110
+ )
111
+
112
+ // Headcount at end of period
113
+ Headcount EOP =
114
+ CALCULATE(
115
+ [Headcount],
116
+ LASTDATE(DimDate[Date])
117
+ )
118
+
119
+ // Average headcount for period
120
+ Headcount Avg =
121
+ AVERAGEX(
122
+ VALUES(DimDate[Date]),
123
+ [Headcount EOP]
124
+ )
125
+
126
+ // Full-Time Equivalent (if tracking FTE)
127
+ FTE =
128
+ CALCULATE(
129
+ SUM(FactEmployeeSnap[FTEFactor]),
130
+ DimEmployee[IsActive] = TRUE()
131
+ )
132
+ ```
133
+
134
+ ### Turnover Metrics
135
+
136
+ ```dax
137
+ // Terminations in period
138
+ Terminations =
139
+ CALCULATE(
140
+ COUNTROWS(DimEmployee),
141
+ DimEmployee[TermDate] <> BLANK(),
142
+ DimEmployee[TermDate] >= MIN(DimDate[Date]),
143
+ DimEmployee[TermDate] <= MAX(DimDate[Date])
144
+ )
145
+
146
+ // Voluntary terminations
147
+ Voluntary Terms =
148
+ CALCULATE(
149
+ [Terminations],
150
+ DimEmployee[TermType] = "Voluntary"
151
+ )
152
+
153
+ // Turnover Rate (annualized)
154
+ Turnover Rate =
155
+ VAR _Terms = [Terminations]
156
+ VAR _AvgHC = [Headcount Avg]
157
+ VAR _Months = DISTINCTCOUNT(DimDate[YearMonth])
158
+ RETURN
159
+ DIVIDE(_Terms, _AvgHC) * (12 / _Months)
160
+
161
+ // Voluntary Turnover Rate
162
+ Voluntary Turnover Rate =
163
+ VAR _VolTerms = [Voluntary Terms]
164
+ VAR _AvgHC = [Headcount Avg]
165
+ VAR _Months = DISTINCTCOUNT(DimDate[YearMonth])
166
+ RETURN
167
+ DIVIDE(_VolTerms, _AvgHC) * (12 / _Months)
168
+
169
+ // Retention Rate
170
+ Retention Rate =
171
+ 1 - [Turnover Rate]
172
+ ```
173
+
174
+ ### Hiring Metrics
175
+
176
+ ```dax
177
+ // New hires in period
178
+ New Hires =
179
+ CALCULATE(
180
+ COUNTROWS(DimEmployee),
181
+ DimEmployee[HireDate] >= MIN(DimDate[Date]),
182
+ DimEmployee[HireDate] <= MAX(DimDate[Date])
183
+ )
184
+
185
+ // Net change in headcount
186
+ Net Headcount Change =
187
+ [New Hires] - [Terminations]
188
+
189
+ // Hiring Rate
190
+ Hiring Rate =
191
+ DIVIDE([New Hires], [Headcount Avg])
192
+
193
+ // 90-Day Turnover (early attrition)
194
+ 90 Day Turnover =
195
+ CALCULATE(
196
+ COUNTROWS(DimEmployee),
197
+ DimEmployee[TermDate] <> BLANK(),
198
+ DimEmployee[TermDate] >= MIN(DimDate[Date]),
199
+ DimEmployee[TermDate] <= MAX(DimDate[Date]),
200
+ DATEDIFF(DimEmployee[HireDate], DimEmployee[TermDate], DAY) <= 90
201
+ )
202
+ ```
203
+
204
+ ### Tenure Metrics
205
+
206
+ ```dax
207
+ // Average tenure (years)
208
+ Avg Tenure =
209
+ AVERAGEX(
210
+ FILTER(
211
+ DimEmployee,
212
+ DimEmployee[IsActive] = TRUE()
213
+ ),
214
+ DATEDIFF(DimEmployee[HireDate], TODAY(), YEAR)
215
+ )
216
+
217
+ // Tenure distribution
218
+ Tenure Bucket =
219
+ SWITCH(
220
+ TRUE(),
221
+ [Tenure Years] < 1, "< 1 Year",
222
+ [Tenure Years] < 2, "1-2 Years",
223
+ [Tenure Years] < 5, "2-5 Years",
224
+ [Tenure Years] < 10, "5-10 Years",
225
+ ">= 10 Years"
226
+ )
227
+
228
+ // Flight risk (high performers with long tenure)
229
+ Flight Risk Count =
230
+ CALCULATE(
231
+ [Headcount],
232
+ FactEmployeeSnap[PerformanceRating] >= 4,
233
+ DimEmployee[TenureYears] >= 5,
234
+ FactEmployeeSnap[EngagementScore] < 3.5
235
+ )
236
+ ```
237
+
238
+ ### Diversity Metrics
239
+
240
+ ```dax
241
+ // Gender diversity
242
+ Female % =
243
+ DIVIDE(
244
+ CALCULATE([Headcount], DimEmployee[Gender] = "Female"),
245
+ [Headcount]
246
+ )
247
+
248
+ // Gender diversity in management
249
+ Female Managers % =
250
+ DIVIDE(
251
+ CALCULATE([Headcount], DimEmployee[Gender] = "Female", DimJob[IsManagement] = TRUE()),
252
+ CALCULATE([Headcount], DimJob[IsManagement] = TRUE())
253
+ )
254
+
255
+ // Diversity index (simplified)
256
+ Diversity Index =
257
+ VAR _Total = [Headcount]
258
+ VAR _Groups =
259
+ ADDCOLUMNS(
260
+ VALUES(DimEmployee[Ethnicity]),
261
+ "@Count", [Headcount]
262
+ )
263
+ VAR _SumSquares =
264
+ SUMX(_Groups, POWER(DIVIDE([@Count], _Total), 2))
265
+ RETURN
266
+ 1 - _SumSquares // Higher = more diverse
267
+ ```
268
+
269
+ See [measures.dax](./measures.dax) for the complete measure library (40+ measures).
270
+
271
+ ---
272
+
273
+ ## Report Pages
274
+
275
+ ### 1. Executive Dashboard
276
+
277
+ | Visual | Content |
278
+ |--------|---------|
279
+ | KPI Cards | Headcount, Turnover Rate, Avg Tenure, Diversity % |
280
+ | Line Chart | Headcount trend over 12 months |
281
+ | Stacked Bar | Hires vs Terms by month |
282
+ | Donut | Headcount by Division |
283
+
284
+ ### 2. Turnover Analysis
285
+
286
+ | Visual | Content |
287
+ |--------|---------|
288
+ | KPI Cards | Turnover Rate, Voluntary %, Regrettable % |
289
+ | Waterfall | Headcount changes breakdown |
290
+ | Bar Chart | Turnover by Department |
291
+ | Table | Top term reasons with counts |
292
+ | Heat Map | Turnover by Tenure × Job Level |
293
+
294
+ ### 3. Workforce Composition
295
+
296
+ | Visual | Content |
297
+ |--------|---------|
298
+ | Tree Map | Headcount by Division > Department |
299
+ | Bar Chart | Headcount by Job Level |
300
+ | Stacked Bar | Demographics breakdown |
301
+ | Map | Headcount by Location |
302
+
303
+ ### 4. Tenure & Risk
304
+
305
+ | Visual | Content |
306
+ |--------|---------|
307
+ | Histogram | Tenure distribution |
308
+ | Scatter | Tenure vs Performance |
309
+ | Table | Flight risk employees |
310
+ | Line Chart | Avg tenure trend |
311
+
312
+ ### 5. Compensation Analysis
313
+
314
+ | Visual | Content |
315
+ |--------|---------|
316
+ | Box Plot | Salary distribution by level |
317
+ | Scatter | Salary vs Performance |
318
+ | Table | Compa-ratio by job family |
319
+ | Bar | Pay equity by gender |
320
+
321
+ ---
322
+
323
+ ## Implementation Checklist
324
+
325
+ ### Data Model
326
+ - [ ] Create DimDate with calendar attributes
327
+ - [ ] Create DimEmployee with demographics and dates
328
+ - [ ] Create DimDepartment with hierarchy
329
+ - [ ] Create DimJob with job family/level
330
+ - [ ] Create DimLocation with geography
331
+ - [ ] Load FactEmployeeSnap (monthly snapshots)
332
+ - [ ] Set up relationships
333
+ - [ ] Mark DimDate as Date Table
334
+
335
+ ### Measures
336
+ - [ ] Create headcount measures
337
+ - [ ] Create turnover/retention measures
338
+ - [ ] Create hiring measures
339
+ - [ ] Create tenure measures
340
+ - [ ] Create diversity measures
341
+ - [ ] Create compensation measures
342
+ - [ ] Organize in display folders
343
+
344
+ ### Reports
345
+ - [ ] Executive Dashboard
346
+ - [ ] Turnover Analysis with drill-through
347
+ - [ ] Workforce Composition
348
+ - [ ] Tenure & Risk Analysis
349
+ - [ ] Compensation Analysis
350
+ - [ ] Apply theme and RLS
351
+
352
+ ---
353
+
354
+ ## Files in This Example
355
+
356
+ | File | Description |
357
+ |------|-------------|
358
+ | [README.md](./README.md) | This overview |
359
+ | [data-model.md](./data-model.md) | Complete table definitions |
360
+ | [measures.dax](./measures.dax) | 40+ DAX measures |
361
+
362
+ ---
363
+
364
+ ## HR Analytics Best Practices
365
+
366
+ 1. **Use snapshots** - Point-in-time data is critical for trend analysis
367
+ 2. **Annualize rates** - Turnover should always be annualized for comparison
368
+ 3. **Segment analysis** - Always allow drill-down by org hierarchy
369
+ 4. **Protect PII** - Use RLS and hide sensitive columns
370
+ 5. **Define "turnover"** - Distinguish voluntary, involuntary, regrettable
371
+ 6. **Benchmark** - Industry benchmarks add context to your metrics
@@ -0,0 +1,315 @@
1
+ # HR Analytics - Data Model
2
+
3
+ Complete table definitions for the HR analytics star schema.
4
+
5
+ ---
6
+
7
+ ## Fact Table
8
+
9
+ ### FactEmployeeSnap
10
+
11
+ Monthly snapshot of employee state - one row per employee per month.
12
+
13
+ | Column | Data Type | Description |
14
+ |--------|-----------|-------------|
15
+ | SnapshotKey | Integer | Surrogate primary key |
16
+ | DateKey | Text | FK to DimDate (YYYYMM01 - first of month) |
17
+ | EmployeeKey | Integer | FK to DimEmployee |
18
+ | DepartmentKey | Integer | FK to DimDepartment |
19
+ | JobKey | Integer | FK to DimJob |
20
+ | LocationKey | Integer | FK to DimLocation |
21
+ | ManagerKey | Integer | FK to DimEmployee (manager) |
22
+ | Salary | Currency | Annual base salary |
23
+ | Bonus | Currency | Annual bonus target |
24
+ | FTEFactor | Decimal | Full-time equivalent (1.0 = full-time) |
25
+ | PerformanceRating | Integer | Last performance rating (1-5) |
26
+ | EngagementScore | Decimal | Last engagement survey score (1-5) |
27
+ | CompaRatio | Decimal | Salary / midpoint of pay range |
28
+
29
+ **Grain:** One row per Employee per Month (end of month snapshot).
30
+
31
+ **Relationships:**
32
+ - FactEmployeeSnap[DateKey] → DimDate[DateKey] (Many:1)
33
+ - FactEmployeeSnap[EmployeeKey] → DimEmployee[EmployeeKey] (Many:1)
34
+ - FactEmployeeSnap[DepartmentKey] → DimDepartment[DepartmentKey] (Many:1)
35
+ - FactEmployeeSnap[JobKey] → DimJob[JobKey] (Many:1)
36
+ - FactEmployeeSnap[LocationKey] → DimLocation[LocationKey] (Many:1)
37
+ - FactEmployeeSnap[ManagerKey] → DimEmployee[EmployeeKey] (Many:1, inactive)
38
+
39
+ ---
40
+
41
+ ## Dimension Tables
42
+
43
+ ### DimEmployee
44
+
45
+ | Column | Data Type | Description | Example |
46
+ |--------|-----------|-------------|---------|
47
+ | EmployeeKey | Integer | Surrogate PK | 10001 |
48
+ | EmployeeID | Text | Business key (badge #) | "E-12345" |
49
+ | FirstName | Text | First name | "John" |
50
+ | LastName | Text | Last name | "Smith" |
51
+ | FullName | Text | Display name | "Smith, John" |
52
+ | Email | Text | Work email | "jsmith@company.com" |
53
+ | Gender | Text | Gender identity | "Male" |
54
+ | Ethnicity | Text | Self-identified ethnicity | "Asian" |
55
+ | BirthDate | Date | Date of birth | 1985-06-15 |
56
+ | HireDate | Date | Original hire date | 2018-03-01 |
57
+ | TermDate | Date | Termination date (null if active) | NULL |
58
+ | TermType | Text | Termination type | "Voluntary" |
59
+ | TermReason | Text | Termination reason | "Career Opportunity" |
60
+ | IsActive | Boolean | Currently employed | TRUE |
61
+ | AgeYears | Integer | Current age (calculated) | 39 |
62
+ | TenureYears | Decimal | Years of service (calculated) | 6.8 |
63
+ | TenureBucket | Text | Tenure range | "5-10 Years" |
64
+ | Generation | Text | Generational cohort | "Millennial" |
65
+
66
+ **Termination Types:**
67
+ - Voluntary: Resignation, retirement
68
+ - Involuntary: Performance, restructuring, misconduct
69
+ - Other: Death, disability
70
+
71
+ **Calculated Columns:**
72
+
73
+ ```dax
74
+ // Age
75
+ AgeYears =
76
+ DATEDIFF(DimEmployee[BirthDate], TODAY(), YEAR)
77
+
78
+ // Tenure
79
+ TenureYears =
80
+ VAR _EndDate = IF(ISBLANK(DimEmployee[TermDate]), TODAY(), DimEmployee[TermDate])
81
+ RETURN
82
+ DATEDIFF(DimEmployee[HireDate], _EndDate, DAY) / 365.25
83
+
84
+ // Tenure Bucket
85
+ TenureBucket =
86
+ SWITCH(
87
+ TRUE(),
88
+ DimEmployee[TenureYears] < 1, "< 1 Year",
89
+ DimEmployee[TenureYears] < 2, "1-2 Years",
90
+ DimEmployee[TenureYears] < 5, "2-5 Years",
91
+ DimEmployee[TenureYears] < 10, "5-10 Years",
92
+ ">= 10 Years"
93
+ )
94
+
95
+ // Generation
96
+ Generation =
97
+ VAR _BirthYear = YEAR(DimEmployee[BirthDate])
98
+ RETURN
99
+ SWITCH(
100
+ TRUE(),
101
+ _BirthYear >= 1997, "Gen Z",
102
+ _BirthYear >= 1981, "Millennial",
103
+ _BirthYear >= 1965, "Gen X",
104
+ _BirthYear >= 1946, "Boomer",
105
+ "Silent"
106
+ )
107
+ ```
108
+
109
+ ---
110
+
111
+ ### DimDepartment
112
+
113
+ | Column | Data Type | Description | Example |
114
+ |--------|-----------|-------------|---------|
115
+ | DepartmentKey | Integer | Surrogate PK | 201 |
116
+ | DepartmentCode | Text | Business key | "DEPT-ENG-001" |
117
+ | DepartmentName | Text | Department name | "Software Engineering" |
118
+ | Division | Text | Division | "Technology" |
119
+ | BusinessUnit | Text | Business unit | "Product Development" |
120
+ | CostCenter | Text | Cost center code | "CC-4500" |
121
+ | DepartmentHead | Text | Department leader | "Jane Doe" |
122
+ | ParentDepartmentKey | Integer | For hierarchy | 200 |
123
+ | Level | Integer | Hierarchy level | 3 |
124
+ | IsActive | Boolean | Currently active | TRUE |
125
+
126
+ **Hierarchies:**
127
+ - Division > BusinessUnit > DepartmentName
128
+
129
+ ---
130
+
131
+ ### DimJob
132
+
133
+ | Column | Data Type | Description | Example |
134
+ |--------|-----------|-------------|---------|
135
+ | JobKey | Integer | Surrogate PK | 301 |
136
+ | JobCode | Text | Job code | "JOB-SWE-003" |
137
+ | JobTitle | Text | Job title | "Senior Software Engineer" |
138
+ | JobFamily | Text | Job family | "Engineering" |
139
+ | JobSubFamily | Text | Sub-family | "Software Development" |
140
+ | JobLevel | Integer | Level (1-10) | 6 |
141
+ | JobLevelName | Text | Level name | "Senior Individual Contributor" |
142
+ | IsManagement | Boolean | People manager | FALSE |
143
+ | IsExempt | Boolean | FLSA exempt | TRUE |
144
+ | PayGrade | Text | Pay grade | "G6" |
145
+ | PayRangeMin | Currency | Grade minimum | 120000 |
146
+ | PayRangeMid | Currency | Grade midpoint | 150000 |
147
+ | PayRangeMax | Currency | Grade maximum | 180000 |
148
+
149
+ **Job Levels:**
150
+
151
+ | Level | LevelName | IsManagement |
152
+ |-------|-----------|--------------|
153
+ | 1-3 | Entry Level | FALSE |
154
+ | 4-5 | Mid Level | FALSE |
155
+ | 6-7 | Senior Individual Contributor | FALSE |
156
+ | 5 | Team Lead | TRUE |
157
+ | 6 | Manager | TRUE |
158
+ | 7 | Senior Manager | TRUE |
159
+ | 8 | Director | TRUE |
160
+ | 9 | VP | TRUE |
161
+ | 10 | C-Suite | TRUE |
162
+
163
+ ---
164
+
165
+ ### DimLocation
166
+
167
+ | Column | Data Type | Description | Example |
168
+ |--------|-----------|-------------|---------|
169
+ | LocationKey | Integer | Surrogate PK | 101 |
170
+ | LocationCode | Text | Location code | "LOC-SF-001" |
171
+ | LocationName | Text | Location name | "San Francisco HQ" |
172
+ | Address | Text | Street address | "100 Main Street" |
173
+ | City | Text | City | "San Francisco" |
174
+ | State | Text | State/Province | "CA" |
175
+ | Country | Text | Country | "USA" |
176
+ | Region | Text | Geographic region | "North America" |
177
+ | Latitude | Decimal | Latitude | 37.7749 |
178
+ | Longitude | Decimal | Longitude | -122.4194 |
179
+ | IsRemote | Boolean | Remote/virtual location | FALSE |
180
+ | Timezone | Text | Timezone | "America/Los_Angeles" |
181
+
182
+ ---
183
+
184
+ ### DimDate
185
+
186
+ | Column | Data Type | Description | Example |
187
+ |--------|-----------|-------------|---------|
188
+ | DateKey | Text | Primary key (YYYYMMDD) | "20240131" |
189
+ | Date | Date | Full date | 2024-01-31 |
190
+ | Year | Integer | Calendar year | 2024 |
191
+ | Quarter | Text | Quarter | "Q1" |
192
+ | Month | Integer | Month number | 1 |
193
+ | MonthName | Text | Month name | "January" |
194
+ | MonthYear | Text | Month-Year label | "Jan 2024" |
195
+ | YearMonth | Text | Year-Month (sortable) | "2024-01" |
196
+ | WeekOfYear | Integer | Week number | 5 |
197
+ | DayOfWeek | Integer | Day of week (1=Mon) | 3 |
198
+ | IsWeekend | Boolean | Weekend flag | FALSE |
199
+ | IsMonthEnd | Boolean | Last day of month | TRUE |
200
+ | IsQuarterEnd | Boolean | Last day of quarter | FALSE |
201
+ | IsYearEnd | Boolean | Last day of year | FALSE |
202
+
203
+ ---
204
+
205
+ ## Sample Data
206
+
207
+ ### DimEmployee (Selected Rows)
208
+
209
+ | EmployeeKey | EmployeeID | FullName | Gender | HireDate | TermDate | IsActive |
210
+ |-------------|------------|----------|--------|----------|----------|----------|
211
+ | 10001 | E-001 | Smith, John | Male | 2018-03-01 | NULL | TRUE |
212
+ | 10002 | E-002 | Johnson, Sarah | Female | 2019-06-15 | NULL | TRUE |
213
+ | 10003 | E-003 | Williams, Mike | Male | 2017-01-10 | 2023-08-31 | FALSE |
214
+ | 10004 | E-004 | Brown, Emily | Female | 2021-09-01 | NULL | TRUE |
215
+ | 10005 | E-005 | Davis, Alex | Non-Binary | 2022-02-14 | NULL | TRUE |
216
+
217
+ ### FactEmployeeSnap (Selected Rows)
218
+
219
+ | SnapshotKey | DateKey | EmployeeKey | DepartmentKey | JobKey | Salary | PerformanceRating |
220
+ |-------------|---------|-------------|---------------|--------|--------|-------------------|
221
+ | 1 | 20240101 | 10001 | 201 | 301 | 145000 | 4 |
222
+ | 2 | 20240101 | 10002 | 202 | 305 | 125000 | 5 |
223
+ | 3 | 20240101 | 10004 | 201 | 302 | 95000 | 3 |
224
+ | 4 | 20240201 | 10001 | 201 | 301 | 145000 | 4 |
225
+ | 5 | 20240201 | 10002 | 202 | 305 | 130000 | 5 |
226
+
227
+ ---
228
+
229
+ ## Relationship Diagram
230
+
231
+ ```
232
+ DimDate[DateKey] ──────────────────────────────────────┐
233
+
234
+ DimEmployee[EmployeeKey] ──────────────────────────┐ │
235
+ │ │
236
+ DimDepartment[DepartmentKey] ────────────────────┐ │ │
237
+ │ │ │
238
+ DimJob[JobKey] ────────────────────────────────┐ │ │ │
239
+ │ │ │ │
240
+ DimLocation[LocationKey] ────────────────────┐ │ │ │ │
241
+ │ │ │ │ │
242
+ ▼ ▼ ▼ ▼ ▼
243
+ ┌──────────────┐
244
+ │FactEmployee │
245
+ │ Snap │
246
+ └──────────────┘
247
+
248
+ All relationships: Many-to-One, Single direction
249
+ ManagerKey relationship: Inactive (activate with USERELATIONSHIP)
250
+ ```
251
+
252
+ ---
253
+
254
+ ## Data Security (RLS)
255
+
256
+ ### Row-Level Security Rules
257
+
258
+ ```dax
259
+ // HR Business Partners see their divisions only
260
+ [Division] = USERPRINCIPALNAME() HRBP Division Lookup
261
+
262
+ // Managers see their direct reports only
263
+ [ManagerKey] IN
264
+ CALCULATETABLE(
265
+ VALUES(FactEmployeeSnap[EmployeeKey]),
266
+ DimEmployee[Email] = USERPRINCIPALNAME()
267
+ )
268
+
269
+ // Sensitive columns hidden for non-HR users
270
+ // - Salary, Bonus, PerformanceRating, EngagementScore
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Power Query - Loading Employee Snapshots
276
+
277
+ ```m
278
+ let
279
+ // Get current month end
280
+ CurrentMonthEnd = Date.EndOfMonth(DateTime.LocalNow()),
281
+
282
+ // Load from HRIS
283
+ Source = Sql.Database("hris-server", "HRDatabase"),
284
+ Employees = Source{[Schema="dbo", Item="vw_EmployeeSnapshot"]}[Data],
285
+
286
+ // Filter to active or recently termed
287
+ Filtered = Table.SelectRows(Employees, each
288
+ [TermDate] = null or [TermDate] >= Date.AddMonths(CurrentMonthEnd, -24)
289
+ ),
290
+
291
+ // Add snapshot date key
292
+ WithDateKey = Table.AddColumn(Filtered, "DateKey",
293
+ each Date.ToText(Date.StartOfMonth([SnapshotDate]), "yyyyMMdd")
294
+ ),
295
+
296
+ // Add calculated tenure
297
+ WithTenure = Table.AddColumn(WithDateKey, "TenureYears",
298
+ each Duration.TotalDays(
299
+ (if [TermDate] = null then DateTime.LocalNow() else [TermDate]) - [HireDate]
300
+ ) / 365.25
301
+ )
302
+ in
303
+ WithTenure
304
+ ```
305
+
306
+ ---
307
+
308
+ ## Performance Tips
309
+
310
+ 1. **Monthly snapshots only** - Don't store daily; monthly is sufficient for HR
311
+ 2. **Pre-calculate tenure** - Avoid complex DATEDIFF in measures
312
+ 3. **Use integer keys** - Faster than employee IDs for joins
313
+ 4. **Partition by year** - Enable incremental refresh
314
+ 5. **Apply RLS early** - Filter before aggregation for performance
315
+ 6. **Limit history** - 2-3 years of snapshots is typically enough