@khester/create-dynamics-app 1.0.8 → 1.1.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/bin/create-dynamics-app.js +1 -1
  2. package/dist/index.js +140 -15
  3. package/dist/index.js.map +1 -1
  4. package/dist/utils/consultingHelpers.d.ts +13 -0
  5. package/dist/utils/consultingHelpers.d.ts.map +1 -0
  6. package/dist/utils/consultingHelpers.js +569 -0
  7. package/dist/utils/consultingHelpers.js.map +1 -0
  8. package/dist/utils/copyTemplate.d.ts.map +1 -1
  9. package/dist/utils/copyTemplate.js.map +1 -1
  10. package/dist/utils/initGit.d.ts.map +1 -1
  11. package/dist/utils/initGit.js.map +1 -1
  12. package/dist/utils/installDependencies.d.ts.map +1 -1
  13. package/dist/utils/installDependencies.js +3 -2
  14. package/dist/utils/installDependencies.js.map +1 -1
  15. package/dist/utils/updatePackageJson.d.ts +1 -1
  16. package/dist/utils/updatePackageJson.d.ts.map +1 -1
  17. package/dist/utils/updatePackageJson.js +11 -1
  18. package/dist/utils/updatePackageJson.js.map +1 -1
  19. package/package.json +1 -1
  20. package/templates/dynamics-365-starter/INTEGRATION_TEST_RESULTS.md +302 -0
  21. package/templates/dynamics-365-starter/PHASE_4_COMPLETION_SUMMARY.md +305 -0
  22. package/templates/dynamics-365-starter/README.md +566 -137
  23. package/templates/dynamics-365-starter/deployment/QUICKSTART-MAC.md +507 -0
  24. package/templates/dynamics-365-starter/deployment/QUICKSTART-WINDOWS.md +372 -0
  25. package/templates/dynamics-365-starter/deployment/README.md +484 -0
  26. package/templates/dynamics-365-starter/deployment/pipelines/README.md +375 -0
  27. package/templates/dynamics-365-starter/deployment/pipelines/azure-pipelines.yml +330 -0
  28. package/templates/dynamics-365-starter/deployment/pipelines/github-actions.yml +422 -0
  29. package/templates/dynamics-365-starter/deployment/pipelines/jenkins.groovy +636 -0
  30. package/templates/dynamics-365-starter/deployment/scripts/deploy.ps1 +417 -0
  31. package/templates/dynamics-365-starter/deployment/scripts/deploy.sh +582 -0
  32. package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.ps1 +486 -0
  33. package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.sh +567 -0
  34. package/templates/dynamics-365-starter/deployment/scripts/validate-setup.ps1 +703 -0
  35. package/templates/dynamics-365-starter/deployment/scripts/validate-setup.sh +671 -0
  36. package/templates/dynamics-365-starter/docs/ARCHITECTURE_OVERVIEW.md +506 -0
  37. package/templates/dynamics-365-starter/docs/BEST_PRACTICES.md +723 -0
  38. package/templates/dynamics-365-starter/docs/MIGRATION_GUIDE.md +447 -0
  39. package/templates/dynamics-365-starter/docs/team-standards/README.md +273 -0
  40. package/templates/dynamics-365-starter/docs/team-standards/client-onboarding.md +577 -0
  41. package/templates/dynamics-365-starter/docs/team-standards/code-review-checklist.md +359 -0
  42. package/templates/dynamics-365-starter/docs/team-standards/coding-standards.md +700 -0
  43. package/templates/dynamics-365-starter/docs/team-standards/cross-platform-team-guide.md +736 -0
  44. package/templates/dynamics-365-starter/docs/team-standards/development-workflows.md +727 -0
  45. package/templates/dynamics-365-starter/docs/troubleshooting/common-errors.md +758 -0
  46. package/templates/dynamics-365-starter/docs/troubleshooting/platform-specific-issues.md +878 -0
  47. package/templates/dynamics-365-starter/package.json +22 -1
  48. package/templates/dynamics-365-starter/public/index.html +8 -11
  49. package/templates/dynamics-365-starter/scripts/custom-build.js +255 -0
  50. package/templates/dynamics-365-starter/src/client-project-template/README.md +234 -0
  51. package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json +114 -0
  52. package/templates/dynamics-365-starter/src/client-project-template/config/environments/template.json +186 -0
  53. package/templates/dynamics-365-starter/src/client-project-template/scripts/client-setup.js +667 -0
  54. package/templates/dynamics-365-starter/src/components/AccountForm.css +71 -0
  55. package/templates/dynamics-365-starter/src/components/AccountForm.tsx +541 -0
  56. package/templates/dynamics-365-starter/src/components/AccountManagement.css +86 -0
  57. package/templates/dynamics-365-starter/src/components/AccountManagement.tsx +370 -0
  58. package/templates/dynamics-365-starter/src/components/ContactForm.tsx +149 -63
  59. package/templates/dynamics-365-starter/src/components/ContactManagement.tsx +153 -63
  60. package/templates/dynamics-365-starter/src/components/Logging/LogDialog.tsx +291 -0
  61. package/templates/dynamics-365-starter/src/components/Logging/LoggingContext.tsx +166 -0
  62. package/templates/dynamics-365-starter/src/components/Logging/LoggingDebugPanel.css +192 -0
  63. package/templates/dynamics-365-starter/src/components/Logging/LoggingDebugPanel.tsx +177 -0
  64. package/templates/dynamics-365-starter/src/components/Logging/LoggingProvider.tsx +3 -0
  65. package/templates/dynamics-365-starter/src/components/Logging/logger.ts +193 -0
  66. package/templates/dynamics-365-starter/src/constants/account.ts +410 -0
  67. package/templates/dynamics-365-starter/src/constants/contact.ts +362 -0
  68. package/templates/dynamics-365-starter/src/examples/README.md +52 -0
  69. package/templates/dynamics-365-starter/src/examples/component-examples/opportunity-management.tsx +625 -0
  70. package/templates/dynamics-365-starter/src/examples/entity-examples/opportunity-model.ts +545 -0
  71. package/templates/dynamics-365-starter/src/examples/integration-examples/custom-pcf-wrapper.tsx +722 -0
  72. package/templates/dynamics-365-starter/src/examples/workflow-examples/sales-workflow.ts +662 -0
  73. package/templates/dynamics-365-starter/src/index.tsx +107 -19
  74. package/templates/dynamics-365-starter/src/models/Account.ts +480 -0
  75. package/templates/dynamics-365-starter/src/models/BaseEntity.ts +204 -0
  76. package/templates/dynamics-365-starter/src/models/Contact.ts +580 -0
  77. package/templates/dynamics-365-starter/src/page-templates/EntityDashboard.tsx +519 -0
  78. package/templates/dynamics-365-starter/src/page-templates/EntityDetailPage.tsx +456 -0
  79. package/templates/dynamics-365-starter/src/page-templates/EntityListPage.tsx +406 -0
  80. package/templates/dynamics-365-starter/src/page-templates/RelatedEntitiesPage.tsx +578 -0
  81. package/templates/dynamics-365-starter/src/page-templates/SearchPage.tsx +629 -0
  82. package/templates/dynamics-365-starter/src/pcf/ContactControlWrapper.tsx +75 -22
  83. package/templates/dynamics-365-starter/src/pcf/MultiEntityControlWrapper.tsx +205 -0
  84. package/templates/dynamics-365-starter/src/providers/DynamicsProvider.tsx +297 -80
  85. package/templates/dynamics-365-starter/src/services/MockApiService.ts +260 -0
  86. package/templates/dynamics-365-starter/src/services/ServiceFactory.ts +65 -0
  87. package/templates/dynamics-365-starter/src/services/XrmApiService.ts +213 -0
  88. package/templates/dynamics-365-starter/src/styles/index.css +74 -7
  89. package/templates/dynamics-365-starter/tools/entity-generator/index.js +168 -0
  90. package/templates/dynamics-365-starter/tools/entity-generator/templates/constants.template.ts +124 -0
  91. package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.css +283 -0
  92. package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.tsx +275 -0
  93. package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.css +204 -0
  94. package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.tsx +413 -0
  95. package/templates/dynamics-365-starter/tools/entity-generator/templates/model.template.ts +250 -0
  96. package/templates/dynamics-365-starter/tools/metadata-sync/d365-client.js +410 -0
  97. package/templates/dynamics-365-starter/tools/metadata-sync/index.js +512 -0
  98. package/templates/dynamics-365-starter/tools/metadata-sync/type-generator.js +675 -0
  99. package/templates/dynamics-365-starter/tsconfig.json +11 -8
  100. package/templates/dynamics-365-starter/webpack.config.js +8 -9
  101. package/templates/power-pages-starter/README.md +7 -1
  102. package/templates/power-pages-starter/public/index.html +8 -11
  103. package/templates/power-pages-starter/src/components/ContactForm.tsx +60 -41
  104. package/templates/power-pages-starter/src/index.tsx +3 -3
  105. package/templates/power-pages-starter/src/providers/PowerPagesProvider.tsx +46 -23
  106. package/templates/power-pages-starter/tsconfig.json +3 -9
  107. package/templates/power-pages-starter/webpack.config.js +8 -3
