@luquimbo/bi-superpowers 3.1.1 → 3.2.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 (107) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.claude-plugin/skill-manifest.json +1 -1
  4. package/.plugin/plugin.json +1 -1
  5. package/bin/build-plugin.js +6 -6
  6. package/bin/cli.js +169 -310
  7. package/bin/commands/install.js +87 -70
  8. package/bin/lib/agents.js +19 -0
  9. package/bin/lib/mcp-config.js +23 -4
  10. package/desktop-extension/manifest.json +4 -11
  11. package/desktop-extension/server.js +34 -25
  12. package/package.json +3 -9
  13. package/skills/pbi-connect/SKILL.md +1 -1
  14. package/skills/project-kickoff/SKILL.md +1 -1
  15. package/bin/commands/add.js +0 -533
  16. package/bin/commands/add.test.js +0 -77
  17. package/bin/commands/changelog.js +0 -443
  18. package/bin/commands/pull.js +0 -287
  19. package/bin/commands/pull.test.js +0 -36
  20. package/bin/commands/push.js +0 -231
  21. package/bin/commands/push.test.js +0 -14
  22. package/bin/commands/search.js +0 -344
  23. package/bin/commands/search.test.js +0 -115
  24. package/bin/commands/setup.js +0 -545
  25. package/bin/commands/setup.test.js +0 -46
  26. package/bin/commands/sync-profile.js +0 -405
  27. package/bin/commands/sync-profile.test.js +0 -14
  28. package/bin/commands/sync-source.js +0 -418
  29. package/bin/commands/sync-source.test.js +0 -14
  30. package/bin/utils/errors.js +0 -159
  31. package/bin/utils/git.js +0 -298
  32. package/bin/utils/logger.js +0 -142
  33. package/bin/utils/pbix.js +0 -305
  34. package/bin/utils/pbix.test.js +0 -37
  35. package/bin/utils/profiles.js +0 -312
  36. package/bin/utils/projects.js +0 -169
  37. package/bin/utils/readline.js +0 -206
  38. package/bin/utils/readline.test.js +0 -47
  39. package/docs/openrouter-free-models.md +0 -92
  40. package/library/examples/README.md +0 -151
  41. package/library/examples/finance-reporting/README.md +0 -351
  42. package/library/examples/finance-reporting/data-model.md +0 -267
  43. package/library/examples/finance-reporting/measures.dax +0 -557
  44. package/library/examples/hr-analytics/README.md +0 -371
  45. package/library/examples/hr-analytics/data-model.md +0 -315
  46. package/library/examples/hr-analytics/measures.dax +0 -460
  47. package/library/examples/marketing-analytics/README.md +0 -37
  48. package/library/examples/marketing-analytics/data-model.md +0 -62
  49. package/library/examples/marketing-analytics/measures.dax +0 -110
  50. package/library/examples/retail-analytics/README.md +0 -439
  51. package/library/examples/retail-analytics/data-model.md +0 -288
  52. package/library/examples/retail-analytics/measures.dax +0 -481
  53. package/library/examples/supply-chain/README.md +0 -37
  54. package/library/examples/supply-chain/data-model.md +0 -69
  55. package/library/examples/supply-chain/measures.dax +0 -77
  56. package/library/examples/udf-library/README.md +0 -228
  57. package/library/examples/udf-library/functions.dax +0 -571
  58. package/library/snippets/dax/README.md +0 -292
  59. package/library/snippets/dax/business-domains.md +0 -576
  60. package/library/snippets/dax/calculate-patterns.md +0 -276
  61. package/library/snippets/dax/calculation-groups.md +0 -489
  62. package/library/snippets/dax/error-handling.md +0 -495
  63. package/library/snippets/dax/iterators-and-aggregations.md +0 -474
  64. package/library/snippets/dax/kpis-and-metrics.md +0 -293
  65. package/library/snippets/dax/rankings-and-topn.md +0 -235
  66. package/library/snippets/dax/security-patterns.md +0 -413
  67. package/library/snippets/dax/text-and-formatting.md +0 -316
  68. package/library/snippets/dax/time-intelligence.md +0 -196
  69. package/library/snippets/dax/user-defined-functions.md +0 -477
  70. package/library/snippets/dax/virtual-tables.md +0 -546
  71. package/library/snippets/excel-formulas/README.md +0 -84
  72. package/library/snippets/excel-formulas/aggregations.md +0 -330
  73. package/library/snippets/excel-formulas/dates-and-times.md +0 -361
  74. package/library/snippets/excel-formulas/dynamic-arrays.md +0 -314
  75. package/library/snippets/excel-formulas/lookups.md +0 -169
  76. package/library/snippets/excel-formulas/text-functions.md +0 -363
  77. package/library/snippets/governance/naming-conventions.md +0 -97
  78. package/library/snippets/governance/review-checklists.md +0 -107
  79. package/library/snippets/power-query/README.md +0 -389
  80. package/library/snippets/power-query/api-integration.md +0 -707
  81. package/library/snippets/power-query/connections.md +0 -434
  82. package/library/snippets/power-query/data-cleaning.md +0 -298
  83. package/library/snippets/power-query/error-handling.md +0 -526
  84. package/library/snippets/power-query/parameters.md +0 -350
  85. package/library/snippets/power-query/performance.md +0 -506
  86. package/library/snippets/power-query/transformations.md +0 -330
  87. package/library/snippets/report-design/accessibility.md +0 -78
  88. package/library/snippets/report-design/chart-selection.md +0 -54
  89. package/library/snippets/report-design/layout-patterns.md +0 -87
  90. package/library/templates/data-models/README.md +0 -93
  91. package/library/templates/data-models/finance-model.md +0 -627
  92. package/library/templates/data-models/retail-star-schema.md +0 -473
  93. package/library/templates/excel/README.md +0 -83
  94. package/library/templates/excel/budget-tracker.md +0 -432
  95. package/library/templates/excel/data-entry-form.md +0 -533
  96. package/library/templates/power-bi/README.md +0 -72
  97. package/library/templates/power-bi/finance-report.md +0 -449
  98. package/library/templates/power-bi/kpi-scorecard.md +0 -461
  99. package/library/templates/power-bi/sales-dashboard.md +0 -281
  100. package/library/themes/excel/README.md +0 -436
  101. package/library/themes/power-bi/README.md +0 -271
  102. package/library/themes/power-bi/accessible.json +0 -307
  103. package/library/themes/power-bi/bi-superpowers-default.json +0 -858
  104. package/library/themes/power-bi/corporate-blue.json +0 -291
  105. package/library/themes/power-bi/dark-mode.json +0 -291
  106. package/library/themes/power-bi/minimal.json +0 -292
  107. package/library/themes/power-bi/print-friendly.json +0 -309
