Skip to main content
Glama

DHIS2 MCP Server

by Dradebo
debugging-helpers.ts64.7 kB
/** * DHIS2 Development Debugging and Troubleshooting Functions * Based on DHIS2 community issues and best practices */ export function diagnoseCORSIssues(args: any): string { const { dhis2Instance, localDevelopmentUrl, browser, errorMessage = '', symptoms = [] } = args; const diagnosis = []; const solutions = []; // Analyze browser-specific issues if (browser === 'chrome') { diagnosis.push('Chrome has strict SameSite cookie policies since version 94+'); solutions.push('Use the --proxy flag when starting your DHIS2 app: `yarn start --proxy`'); solutions.push('Alternative: Start Chrome with disabled security for development: `google-chrome --disable-web-security --user-data-dir=/tmp/chrome-dev`'); } else if (browser === 'firefox') { diagnosis.push('Firefox recently changed SameSite cookie behavior to be more strict'); solutions.push('Temporarily modify Firefox settings:'); solutions.push(' 1. Open about:config'); solutions.push(' 2. Set `network.cookie.sameSite.laxByDefault` to `false`'); solutions.push(' 3. Set `network.cookie.sameSite.noneRequiresSecure` to `false`'); } // Analyze specific symptoms symptoms.forEach((symptom: string) => { switch (symptom) { case 'login_fails': diagnosis.push('Authentication requests are being blocked by CORS policy'); solutions.push('Add your development URL to DHIS2 CORS allowlist'); solutions.push('Check if DHIS2 instance supports cross-origin authentication'); break; case 'api_requests_blocked': diagnosis.push('API calls are failing due to cross-origin restrictions'); solutions.push('Configure proxy to route requests through same origin'); break; case 'cookies_not_sent': diagnosis.push('Browser is not sending cookies with cross-origin requests'); solutions.push('Use credentials: "include" in fetch requests'); solutions.push('Ensure SameSite cookie settings allow cross-origin'); break; case '302_errors': diagnosis.push('Login endpoint is redirecting, causing CORS preflight failure'); solutions.push('Use direct API authentication instead of login forms'); break; case 'preflight_failed': diagnosis.push('CORS preflight OPTIONS requests are failing'); solutions.push('Check DHIS2 server CORS configuration'); break; } }); // DHIS2 Play server specific issues if (dhis2Instance.includes('play.dhis2.org')) { diagnosis.push('DHIS2 Play instances use nginx with hardened security settings'); solutions.push('⚠️ DHIS2 Play instances prevent cross-site cookies completely'); solutions.push('Recommended: Use local DHIS2 instance for development'); solutions.push('Alternative: Run DHIS2 locally with Docker: `d2 cluster up`'); } return `# CORS Issues Diagnosis ## Configuration Details - **DHIS2 Instance**: ${dhis2Instance} - **Local Development**: ${localDevelopmentUrl} - **Browser**: ${browser.toUpperCase()} - **Error Message**: ${errorMessage} - **Symptoms**: ${symptoms.join(', ')} ## Diagnosis ${diagnosis.map(d => `- ${d}`).join('\n')} ## Recommended Solutions ### Immediate Solutions ${solutions.map((s, i) => `${i + 1}. ${s}`).join('\n')} ### Long-term Solutions 1. **Configure CORS Allowlist** - Login to your DHIS2 instance as admin - Go to Apps → System Settings → Access - Add your development URL to "CORS allowlist" 2. **Use Proxy Configuration** \`\`\`bash # Start with proxy (recommended) yarn start --proxy \`\`\` 3. **Local Development Instance** \`\`\`bash # Set up local DHIS2 instance npx @dhis2/cli cluster init d2 cluster up \`\`\` ## Testing CORS Configuration \`\`\`bash # Test CORS headers curl -H "Origin: ${localDevelopmentUrl}" \\ -H "Access-Control-Request-Method: GET" \\ -H "Access-Control-Request-Headers: X-Requested-With" \\ -X OPTIONS \\ ${dhis2Instance}/api/me # Expected response should include: # Access-Control-Allow-Origin: ${localDevelopmentUrl} # Access-Control-Allow-Credentials: true \`\`\` ## Browser Dev Tools Checklist 1. Open Network tab and check for: - OPTIONS requests (preflight) - Response headers with Access-Control-* - Cookie header presence in requests 2. Console errors related to: - "Cross-Origin Request Blocked" - "CORS policy" messages - SameSite warnings ## Alternative Development Approaches ${dhis2Instance.includes('play.dhis2.org') ? ` ⚠️ Since you're using DHIS2 Play, consider these alternatives: 1. **Local DHIS2 Instance (Recommended)** \`\`\`bash # Quick setup with Docker docker run -d -p 8080:8080 dhis2/core:2.40.4 \`\`\` 2. **Use DHIS2 CLI Cluster** \`\`\`bash npx @dhis2/cli cluster init my-cluster cd my-cluster d2 cluster up \`\`\` 3. **Request Dedicated Development Instance** - Contact your DHIS2 administrator - Request CORS configuration for development URLs ` : ''} ## Security Considerations ⚠️ **Development Only**: Never disable browser security in production ⚠️ **Temporary**: Revert Firefox settings after development ⚠️ **Credentials**: Use separate development credentials `; } export function generateCORSConfiguration(args: any): string { const { allowedOrigins, dhis2Version = '2.40.4', includeSteps = true } = args; return `# DHIS2 CORS Configuration Guide ## System Settings Configuration ${includeSteps ? ` ### Step-by-Step Instructions 1. **Login to DHIS2** as a user with system administration privileges 2. **Navigate to System Settings** - Click on the Apps icon (grid icon) - Search for "System Settings" - Click on the System Settings app 3. **Configure CORS** - In the left sidebar, click "Access" - Scroll down to find "CORS allowlist" - Add your development URLs 4. **Save Changes** - Click "Save" at the bottom of the page - Wait for confirmation message ` : ''} ## CORS Allowlist Configuration ### URLs to Add ${allowedOrigins.map((url: string) => `- ${url}`).join('\n')} ### Configuration Format \`\`\` ${allowedOrigins.join('\n')} \`\`\` ## Advanced CORS Configuration (System Properties) For system administrators, you can also configure CORS via system properties: ### dhis.conf Configuration \`\`\`properties # CORS Configuration cors.allowedOrigins=${allowedOrigins.join(',')} cors.allowCredentials=true cors.allowedMethods=GET,POST,PUT,DELETE,OPTIONS,PATCH cors.allowedHeaders=Accept,Content-Type,Origin,X-Requested-With,Authorization cors.maxAge=3600 \`\`\` ## Environment-Specific Configurations ### Development Environment \`\`\` # Local development http://localhost:3000 http://localhost:3001 http://127.0.0.1:3000 # Common development ports http://localhost:8080 http://localhost:9000 \`\`\` ### Staging Environment \`\`\` https://staging-app.yourdomain.com https://test-app.yourdomain.com \`\`\` ### Production Environment \`\`\` https://app.yourdomain.com https://health-dashboard.yourdomain.com \`\`\` ## Validation Commands ### Test CORS Configuration \`\`\`bash # Test basic CORS curl -H "Origin: ${allowedOrigins[0]}" \\ ${dhis2Version ? `https://your-dhis2-instance.com/api/system/info` : 'https://your-dhis2-instance.com/api/system/info'} # Test with authentication curl -H "Origin: ${allowedOrigins[0]}" \\ -H "Authorization: Basic $(echo -n 'username:password' | base64)" \\ https://your-dhis2-instance.com/api/me # Test preflight request curl -H "Origin: ${allowedOrigins[0]}" \\ -H "Access-Control-Request-Method: POST" \\ -H "Access-Control-Request-Headers: Content-Type" \\ -X OPTIONS \\ https://your-dhis2-instance.com/api/dataElements \`\`\` ### Expected Response Headers \`\`\` Access-Control-Allow-Origin: ${allowedOrigins[0]} Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH Access-Control-Allow-Headers: Accept, Content-Type, Origin, X-Requested-With, Authorization Access-Control-Max-Age: 3600 \`\`\` ## Troubleshooting Common Issues ### Issue: "CORS allowlist not found" **Solution**: Update to DHIS2 2.35+ (older versions use different settings) ### Issue: "Changes not taking effect" **Solutions**: 1. Clear browser cache completely 2. Restart DHIS2 server (if self-hosted) 3. Wait 5-10 minutes for changes to propagate 4. Check if nginx/reverse proxy needs updating ### Issue: "Still getting CORS errors" **Checklist**: - [ ] URLs match exactly (including protocol) - [ ] No trailing slashes mismatch - [ ] Case sensitivity check - [ ] Wildcard not used (DHIS2 doesn't support wildcards) - [ ] Browser cache cleared ## Security Best Practices ### Development - Only add localhost URLs for development - Use specific ports, not wildcards - Remove development URLs before production ### Production - Only add your production domain(s) - Use HTTPS URLs only - Regularly audit allowed origins - Document all entries with purpose ### Monitoring \`\`\`bash # Check current CORS settings via API curl -u admin:password \\ https://your-dhis2-instance.com/api/systemSettings/keyJsCorallowlist \`\`\` ## Version-Specific Notes ${dhis2Version >= '2.38' ? ` ### DHIS2 ${dhis2Version}+ - Full CORS support available - GUI configuration available - API endpoint for configuration ` : ` ### DHIS2 ${dhis2Version} - Limited CORS support - May require manual configuration - Check documentation for version-specific settings `} `; } export function debugAuthentication(args: any): string { const { issueType, dhis2Instance, authMethod, errorDetails = {}, browserSettings = {} } = args; const diagnosis = []; const solutions = []; // Analyze authentication issue type switch (issueType) { case 'login_failure': diagnosis.push('Authentication credentials may be invalid or endpoint unreachable'); solutions.push('Verify username and password are correct'); solutions.push('Test credentials directly in DHIS2 web interface'); solutions.push('Check if account is locked or disabled'); break; case 'session_timeout': diagnosis.push('User session has expired or is not being maintained'); solutions.push('Implement session refresh mechanism'); solutions.push('Check session timeout settings in DHIS2'); solutions.push('Ensure cookies are being sent with requests'); break; case 'cookie_issues': diagnosis.push('Browser cookie handling issues affecting authentication'); solutions.push('Check SameSite cookie attributes'); solutions.push('Ensure cookies are enabled in browser'); solutions.push('Verify domain/path settings for cookies'); break; case 'token_problems': diagnosis.push('Authentication token is invalid, expired, or malformed'); solutions.push('Check token format and expiration'); solutions.push('Implement token refresh logic'); solutions.push('Verify token is included in Authorization header'); break; case 'proxy_auth': diagnosis.push('Proxy server authentication issues'); solutions.push('Check proxy credentials and configuration'); solutions.push('Verify proxy target URL is correct'); solutions.push('Ensure proxy is handling auth headers properly'); break; } // Analyze HTTP status codes if (errorDetails.httpStatus) { switch (errorDetails.httpStatus) { case 401: diagnosis.push('HTTP 401: Unauthorized - Invalid credentials'); solutions.push('Double-check username and password'); solutions.push('Ensure Authorization header is properly formatted'); break; case 403: diagnosis.push('HTTP 403: Forbidden - Valid credentials but insufficient permissions'); solutions.push('Check user authorities/permissions in DHIS2'); solutions.push('Verify user is assigned to appropriate user groups'); break; case 302: diagnosis.push('HTTP 302: Redirect - Authentication endpoint is redirecting'); solutions.push('Follow redirect chain to find final login endpoint'); solutions.push('Use direct API authentication instead of login forms'); break; case 404: diagnosis.push('HTTP 404: Not Found - Authentication endpoint does not exist'); solutions.push('Verify DHIS2 instance URL is correct'); solutions.push('Check if DHIS2 version supports the authentication method'); break; case 500: diagnosis.push('HTTP 500: Server Error - DHIS2 server experiencing issues'); solutions.push('Check DHIS2 server logs for detailed error information'); solutions.push('Verify database connectivity and server health'); break; } } return `# Authentication Debug Report ## Issue Details - **Issue Type**: ${issueType.replace(/_/g, ' ').toUpperCase()} - **DHIS2 Instance**: ${dhis2Instance} - **Auth Method**: ${authMethod.toUpperCase()} - **HTTP Status**: ${errorDetails.httpStatus || 'Not provided'} - **Error Message**: ${errorDetails.errorMessage || 'Not provided'} ## Diagnosis ${diagnosis.map(d => `- ${d}`).join('\n')} ## Recommended Solutions ${solutions.map((s, i) => `${i + 1}. ${s}`).join('\n')} ## Authentication Method Testing ${generateAuthMethodTests(authMethod, dhis2Instance)} ## Browser Settings Analysis ${browserSettings.cookiesEnabled !== undefined ? `- **Cookies Enabled**: ${browserSettings.cookiesEnabled ? 'Yes' : 'No'}` : ''} ${browserSettings.thirdPartyCookies !== undefined ? `- **Third-party Cookies**: ${browserSettings.thirdPartyCookies ? 'Enabled' : 'Disabled'}` : ''} ${browserSettings.sameSiteSettings ? `- **SameSite Settings**: ${browserSettings.sameSiteSettings}` : ''} ## Debug Commands ### Test Authentication Endpoint \`\`\`bash # Test basic authentication curl -X POST \\ -H "Content-Type: application/json" \\ -d '{"username":"your-username","password":"your-password"}' \\ ${dhis2Instance}/api/auth/login # Test current user endpoint curl -H "Authorization: Basic $(echo -n 'username:password' | base64)" \\ ${dhis2Instance}/api/me \`\`\` ### Network Analysis \`\`\`javascript // Browser console - check authentication headers fetch('${dhis2Instance}/api/me', { method: 'GET', headers: { 'Authorization': 'Basic ' + btoa('username:password') }, credentials: 'include' }).then(response => { console.log('Status:', response.status); console.log('Headers:', [...response.headers.entries()]); return response.json(); }).then(data => console.log('User data:', data)) .catch(err => console.error('Error:', err)); \`\`\` ## Browser Dev Tools Checklist 1. **Network Tab**: - [ ] Authentication request sent - [ ] Correct Authorization header present - [ ] Response status code - [ ] Set-Cookie headers in response 2. **Application Tab**: - [ ] Cookies stored correctly - [ ] Local/Session storage items - [ ] Cookie domain and path settings 3. **Console**: - [ ] No CORS errors - [ ] No cookie warnings - [ ] No security policy violations ## Common Authentication Patterns ### Basic Authentication \`\`\`javascript const credentials = btoa(\`\${username}:\${password}\`); fetch('/api/me', { headers: { 'Authorization': \`Basic \${credentials}\` } }); \`\`\` ### Cookie-based Authentication \`\`\`javascript // Login fetch('/dhis-web-commons-security/login.action', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: \`j_username=\${username}&j_password=\${password}\`, credentials: 'include' }); // Subsequent requests fetch('/api/me', { credentials: 'include' }); \`\`\` ## Environment-Specific Issues ### Development Environment - CORS configuration - Proxy authentication - Self-signed certificates - Local network restrictions ### Production Environment - Load balancer configuration - SSL/TLS certificate issues - Firewall restrictions - Session persistence ## Session Management Best Practices 1. **Session Timeout**: Configure appropriate timeout values 2. **Session Refresh**: Implement automatic session renewal 3. **Secure Storage**: Store credentials/tokens securely 4. **Logout Cleanup**: Clear all auth data on logout ## Security Considerations ⚠️ **Never log credentials in production** ⚠️ **Use HTTPS for authentication in production** ⚠️ **Implement proper session management** ⚠️ **Regular security audits of authentication flow** `; } function generateAuthMethodTests(authMethod: string, dhis2Instance: string): string { switch (authMethod) { case 'basic': return `### Basic Authentication Test \`\`\`bash # Test basic auth credentials curl -v -u username:password ${dhis2Instance}/api/me # Check response headers curl -I -u username:password ${dhis2Instance}/api/me \`\`\``; case 'oauth2': return `### OAuth2 Authentication Test \`\`\`bash # Step 1: Get authorization code open "${dhis2Instance}/uaa/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI" # Step 2: Exchange code for token curl -X POST \\ -H "Content-Type: application/x-www-form-urlencoded" \\ -d "grant_type=authorization_code&code=AUTH_CODE&redirect_uri=YOUR_REDIRECT_URI" \\ -u "CLIENT_ID:CLIENT_SECRET" \\ ${dhis2Instance}/uaa/oauth/token \`\`\``; case 'cookie': return `### Cookie-based Authentication Test \`\`\`bash # Test cookie authentication curl -c cookies.txt -b cookies.txt \\ -d "j_username=username&j_password=password" \\ -X POST \\ ${dhis2Instance}/dhis-web-commons-security/login.action # Test with saved cookies curl -b cookies.txt ${dhis2Instance}/api/me \`\`\``; case 'token': return `### Token-based Authentication Test \`\`\`bash # Get token TOKEN=$(curl -s -X POST \\ -H "Content-Type: application/json" \\ -d '{"username":"your-username","password":"your-password"}' \\ ${dhis2Instance}/api/auth/token | jq -r '.token') # Use token curl -H "Authorization: Bearer $TOKEN" ${dhis2Instance}/api/me \`\`\``; default: return '### Custom Authentication Test\n```bash\n# Add your authentication test commands here\n```'; } } export function generateProxyConfiguration(args: any): string { const { proxyType, targetInstance, localPort = 3000, authentication, sslOptions = {} } = args; return `# Proxy Configuration for DHIS2 Development ## ${proxyType.replace(/_/g, ' ').toUpperCase()} Configuration ${generateProxyConfig(proxyType, targetInstance, localPort, authentication, sslOptions)} ## Testing Proxy Configuration ### Test Proxy Connection \`\`\`bash # Test direct connection to DHIS2 curl ${targetInstance}/api/me # Test through proxy curl http://localhost:${localPort}/api/me \`\`\` ### Browser Testing 1. Start your application with proxy enabled 2. Open browser dev tools Network tab 3. Navigate to your application 4. Check that API requests go to localhost:${localPort} 5. Verify requests are forwarded to ${targetInstance} ## Common Proxy Issues and Solutions ### Issue: 502 Bad Gateway **Causes**: - Target DHIS2 instance is unreachable - Authentication credentials are incorrect - SSL certificate verification failing **Solutions**: - Verify target instance URL: ${targetInstance} - Check authentication credentials - ${sslOptions.secure === false ? 'SSL verification is disabled (good for development)' : 'Consider disabling SSL verification for development'} ### Issue: Authentication Not Working **Solutions**: - Ensure credentials are correct: ${authentication?.username || '[username]'} - Check if user account is locked - Verify proxy is forwarding auth headers ### Issue: CORS Still Occurring **Solutions**: - Restart development server after proxy configuration - Clear browser cache completely - Check proxy configuration syntax ## Security Considerations ### Development Environment ✅ **Safe for development**: - Using proxy to avoid CORS issues - Credentials stored in configuration files ${sslOptions.secure === false ? '- SSL verification disabled for development certificates' : ''} ⚠️ **Security reminders**: - Never commit credentials to version control - Use separate development credentials - Enable SSL verification in production ### Production Environment ❌ **Not suitable for production**: - This proxy configuration is for development only - Production should use proper authentication flows - Enable all security features for production deployment ## Environment Variables Create a \`.env.local\` file: \`\`\`bash # Proxy configuration DHIS2_PROXY_TARGET=${targetInstance} DHIS2_PROXY_USERNAME=${authentication?.username || 'your-username'} DHIS2_PROXY_PASSWORD=${authentication?.password || 'your-password'} PROXY_PORT=${localPort} \`\`\` ## Alternative Solutions ### 1. DHIS2 CLI Proxy \`\`\`bash # Use built-in DHIS2 CLI proxy yarn start --proxy \`\`\` ### 2. Local DHIS2 Instance \`\`\`bash # Set up local development instance npx @dhis2/cli cluster init d2 cluster up \`\`\` ### 3. Browser Extension - Use CORS browser extensions for development - ⚠️ Remember to disable in production `; } function generateProxyConfig(proxyType: string, targetInstance: string, localPort: number, authentication: any, sslOptions: any): string { switch (proxyType) { case 'webpack_dev_server': return `### Webpack Dev Server Configuration \`\`\`javascript // webpack.config.js module.exports = { devServer: { port: ${localPort}, proxy: { '/api': { target: '${targetInstance}', changeOrigin: true, secure: ${sslOptions.secure !== false}, ${authentication ? `auth: '${authentication.username}:${authentication.password}',` : ''} headers: { 'Authorization': 'Basic ' + Buffer.from('${authentication?.username || 'username'}:${authentication?.password || 'password'}').toString('base64') } } } } }; \`\`\``; case 'create_react_app': return `### Create React App Configuration #### Option 1: package.json proxy field \`\`\`json { "name": "my-dhis2-app", "proxy": "${targetInstance}", "scripts": { "start": "react-scripts start" } } \`\`\` #### Option 2: setupProxy.js (for advanced configuration) \`\`\`javascript // src/setupProxy.js const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app) { app.use( '/api', createProxyMiddleware({ target: '${targetInstance}', changeOrigin: true, secure: ${sslOptions.secure !== false}, ${authentication ? `auth: '${authentication.username}:${authentication.password}',` : ''} headers: { 'Authorization': 'Basic ' + Buffer.from('${authentication?.username || 'username'}:${authentication?.password || 'password'}').toString('base64') } }) ); }; \`\`\` #### Start with proxy \`\`\`bash npm start \`\`\``; case 'vite': return `### Vite Configuration \`\`\`javascript // vite.config.js import { defineConfig } from 'vite'; export default defineConfig({ server: { port: ${localPort}, proxy: { '/api': { target: '${targetInstance}', changeOrigin: true, secure: ${sslOptions.secure !== false}, configure: (proxy, options) => { proxy.on('proxyReq', (proxyReq, req, res) => { const auth = Buffer.from('${authentication?.username || 'username'}:${authentication?.password || 'password'}').toString('base64'); proxyReq.setHeader('Authorization', \`Basic \${auth}\`); }); } } } } }); \`\`\` #### Start development server \`\`\`bash npm run dev \`\`\``; case 'custom_express': return `### Custom Express Proxy Server \`\`\`javascript // proxy-server.js const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express(); const proxyOptions = { target: '${targetInstance}', changeOrigin: true, secure: ${sslOptions.secure !== false}, ${authentication ? `auth: '${authentication.username}:${authentication.password}',` : ''} pathRewrite: { '^/proxy': '', // Remove /proxy prefix }, onProxyReq: (proxyReq, req, res) => { const auth = Buffer.from('${authentication?.username || 'username'}:${authentication?.password || 'password'}').toString('base64'); proxyReq.setHeader('Authorization', \`Basic \${auth}\`); }, logLevel: 'debug' }; app.use('/api', createProxyMiddleware(proxyOptions)); // Serve static files app.use(express.static('public')); app.listen(${localPort}, () => { console.log(\`Proxy server running on http://localhost:${localPort}\`); console.log(\`Forwarding to: ${targetInstance}\`); }); \`\`\` #### Start proxy server \`\`\`bash node proxy-server.js \`\`\``; default: return '### Custom Proxy Configuration\n```javascript\n// Add your proxy configuration here\n```'; } } export function resolveBuildIssues(args: any): string { const { buildTool, issueType, errorMessage = '', packageManager = 'npm', nodeVersion, dependencies = {} } = args; const diagnosis = []; const solutions = []; // Analyze build tool specific issues if (buildTool === 'd2_cli_deprecated') { diagnosis.push('⚠️ The d2 CLI library has been deprecated'); solutions.push('Migrate to @dhis2/app-platform for modern DHIS2 development'); solutions.push('Use the migration assistant: `dhis2_migration_assistant` tool'); solutions.push('Reference: https://developers.dhis2.org/docs/app-platform/getting-started'); } // Analyze specific issue types switch (issueType) { case 'dependency_conflicts': diagnosis.push('Conflicting package versions or peer dependency issues'); solutions.push('Clear node_modules and package lock file'); solutions.push(`rm -rf node_modules ${packageManager === 'yarn' ? 'yarn.lock' : 'package-lock.json'}`); solutions.push(`${packageManager} install`); if (packageManager === 'yarn' && dependencies.dhis2Cli) { solutions.push('Ensure using yarn for DHIS2 projects (yarn.lock included)'); } break; case 'module_resolution': diagnosis.push('Module resolution failing - TypeScript or import path issues'); solutions.push('Check tsconfig.json paths configuration'); solutions.push('Verify all imports use correct file extensions'); solutions.push('Ensure moduleResolution is set to "node" in tsconfig.json'); break; case 'bundle_size': diagnosis.push('Bundle size exceeding limits or performance issues'); solutions.push('Implement code splitting with React.lazy()'); solutions.push('Use tree shaking to eliminate dead code'); solutions.push('Analyze bundle with: npm run build -- --analyze'); break; case 'tree_shaking': diagnosis.push('Dead code elimination not working properly'); solutions.push('Ensure using ES6 modules (import/export)'); solutions.push('Check sideEffects configuration in package.json'); solutions.push('Upgrade to latest @dhis2/cli-app-scripts version'); break; case 'compilation_errors': diagnosis.push('TypeScript or JavaScript compilation failing'); solutions.push('Check for TypeScript version compatibility'); solutions.push('Verify all types are properly imported'); solutions.push('Run type check separately: npm run type-check'); break; case 'memory_issues': diagnosis.push('Build process running out of memory'); solutions.push('Increase Node.js memory limit: --max-old-space-size=4096'); solutions.push('Use incremental builds when possible'); solutions.push('Consider splitting large applications'); break; } // Node.js version specific issues if (nodeVersion) { const majorVersion = parseInt(nodeVersion.split('.')[0]); if (majorVersion < 16) { diagnosis.push(`Node.js version ${nodeVersion} may be too old for modern DHIS2 development`); solutions.push('Upgrade to Node.js 16+ (LTS recommended)'); solutions.push('Use Node Version Manager (nvm) for easy version switching'); } else if (majorVersion >= 18) { diagnosis.push('Node.js 18+ may have stricter module resolution'); solutions.push('Ensure all dependencies support Node.js ' + majorVersion); } } return `# Build Issues Resolution ## Issue Analysis - **Build Tool**: ${buildTool.replace(/_/g, ' ').toUpperCase()} - **Issue Type**: ${issueType.replace(/_/g, ' ').toUpperCase()} - **Package Manager**: ${packageManager.toUpperCase()} - **Node Version**: ${nodeVersion || 'Not specified'} - **Error**: ${errorMessage} ## Diagnosis ${diagnosis.map(d => `- ${d}`).join('\n')} ## Immediate Solutions ${solutions.map((s, i) => `${i + 1}. ${s}`).join('\n')} ## Build Tool Specific Fixes ${generateBuildToolFixes(buildTool, dependencies)} ## Version Compatibility Check ### Current Dependencies ${Object.entries(dependencies).map(([key, version]) => `- **${key}**: ${version}`).join('\n')} ### Recommended Versions - **@dhis2/cli-app-scripts**: ^10.3.0+ - **@dhis2/app-platform**: ^11.0.0+ - **Node.js**: 16.x or 18.x (LTS) - **npm**: 8.x+ - **yarn**: 1.22.x+ ## Generic Build Troubleshooting ### Clear Build Artifacts \`\`\`bash # Clear all caches and artifacts rm -rf node_modules rm -rf dist rm -rf build rm -rf .cache ${packageManager === 'yarn' ? 'rm yarn.lock' : 'rm package-lock.json'} # Fresh install ${packageManager} install \`\`\` ### Memory Issues \`\`\`bash # Increase memory limit export NODE_OPTIONS="--max-old-space-size=4096" npm run build # Alternative: Set in package.json scripts "build": "NODE_OPTIONS='--max-old-space-size=4096' react-scripts build" \`\`\` ### Debug Build Process \`\`\`bash # Verbose build output npm run build -- --verbose # TypeScript compilation check npx tsc --noEmit # ESLint check npx eslint src/ \`\`\` ## Performance Optimization ### Bundle Analysis \`\`\`bash # Analyze bundle size npm run build -- --analyze # Alternative tools npx webpack-bundle-analyzer build/static/js/*.js npx source-map-explorer build/static/js/*.js \`\`\` ### Code Splitting Example \`\`\`javascript // Implement lazy loading const LazyComponent = React.lazy(() => import('./LazyComponent')); function App() { return ( <Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </Suspense> ); } \`\`\` ### Tree Shaking Configuration \`\`\`json // package.json { "sideEffects": false, "main": "lib/index.js", "module": "es/index.js" } \`\`\` ## Environment-Specific Issues ### Development Build Issues - Hot reload not working - Slow compilation times - Memory leaks in watch mode ### Production Build Issues - Minification errors - Missing environment variables - Asset path issues ## Migration Recommendations ${buildTool === 'd2_cli_deprecated' ? ` ### Migrate from d2 CLI to App Platform 1. **Install App Platform** \`\`\`bash npm install --save-dev @dhis2/cli-app-scripts \`\`\` 2. **Update package.json scripts** \`\`\`json { "scripts": { "start": "d2-app-scripts start", "build": "d2-app-scripts build", "test": "d2-app-scripts test", "deploy": "d2-app-scripts deploy" } } \`\`\` 3. **Create d2.config.js** \`\`\`javascript const config = { type: 'app', name: 'my-app', title: 'My DHIS2 App', description: 'A DHIS2 application' }; module.exports = config; \`\`\` 4. **Update imports** - Replace d2 library imports - Use @dhis2/app-runtime for API calls - Update component imports to @dhis2/ui ` : ''} ## Support Resources - **DHIS2 Developer Portal**: https://developers.dhis2.org - **Community Forum**: https://community.dhis2.org/c/development - **GitHub Issues**: https://github.com/dhis2/app-platform/issues - **Documentation**: https://docs.dhis2.org ## Automated Diagnostics \`\`\`bash # Run comprehensive diagnostics npx @dhis2/cli-app-scripts doctor # Check environment setup npx envinfo --binaries --languages --utilities \`\`\` `; } function generateBuildToolFixes(buildTool: string, dependencies: any): string { switch (buildTool) { case 'app_platform': return `### DHIS2 App Platform Fixes #### Update to Latest Version \`\`\`bash npm install --save-dev @dhis2/cli-app-scripts@latest \`\`\` #### Configuration Check \`\`\`javascript // d2.config.js validation const config = { type: 'app', name: 'my-app', // Must be valid package name title: 'My App', description: 'App description', // Optional: Custom entry points entryPoints: { app: './src/App.js' } }; module.exports = config; \`\`\` #### Common App Platform Issues 1. **Missing d2.config.js**: App Platform requires this configuration file 2. **Invalid app name**: Must follow npm package naming rules 3. **Missing manifest.webapp**: Required for DHIS2 app installation`; case 'webpack': return `### Webpack Configuration Fixes #### Update Webpack \`\`\`bash npm install --save-dev webpack@latest webpack-cli@latest \`\`\` #### Basic webpack.config.js \`\`\`javascript const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [ { test: /\\.jsx?$/, exclude: /node_modules/, use: 'babel-loader' } ] } }; \`\`\``; case 'vite': return `### Vite Configuration Fixes #### Update Vite \`\`\`bash npm install --save-dev vite@latest @vitejs/plugin-react@latest \`\`\` #### vite.config.js \`\`\`javascript import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { outDir: 'build' } }); \`\`\``; default: return '### Custom Build Tool Fixes\n```bash\n# Add specific fixes for your build tool\n```'; } } export function generatePerformanceOptimizations(args: any): string { const { performanceIssue, metrics = {}, targetMetrics = {}, appComplexity = 'moderate' } = args; return `# DHIS2 App Performance Optimization ## Current Performance Analysis - **Issue Type**: ${performanceIssue.replace(/_/g, ' ').toUpperCase()} - **App Complexity**: ${appComplexity.toUpperCase()} ### Current Metrics ${Object.entries(metrics).map(([key, value]) => `- **${key.replace(/_/g, ' ').toUpperCase()}**: ${value}${getMetricUnit(key)}`).join('\n')} ### Target Metrics ${Object.entries(targetMetrics).map(([key, value]) => `- **${key.replace(/target_/g, '').replace(/_/g, ' ').toUpperCase()}**: ${value}${getMetricUnit(key.replace('target_', ''))}`).join('\n')} ## Optimization Strategy ${generateOptimizationStrategy(performanceIssue, metrics, appComplexity)} ## Implementation Guide ${generateImplementationGuide(performanceIssue)} ## Monitoring and Measurement ### Performance Testing Setup \`\`\`javascript // Performance measurement utility const measurePerformance = (name, fn) => { const start = performance.now(); const result = fn(); const end = performance.now(); console.log(\`\${name} took \${end - start} milliseconds\`); return result; }; // Usage example measurePerformance('Data Element Load', () => { // Load data elements }); \`\`\` ### Browser Performance API \`\`\`javascript // Track Core Web Vitals import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'; getCLS(console.log); getFID(console.log); getFCP(console.log); getLCP(console.log); getTTFB(console.log); \`\`\` ## Performance Budget ${generatePerformanceBudget(appComplexity)} ## DHIS2-Specific Optimizations ${generateDHIS2Optimizations()} ## Monitoring Dashboard \`\`\`javascript // Simple performance dashboard component const PerformanceDashboard = () => { const [metrics, setMetrics] = React.useState({}); React.useEffect(() => { // Collect performance metrics const observer = new PerformanceObserver((list) => { const entries = list.getEntries(); setMetrics(prev => ({ ...prev, ...entries.reduce((acc, entry) => ({ ...acc, [entry.name]: entry.duration }), {}) })); }); observer.observe({ entryTypes: ['measure'] }); return () => observer.disconnect(); }, []); return ( <div> <h3>Performance Metrics</h3> {Object.entries(metrics).map(([name, value]) => ( <p key={name}>{name}: {value.toFixed(2)}ms</p> ))} </div> ); }; \`\`\` `; } function getMetricUnit(metric: string): string { switch (metric) { case 'loadTime': case 'apiResponseTime': return 'ms'; case 'bundleSize': return 'KB'; case 'memoryUsage': return 'MB'; default: return ''; } } function generateOptimizationStrategy(issue: string, metrics: any, complexity: string): string { switch (issue) { case 'slow_loading': return `### Slow Loading Optimization Strategy #### Immediate Actions (Quick Wins) 1. **Code Splitting**: Implement lazy loading for routes and components 2. **Bundle Analysis**: Identify and remove unnecessary dependencies 3. **Image Optimization**: Compress and lazy load images 4. **Preloading**: Preload critical resources #### Medium-term Actions 1. **Service Worker**: Implement caching strategies 2. **CDN**: Use CDN for static assets 3. **Database Optimization**: Optimize DHIS2 queries 4. **Component Optimization**: Memoize expensive components #### Long-term Actions 1. **Architecture Review**: Consider micro-frontends for complex apps 2. **Progressive Enhancement**: Implement progressive loading 3. **Performance Monitoring**: Set up continuous monitoring`; case 'memory_leaks': return `### Memory Leak Resolution Strategy #### Detection 1. **Chrome DevTools**: Use Memory tab to identify leaks 2. **Component Profiling**: Use React Profiler 3. **Event Listener Audit**: Check for unremoved listeners #### Common React Memory Leaks 1. **Unmounted Components**: Clean up subscriptions in useEffect 2. **Event Listeners**: Remove listeners in cleanup functions 3. **Timers**: Clear intervals and timeouts 4. **DOM References**: Avoid storing DOM nodes in state #### DHIS2-Specific Leaks 1. **Data Query Subscriptions**: Properly cleanup useDataQuery 2. **WebSocket Connections**: Close connections on unmount 3. **Large Datasets**: Implement virtual scrolling`; case 'api_bottlenecks': return `### API Performance Optimization #### Request Optimization 1. **Batch Requests**: Combine multiple API calls 2. **Pagination**: Implement proper pagination 3. **Field Selection**: Only request needed fields 4. **Caching**: Implement request caching #### DHIS2 API Optimization 1. **Query Parameters**: Use optimal filter and field parameters 2. **Bulk Operations**: Use bulk endpoints for mass operations 3. **Analytics Optimization**: Optimize analytics queries 4. **Metadata Caching**: Cache metadata locally`; default: return '### Generic Performance Strategy\n- Identify bottlenecks\n- Implement optimizations\n- Monitor improvements'; } } function generateImplementationGuide(issue: string): string { switch (issue) { case 'slow_loading': return `### Code Splitting Implementation \`\`\`javascript // Route-based code splitting import { lazy, Suspense } from 'react'; const DataEntry = lazy(() => import('./pages/DataEntry')); const Reports = lazy(() => import('./pages/Reports')); function App() { return ( <Suspense fallback={<div>Loading...</div>}> <Routes> <Route path="/data-entry" element={<DataEntry />} /> <Route path="/reports" element={<Reports />} /> </Routes> </Suspense> ); } \`\`\` ### Bundle Optimization \`\`\`javascript // webpack.config.js optimization module.exports = { optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\\\/]node_modules[\\\\/]/, name: 'vendors', chunks: 'all', }, dhis2: { test: /[\\\\/]node_modules[\\\\/]@dhis2[\\\\/]/, name: 'dhis2', chunks: 'all', }, }, }, }, }; \`\`\``; case 'memory_leaks': return `### Memory Leak Prevention \`\`\`javascript // Proper cleanup in React hooks function MyComponent() { React.useEffect(() => { const subscription = dataService.subscribe(handleData); const interval = setInterval(updateData, 1000); return () => { subscription.unsubscribe(); clearInterval(interval); }; }, []); const handleData = React.useCallback((data) => { // Handle data }, []); return <div>Component content</div>; } \`\`\` ### DHIS2 Data Query Cleanup \`\`\`javascript // Proper useDataQuery usage function DataComponent() { const { loading, error, data, refetch } = useDataQuery(query); React.useEffect(() => { return () => { // Cleanup is handled automatically by useDataQuery // but you can add custom cleanup here if needed }; }, []); return loading ? <Loading /> : <DataDisplay data={data} />; } \`\`\``; default: return '### Implementation Guide\n```javascript\n// Add specific implementation details\n```'; } } function generatePerformanceBudget(complexity: string): string { let budgets; switch (complexity) { case 'simple': budgets = { 'Bundle Size': '< 200KB', 'Load Time': '< 2 seconds', 'API Response': '< 500ms', 'Memory Usage': '< 50MB' }; break; case 'moderate': budgets = { 'Bundle Size': '< 500KB', 'Load Time': '< 3 seconds', 'API Response': '< 1 second', 'Memory Usage': '< 100MB' }; break; case 'complex': budgets = { 'Bundle Size': '< 1MB', 'Load Time': '< 5 seconds', 'API Response': '< 2 seconds', 'Memory Usage': '< 200MB' }; break; default: budgets = { 'Bundle Size': '< 500KB', 'Load Time': '< 3 seconds', 'API Response': '< 1 second', 'Memory Usage': '< 100MB' }; } return `### Performance Budget for ${complexity.toUpperCase()} App ${Object.entries(budgets).map(([metric, target]) => `- **${metric}**: ${target}`).join('\n')} ### Budget Configuration (webpack-bundle-analyzer) \`\`\`json { "budgets": [ { "type": "bundle", "name": "main", "maximumError": "${budgets['Bundle Size'].replace('< ', '').replace('KB', '').replace('MB', '000')}kb" } ] } \`\`\``; } function generateDHIS2Optimizations(): string { return `### API Request Optimization \`\`\`javascript // Optimize DHIS2 API requests const optimizedQuery = { dataElements: { resource: 'dataElements', params: { fields: 'id,displayName,valueType', // Only request needed fields filter: 'domainType:eq:AGGREGATE', // Filter server-side pageSize: 50, // Reasonable page size paging: true // Enable pagination } } }; \`\`\` ### Metadata Caching \`\`\`javascript // Cache metadata for performance const MetadataCache = { cache: new Map(), get(key) { const cached = this.cache.get(key); if (cached && Date.now() - cached.timestamp < 5 * 60 * 1000) { // 5 minutes return cached.data; } return null; }, set(key, data) { this.cache.set(key, { data, timestamp: Date.now() }); } }; \`\`\` ### Virtual Scrolling for Large Lists \`\`\`javascript // Use react-window for large datasets import { VariableSizeList } from 'react-window'; const VirtualizedDataElementList = ({ dataElements }) => { const getItemSize = (index) => 60; // Height of each item const renderItem = ({ index, style }) => ( <div style={style}> {dataElements[index].displayName} </div> ); return ( <VariableSizeList height={400} itemCount={dataElements.length} itemSize={getItemSize} itemData={dataElements} > {renderItem} </VariableSizeList> ); }; \`\`\` ### Debounced Search \`\`\`javascript // Debounce search requests import { useDebounce } from 'use-debounce'; const SearchableList = () => { const [searchTerm, setSearchTerm] = useState(''); const [debouncedSearchTerm] = useDebounce(searchTerm, 300); const query = { dataElements: { resource: 'dataElements', params: { filter: debouncedSearchTerm ? \`name:ilike:\${debouncedSearchTerm}\` : undefined } } }; const { data } = useDataQuery(query, { enabled: debouncedSearchTerm.length > 2 }); return ( <div> <input value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="Search..." /> {/* Render results */} </div> ); }; \`\`\``; } export function validateEnvironment(args: any): string { const { checkAll = false, components = [], nodeVersion, dhis2Instance, operatingSystem = 'unknown' } = args; const checks = checkAll ? [ 'node_version', 'npm_yarn', 'dhis2_cli', 'browser_settings', 'network_connectivity', 'cors_config' ] : components; return `# DHIS2 Development Environment Validation ## Environment Information - **Operating System**: ${operatingSystem.toUpperCase()} - **Node Version**: ${nodeVersion || 'Not provided'} - **DHIS2 Instance**: ${dhis2Instance || 'Not provided'} ## Validation Results ${checks.map((check: string) => generateEnvironmentCheck(check, { nodeVersion, dhis2Instance, operatingSystem })).join('\n\n')} ## Automated Validation Script \`\`\`bash #!/bin/bash # DHIS2 Environment Validator echo "🔍 DHIS2 Development Environment Validation" echo "============================================" # Node.js version check echo "📦 Checking Node.js version..." NODE_VERSION=$(node --version) echo "Node.js: $NODE_VERSION" if [[ "$NODE_VERSION" < "v16" ]]; then echo "❌ Node.js 16+ required" else echo "✅ Node.js version OK" fi # Package manager check echo "📦 Checking package managers..." if command -v npm &> /dev/null; then echo "✅ npm: $(npm --version)" else echo "❌ npm not found" fi if command -v yarn &> /dev/null; then echo "✅ yarn: $(yarn --version)" else echo "⚠️ yarn not found (recommended for DHIS2)" fi # DHIS2 CLI check echo "🔧 Checking DHIS2 CLI tools..." if command -v d2 &> /dev/null; then echo "✅ d2 CLI: $(d2 --version)" else echo "❌ d2 CLI not found" echo "Install: npm install -g @dhis2/cli" fi # Network connectivity check ${dhis2Instance ? ` echo "🌐 Testing DHIS2 instance connectivity..." if curl -Is "${dhis2Instance}/api/system/info" | head -n 1 | grep -q "200 OK"; then echo "✅ DHIS2 instance reachable" else echo "❌ Cannot reach DHIS2 instance" fi ` : ''} echo "✅ Environment validation complete" \`\`\` ## Fix Common Issues ### Node.js Version Issues \`\`\`bash # Install Node Version Manager curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash # Install and use Node.js 18 LTS nvm install 18 nvm use 18 nvm alias default 18 \`\`\` ### Package Manager Issues \`\`\`bash # Install/Update yarn (recommended for DHIS2) npm install -g yarn # Clear package caches npm cache clean --force yarn cache clean \`\`\` ### DHIS2 CLI Issues \`\`\`bash # Install DHIS2 CLI tools npm install -g @dhis2/cli # Verify installation d2 --version d2 --help \`\`\` ## Development Environment Setup ### Complete Setup Script \`\`\`bash #!/bin/bash # Complete DHIS2 development environment setup echo "🚀 Setting up DHIS2 development environment..." # Install Node.js 18 LTS (if using nvm) nvm install 18 nvm use 18 # Install global tools npm install -g @dhis2/cli yarn # Verify installations echo "Node.js: $(node --version)" echo "npm: $(npm --version)" echo "yarn: $(yarn --version)" echo "DHIS2 CLI: $(d2 --version)" # Create development project mkdir my-dhis2-app cd my-dhis2-app # Initialize DHIS2 app d2 app scripts init my-app cd my-app # Install dependencies yarn install echo "✅ DHIS2 development environment ready!" echo "Run 'yarn start' to begin development" \`\`\` ## IDE Configuration ### VS Code Extensions \`\`\`json { "recommendations": [ "ms-vscode.vscode-typescript-next", "bradlc.vscode-tailwindcss", "esbenp.prettier-vscode", "ms-vscode.vscode-eslint", "formulahendry.auto-rename-tag", "christian-kohler.path-intellisense" ] } \`\`\` ### VS Code Settings \`\`\`json { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "typescript.preferences.importModuleSpecifier": "relative", "emmet.includeLanguages": { "javascript": "javascriptreact" } } \`\`\` ## Troubleshooting Common Environment Issues ### Permission Issues (macOS/Linux) \`\`\`bash # Fix npm permissions sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share} # Alternative: Use nvm to avoid sudo curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \`\`\` ### Windows-Specific Issues \`\`\`powershell # Set execution policy (Windows PowerShell as Administrator) Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # Install Node.js via Chocolatey choco install nodejs # Install yarn choco install yarn \`\`\` ### Network/Corporate Firewall Issues \`\`\`bash # Configure npm proxy (if behind corporate firewall) npm config set proxy http://proxy.company.com:8080 npm config set https-proxy http://proxy.company.com:8080 # Configure yarn proxy yarn config set proxy http://proxy.company.com:8080 yarn config set https-proxy http://proxy.company.com:8080 \`\`\` `; } function generateEnvironmentCheck(check: string, context: any): string { switch (check) { case 'node_version': return `### Node.js Version Check ${context.nodeVersion ? ` - **Current Version**: ${context.nodeVersion} - **Status**: ${context.nodeVersion ? checkNodeVersion(context.nodeVersion) : '❌ Not available'} ` : ` - **Status**: ❌ Node.js version not provided - **Action**: Run \`node --version\` to check current version `} - **Recommended**: Node.js 16.x or 18.x LTS - **Minimum**: Node.js 14.x`; case 'npm_yarn': return `### Package Manager Check \`\`\`bash # Check package manager versions node --version npm --version yarn --version \`\`\` - **npm**: Required for Node.js package management - **yarn**: Recommended for DHIS2 projects (includes yarn.lock files) - **Status**: Run commands above to verify installation`; case 'dhis2_cli': return `### DHIS2 CLI Tools Check \`\`\`bash # Install DHIS2 CLI npm install -g @dhis2/cli # Verify installation d2 --version d2 app --help d2 cluster --help \`\`\` - **Required for**: App scaffolding, development server, deployment - **Alternative**: Use npx if global installation is not preferred`; case 'browser_settings': return `### Browser Settings Check #### Chrome (Recommended for Development) - [ ] Developer Tools accessible (F12) - [ ] Allow cross-origin requests (for development) - [ ] Extensions disabled for testing #### Firefox - [ ] about:config accessible - [ ] CORS settings configurable - [ ] Developer Tools available #### Settings to verify: - Cookies enabled - JavaScript enabled - Local storage available - Network tab in dev tools functional`; case 'network_connectivity': return `### Network Connectivity Check ${context.dhis2Instance ? ` \`\`\`bash # Test DHIS2 instance connectivity curl -I ${context.dhis2Instance}/api/system/info # Test with authentication curl -u username:password ${context.dhis2Instance}/api/me \`\`\` - **Target Instance**: ${context.dhis2Instance} - **Expected Response**: 200 OK with JSON content ` : ` \`\`\`bash # Test general connectivity ping google.com curl -I https://github.com # Test npm registry npm ping \`\`\` - **Status**: Verify internet connectivity and npm registry access `}`; case 'cors_config': return `### CORS Configuration Check ${context.dhis2Instance ? ` #### Test CORS Headers \`\`\`bash # Test CORS preflight curl -H "Origin: http://localhost:3000" \\ -H "Access-Control-Request-Method: GET" \\ -H "Access-Control-Request-Headers: Content-Type" \\ -X OPTIONS \\ ${context.dhis2Instance}/api/me \`\`\` #### Expected Headers - \`Access-Control-Allow-Origin: http://localhost:3000\` - \`Access-Control-Allow-Credentials: true\` - \`Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS\` #### Configuration Steps 1. Login to DHIS2 as administrator 2. Navigate to System Settings → Access 3. Add development URLs to CORS allowlist ` : ` #### CORS Configuration Requirements - DHIS2 instance must allow cross-origin requests - Development URLs must be in CORS allowlist - Proper preflight handling required #### Common Issues - Missing CORS allowlist entries - Incorrect URL formats (protocol, port) - Browser cache preventing updates `}`; default: return `### ${check.replace(/_/g, ' ').toUpperCase()} Check - Status: Not implemented - Action: Add specific validation for this component`; } } function checkNodeVersion(version: string): string { // Simplified version check to avoid TypeScript issues if (version.includes('16.') || version.includes('18.')) return '✅ Compatible'; if (version.includes('14.') || version.includes('15.')) return '⚠️ Older version (recommend: 16.x+)'; if (version.includes('19.') || version.includes('20.')) return '⚠️ Very new (test compatibility)'; return '❓ Unknown version format'; } export function generateMigrationGuide(args: any): string { const { currentStack, targetPlatform = {}, migrationScope = 'incremental', codeComplexity = 'moderate' } = args; return `# DHIS2 Migration Guide: d2 Library to App Platform ## Migration Overview - **Current Stack**: d2 ${currentStack?.d2Version || 'unknown'}, React ${currentStack?.reactVersion || 'unknown'}, ${currentStack?.buildSystem || 'unknown'} - **Target Platform**: App Platform ${targetPlatform?.appPlatformVersion || 'latest'} - **Migration Scope**: ${migrationScope.replace(/_/g, ' ').toUpperCase()} - **Code Complexity**: ${codeComplexity.toUpperCase()} ⚠️ **Important**: The d2 library is deprecated. Modern DHIS2 development uses @dhis2/app-platform. ## Pre-Migration Checklist - [ ] Backup current codebase - [ ] Document current dependencies - [ ] Test current functionality thoroughly - [ ] Review breaking changes in target platform - [ ] Plan rollback strategy ## Step-by-Step Migration ### 1. Environment Setup \`\`\`bash # Install modern DHIS2 tooling npm install -g @dhis2/cli # Create new App Platform project (for reference) d2 app scripts init migration-reference \`\`\` ### 2. Package.json Updates ${generatePackageJsonMigration(currentStack, targetPlatform)} ### 3. Configuration Migration ${generateConfigMigration(currentStack)} ### 4. Code Migration ${generateCodeMigration(migrationScope, codeComplexity)} ### 5. API Migration ${generateAPIMigration(targetPlatform.features)} ## Migration Phases ${generateMigrationPhases(migrationScope, codeComplexity)} ## Testing Strategy ${generateTestingStrategy(codeComplexity)} ## Rollback Plan \`\`\`bash # If migration fails, rollback strategy: git stash git checkout pre-migration-branch npm install npm start \`\`\` ## Post-Migration Validation - [ ] All features working correctly - [ ] Performance comparable or better - [ ] Bundle size acceptable - [ ] Tests passing - [ ] No console errors - [ ] Authentication working - [ ] API calls functioning ## Common Migration Issues ### Dependency Conflicts **Issue**: Conflicting versions between d2 and App Platform dependencies **Solution**: Remove all d2-related dependencies and use App Platform equivalents ### API Changes **Issue**: d2.Api methods don't exist in App Runtime **Solution**: Replace with useDataQuery/useDataMutation hooks ### Styling Conflicts **Issue**: d2-ui styles conflict with @dhis2/ui components **Solution**: Gradually replace d2-ui components with @dhis2/ui ### Build Configuration **Issue**: Custom webpack config no longer works **Solution**: Use d2.config.js for App Platform configuration ## Resources and Support - **Migration Documentation**: https://developers.dhis2.org/docs/app-platform/migration - **App Platform Guide**: https://developers.dhis2.org/docs/app-platform/getting-started - **Community Forum**: https://community.dhis2.org/c/development - **Code Examples**: https://github.com/dhis2/app-platform ## Success Metrics After migration, you should have: - ✅ Modern, maintainable codebase - ✅ Better development experience - ✅ Improved performance - ✅ Future-proof architecture - ✅ Access to latest DHIS2 features `; } function generatePackageJsonMigration(currentStack: any, targetPlatform: any): string { return ` #### Remove Deprecated Dependencies \`\`\`bash # Remove d2 library and related packages npm uninstall d2 d2-ui d2-utilizr # Remove old build tools npm uninstall @dhis2/d2-app-scripts \`\`\` #### Add App Platform Dependencies \`\`\`bash # Install App Platform npm install --save-dev @dhis2/cli-app-scripts@${targetPlatform.appPlatformVersion || 'latest'} # Install runtime dependencies npm install @dhis2/app-runtime @dhis2/ui \`\`\` #### Update Scripts \`\`\`json { "scripts": { "start": "d2-app-scripts start", "build": "d2-app-scripts build", "test": "d2-app-scripts test", "deploy": "d2-app-scripts deploy" } } \`\`\``; } function generateConfigMigration(currentStack: any): string { return ` #### Create d2.config.js \`\`\`javascript // d2.config.js (replaces custom webpack config) const config = { type: 'app', name: 'my-migrated-app', title: 'My Migrated DHIS2 App', description: 'Migrated from d2 library to App Platform', // Entry point (if custom) entryPoints: { app: './src/App.js' }, // Custom authorities authorities: [ 'F_METADATA_IMPORT', 'F_DATA_VALUE_ADD' ] }; module.exports = config; \`\`\` #### Update Manifest \`\`\`json // public/manifest.webapp { "version": "1.0.0", "name": "My Migrated App", "description": "Migrated DHIS2 application", "developer": { "name": "Your Organization" }, "activities": { "dhis": { "href": "./index.html" } } } \`\`\``; } function generateCodeMigration(scope: string, complexity: string): string { switch (scope) { case 'full_migration': return ` #### Complete Code Rewrite \`\`\`javascript // Before (d2 library) import { getInstance } from 'd2'; const d2 = await getInstance(); const dataElements = await d2.models.dataElements.list(); // After (App Platform) import { useDataQuery } from '@dhis2/app-runtime'; const DATA_ELEMENTS_QUERY = { dataElements: { resource: 'dataElements', params: { fields: 'id,displayName,valueType', paging: false } } }; function DataElementsList() { const { loading, error, data } = useDataQuery(DATA_ELEMENTS_QUERY); if (loading) return <div>Loading...</div>; if (error) return <div>Error: {error.message}</div>; return ( <ul> {data.dataElements.dataElements.map(de => ( <li key={de.id}>{de.displayName}</li> ))} </ul> ); } \`\`\``; case 'incremental': return ` #### Incremental Migration Strategy 1. **Phase 1**: Replace d2.Api calls with useDataQuery 2. **Phase 2**: Migrate UI components to @dhis2/ui 3. **Phase 3**: Update routing and navigation 4. **Phase 4**: Remove remaining d2 dependencies \`\`\`javascript // Step-by-step API migration // Phase 1: Replace simple GET requests const { data } = useDataQuery({ systemInfo: { resource: 'system/info' } }); // Phase 2: Replace POST/PUT requests const [mutate] = useDataMutation({ resource: 'dataElements', type: 'create', data: formData => formData }); \`\`\``; default: return '#### Custom Migration Strategy\n- Define your migration approach\n- Plan incremental changes\n- Test each phase thoroughly'; } } function generateAPIMigration(features: string[] = []): string { return ` #### API Call Migration Patterns ##### GET Requests (Read Operations) \`\`\`javascript // d2 library approach const dataElements = await d2.models.dataElements.list({ paging: false, fields: 'id,displayName,valueType' }); // App Platform approach const { data } = useDataQuery({ dataElements: { resource: 'dataElements', params: { paging: false, fields: 'id,displayName,valueType' } } }); \`\`\` ##### POST/PUT Requests (Write Operations) \`\`\`javascript // d2 library approach const dataElement = d2.models.dataElements.create(payload); await dataElement.save(); // App Platform approach const [createDataElement] = useDataMutation({ resource: 'dataElements', type: 'create', data: payload => payload }); await createDataElement(payload); \`\`\` ##### Complex Queries with Filters \`\`\`javascript // App Platform advanced queries const FILTERED_QUERY = { filteredElements: { resource: 'dataElements', params: ({ searchTerm, domainType }) => ({ filter: [ \`name:ilike:\${searchTerm}\`, \`domainType:eq:\${domainType}\` ], fields: 'id,displayName,valueType,domainType' }) } }; const { data } = useDataQuery(FILTERED_QUERY, { variables: { searchTerm: 'population', domainType: 'AGGREGATE' } }); \`\`\` ${features.includes('data_query') ? '✅ Data Query enabled' : ''} ${features.includes('data_mutation') ? '✅ Data Mutation enabled' : ''} ${features.includes('alerts') ? '✅ Alerts system enabled' : ''} ${features.includes('offline') ? '✅ Offline support enabled' : ''} `; } function generateMigrationPhases(scope: string, complexity: string): string { if (scope === 'full_migration') { return ` ### Full Migration Timeline (${complexity} complexity) #### Phase 1: Foundation (Week 1) - [ ] Set up App Platform environment - [ ] Create new project structure - [ ] Migrate basic configuration - [ ] Set up development workflow #### Phase 2: Core Migration (Week 2-3) - [ ] Replace d2.Api with App Runtime hooks - [ ] Migrate authentication system - [ ] Update routing configuration - [ ] Replace d2-ui components #### Phase 3: Feature Migration (Week 3-4) - [ ] Migrate all application features - [ ] Update tests - [ ] Performance optimization - [ ] UI/UX improvements #### Phase 4: Testing & Deployment (Week 5) - [ ] Comprehensive testing - [ ] User acceptance testing - [ ] Performance benchmarking - [ ] Production deployment `; } else { return ` ### Incremental Migration Timeline #### Phase 1: Setup & Planning (Week 1) - [ ] Install App Platform alongside d2 - [ ] Create migration plan - [ ] Set up dual build system - [ ] Identify migration priorities #### Phase 2: API Migration (Week 2-4) - [ ] Replace critical API calls - [ ] Migrate authentication - [ ] Update data fetching logic - [ ] Test API compatibility #### Phase 3: UI Migration (Week 5-8) - [ ] Replace d2-ui components gradually - [ ] Update styling system - [ ] Migrate forms and interactions - [ ] Test UI consistency #### Phase 4: Cleanup (Week 9-10) - [ ] Remove d2 dependencies - [ ] Clean up configuration - [ ] Final testing - [ ] Documentation updates `; } } function generateTestingStrategy(complexity: string): string { return ` ### Testing Strategy for ${complexity.toUpperCase()} Migration #### Pre-Migration Tests \`\`\`bash # Document current functionality npm test npm run e2e:test npm run build \`\`\` #### Migration Testing \`\`\`javascript // API compatibility tests describe('API Migration', () => { it('should maintain data fetching functionality', () => { // Test data queries work as expected }); it('should handle authentication correctly', () => { // Test auth flow }); }); // UI compatibility tests describe('UI Migration', () => { it('should maintain visual consistency', () => { // Visual regression tests }); it('should preserve user interactions', () => { // Interaction tests }); }); \`\`\` #### Post-Migration Validation - [ ] All existing features work - [ ] Performance is maintained or improved - [ ] No new console errors - [ ] Authentication flows correctly - [ ] Data persistence works - [ ] UI is visually consistent #### Automated Testing Setup \`\`\`bash # Set up comprehensive testing npm install --save-dev jest @testing-library/react npm install --save-dev cypress # for e2e testing # Run migration validation suite npm run test:migration npm run test:e2e:migration \`\`\` `; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Dradebo/dhis2-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server