@@ -5,11 +5,28 @@
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "build": "webpack --mode=production",
8
+ "build:dev": "node scripts/custom-build.js --dev",
9
+ "build:prod": "node scripts/custom-build.js",
10
+ "build:d365": "node scripts/custom-build.js",
8
11
  "dev": "webpack serve --mode=development",
9
12
  "start": "webpack serve --mode=development",
13
+ "serve": "serve -s dist -l 62874",
10
14
  "typecheck": "tsc --noEmit",
11
15
  "clean": "rimraf dist",
12
- "lint": "eslint src --ext .ts,.tsx"
16
+ "lint": "eslint src --ext .ts,.tsx",
17
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
18
+ "quality": "npm run lint && npm run typecheck",
19
+ "quality:fix": "npm run lint:fix && npm run typecheck",
20
+ "validate": "npm run quality && npm run build:prod",
21
+ "test:build": "npm run clean && npm run build:dev && npm run build:prod",
22
+ "test:serve": "npm run build:prod && npm run serve",
23
+ "precommit": "npm run quality",
24
+ "prepublishOnly": "npm run validate",
25
+ "generate:entity": "node tools/entity-generator/index.js generate",
26
+ "metadata:pull": "node tools/metadata-sync/index.js pull",
27
+ "metadata:generate": "node tools/metadata-sync/index.js generate",
28
+ "metadata:validate": "node tools/metadata-sync/index.js validate",
29
+ "metadata:sync": "node tools/metadata-sync/index.js sync"
13
30
  },