@@ -1,169 +0,0 @@
1
- /**
2
- * Projects Utility
3
- * =================
4
- *
5
- * Shared functions for working with bi-repo projects.
6
- * Extracted from add.js, pull.js, push.js to reduce duplication.
7
- *
8
- * @module utils/projects
9
- */
10
-
11
- const fs = require('fs');
12
- const path = require('path');
13
-
14
- /**
15
- * Get a specific project by name
16
- * @param {string} repoPath - Path to bi-repo
17
- * @param {string} projectName - Name of the project
18
- * @returns {Object|null} Project config with projectPath added, or null
19
- */
20
- function getProject(repoPath, projectName) {
21
- const projectPath = path.join(repoPath, 'projects', projectName);
22
- const configPath = path.join(projectPath, 'project.json');
23
-
24
- if (!fs.existsSync(configPath)) {
25
- return null;
26
- }
27
-
28
- try {
29
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
30
- return {
31
- ...config,
32
- projectPath,
33
- };
34
- } catch (e) {
35
- // Invalid JSON in config file
36
- if (process.env.DEBUG === 'true') {
37
- console.error(`[DEBUG] Failed to parse project config: ${configPath}`);
38
- }
39
- return null;
40
- }
41
- }
42
-
43
- /**
44
- * Get list of all projects in the repo
45
- * @param {string} repoPath - Path to bi-repo
46
- * @returns {Object[]} Array of project configs with projectPath added
47
- */
48
- function getAllProjects(repoPath) {
49
- const projectsDir = path.join(repoPath, 'projects');
50
-
51
- if (!fs.existsSync(projectsDir)) {
52
- return [];
53
- }
54
-
55
- const projects = [];
56
- const dirs = fs.readdirSync(projectsDir);
57
-
58
- for (const dir of dirs) {
59
- const projectPath = path.join(projectsDir, dir);
60
-
61
- // Skip if not a directory
62
- try {
63
- if (!fs.statSync(projectPath).isDirectory()) {
64
- continue;
65
- }
66
- } catch (e) {
67
- continue;
68
- }
69
-
70
- const configPath = path.join(projectPath, 'project.json');
71
-
72
- if (fs.existsSync(configPath)) {
73
- try {
74
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
75
- projects.push({
76
- ...config,
77
- projectPath,
78
- });
79
- } catch (e) {
80
- // Warn user about broken config so they can fix it
81
- console.warn(`⚠ Config de proyecto inválido en ${configPath}: ${e.message}`);
82
- if (process.env.DEBUG === 'true') {
83
- console.error('[DEBUG] Full error:', e);
84
- }
85
- }
86
- }
87
- }
88
-
89
- return projects;
90
- }
91
-
92
- /**
93
- * Detect current project based on working directory
94
- * @param {string} repoPath - Path to bi-repo
95
- * @returns {Object|null} Project config or null if not in a project folder
96
- */
97
- function detectCurrentProject(repoPath) {
98
- const cwd = process.cwd();
99
- const projectsBase = path.join(repoPath, 'projects');
100
-
101
- // Check if we're inside a project folder
102
- if (cwd.startsWith(projectsBase)) {
103
- const relative = path.relative(projectsBase, cwd);
104
- const projectName = relative.split(path.sep)[0];
105
-
106
- if (projectName && projectName !== '..') {
107
- return getProject(repoPath, projectName);
108
- }
109
- }
110
-
111
- return null;
112
- }
113
-
114
- /**
115
- * List project names
116
- * @param {string} repoPath - Path to bi-repo
117
- * @returns {string[]} Array of project names
118
- */
119
- function listProjectNames(repoPath) {
120
- return getAllProjects(repoPath).map((p) => p.name);
121
- }
122
-
123
- /**
124
- * Check if a project exists
125
- * @param {string} repoPath - Path to bi-repo
126
- * @param {string} projectName - Name of the project
127
- * @returns {boolean} True if project exists
128
- */
129
- function projectExists(repoPath, projectName) {
130
- const projectPath = path.join(repoPath, 'projects', projectName);
131
- const configPath = path.join(projectPath, 'project.json');
132
- return fs.existsSync(configPath);
133
- }
134
-
135
- /**
136
- * Get project path
137
- * @param {string} repoPath - Path to bi-repo
138
- * @param {string} projectName - Name of the project
139
- * @returns {string} Path to project directory
140
- */
141
- function getProjectPath(repoPath, projectName) {
142
- return path.join(repoPath, 'projects', projectName);
143
- }
144
-
145
- /**
146
- * Print available projects to console
147
- * @param {string} repoPath - Path to bi-repo
148
- * @param {string} prefix - Prefix for each line (default: ' - ')
149
- */
150
- function printAvailableProjects(repoPath, prefix = ' - ') {
151
- const projects = getAllProjects(repoPath);
152
- if (projects.length === 0) {
153
- console.log(`${prefix}(no projects found)`);
154
- } else {
155
- projects.forEach((p) => {
156
- console.log(`${prefix}${p.name}`);
157
- });
158
- }
159
- }
160
-
161
- module.exports = {
162
- getProject,
163
- getAllProjects,
164
- detectCurrentProject,
165
- listProjectNames,
166
- projectExists,
167
- getProjectPath,
168
- printAvailableProjects,
169
- };
@@ -1,206 +0,0 @@
1
- /**
2
- * Readline Utilities for BI Agent Superpowers
3
- * ============================================
4
- *
5
- * Shared readline functions for interactive CLI commands.
6
- * Consolidates duplicated code from setup.js, add.js, sync-source.js, sync-profile.js
7
- *
8
- * @module utils/readline
9
- */
10
-
11
- const readline = require('readline');
12
-
13
- /**
14
- * Create a readline interface for interactive prompts
15
- * @returns {readline.Interface} Readline interface
16
- */
17
- function createReadline() {
18
- return readline.createInterface({
19
- input: process.stdin,
20
- output: process.stdout,
21
- });
22
- }
23
-
24
- /**
25
- * Prompt the user for input
26
- * @param {readline.Interface} rl - Readline interface
27
- * @param {string} question - Question to ask
28
- * @returns {Promise<string>} User's answer (trimmed)
29
- */
30
- function prompt(rl, question) {
31
- return new Promise((resolve) => {
32
- rl.question(question, (answer) => {
33
- resolve(answer.trim());
34
- });
35
- });
36
- }
37
-
38
- /**
39
- * Ask for yes/no confirmation
40
- * @param {readline.Interface} rl - Readline interface
41
- * @param {string} question - Question to ask (without y/n suffix)
42
- * @param {boolean} defaultValue - Default value if user just presses Enter
43
- * @returns {Promise<boolean>} True if confirmed, false otherwise
44
- */
45
- function confirm(rl, question, defaultValue = false) {
46
- const suffix = defaultValue ? ' (S/n): ' : ' (s/N): ';
47
- return new Promise((resolve) => {
48
- rl.question(question + suffix, (answer) => {
49
- const trimmed = answer.trim().toLowerCase();
50
- if (trimmed === '') {
51
- resolve(defaultValue);
52
- } else {
53
- resolve(trimmed === 's' || trimmed === 'y' || trimmed === 'si' || trimmed === 'yes');
54
- }
55
- });
56
- });
57
- }
58
-
59
- /**
60
- * Ask user to select from a list of options
61
- * @param {readline.Interface} rl - Readline interface
62
- * @param {string} question - Question to ask
63
- * @param {string[]} options - Array of option strings
64
- * @param {number} defaultIndex - Default option index (0-based)
65
- * @returns {Promise<{index: number, value: string}>} Selected option
66
- */
67
- async function select(rl, question, options, defaultIndex = 0) {
68
- console.log(`\n${question}\n`);
69
-
70
- options.forEach((option, i) => {
71
- const marker = i === defaultIndex ? '>' : ' ';
72
- console.log(` ${marker} ${i + 1}. ${option}`);
73
- });
74
-
75
- console.log('');
76
-
77
- const answer = await prompt(rl, `Elige una opción (1-${options.length}) [${defaultIndex + 1}]: `);
78
-
79
- if (answer === '') {
80
- return { index: defaultIndex, value: options[defaultIndex] };
81
- }
82
-
83
- const num = parseInt(answer, 10);
84
- if (isNaN(num) || num < 1 || num > options.length) {
85
- console.log('Opción no válida, usando la predeterminada.');
86
- return { index: defaultIndex, value: options[defaultIndex] };
87
- }
88
-
89
- return { index: num - 1, value: options[num - 1] };
90
- }
91
-
92
- /**
93
- * Ask user to select multiple options from a list
94
- * @param {readline.Interface} rl - Readline interface
95
- * @param {string} question - Question to ask
96
- * @param {Array<{label: string, value: any, selected?: boolean}>} options - Options with labels and values
97
- * @returns {Promise<any[]>} Array of selected values
98
- */
99
- async function multiSelect(rl, question, options) {
100
- console.log(`\n${question}\n`);
101
- console.log(' Instrucciones:');
102
- console.log(' - Escribe números separados por comas (ej: 1,3,5)');
103
- console.log(' - "a" para seleccionar todos');
104
- console.log(' - "n" para deseleccionar todos');
105
- console.log(' - Enter para confirmar selección actual\n');
106
-
107
- // Show options with current selection
108
- options.forEach((option, i) => {
109
- const marker = option.selected ? '[x]' : '[ ]';
110
- console.log(` ${marker} ${i + 1}. ${option.label}`);
111
- });
112
-
113
- console.log('');
114
-
115
- const answer = await prompt(rl, 'Selección: ');
116
-
117
- if (answer.toLowerCase() === 'a') {
118
- return options.map((o) => o.value);
119
- }
120
-
121
- if (answer.toLowerCase() === 'n' || answer === '') {
122
- return options.filter((o) => o.selected).map((o) => o.value);
123
- }
124
-
125
- // Parse comma-separated numbers
126
- const indices = answer
127
- .split(',')
128
- .map((s) => parseInt(s.trim(), 10) - 1)
129
- .filter((n) => !isNaN(n) && n >= 0 && n < options.length);
130
-
131
- return indices.map((i) => options[i].value);
132
- }
133
-
134
- /**
135
- * Show a spinner while executing an async operation
136
- * @param {string} message - Message to show
137
- * @param {Promise} promise - Promise to wait for
138
- * @returns {Promise} Result of the promise
139
- */
140
- async function withSpinner(message, promise) {
141
- const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
142
- let i = 0;
143
-
144
- const interval = setInterval(() => {
145
- process.stdout.write(`\r${frames[i]} ${message}`);
146
- i = (i + 1) % frames.length;
147
- }, 80);
148
-
149
- try {
150
- const result = await promise;
151
- clearInterval(interval);
152
- process.stdout.write(`\r✓ ${message}\n`);
153
- return result;
154
- } catch (error) {
155
- clearInterval(interval);
156
- process.stdout.write(`\r✗ ${message}\n`);
157
- throw error;
158
- }
159
- }
160
-
161
- /**
162
- * Exit with error message
163
- * @param {string} message - Error message
164
- * @param {number} code - Exit code (default 1)
165
- */
166
- function exitWithError(message, code = 1) {
167
- console.error(`\n✗ ${message}\n`);
168
- process.exit(code);
169
- }
170
-
171
- /**
172
- * Show success message
173
- * @param {string} message - Success message
174
- */
175
- function showSuccess(message) {
176
- console.log(`✓ ${message}`);
177
- }
178
-
179
- /**
180
- * Show warning message
181
- * @param {string} message - Warning message
182
- */
183
- function showWarning(message) {
184
- console.log(`⚠ ${message}`);
185
- }
186
-
187
- /**
188
- * Show info message
189
- * @param {string} message - Info message
190
- */
191
- function showInfo(message) {
192
- console.log(`ℹ ${message}`);
193
- }
194
-
195
- module.exports = {
196
- createReadline,
197
- prompt,
198
- confirm,
199
- select,
200
- multiSelect,
201
- withSpinner,
202
- exitWithError,
203
- showSuccess,
204
- showWarning,
205
- showInfo,
206
- };
@@ -1,47 +0,0 @@
1
- /**
2
- * Tests for Readline Utilities
3
- * @module utils/readline.test
4
- */
5
-
6
- const { test, describe } = require('node:test');
7
- const assert = require('node:assert');
8
-
9
- const readline = require('./readline');
10
-
11
- describe('Readline Utilities', () => {
12
- test('exports createReadline function', () => {
13
- assert.strictEqual(typeof readline.createReadline, 'function');
14
- });
15
-
16
- test('exports prompt function', () => {
17
- assert.strictEqual(typeof readline.prompt, 'function');
18
- });
19
-
20
- test('exports confirm function', () => {
21
- assert.strictEqual(typeof readline.confirm, 'function');
22
- });
23
-
24
- test('exports select function', () => {
25
- assert.strictEqual(typeof readline.select, 'function');
26
- });
27
-
28
- test('exports multiSelect function', () => {
29
- assert.strictEqual(typeof readline.multiSelect, 'function');
30
- });
31
-
32
- test('exports exitWithError function', () => {
33
- assert.strictEqual(typeof readline.exitWithError, 'function');
34
- });
35
-
36
- test('exports showSuccess function', () => {
37
- assert.strictEqual(typeof readline.showSuccess, 'function');
38
- });
39
-
40
- test('exports showWarning function', () => {
41
- assert.strictEqual(typeof readline.showWarning, 'function');
42
- });
43
-
44
- test('exports showInfo function', () => {
45
- assert.strictEqual(typeof readline.showInfo, 'function');
46
- });
47
- });
@@ -1,92 +0,0 @@
1
- # Configure Claude Code with OpenRouter (Free Models)
2
-
3
- Use free AI models with Claude Code CLI and 1code.dev via OpenRouter.
4
-
5
- ## Prerequisites
6
-
7
- - Node.js installed
8
- - Claude Code CLI installed (`npm install -g @anthropic-ai/claude-code`)
9
- - Free account at [openrouter.ai](https://openrouter.ai)
10
-
11
- ## Step 1: Create OpenRouter API Key
12
-
13
- 1. Go to [openrouter.ai](https://openrouter.ai) and create account (free)
14
- 2. Go to [openrouter.ai/keys](https://openrouter.ai/keys)
15
- 3. Click "Create Key"
16
- 4. Copy the key (starts with `sk-or-v1-...`)
17
-
18
- ## Step 2: Configure Environment Variables
19
-
20
- Add to the end of `~/.zshrc` (macOS/Linux) or your shell profile:
21
-
22
- ```bash
23
- # OpenRouter + Claude Code
24
- export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
25
- export ANTHROPIC_AUTH_TOKEN="sk-or-v1-YOUR-KEY-HERE"
26
- export ANTHROPIC_API_KEY=""
27
- ```
28
-
29
- > **Important**: `ANTHROPIC_API_KEY` MUST be empty (`""`). If it doesn't exist, Claude Code will try to authenticate with Anthropic directly.
30
-
31
- Then reload the shell:
32
-
33
- ```bash
34
- source ~/.zshrc
35
- ```
36
-
37
- ## Step 3: Sign Out of Anthropic (if needed)
38
-
39
- If you previously used Claude Code with an Anthropic account:
40
-
41
- ```bash
42
- claude
43
- # inside the session:
44
- /logout
45
- ```
46
-
47
- ## Step 4: Verify Connection
48
-
49
- ```bash
50
- claude
51
- # inside the session:
52
- /status
53
- ```
54
-
55
- Should show that it's connected to OpenRouter.
56
-
57
- ## Recommended Free Models for Coding
58
-
59
- | Model | OpenRouter ID | Context | Best For |
60
- |-------|---------------|---------|----------|
61
- | **Qwen3 Coder 480B** | `qwen/qwen3-coder-480b-a35b:free` | 262K | Best free model for agentic coding |
62
- | **DeepSeek R1** | `deepseek/deepseek-r1:free` | 164K | Complex reasoning, debugging |
63
- | **Devstral** | `mistralai/devstral-small:free` | 128K | Multi-file, agentic coding |
64
- | **Llama 3.3 70B** | `meta-llama/llama-3.3-70b-instruct:free` | 128K | General purpose, fast |
65
-
66
- To select a specific model, add to `~/.zshrc`:
67
-
68
- ```bash
69
- export ANTHROPIC_MODEL="qwen/qwen3-coder-480b-a35b:free"
70
- ```
71
-
72
- Or use the free automatic router:
73
-
74
- ```bash
75
- export ANTHROPIC_MODEL="openrouter/free"
76
- ```
77
-
78
- ## Limitations
79
-
80
- - **Rate limits**: ~20 requests/min, ~200 requests/day on free models
81
- - **Tool use**: Not all free models support tool calling (needed for agents)
82
- - **Quality**: Inferior to Claude Opus/Sonnet for complex tasks
83
- - **Availability**: Free models may disappear without notice
84
- - **Not recommended for production**
85
-
86
- ## Verification
87
-
88
- 1. Open a new terminal (to load the variables)
89
- 2. `echo $ANTHROPIC_BASE_URL` → should show `https://openrouter.ai/api`
90
- 3. `claude` → should start without asking for Anthropic login
91
- 4. `/status` → confirm connection to OpenRouter
92
- 5. Ask a simple coding question to verify response
@@ -1,151 +0,0 @@
1
- # Examples
2
-
3
- Complete, end-to-end examples demonstrating BI Agent Superpowers patterns in real-world scenarios.
4
-
5
- ---
6
-
7
- ## Available Examples
8
-
9
- | Example | Description | Components |
10
- |---------|-------------|------------|
11
- | [retail-analytics](./retail-analytics/) | Complete retail sales analytics solution | Star schema, 50+ DAX measures, data model |
12
- | [finance-reporting](./finance-reporting/) | P&L, Balance Sheet, variance analysis | Multi-statement model, 60+ financial measures |
13
- | [hr-analytics](./hr-analytics/) | Headcount, turnover, diversity metrics | Employee snapshots, 40+ HR measures |
14
- | [udf-library](./udf-library/) | DAX User Defined Functions library | 50+ reusable UDFs, typed parameters |
15
-
16
- ---
17
-
18
- ## Learning Path (Recommended Order)
19
-
20
- New to Power BI? Follow this progression to build your skills:
21
-
22
- ### Level 1: Foundations
23
- 1. **[retail-analytics](./retail-analytics/)** - Start here!
24
- - Learn star schema basics (facts + dimensions)
25
- - Understand fundamental DAX patterns (SUM, CALCULATE, time intelligence)
26
- - Build your first KPI dashboard
27
-
28
- ### Level 2: Intermediate
29
- 2. **[hr-analytics](./hr-analytics/)** - Expand your skills
30
- - Work with snapshot data (point-in-time analysis)
31
- - Learn turnover and retention calculations
32
- - Understand Row-Level Security (RLS) basics
33
-
34
- ### Level 3: Advanced
35
- 3. **[finance-reporting](./finance-reporting/)** - Master complex scenarios
36
- - Handle multi-statement financial models
37
- - Work with hierarchical account structures
38
- - Build variance analysis (Actual vs Budget)
39
-
40
- ### Level 4: Expert
41
- 4. **[udf-library](./udf-library/)** - Cutting-edge DAX
42
- - Create reusable User Defined Functions (preview feature)
43
- - Build a personal library of typed functions
44
- - Master advanced DAX patterns
45
-
46
- ---
47
-
48
- ## What Each Example Includes
49
-
50
- ### Documentation
51
- - **README.md** - Overview, business requirements, implementation guide
52
- - **data-model.md** - Complete table definitions, relationships, sample data
53
-
54
- ### Code
55
- - **measures.dax** - Complete DAX measure library, organized by category
56
-
57
- ### Styling
58
- - Use themes from `library/themes/power-bi/` for consistent formatting
59
-
60
- ---
61
-
62
- ## Using Examples
63
-
64
- ### 1. Understand the Scenario
65
-
66
- Read the README.md to understand:
67
- - Business requirements and stakeholders
68
- - Key questions the solution answers
69
- - Recommended visualizations
70
-
71
- ### 2. Adapt the Data Model
72
-
73
- Use data-model.md as a template:
74
- - Match columns to your source data
75
- - Adjust data types as needed
76
- - Add/remove columns for your scenario
77
-
78
- ### 3. Copy Relevant Measures
79
-
80
- From measures.dax:
81
- - Start with base measures (Revenue, Cost, Profit)
82
- - Add time intelligence as needed
83
- - Customize rankings and percentages
84
-
85
- ### 4. Apply a Theme
86
-
87
- 1. Choose a theme from `library/themes/power-bi/`
88
- 2. View > Themes > Browse for themes
89
- 3. Select the JSON file
90
-
91
- ---
92
-
93
- ## Example Structure
94
-
95
- ```
96
- library/examples/
97
- ├── README.md # This file
98
-
99
- ├── retail-analytics/ # Retail sales analytics
100
- │ ├── README.md # Overview and guide
101
- │ ├── data-model.md # Table definitions
102
- │ └── measures.dax # 50+ DAX measures
103
-
104
- ├── finance-reporting/ # Financial statements
105
- │ ├── README.md # P&L, Balance Sheet guide
106
- │ ├── data-model.md # Account structure, scenarios
107
- │ └── measures.dax # 60+ financial measures
108
-
109
- ├── hr-analytics/ # HR workforce analytics
110
- │ ├── README.md # Headcount, turnover guide
111
- │ ├── data-model.md # Employee snapshot model
112
- │ └── measures.dax # 40+ HR measures
113
-
114
- └── udf-library/ # DAX User Defined Functions
115
- ├── README.md # UDF usage guide and catalog
116
- └── functions.dax # 50+ reusable typed functions
117
- ```
118
-
119
- ---
120
-
121
- ## Upcoming Examples
122
-
123
- - **marketing-dashboard** - Campaign performance, funnel analysis
124
- - **supply-chain** - Inventory, fulfillment, vendor performance
125
- - **project-management** - Resource allocation, timeline tracking
126
-
127
- ---
128
-
129
- ## Contributing Examples
130
-
131
- Want to add an example? Include:
132
-
133
- 1. **README.md** with:
134
- - Business scenario description
135
- - Stakeholder requirements
136
- - Data model diagram
137
- - Visualization recommendations
138
- - Implementation checklist
139
-
140
- 2. **data-model.md** with:
141
- - All table definitions
142
- - Column specifications
143
- - Relationship diagram
144
- - Sample data
145
-
146
- 3. **measures.dax** with:
147
- - Organized by category
148
- - Comments explaining each measure
149
- - Naming conventions followed
150
-
151
- See [CONTRIBUTING.md](../../CONTRIBUTING.md) for submission guidelines.