14
31
  "dependencies": {
15
32
  "@khester/dynamics-ui-api-client": "^1.0.0",
@@ -20,8 +37,12 @@
20
37
  "devDependencies": {
21
38
  "@types/react": "^18.2.0",
22
39
  "@types/react-dom": "^18.2.0",
40
+ "commander": "^11.1.0",
23
41
  "css-loader": "^6.8.1",
42
+ "eslint": "^8.57.0",
24
43
  "html-webpack-plugin": "^5.5.3",
44
+ "rimraf": "^5.0.5",
45
+ "serve": "^14.2.1",
25
46
  "style-loader": "^3.3.3",
26
47
  "ts-loader": "^9.5.1",
27
48
  "typescript": "^5.3.3",
@@ -1,18 +1,15 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
- <head>
3
+ <head>
4
4
  <meta charset="utf-8" />
5
- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
5
+ <link rel="icon" href="data:," />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <meta name="theme-color" content="#0078d4" />
8
- <meta
9
- name="description"
10
- content="Dynamics 365 application built with Dynamics UI Kit"
11
- />
7
+ <meta name="theme-color" content="#000000" />
8
+ <meta name="description" content="Dynamics 365 Application built with Dynamics UI Kit" />
12
9
  <title>Dynamics 365 App - Dynamics UI Kit</title>
13
- </head>
14
- <body>
10
+ </head>
11
+ <body>
15
12
  <noscript>You need to enable JavaScript to run this app.</noscript>
16
13
  <div id="root"></div>
17
- </body>
18
- </html>
14
+ </body>
15
+ </html>
@@ -0,0 +1,255 @@
1
+ const webpack = require('webpack');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ // Get webpack config
6
+ const webpackConfigPath = path.resolve(__dirname, '../webpack.config.js');
7
+ const getWebpackConfig = require(webpackConfigPath);
8
+
9
+ // Check command line arguments for dev mode
10
+ const isDev = process.argv.includes('--dev') || process.argv.includes('-dev');
11
+ const mode = isDev ? 'development' : 'production';
12
+
13
+ console.log(`Custom Build Script - Mode: ${mode}`);
14
+
15
+ // Create custom webpack config for D365 deployment
16
+ function createD365WebpackConfig() {
17
+ // Get base config
18
+ const baseConfig = getWebpackConfig({}, { mode });
19
+
20
+ // D365-specific optimizations
21
+ const d365Config = {
22
+ ...baseConfig,
23
+ mode,
24
+ optimization: {
25
+ // Disable code splitting for single file deployment
26
+ splitChunks: {
27
+ cacheGroups: {
28
+ default: false,
29
+ vendors: false,
30
+ },
31
+ },
32
+ // Disable runtime chunk
33
+ runtimeChunk: false,
34
+ // Control minimization based on mode
35
+ minimize: !isDev,
36
+ },
37
+ output: {
38
+ ...baseConfig.output,
39
+ // Remove hashes for consistent D365 web resource naming
40
+ filename: '[name].js',
41
+ chunkFilename: '[name].chunk.js',
42
+ assetModuleFilename: '[name][ext]',
43
+ // Set public path for D365 context
44
+ publicPath: './',
45
+ },
46
+ // Add performance hints for large bundles
47
+ performance: {
48
+ hints: isDev ? false : 'warning',
49
+ maxEntrypointSize: 2000000, // 2MB - reasonable for D365
50
+ maxAssetSize: 2000000,
51
+ },
52
+ };
53
+
54
+ // Modify CSS handling for single file output
55
+ const rules = d365Config.module.rules.map((rule) => {
56
+ if (rule.test && rule.test.toString().includes('css')) {
57
+ return {
58
+ ...rule,
59
+ use: [
60
+ 'style-loader', // Inline CSS instead of separate files
61
+ 'css-loader',
62
+ ],
63
+ };
64
+ }
65
+ return rule;
66
+ });
67
+
68
+ d365Config.module.rules = rules;
69
+
70
+ // Modify HTML plugin for D365
71
+ const htmlPluginIndex = d365Config.plugins.findIndex(
72
+ (plugin) => plugin.constructor.name === 'HtmlWebpackPlugin'
73
+ );
74
+
75
+ if (htmlPluginIndex !== -1) {
76
+ d365Config.plugins[htmlPluginIndex] = new (require('html-webpack-plugin'))({
77
+ template: './public/index.html',
78
+ filename: 'index.html',
79
+ inject: 'body',
80
+ // Inline all assets for single-file deployment
81
+ inlineSource: isDev ? false : '.(js|css)$',
82
+ });
83
+ }
84
+
85
+ // Add banner for D365 deployment info
86
+ d365Config.plugins.push(
87
+ new webpack.BannerPlugin({
88
+ banner: `
89
+ Dynamics 365 Custom Page Bundle
90
+ Built: ${new Date().toISOString()}
91
+ Mode: ${mode}
92
+ Environment: ${isDev ? 'Development' : 'Production'}
93
+ Generated with Dynamics UI Kit
94
+ `.trim(),
95
+ raw: false,
96
+ })
97
+ );
98
+
99
+ // Add define plugin for environment variables
100
+ d365Config.plugins.push(
101
+ new webpack.DefinePlugin({
102
+ 'process.env.NODE_ENV': JSON.stringify(mode),
103
+ 'process.env.D365_BUILD': JSON.stringify(true),
104
+ 'process.env.BUILD_MODE': JSON.stringify(mode),
105
+ })
106
+ );
107
+
108
+ return d365Config;
109
+ }
110
+
111
+ // Build function
112
+ function build() {
113
+ const config = createD365WebpackConfig();
114
+
115
+ console.log('Starting D365-optimized build...');
116
+ console.log(`Output directory: ${config.output.path}`);
117
+ console.log(
118
+ `Bundle splitting: ${config.optimization.splitChunks ? 'enabled' : 'disabled'}`
119
+ );
120
+ console.log(`Minimization: ${config.optimization.minimize}`);
121
+
122
+ const compiler = webpack(config);
123
+
124
+ compiler.run((err, stats) => {
125
+ if (err) {
126
+ console.error('Build failed with error:', err);
127
+ process.exit(1);
128
+ }
129
+
130
+ if (stats.hasErrors()) {
131
+ console.error('Build completed with errors:');
132
+ console.error(
133
+ stats.toString({
134
+ colors: true,
135
+ chunks: false,
136
+ modules: false,
137
+ errorDetails: true,
138
+ })
139
+ );
140
+ process.exit(1);
141
+ }
142
+
143
+ if (stats.hasWarnings()) {
144
+ console.warn('Build completed with warnings:');
145
+ console.warn(
146
+ stats.toString({
147
+ colors: true,
148
+ chunks: false,
149
+ modules: false,
150
+ warningsFilter: /export.*was not found in/,
151
+ })
152
+ );
153
+ }
154
+
155
+ console.log('Build completed successfully!');
156
+ console.log(
157
+ stats.toString({
158
+ colors: true,
159
+ chunks: false,
160
+ modules: false,
161
+ assets: true,
162
+ performance: true,
163
+ })
164
+ );
165
+
166
+ // Generate deployment info
167
+ generateDeploymentInfo(stats, config);
168
+
169
+ compiler.close((closeErr) => {
170
+ if (closeErr) {
171
+ console.error('Error closing compiler:', closeErr);
172
+ }
173
+ });
174
+ });
175
+ }
176
+
177
+ // Generate deployment information file
178
+ function generateDeploymentInfo(stats, config) {
179
+ const distPath = config.output.path;
180
+ const deploymentInfo = {
181
+ buildTime: new Date().toISOString(),
182
+ mode: config.mode,
183
+ isDevelopment: isDev,
184
+ assets: [],
185
+ entrypoints: {},
186
+ performance: {
187
+ totalSize: 0,
188
+ maxAssetSize: config.performance?.maxAssetSize || 'unlimited',
189
+ maxEntrypointSize: config.performance?.maxEntrypointSize || 'unlimited',
190
+ },
191
+ d365Integration: {
192
+ singleFileDeployment: !config.optimization.splitChunks,
193
+ webResourceReady: true,
194
+ customPageReady: true,
195
+ pcfReady: true,
196
+ },
197
+ };
198
+
199
+ const compilation = stats.compilation;
200
+
201
+ // Collect asset information
202
+ Object.keys(compilation.assets).forEach((assetName) => {
203
+ const asset = compilation.assets[assetName];
204
+ const assetInfo = {
205
+ name: assetName,
206
+ size: asset.size(),
207
+ type: path.extname(assetName) || 'unknown',
208
+ };
209
+ deploymentInfo.assets.push(assetInfo);
210
+ deploymentInfo.performance.totalSize += assetInfo.size;
211
+ });
212
+
213
+ // Collect entrypoint information
214
+ if (compilation.entrypoints) {
215
+ compilation.entrypoints.forEach((entrypoint, entryName) => {
216
+ const files = entrypoint.getFiles ? entrypoint.getFiles() : [];
217
+ deploymentInfo.entrypoints[entryName] = {
218
+ assets: files,
219
+ size: files.reduce((total, fileName) => {
220
+ const asset = compilation.assets[fileName];
221
+ return total + (asset ? asset.size() : 0);
222
+ }, 0),
223
+ };
224
+ });
225
+ }
226
+
227
+ // Write deployment info file
228
+ const deploymentInfoPath = path.join(distPath, 'deployment-info.json');
229
+ fs.writeFileSync(deploymentInfoPath, JSON.stringify(deploymentInfo, null, 2));
230
+
231
+ console.log('\n📋 Deployment Information:');
232
+ console.log(
233
+ ` Total bundle size: ${(deploymentInfo.performance.totalSize / 1024).toFixed(2)} KB`
234
+ );
235
+ console.log(` Assets generated: ${deploymentInfo.assets.length}`);
236
+ console.log(` Deployment info saved: ${deploymentInfoPath}`);
237
+
238
+ // D365 deployment recommendations
239
+ console.log('\n🚀 D365 Deployment Guidelines:');
240
+ console.log(' 1. Upload JS files as Script (JScript) web resources');
241
+ console.log(' 2. Upload CSS files as Style Sheet (CSS) web resources');
242
+ console.log(' 3. Upload HTML file as Web Page (HTML) web resource');
243
+ console.log(' 4. Set "Available for Dynamics 365 mobile" if needed');
244
+ console.log(' 5. Publish all web resources after upload');
245
+
246
+ if (deploymentInfo.performance.totalSize > 1000000) {
247
+ console.log('\n⚠️ Warning: Bundle size is large (>1MB). Consider:');
248
+ console.log(' - Using code splitting for better performance');
249
+ console.log(' - Removing unused dependencies');
250
+ console.log(' - Enabling compression in D365');
251
+ }
252
+ }
253
+
254
+ // Start the build
255
+ build();
@@ -0,0 +1,234 @@
1
+ # Client Project Architecture Template
2
+
3
+ This template provides a standardized structure for multi-client Dynamics 365 consulting projects.
4
+
5
+ ## Directory Structure
6
+
7
+ ```
8
+ client-project/
9
+ ├── config/
10
+ │ ├── client.json # Client-specific configuration
11
+ │ ├── environments/ # Environment configurations
12
+ │ │ ├── dev.json
13
+ │ │ ├── test.json
14
+ │ │ └── prod.json
15
+ │ └── deployment.json # Deployment settings
16
+ ├── src/
17
+ │ ├── branding/ # Client-specific branding
18
+ │ │ ├── theme.ts # Theme customization
19
+ │ │ ├── logos/ # Client logos and assets
20
+ │ │ └── styles.css # Client-specific styles
21
+ │ ├── entities/ # Client entity definitions
22
+ │ │ ├── custom/ # Custom entities
23
+ │ │ └── extensions/ # Standard entity extensions
24
+ │ ├── workflows/ # Business logic workflows
25
+ │ ├── integrations/ # External system integrations
26
+ │ └── reports/ # Custom reports and dashboards
27
+ ├── deployment/
28
+ │ ├── scripts/ # Deployment automation
29
+ │ ├── solutions/ # Dynamics 365 solutions
30
+ │ └── documentation/ # Deployment guides
31
+ └── docs/
32
+ ├── client-requirements.md # Client-specific requirements
33
+ ├── technical-specifications.md
34
+ └── user-guides/
35
+ ```
36
+
37
+ ## Configuration Files
38
+
39
+ ### client.json
40
+ ```json
41
+ {
42
+ "name": "Client Name",
43
+ "code": "CLI",
44
+ "industry": "Manufacturing",
45
+ "timezone": "America/New_York",
46
+ "locale": "en-US",
47
+ "branding": {
48
+ "primaryColor": "#0078d4",
49
+ "secondaryColor": "#106ebe",
50
+ "logoPath": "src/branding/logos/client-logo.png"
51
+ },
52
+ "features": {
53
+ "enableAdvancedLogging": true,
54
+ "enableCustomWorkflows": true,
55
+ "enableReporting": true
56
+ }
57
+ }
58
+ ```
59
+
60
+ ### environments/prod.json
61
+ ```json
62
+ {
63
+ "name": "Production",
64
+ "dynamics365Url": "https://client.crm.dynamics.com",
65
+ "webApiUrl": "https://client.api.crm.dynamics.com/api/data/v9.2",
66
+ "tenantId": "client-tenant-id",
67
+ "clientId": "client-app-id",
68
+ "security": {
69
+ "enableAuditLogging": true,
70
+ "requireMFA": true,
71
+ "sessionTimeout": 480
72
+ },
73
+ "performance": {
74
+ "enableCaching": true,
75
+ "batchSize": 100,
76
+ "timeoutMs": 30000
77
+ }
78
+ }
79
+ ```
80
+
81
+ ## Usage
82
+
83
+ 1. **Initialize Client Project**:
84
+ ```bash
85
+ create-dynamics-app my-client-project --client-name "ACME Corp" --entities "opportunity,quote,invoice"
86
+ ```
87
+
88
+ 2. **Configure Client Settings**:
89
+ - Update `config/client.json` with client details
90
+ - Customize branding in `src/branding/`
91
+ - Configure environments in `config/environments/`
92
+
93
+ 3. **Generate Custom Entities**:
94
+ ```bash
95
+ npm run generate:entity -- --entity customopportunity --display-name "Custom Opportunity"
96
+ ```
97
+
98
+ 4. **Deploy to Environment**:
99
+ ```bash
100
+ npm run deploy:prod
101
+ ```
102
+
103
+ ## Best Practices
104
+
105
+ ### Multi-Tenant Considerations
106
+ - Use environment-specific configurations
107
+ - Implement client-specific theming
108
+ - Maintain separate deployment pipelines
109
+ - Use feature flags for client-specific functionality
110
+
111
+ ### Security
112
+ - Store sensitive configuration in Azure Key Vault
113
+ - Use managed identities for authentication
114
+ - Implement proper access controls
115
+ - Enable audit logging
116
+
117
+ ### Development Workflow
118
+ 1. Create feature branch for client customization
119
+ 2. Implement and test changes
120
+ 3. Run quality checks: `npm run quality`
121
+ 4. Deploy to test environment
122
+ 5. Get client approval
123
+ 6. Deploy to production
124
+
125
+ ### Code Organization
126
+ - Keep client-specific code in dedicated directories
127
+ - Use dependency injection for client configurations
128
+ - Implement factory patterns for environment-specific services
129
+ - Document all customizations
130
+
131
+ ## Deployment
132
+
133
+ ### Automated Deployment
134
+ The template includes scripts for automated deployment:
135
+
136
+ ```bash
137
+ # Deploy to specific environment
138
+ ./scripts/deploy.sh dev
139
+ ./scripts/deploy.sh test
140
+ ./scripts/deploy.sh prod
141
+
142
+ # Deploy with client validation
143
+ ./scripts/deploy-client.sh --client ACME --env prod
144
+ ```
145
+
146
+ ### Manual Deployment Checklist
147
+ - [ ] Update client configuration
148
+ - [ ] Build and test locally
149
+ - [ ] Deploy to test environment
150
+ - [ ] Run smoke tests
151
+ - [ ] Get client sign-off
152
+ - [ ] Deploy to production
153
+ - [ ] Verify deployment
154
+ - [ ] Update documentation
155
+
156
+ ## Customization Examples
157
+
158
+ ### Client Theming
159
+ ```typescript
160
+ // src/branding/theme.ts
161
+ export const clientTheme = {
162
+ palette: {
163
+ themePrimary: '#0078d4',
164
+ themeSecondary: '#106ebe',
165
+ neutralPrimary: '#323130'
166
+ },
167
+ fonts: {
168
+ medium: {
169
+ fontFamily: 'Client Corporate Font, Segoe UI, sans-serif'
170
+ }
171
+ }
172
+ };
173
+ ```
174
+
175
+ ### Custom Entity Extensions
176
+ ```typescript
177
+ // src/entities/extensions/OpportunityExtensions.ts
178
+ export class ClientOpportunity extends Opportunity {
179
+ public customField1: string = '';
180
+ public customField2: number = 0;
181
+
182
+ public validateClientSpecificRules(): ValidationResult {
183
+ // Client-specific validation logic
184
+ }
185
+ }
186
+ ```
187
+
188
+ ### Environment-Specific Services
189
+ ```typescript
190
+ // src/services/ClientServiceFactory.ts
191
+ export class ClientServiceFactory {
192
+ public static createApiService(environment: string): IApiService {
193
+ const config = getEnvironmentConfig(environment);
194
+
195
+ if (config.enableMockServices) {
196
+ return new MockApiService();
197
+ } else {
198
+ return new XrmApiService(config);
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ ## Maintenance
205
+
206
+ ### Regular Tasks
207
+ - Update client configurations as requirements change
208
+ - Monitor deployment success rates
209
+ - Review and update documentation
210
+ - Conduct security audits
211
+ - Performance monitoring and optimization
212
+
213
+ ### Upgrade Path
214
+ 1. Test new framework versions in dev environment
215
+ 2. Update client projects incrementally
216
+ 3. Maintain backward compatibility
217
+ 4. Document breaking changes
218
+ 5. Coordinate client upgrade schedules
219
+
220
+ ## Support
221
+
222
+ For client project support:
223
+ 1. Check project documentation in `docs/`
224
+ 2. Review deployment logs
225
+ 3. Contact development team with client context
226
+ 4. Escalate to client success team if needed
227
+
228
+ ## Templates Available
229
+
230
+ - **Standard CRM**: Contact, Account, Opportunity management
231
+ - **Sales Pipeline**: Quote, Order, Invoice workflow
232
+ - **Service Management**: Case, Knowledge base, SLA tracking
233
+ - **Project Management**: Project, Task, Resource allocation
234
+ - **Custom Industry**: Tailored for specific industry needs
@@ -0,0 +1,114 @@
1
+ {
2
+ "name": "{{clientName}}",
3
+ "code": "{{clientCode}}",
4
+ "industry": "{{industry}}",
5
+ "timezone": "{{timezone}}",
6
+ "locale": "{{locale}}",
7
+ "version": "1.0.0",
8
+ "created": "{{currentDate}}",
9
+ "lastUpdated": "{{currentDate}}",
10
+ "contact": {
11
+ "primaryContact": "{{primaryContact}}",
12
+ "email": "{{contactEmail}}",
13
+ "phone": "{{contactPhone}}"
14
+ },
15
+ "branding": {
16
+ "primaryColor": "{{primaryColor}}",
17
+ "secondaryColor": "{{secondaryColor}}",
18
+ "accentColor": "{{accentColor}}",
19
+ "logoPath": "src/branding/logos/{{clientCode}}-logo.png",
20
+ "faviconPath": "src/branding/logos/{{clientCode}}-favicon.ico",
21
+ "fontFamily": "{{fontFamily}}",
22
+ "customCss": "src/branding/{{clientCode}}-custom.css"
23
+ },
24
+ "features": {
25
+ "enableAdvancedLogging": true,
26
+ "enableCustomWorkflows": true,
27
+ "enableReporting": true,
28
+ "enableMobileOptimization": true,
29
+ "enableOfflineCapability": false,
30
+ "enableMultiLanguage": false,
31
+ "enableCustomDashboards": true,
32
+ "enableDataExport": true,
33
+ "enableBulkOperations": true,
34
+ "enableAdvancedSecurity": true
35
+ },
36
+ "customEntities": [
37
+ {{#each customEntities}}
38
+ {
39
+ "name": "{{name}}",
40
+ "displayName": "{{displayName}}",
41
+ "description": "{{description}}",
42
+ "enabled": true
43
+ }{{#unless @last}},{{/unless}}
44
+ {{/each}}
45
+ ],
46
+ "integrations": {
47
+ "sharepoint": {
48
+ "enabled": false,
49
+ "siteUrl": ""
50
+ },
51
+ "teams": {
52
+ "enabled": false,
53
+ "appId": ""
54
+ },
55
+ "powerBI": {
56
+ "enabled": false,
57
+ "workspaceId": ""
58
+ },
59
+ "powerAutomate": {
60
+ "enabled": true
61
+ },
62
+ "externalAPIs": [
63
+ {{#each externalAPIs}}
64
+ {
65
+ "name": "{{name}}",
66
+ "endpoint": "{{endpoint}}",
67
+ "authType": "{{authType}}",
68
+ "enabled": {{enabled}}
69
+ }{{#unless @last}},{{/unless}}
70
+ {{/each}}
71
+ ]
72
+ },
73
+ "compliance": {
74
+ "gdprCompliant": true,
75
+ "hipaaCompliant": false,
76
+ "soxCompliant": false,
77
+ "auditRetentionDays": 365,
78
+ "dataClassification": "Internal"
79
+ },
80
+ "deployment": {
81
+ "strategy": "blue-green",
82
+ "rollbackEnabled": true,
83
+ "approvalRequired": true,
84
+ "notificationEmail": "{{contactEmail}}",
85
+ "maintenanceWindow": {
86
+ "timezone": "{{timezone}}",
87
+ "startTime": "02:00",
88
+ "duration": 120
89
+ }
90
+ },
91
+ "support": {
92
+ "level": "Enterprise",
93
+ "hours": "24/7",
94
+ "escalationEmail": "{{supportEmail}}",
95
+ "slaTier": "Gold"
96
+ },
97
+ "customizations": {
98
+ "entities": {
99
+ "naming": "{{clientCode}}_",
100
+ "prefix": "{{clientCode}}",
101
+ "suffix": ""
102
+ },
103
+ "workflows": {
104
+ "customValidation": true,
105
+ "customBusinessLogic": true,
106
+ "customIntegrations": true
107
+ },
108
+ "ui": {
109
+ "customTheme": true,
110
+ "customComponents": true,
111
+ "customLayouts": true
112
+ }
113
+ }
114
+ }