Developer & Architecture Guide
This document provides a comprehensive overview of the Mermaid to Dataverse Converter application architecture, design decisions, and implementation details for developers who want to understand, maintain, or contribute to the project. Because after all - this is open-source - which is not only free, but I'd love to invite you to join me in this and make a good thing even better!
System Overview
The Mermaid to Dataverse Converter is a modern React-based web application deployed on Azure App Service that converts Mermaid ERD diagrams into Microsoft Dataverse entities, columns, and relationships. The application features a React 18 frontend with Fluent UI v9 components and a custom Node.js HTTP server backend.
Key Features
- Modern React Frontend - React 18 + TypeScript + Fluent UI v9 wizard interface
- Real-time ERD Validation - Auto-correction and syntax checking
- CDM Integration - Automatic detection and mapping to Microsoft Common Data Model entities
- Global Choices Integration - Upload and manage option sets
- Publisher Management - Create or select existing publishers
- Deployment History - Comprehensive tracking with solution links and Power Platform integration
- Azure AD Authentication - Enterprise-grade user authentication with MSAL
- Backend API Protection - JWT token validation on all API endpoints
- Enterprise Security - Managed Identity authentication for Dataverse access
- Two-Step Deployment - Separate infrastructure setup and application deployment
Architecture Overview
- Frontend: React 18 + TypeScript + Fluent UI v9 (built with Vite)
- Modular Architecture: All wizard steps are fully modularized with clean separation of concerns
- FileUploadStep: Modular components, hooks, types, and utilities for ERD processing
- SolutionSetupStep: Modular configuration forms with reusable components and business logic
- DeploymentStep: Modular deployment interface with summary, progress, and results components
- Comprehensive Testing: 100% test coverage across all modular components and hooks
- Backend: Node.js + Custom HTTP Server
- Build System: Vite for frontend, npm for backend
- Deployment: Azure App Service with Managed Identity
- Security: Managed Identity for secure authentication
- Infrastructure: Azure Bicep templates for repeatable deployments
Architecture Overview Diagram
Core Components
1. React Frontend (src/frontend/
)
Purpose: Modern React 18 application providing the primary user interface with step-by-step wizard functionality.
Technology Stack:
- React 18 with TypeScript
- Fluent UI v9
- Vite for fast development and optimized production builds
Key Features:
- Multistep wizard interface with progress tracking
- Real-time form validation and user feedback
- File upload with drag-and-drop support
- Publisher and solution management UI
- Global choices integration interface
- Responsive design for all device sizes
Main Components:
App.tsx
- Main application component with wizard orchestrationcomponents/
- Reusable Fluent UI componentstypes/
- TypeScript type definitionsservices/
- API client services for backend communication
Build Process:
cd src/frontend
npm install
npm run build # Creates optimized dist/ folder
2. Node.js Backend (src/backend/
)
Purpose: Service-oriented Node.js HTTP server with controllers, services, repositories, and middleware layers.
Architecture Pattern: Clean architecture with dependency injection and separation of concerns.
Technology Stack:
- Node.js HTTP Server for HTTP handling and custom routing
- Node.js with modern ES6+ patterns
- Dependency Injection for testable components
- Repository Pattern for data access abstraction
Layer Structure:
src/backend/
├── controllers/ # HTTP request/response handling
│ ├── base-controller.js
│ ├── wizard-controller.js
│ ├── validation-controller.js
│ ├── deployment-controller.js
│ └── admin-controller.js
├── services/ # Business logic layer
│ ├── base-service.js
│ ├── validation-service.js
│ ├── deployment-service.js
│ ├── publisher-service.js
│ ├── global-choices-service.js
│ └── solution-service.js
├── repositories/ # Data access layer
│ ├── base-repository.js
│ ├── dataverse-repository.js
│ └── configuration-repository.js
├── middleware/ # Cross-cutting concerns
│ ├── request-logger-middleware.js
│ ├── error-handler-middleware.js
│ ├── cors-middleware.js
│ └── streaming-middleware.js
└── server.js # Application bootstrapping and DI container
Key Features:
- Controllers: Handle HTTP requests, validate input, format responses
- Services: Implement business logic and coordinate between repositories
- Repositories: Abstract data access to Dataverse and configuration sources
- Middleware: Provide logging, error handling, CORS, and streaming capabilities
- Dependency Injection: Full IoC pattern for testable and maintainable code
Main Files:
server.js
- Application bootstrap with dependency injection containercontrollers/
- HTTP layer with request/response handlingservices/
- Business logic and workflow orchestrationrepositories/
- Data access abstraction over external APIsmiddleware/
- Shared functionality across requests
3. Application Server (src/backend/server.js
)
Purpose: Application bootstrap that initializes the service-oriented architecture with dependency injection.
Key Responsibilities:
- Dependency Container: Initializes and wires all services, repositories, and controllers
- HTTP Routing: Routes requests to appropriate controllers
- Middleware Pipeline: Applies logging, CORS, error handling, and streaming
- Static File Serving: Serves React frontend files
Architecture Pattern: Uses dependency injection with repositories → services → controllers pattern
Main Routes:
GET /
- Redirects to React wizardGET /wizard
- Serves React applicationPOST /api/*
- API endpoints routed to controllersGET /health
- Health check endpoint
4. Mermaid Parser (src/backend/mermaid-parser.js
)
Purpose: Parses Mermaid ERD syntax into structured JavaScript objects for Dataverse entity creation.
Key Features:
- CommonJS Module: Compatible with Node.js server environment
- Regex-based Parsing: Robust extraction of entities and relationships
- Attribute Processing: Support for types, constraints (PK, FK)
- Relationship Detection: One-to-many relationship parsing (many-to-many via junction tables)
- Error Handling: Comprehensive validation and error reporting
Supported Syntax:
Validation & Auto-Correction:
- Automatically adds missing primary keys
- Validates relationship consistency
- Suggests proper naming conventions
- Detects Common Data Model (CDM) entities
5. React Wizard Interface (src/frontend/src/App.tsx
)
Purpose: Modern React-based user interface providing step-by-step guided deployment experience with Fluent UI components.
Technology Stack:
- React 18 with functional components and hooks
- TypeScript for type safety and better developer experience
- Fluent UI v9 for Microsoft-consistent design system
- Modern CSS with responsive design patterns
Key Features:
- Multistep Wizard: Progressive disclosure with clear navigation
- Real-time Validation: Live ERD syntax checking with auto-corrections
- File Upload: Drag-and-drop support with validation
- Publisher Management: Visual selection and creation interface
- Global Choices Integration: Upload and preview functionality
- Responsive Design: Works on desktop, tablet, and mobile devices
Wizard Steps Flow:
Step 1: ERD Upload & Validation
- Modern file upload with drag-and-drop support
- Real-time syntax validation with detailed error messages
- Autocorrection suggestions with preview
- CDM Detection: Visual indication of Common Data Model matches
- ERD Rendering: Live Mermaid diagram display after validation
- Entity and relationship preview with expandable details
Modular Architecture: The FileUploadStep has been completely modularized using modern React patterns with clean separation of concerns. See The FileUploadStep Modular Architecture section for detailed implementation.
Step 2: Solution & Publisher Configuration
- Clean form design with Fluent UI components
- Publisher selection with search and filter capabilities
- New publisher creation with prefix validation
- Solution name validation and conflict checking
Modular Architecture: The SolutionSetupStep has been completely modularized using modern React patterns with extracted components and business logic hooks. See The SolutionSetupStep Modular Architecture section for detailed implementation.
Step 3: Global Choices Management (Optional)
- Modular global choices step with comprehensive choice management
- File upload for custom global choice definitions
- Preview table with sortable columns
- Integration with existing Dataverse choices
- Search and filter functionality
- Modular architecture with separate components for search, selection, and upload
Step 4: Review & Deploy
- Modular deployment step with comprehensive configuration summary
- CDM Integration Options: Clear choice between CDM and custom entities
- Real-time deployment progress with streaming logs
- Success/error handling with detailed feedback
- Modular architecture with separate components for review and deployment
Component Structure:
// Main application component
export const App: React.FC = () => {
const [currentStep, setCurrentStep] = useState(1);
const [erdData, setErdData] = useState<ERDData | null>(null);
const [publishers, setPublishers] = useState<Publisher[]>([]);
return (
<FluentProvider theme={webLightTheme}>
<div className="wizard-container">
<ProgressIndicator currentStep={currentStep} totalSteps={4} />
{renderCurrentStep()}
</div>
</FluentProvider>
);
};
Modern React Patterns:
- Hooks: useState, useEffect, useCallback for state management
- Context: For sharing state across components
- Error Boundaries: Graceful error handling
- Code Splitting: Lazy loading for optimal performance
6. Deployment History Feature (src/frontend/src/components/deployment-history/
)
Purpose: Comprehensive deployment tracking and management system that provides users with detailed visibility into their Dataverse solution deployments.
Technology Stack:
- React 18 with TypeScript and Fluent UI v9 components
- Modal Dialog Interface with expandable accordions for deployment details
- API Integration with backend deployment history service
- Power Platform Integration with direct solution links
Key Features:
- Complete Deployment Tracking: Records all deployments with timestamps, status, and detailed entity information
- Solution Links: Direct links to Power Platform solutions with dynamic environment ID configuration
- Deployment Details: Expandable accordions showing deployed entities, columns, and relationships
- Status Visualization: Clear success/failure indicators with detailed error information
- Table Styling: Alternating row backgrounds and professional column formatting
- Environment Integration: Configurable Power Platform environment ID for accurate solution URLs
Component Architecture:
// Main deployment history modal component
export const DeploymentHistory: React.FC = () => {
// Solution URL generation with environment ID
const generateSolutionUrl = (solutionId: string) => {
if (!config?.powerPlatformEnvironmentId) {
throw new Error('Power Platform Environment ID not configured');
}
return `https://make.powerapps.com/environments/${config.powerPlatformEnvironmentId}/solutions/${solutionId}`;
};
// Deployment history display with accordions
return (
<Dialog modal open={isOpen} onOpenChange={onOpenChange}>
<DialogSurface style={{ maxWidth: '90vw', width: '1200px' }}>
{/* Deployment history table with solution links */}
{/* Expandable deployment details with entity information */}
</DialogSurface>
</Dialog>
);
};
Backend Integration:
- DeploymentController: Handles deployment history API endpoints
- DeploymentHistoryService: Manages deployment data persistence and retrieval
- Configuration API: Provides Power Platform environment ID for solution links
- File-based Storage: JSON files for deployment tracking with an environment-specific organization
Configuration Management:
- Environment ID Setup: Configured via PowerShell scripts during Azure deployment
- API Configuration: Backend
/api/config
endpoint provides frontend with environment settings - Dynamic Solution Links: Real-time URL generation based on the configured environment
- Security Compliance: No hardcoded environment-specific values in source code
User Experience Features:
- Professional Table Design: Alternating row backgrounds and bold column headers
- Expandable Details: Deployment and entity accordions for comprehensive information viewing
- Direct Navigation: Solution links open Power Platform in new tabs for seamless workflow
- Responsive Design: Modal scales appropriately for different screen sizes
- Loading States: Proper loading indicators during data fetching
This deployment history system provides enterprise-grade deployment tracking with seamless Power Platform integration, enabling users to effectively manage and monitor their Dataverse solution deployments.
FileUploadStep Modular Architecture
Purpose: The FileUploadStep has been modularized
Architecture Overview
file-upload/
├── FileUploadStep.tsx # Main orchestrator component
├── index.ts # Public API exports
├── components/ # UI Components
│ ├── FileUploadZone.tsx # File upload
│ ├── MermaidDiagramViewer.tsx # Diagram rendering
│ ├── CDMDetectionCard.tsx # CDM entity detection
│ ├── ERDValidationPanel.tsx # Validation results display
│ ├── AutoFixSuggestions.tsx # Auto-fix options
│ ├── ERDSummaryAccordion.tsx # ERD structure summary
│ ├── [Component].module.css # Scoped component styles
│ └── index.ts # Component exports
├── hooks/ # Custom Business Logic Hooks
│ ├── useFileProcessing.ts # File upload and processing
│ ├── useCDMDetection.ts # CDM entity detection
│ ├── useERDValidation.ts # ERD validation logic
│ ├── useAutoFix.ts # Auto-fix generation
│ ├── useMermaidRenderer.ts # Diagram rendering
│ └── index.ts # Hook exports
├── types/ # TypeScript Definitions
│ ├── file-upload.types.ts # Component and data types
│ └── validation.types.ts # Validation-specific types
└── utils/ # Pure Utility Functions
├── cdmEntityList.ts # CDM entity definitions
├── erdParser.ts # ERD parsing logic
└── validationRules.ts # Validation rules
Design Principles
1. Single Responsibility Principle
- Each component has one focused purpose
- Each hook manages one aspect of business logic
- Each utility handles one specific operation
2. Separation of Concerns
- UI Components: Pure presentation with props-based interface
- Custom Hooks: Business logic and state management
- Utilities: Pure functions with no side effects
- Types: Comprehensive TypeScript definitions
3. Dependency Inversion
- Components depend on abstractions (props interfaces)
- Hooks abstract complex business logic
- Clean interfaces between layers
Component Architecture
UI Components (Presentation Layer)
FileUploadZone
interface FileUploadZoneProps {
onFileSelected: (file: File, content: string) => void;
disabled?: boolean;
className?: string;
}
- Pure presentation component for file upload
- Drag-and-drop functionality with visual feedback
- Scoped CSS modules for styling isolation
MermaidDiagramViewer
interface MermaidDiagramViewerProps {
content: string;
onRenderError?: (error: string) => void;
className?: string;
}
- Mermaid.js integration for ERD visualization
- Error boundary handling for render failures
- Responsive design with proper scaling
CDMDetectionCard
interface CDMDetectionCardProps {
detectionResult: CDMDetectionResult;
onChoiceSelected: (choice: 'cdm' | 'custom') => void;
onChoiceChanged: () => void;
className?: string;
}
- Visual presentation of CDM entity matches
- User choice interface for CDM vs. custom entities
- Confidence indicators and entity details
ERDValidationPanel
interface ERDValidationPanelProps {
validationResult: ERDValidationResult;
className?: string;
}
- Comprehensive validation results display
- Severity-based issue categorization (error, warning, info)
- Visual indicators and detailed descriptions
AutoFixSuggestions
interface AutoFixSuggestionsProps {
autoFixes: AutoFix[];
onApplyFix: (fixId: string) => void;
onApplyAllFixes: () => void;
isLoading?: boolean;
className?: string;
}
- Interactive auto-fix recommendations
- Preview of changes before application
- Batch operations for multiple fixes
ERDSummaryAccordion
interface ERDSummaryAccordionProps {
erdStructure: ERDStructure;
className?: string;
}
- Collapsible summary of parsed ERD structure
- DataGrid components for entities and relationships
- Sortable and filterable content
Custom Hooks (Business Logic Layer)
useFileProcessing
export const useFileProcessing = () => {
const [isLoading, setIsLoading] = useState(false);
const processFile = useCallback(async (file: File, content: string) => {
// File validation and processing logic
}, []);
return { processFile, isLoading };
};
- File upload handling and validation
- Content extraction and format checking
- Error handling and loading states
useCDMDetection
export const useCDMDetection = () => {
const [cdmDetection, setCdmDetection] = useState<CDMDetectionResult | null>(null);
const detectCDMEntities = useCallback(async (content: string) => {
// CDM entity detection algorithm
}, []);
return { detectCDMEntities, cdmDetection, setCDMChoice };
};
- CDM entity matching algorithm
- Confidence scoring and entity analysis
- User choice management
useERDValidation
export const useERDValidation = () => {
const [validationResult, setValidationResult] = useState<ERDValidationResult | null>(null);
const validateERD = useCallback(async (content: string, isCdm: boolean) => {
// ERD validation logic with severity categorization
}, []);
return { validateERD, validationResult };
};
- Comprehensive ERD structure validation
- Issue detection with severity levels
- Integration with the validation rules engine
useAutoFix
export const useAutoFix = () => {
const [autoFixes, setAutoFixes] = useState<AutoFix[]>([]);
const [isApplying, setIsApplying] = useState(false);
const generateAutoFixes = useCallback(async (validation: ERDValidationResult, content: string) => {
// Auto-fix generation logic
}, []);
return { generateAutoFixes, applyFix, applyAllFixes, autoFixes, isApplying };
};
- Intelligent fix suggestion generation
- Content modification and validation
- Progress tracking for a fix application
useMermaidRenderer
export const useMermaidRenderer = () => {
const [renderResult, setRenderResult] = useState<MermaidRenderResult | null>(null);
const renderDiagram = useCallback(async (content: string) => {
// Mermaid.js integration and error handling
}, []);
return { renderDiagram, renderResult };
};
- Mermaid.js diagram generation
- SVG output management
- Render error handling and fallbacks
Integration Pattern
Main Orchestrator Component
export const FileUploadStep: React.FC = () => {
// State management
const [currentFile, setCurrentFile] = useState<UploadedFile | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
// Custom hooks integration
const { processFile, isLoading: isFileProcessing } = useFileProcessing();
const { detectCDMEntities, cdmDetection, setCDMChoice } = useCDMDetection();
const { validateERD, validationResult } = useERDValidation();
const { generateAutoFixes, applyFix, autoFixes } = useAutoFix();
const { renderDiagram, renderResult } = useMermaidRenderer();
// Orchestrated workflow
const handleFileSelected = useCallback(async (file: File, content: string) => {
const result = await processFile(file, content);
if (result.success) {
setCurrentFile({ file, content, processed: true });
await detectCDMEntities(content);
await renderDiagram(content);
}
}, [processFile, detectCDMEntities, renderDiagram]);
return (
<div className={styles.fileUploadStep}>
<FileUploadZone onFileSelected={handleFileSelected} disabled={isProcessing} />
{cdmDetection && <CDMDetectionCard detectionResult={cdmDetection} onChoiceSelected={handleCDMChoice} />}
{renderResult && <MermaidDiagramViewer content={currentFile.content} />}
{validationResult && <ERDValidationPanel validationResult={validationResult} />}
{autoFixes?.length > 0 && <AutoFixSuggestions autoFixes={autoFixes} onApplyFix={handleApplyFix} />}
{erdStructure && <ERDSummaryAccordion erdStructure={erdStructure} />}
</div>
);
};
Testing Strategy
Unit Tests: Each hook and utility function has dedicated unit tests Component Tests: UI components tested with React Testing Library Integration Tests: Full workflow tested with mocked dependencies Validation: All 317 tests pass, confirming architectural integrity
Test Coverage:
- Utilities: 100% coverage of pure functions
- Hooks: State management and business logic validation
- Components: Props interface and rendering behavior
- Integration: End-to-end workflow validation
Usage Examples
Simple Component Import:
import { FileUploadZone } from './components/wizard/steps/file-upload';
<FileUploadZone onFileSelected={handleFile} disabled={isLoading} />
Business Logic Hook Usage:
import { useFileProcessing, useCDMDetection } from './components/wizard/steps/file-upload';
const { processFile } = useFileProcessing();
const { detectCDMEntities, cdmDetection } = useCDMDetection();
Complete Module Import:
import { FileUploadStep } from './components/wizard/steps/file-upload';
// Fully integrated, production-ready component
<FileUploadStep />
SolutionSetupStep Modular Architecture
Purpose: The SolutionSetupStep has been modularized using clean architecture principles with extracted components and business logic hooks.
Architecture Overview
solution-setup/
├── SolutionSetupStep.tsx # Main orchestrator component
├── index.ts # Public API exports
├── components/ # UI Components
│ ├── SearchableDropdown.tsx # Reusable searchable dropdown
│ ├── SolutionConfigSection.tsx # Solution configuration form
│ ├── PublisherConfigSection.tsx # Publisher configuration form
│ ├── [Component].module.css # Scoped component styles
│ └── index.ts # Component exports
├── hooks/ # Custom Business Logic Hooks
│ ├── useSolutionConfiguration.ts # Solution state management
│ ├── usePublisherConfiguration.ts # Publisher state management
│ ├── useSearchableDropdown.ts # Dropdown search logic
│ ├── useNameGeneration.ts # Name generation utilities
│ ├── useFormValidation.ts # Form validation logic
│ └── index.ts # Hook exports
├── types/ # TypeScript Definitions
│ ├── solution-setup.types.ts # Component and data types
│ └── validation.types.ts # Validation-specific types
└── utils/ # Pure Utility Functions
├── validation.ts # Validation rules and logic
├── filtering.ts # Data filtering utilities
└── nameGeneration.ts # Name generation functions
Design Principles
1. Separation of Concerns
- UI Components: Pure presentation with props-based interface
- Business Logic Hooks: State management and API integration
- Utilities: Pure functions for validation and data transformation
- Types: Comprehensive TypeScript definitions
2. Reusability
- SearchableDropdown extracted as a reusable component
- Configuration hooks usable across different forms
- Validation utilities applicable to other wizard steps
3. Testability
- Each hook independently testable
- Components tested in isolation
- 97 passing tests validate all functionality
Testing Strategy
Comprehensive Test Coverage: 97/97 tests passing across all components and hooks
- SearchableDropdown: 21 tests covering ARIA, keyboard navigation, error states
- useSearchableDropdown: 23 tests for search logic and state management
- useSolutionConfiguration: 12 tests for solution state and validation
- usePublisherConfiguration: 11 tests for publisher state and form handling
- useNameGeneration: 13 tests for name generation utilities
- SolutionSetupStep: 17 tests for integration and accessibility
This modular architecture ensures the SolutionSetupStep is maintainable, testable, reusable, and scalable while providing robust form validation and user experience.
GlobalChoicesStep Modular Architecture
Purpose: The GlobalChoicesStep has been completely modularized using clean architecture principles, transforming a 372-line monolithic component into a maintainable modular structure with separated components for choice search, selection, file upload, and navigation.
Architecture Overview
global-choices/
├── GlobalChoicesStep.tsx # Main orchestrator component
├── index.ts # Public API exports
├── components/ # UI Components
│ ├── ChoiceSearch.tsx # Search and filtering interface
│ ├── GlobalChoicesList.tsx # Choice display and selection
│ ├── CustomChoicesUpload.tsx # File upload functionality
│ ├── UploadedChoicesPreview.tsx # Preview uploaded choices
│ ├── GlobalChoicesNavigation.tsx # Step navigation controls
│ └── index.ts # Component exports
├── hooks/ # Custom Business Logic Hooks
│ ├── useGlobalChoicesData.ts # Data fetching and state
│ ├── useChoiceSelection.ts # Selection state management
│ ├── useFileUpload.ts # File upload and parsing
│ ├── useChoicesValidation.ts # Validation logic
│ └── index.ts # Hook exports
├── types/ # TypeScript Definitions
│ ├── global-choices.types.ts # Component and data types
│ └── index.ts # Type exports
└── utils/ # Pure Utility Functions (pre-existing)
├── global-choices.utils.ts # Choice filtering and parsing
└── index.ts # Utility exports
Design Principles
1. Component Separation
- ChoiceSearch: Clean search interface with debounced filtering
- GlobalChoicesList: Organized choice display with grouping by prefix
- CustomChoicesUpload: File upload with progress and error handling
- UploadedChoicesPreview: Display and management of uploaded choices
- GlobalChoicesNavigation: Step navigation with validation state
2. Business Logic Abstraction
- useGlobalChoicesData: Integrates with existing useGlobalChoices service hook
- useChoiceSelection: Manages selection state and choice management logic
- useFileUpload: Handles file upload, JSON parsing, and error handling
- useChoicesValidation: Validates step completion (always valid since optional)
3. Data Flow Management
- Types: Comprehensive TypeScript definitions for all component and hook interfaces
- Clean Dependencies: Each component depends only on its required props
- State Management: Centralized through wizard context with hook abstractions
Key Component Interfaces
ChoiceSearch Component
interface ChoiceSearchProps {
value: string;
onChange: (value: string) => void;
placeholder?: string;
disabled?: boolean;
}
GlobalChoicesList Component
interface GlobalChoicesListProps {
choices: GlobalChoice[];
selectedChoices: GlobalChoice[];
onChoiceSelect: (choiceId: string, selected: boolean) => void;
searchTerm?: string;
loading?: boolean;
}
CustomChoicesUpload Component
interface CustomChoicesUploadProps {
onFileUpload: (file: File) => void;
uploadedFile?: File | null;
isUploading?: boolean;
error?: string | null;
}
Hook Architecture
useGlobalChoicesData: Data fetching and integration
- Integrates with existing
useGlobalChoices
service hook - Provides built-in and custom choices with loading states
- Maps service data to component-compatible formats
useChoiceSelection: Selection state management
- Manages selected choices in the wizard context
- Provides selection, deselection, and bulk operations
- Validates selection state and provides error feedback
useFileUpload: File processing and validation
- Handles file upload with progress tracking
- Parses JSON files and validates a format
- Integrates uploaded choices with the wizard state
useChoicesValidation: Step validation logic
- Always returns valid since global choices are optional
- Provides informational messages about current selections
- Supports future enhancement for required choice scenarios
User Experience Enhancements
1. Search and Filtering
- Real-time search across choice names and logical names
- Prefix-based grouping for better organization
- Clear visual feedback for empty states
2. File Upload Experience
- Drag-and-drop file upload interface
- Real-time upload progress indication
- Clear error messaging for invalid files
- Preview of uploaded choices before confirmation
3. Selection Management
- Visual selection state with checkboxes
- Bulk selection/deselection capabilities
- Selection count and validation feedback
- Persistent selection state across navigation
Testing Strategy
Comprehensive Test Coverage: 19/19 tests passing across all components and utilities
Component Tests (8 tests):
- ChoiceSearch: Search functionality and user input handling
- GlobalChoicesList: Choice rendering, selection, and filtering
- CustomChoicesUpload: File upload interface and error states
- UploadedChoicesPreview: Choice preview and removal functionality
- GlobalChoicesNavigation: Navigation controls and validation display
Hook Tests (5 tests):
- useGlobalChoicesData: Data fetching and state management
- useChoiceSelection: Selection logic and wizard context integration
- useFileUpload: File processing, parsing, and error handling
- useChoicesValidation: Validation logic and message generation
Integration Tests (6 tests):
- GlobalChoicesStep: Full component integration and workflow
- Wizard Context: State persistence and cross-step data flow
- Error Handling: File upload errors and recovery scenarios
- User Workflows: Complete selection and upload scenarios
Test Categories:
- Unit Tests: Individual component and hook behavior with mock dependencies
- Integration Tests: Component interaction and wizard context integration
- Error Handling: File upload errors, validation edge cases, and error recovery
- User Interaction: Search, selection, upload, and navigation workflows
- Accessibility: Screen reader support and keyboard navigation
Migration Impact
Before Modularization: 372-line monolithic component with mixed concerns After Modularization: Clean separation across 5 components and 4 hooks
Benefits Achieved:
- Maintainability: Each component has a single responsibility
- Testability: Comprehensive test coverage with isolated testing
- Reusability: Components can be used independently or in other contexts
- Scalability: Easy to extend with new features or choice types
- Type Safety: Comprehensive TypeScript definitions prevent runtime errors
This modular architecture ensures the GlobalChoicesStep is production-ready, maintainable, testable, and scalable while preserving all existing functionality and enhancing the user experience.
DeploymentStep Modular Architecture
Purpose: The DeploymentStep has been completely modularized using clean architecture principles with separated components for configuration summary, deployment progress, and result handling.
Architecture Overview
deployment/
├── DeploymentStep.tsx # Main orchestrator component
├── index.ts # Public API exports
├── components/ # UI Components
│ ├── ConfigurationSummary.tsx # Solution and entity summary
│ ├── DeploymentProgress.tsx # Real-time progress display
│ ├── DeploymentResults.tsx # Success/error results
│ ├── DeploymentControls.tsx # Navigation and deploy buttons
│ ├── [Component].module.css # Scoped component styles
│ └── index.ts # Component exports
├── hooks/ # Custom Business Logic Hooks
│ ├── useConfigurationSummary.ts # Data aggregation and filtering
│ ├── useDeploymentStatus.ts # Deployment state management
│ ├── useDeploymentProgress.ts # Progress tracking and updates
│ └── index.ts # Hook exports
├── types/ # TypeScript Definitions
│ ├── deployment.types.ts # Component and data types
│ └── index.ts # Type exports
└── utils/ # Pure Utility Functions
├── dataTransformation.ts # Wizard data to deployment mapping
├── validation.ts # Deployment data validation
└── index.ts # Utility exports
Design Principles
1. Component Separation
- ConfigurationSummary: Pure presentation of a solution, publisher, entities, and relationships
- DeploymentProgress: Real-time streaming deployment progress with logs
- DeploymentResults: Success/error result display with detailed feedback
- DeploymentControls: Navigation buttons and deployment trigger
2. Business Logic Abstraction
- useConfigurationSummary: Aggregates wizard data into a deployment-ready format
- useDeploymentStatus: Manages deployment state and API integration
- useDeploymentProgress: Handles streaming progress updates and error states
3. Data Flow Management
- Utils: Pure functions for data transformation and validation
- Types: Comprehensive TypeScript definitions for all interfaces
- Clean Dependencies: Each component depends only on its required props
Testing Strategy
Comprehensive Test Coverage: 19/19 tests passing across all components and utilities
- Utils Tests (11 tests): Data transformation, validation, and filtering functions
- Hooks Tests (4 tests): Configuration summary and business logic validation
- Integration Tests (4 tests): Full component integration and rendering behavior
Test Categories:
- Unit Tests: Pure utility functions with 100% coverage
- Hook Tests: State management and wizard context integration
- Component Tests: UI rendering and props interface validation
- Integration Tests: End-to-end deployment step workflow
This modular architecture ensures the DeploymentStep is production-ready, maintainable, testable, and scalable while providing comprehensive deployment functionality with real-time progress tracking.
API Endpoints Reference
This section provides detailed documentation for all available API endpoints implemented through the controller-based architecture.
Core Endpoints
Endpoint | Method | Controller | Description |
---|---|---|---|
GET / | GET | WizardController | Redirects to React wizard interface |
GET /wizard | GET | WizardController | Serves React application |
GET /health | GET | AdminController | Application health status and diagnostics |
POST /upload | POST | DeploymentController | Primary deployment with streaming response |
POST /api/validate-erd | POST | ValidationController | ERD validation with auto-corrections |
GET /api/publishers | GET | AdminController | Lists available publishers in Dataverse |
GET /api/global-choices-list | GET | AdminController | Lists available global choice sets |
GET /api/solution-status | GET | AdminController | Solution component status verification |
GET /api/health-detailed | GET | AdminController | Detailed health check with components |
GET /api/logs | GET | AdminController | Recent application logs |
Architecture Implementation
Request Flow:
- Middleware Pipeline: Request logging, CORS handling
- Controller Layer: HTTP request/response handling
- Service Layer: Business logic execution
- Repository Layer: Data access to Dataverse/configuration
- Response: Formatted JSON or streaming data
Error Handling: Centralized through ErrorHandlerMiddleware with proper HTTP status codes and structured error responses.
Frontend Routes
GET /
GET /wizard
Purpose: Serves the React application for all frontend routes.
Response: Returns the React application HTML with proper SPA routing support.
Static Assets:
/static/css/*
- Compiled CSS from Vite build/static/js/*
- Compiled JavaScript bundles/static/assets/*
- Images, fonts, and other assets
Health Endpoint
GET /health
Purpose: Comprehensive health check including managed identity authentication and Dataverse connectivity.
Response:
{
"status": "healthy",
"timestamp": "2025-09-07T14:30:00.000Z",
"version": "2.0.0",
"managedIdentity": {
"authenticated": true,
"tokenValid": true
},
"dataverse": {
"authenticated": true,
"connectionTest": "passed"
}
}
Upload Endpoint (Primary Deployment)
POST /api/upload
Purpose: Deploys entities and relationships to Dataverse with real-time streaming progress updates.
Request: JSON with mermaidContent, entities, relationships, solutionName, publisherInfo, and deploymentOptions Response: Streaming JSON with real-time progress updates and final deployment results
ERD Validation Endpoint
POST /api/validate-erd
Purpose: Validates Mermaid ERD syntax, provides auto-corrections, and detects CDM entities.
Request: JSON with mermaid ERD content Response: JSON with validation results, entities, relationships, CDM matches, and corrections
Publishers Endpoint
GET /api/publishers
Purpose: Retrieves available publishers from Dataverse for frontend selection.
Global Choices Endpoint
GET /api/global-choices
Purpose: Retrieves available global choice sets with grouping and filtering support. "builtin": 145 } }
Solution Status Endpoint (Timeout Handling)
GET /api/solution-status?solution=SolutionName
Purpose: Retrieves solution components for deployment verification, especially after HTTP timeouts.
Query Parameters:
solution
(required): The unique name of the solution to check
Response:
{
"success": true,
"solution": {
"uniqueName": "CustomerSolution",
"friendlyName": "Customer Management Solution",
"solutionId": "guid-value"
},
"components": {
"entities": [
{
"logicalName": "myp_customer",
"displayName": "Customer",
"type": "entity"
}
],
"optionSets": [
{
"logicalName": "myp_priority_level",
"displayName": "Priority Level",
"type": "optionset"
}
],
"others": [],
"totalCount": 2
},
"lastModified": "2025-09-07T14:30:00.000Z"
}
Dataverse Client
Purpose: Handle all Microsoft Dataverse Web API interactions with comprehensive entity, relationship, and solution management.
Location: src/backend/dataverse-client.js
Key Features:
- Managed Identity Authentication: Passwordless authentication via Azure
- Publisher and Solution Management: Create or use existing resources
- Entity Creation: Full metadata support with proper naming conventions
- Column and Relationship Creation: Complete attribute and relationship support
- Global Choice Management: Create and integrate option sets
- Solution Introspection: Verify deployment results and component status
- Comprehensive Error Handling: Robust error recovery and logging
Main Operations:
- Connection Testing: Validates Dataverse connectivity and authentication
- Publisher Management: Creates or uses existing publishers with custom prefixes
- Solution Management: Creates or uses existing solutions with proper metadata
- Entity Creation: Creates custom entities with full metadata and naming conventions
- Column Creation: Adds custom columns with complete attribute support
- Relationship Creation: Establishes one-to-many and many-to-many relationships
- Global Choice Management: Creates and manages global choice sets with solution integration
- Solution Component Verification: Retrieves and validates deployment results
Authentication: Uses Azure Managed Identity for passwordless authentication with proper headers and token management
Entity Creation Flow: Validates connection → Creates/validates publisher → Creates/validates a solution → Creates entities with metadata → Adds to a solution → Creates columns and relationships
Solution Status Verification: Retrieves solution metadata and enumerates all components (entities, option sets, etc.) for deployment verification
7. User Authentication & API Protection (src/backend/middleware/auth.js
, src/frontend/src/auth/
)
Purpose: Protect all backend API endpoints with Azure AD authentication using MSAL (Microsoft Authentication Library) for enterprise-grade user authentication.
Key Features:
- Azure AD Integration: Enterprise Single Sign-On with Microsoft Entra ID
- JWT Token Validation: Backend validates ID tokens on all
/api/*
routes - Automatic Token Management: MSAL handles token acquisition, caching, and refresh
- Protected API Client: All frontend services use authenticated HTTP client
- Zero Trust Architecture: No API access without valid authentication token
Frontend Authentication (src/frontend/src/auth/
):
- MSAL Browser: @azure/msal-browser v3.7.1 for SPA authentication
- Auth Provider: React context provider wraps entire application
- Auth Config: Environment-specific Azure AD app registration configuration
- API Client: Authenticated axios instance with request interceptor (
src/frontend/src/api/apiClient.ts
)
Backend Protection (src/backend/middleware/auth.js
):
- JWT Validation: Validates Azure AD ID tokens on every request
- Protected Routes: All
/api/*
endpoints require valid Bearer token - 401 Response: Returns
{ "success": false, "error": "Unauthorized: Authentication token required" }
when token missing/invalid - Token Extraction: Parses
Authorization: Bearer ${token}
header
Authentication Flow:
// Frontend: API client automatically adds auth token
import { apiClient } from '../api/apiClient';
// All requests automatically include Authorization header
const publishers = await apiClient.get('/publishers');
const solutions = await apiClient.post('/solutions', data);
// For streaming endpoints (manual token required)
const msalInstance = getMsalInstance();
const accounts = msalInstance.getAllAccounts();
const response = await msalInstance.acquireTokenSilent({
account: accounts[0],
scopes: ['User.Read']
});
const authToken = response.idToken;
// Include token in streaming request
const streamResponse = await fetch('/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${authToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
Required Environment Variables (Frontend):
VITE_AZURE_CLIENT_ID
- Azure AD app registration client IDVITE_AZURE_TENANT_ID
- Azure AD tenant IDVITE_AZURE_REDIRECT_URI
- OAuth redirect URI (app URL)
Backend Middleware Implementation:
// All /api/* routes protected
if (pathname.startsWith('/api/')) {
const authHeader = req.headers['authorization'];
if (!authHeader || !authHeader.startsWith('Bearer ')) {
res.writeHead(401, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
success: false,
error: 'Unauthorized: Authentication token required'
}));
return;
}
const token = authHeader.substring(7);
const isValid = await validateJwtToken(token);
if (!isValid) {
res.writeHead(401, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
success: false,
error: 'Unauthorized: Invalid token'
}));
return;
}
}
Security Benefits:
- Enterprise SSO: Users authenticate with existing Microsoft credentials
- No Password Storage: Authentication handled entirely by Azure AD
- Token-Based Access: Short-lived JWT tokens with automatic refresh
- API Protection: Backend validates every request before processing
- Audit Trail: All authentication events logged in Azure AD
Testing Authentication:
# Test unauthenticated access (should return 401)
Invoke-WebRequest -Uri "https://your-app.azurewebsites.net/api/publishers"
# Test authenticated access (should return 200)
$token = "your-id-token-from-browser"
$headers = @{ "Authorization" = "Bearer $token" }
Invoke-WebRequest -Uri "https://your-app.azurewebsites.net/api/publishers" -Headers $headers
8. Managed Identity Authentication (src/backend/dataverse-client.js
)
Purpose: Secure, passwordless authentication using Azure Managed Identity for Dataverse access.
Location: src/backend/dataverse-client.js
Key Features:
- Zero Secrets: No client secrets, passwords, or certificates required
- Automatic Token Management: Managed Identity handles token lifecycle
- Environment Variable Configuration: Simple configuration via environment variables
- Comprehensive Error Handling: Robust error recovery and logging
- Multiple Authentication Methods: Support for both user-assigned and system-assigned managed identity
Required Environment Variables:
DATAVERSE_URL
- Target Dataverse environment URLCLIENT_ID
- Entra ID app registration client ID (for user-assigned managed identity)TENANT_ID
- Azure Active Directory tenant IDSOLUTION_NAME
- Default solution name for deployments
Authentication Implementation:
async authenticateWithManagedIdentity() {
try {
// Use user-assigned managed identity if CLIENT_ID is provided
const clientId = process.env.CLIENT_ID;
let credential;
if (clientId) {
credential = new ManagedIdentityCredential(clientId);
} else {
credential = new ManagedIdentityCredential(); // System-assigned
}
// Get token for Dataverse
const tokenResponse = await credential.getToken('https://cds.dynamics.com/.default');
if (!tokenResponse) {
throw new Error('Failed to obtain access token from managed identity');
}
return {
accessToken: tokenResponse.token,
expiresOn: tokenResponse.expiresOnTimestamp
};
} catch (error) {
console.error('Managed Identity authentication failed:', error.message);
throw error;
}
}
// Environment configuration validation
validateConfiguration() {
const required = ['DATAVERSE_URL', 'CLIENT_ID', 'TENANT_ID', 'SOLUTION_NAME'];
const missing = required.filter(env => !process.env[env]);
if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
}
Security Benefits:
- Zero Hardcoded Secrets: No sensitive data in code or configuration files
- Managed Identity: Azure handles all credential lifecycle management
- Audit Trail: All authentication events logged through Azure monitoring
- RBAC Integration: Fine-grained access control via Azure role assignments
- Rotation Support: Supports secret rotation without application changes
Advanced Features
CDM Integration
Purpose: Automatically detect and map Mermaid entities to Microsoft Common Data Model (CDM) standard entities to leverage existing Dataverse capabilities.
Key Capabilities:
- Automatic Detection: Analyzes entity names and attributes to identify potential CDM matches
- Smart Mapping: Matches entities like "Contact" → "contact"
- Attribute Analysis: Compares entity attributes against CDM entity schemas
- User Choice: Provides an option to use CDM entities or create custom entities
- Relationship Preservation: Maintains relationships between CDM and custom entities
Detection Algorithm:
- Name-based Matching: Fuzzy string matching against CDM entity names and display names
- Attribute Analysis: Compares common attributes (name, email, phone) for validation
- Confidence Scoring: Rates match quality based on name similarity and attribute overlap
- User Presentation: Shows detected matches with confidence levels for user decision
CDM Entity Examples:
Customer
→account
(Customer entity with business attributes)Contact
→contact
(Individual person contacts)Opportunity
→opportunity
(Sales opportunities)Lead
→lead
(Potential customers)
Integration Benefits:
- Standard Fields: Leverage pre-built CDM attributes and relationships
- Business Processes: Access to standard Dataverse business processes
- Integration Ready: Compatible with Power Platform and Dynamics 365
- Future-Proof: Benefits from ongoing CDM standard updates
Global Choices Integration
Purpose: Manage Dataverse global choice sets (option sets) alongside entity creation with robust creation, verification, and solution integration processes.
Key Features:
- Custom Global Choices: Upload and create custom global choice sets with user-defined options
- Duplicate Detection: Case-insensitive duplicate checking to prevent conflicts
- Solution Integration: Automatic addition of created choices to the target solution
- Robust Verification: Multi-attempt verification with fallback mechanisms
- API Constraint Handling: Workarounds for Dataverse API limitations
Supported Operations:
- Create new global choice sets in Dataverse
- Add existing global choices to solutions
- Verify creation success with retry logic
- Handle API timing and caching issues
JSON Format:
[
{
"name": "Status",
"displayName": "Status",
"description": "Simple status options",
"options": [
{
"value": 1,
"label": "Active"
},
{
"value": 2,
"label": "Inactive"
}
]
}
]
Required Fields:
name
: Logical name of the choice setdisplayName
: Display name shown in UIoptions
: Array of choice options
Optional Fields:
description
: Description of the choice setvalue
: Numeric value for each option (auto-generated if not provided)
Global Choice Creation & Verification Process
Duplicate Detection Process:
- Fetch all existing global choices using
GlobalOptionSetDefinitions?$select=Name
- Convert existing names to lowercase for case-insensitive comparison
- Check if a choice name (with publisher prefix) already exists
- If a duplicate is found, skip creation but attempt to add the existing choice to a solution
Creation and Verification Workflow:
- Create Choice Set: POST to
/GlobalOptionSetDefinitions
with choice metadata - Multi-Attempt Verification: Try up to 5 times with progressive delays (3s, 5s, 7s, 9s, 10s)
- Fallback Verification: Use a comprehensive global choices list if a direct lookup fails
- Solution Addition: Add successfully created/found choices to target a solution
API Constraints and Workarounds:
The Dataverse API has several limitations that require specific workarounds:
Issue | Problem | Workaround |
---|---|---|
No Filter Support | $filter parameter not supported on GlobalOptionSetDefinitions | Fetch all choices and filter client-side |
Property Limitations | IsCustom property not available on OptionSetMetadataBase | Use IsManaged property instead |
Caching Delays | Created choices may not be immediately discoverable | Progressive retry with increasing delays |
ERD Validation
Purpose: Provide comprehensive validation with autocorrection capabilities.
Validation Features:
- Syntax checking with specific error locations
- Relationship validation with cardinality verification
- Naming convention enforcement
- Auto-correction suggestions for common issues
- Warning categorization (errors vs. warnings vs. info)
Auto-Corrections:
- Missing primary keys → Automatic ID field generation
- Invalid naming → Proper naming convention suggestions
- Relationship inconsistencies → Corrected relationship definitions
ERD Visual Rendering
Purpose: Provide visual diagram rendering of Mermaid ERDs after validation and correction to enhance user understanding and verification.
Key Features:
- Mermaid.js Integration: Client-side rendering using the official Mermaid.js library in React components
- Post-Correction Rendering: Diagrams appear only after users apply corrected ERD
- Strategic Placement: Positioned between validation results and parsed schema overview
- Clean UI Flow: No overwhelming red/green comparisons, just clean visualization
- React Integration: Seamless integration with Fluent UI components
Implementation Details:
- Library: Mermaid.js loaded as a npm dependency in React frontend
- Trigger: Diagram renders when the "Use Corrected ERD" button is clicked
- Container: Dedicated React component with proper styling
- Error Handling: Graceful fallback if diagram cannot be rendered
User Experience Flow:
- Upload & Validate: User uploads ERD, sees validation results with corrections
- Apply Corrections: User clicks the "Use Corrected ERD" button
- Visual Confirmation: React component displays the rendered Mermaid diagram above schema overview
- Proceed: User can visually verify structure before deployment
Technical Implementation (React + TypeScript):
// ERD Diagram React Component
import mermaid from 'mermaid';
import { useEffect, useRef } from 'react';
interface ERDDiagramProps {
mermaidCode: string;
diagramId: string;
}
export const ERDDiagram: React.FC<ERDDiagramProps> = ({ mermaidCode, diagramId }) => {
const diagramRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const renderDiagram = async () => {
if (diagramRef.current && mermaidCode) {
try {
mermaid.initialize({
startOnLoad: false,
theme: 'default',
er: { useMaxWidth: true }
});
const { svg } = await mermaid.render(diagramId, mermaidCode);
diagramRef.current.innerHTML = svg;
} catch (error) {
console.error('Failed to render diagram:', error);
diagramRef.current.innerHTML = '<p>Failed to render diagram</p>';
}
}
};
renderDiagram();
}, [mermaidCode, diagramId]);
return (
<div
ref={diagramRef}
className="erd-diagram-container"
style={{ textAlign: 'center', margin: '20px 0' }}
/>
);
};
Benefits:
- Visual Verification: Users can see the structure before deployment
- Error Detection: Visual inconsistencies are easier to spot than text
- Confidence Building: Users feel more confident about their ERD structure
- Professional UX: Clean, modern interface with visual feedback integrated into React flow
Advanced Relationship Handling
The parser supports the following relationship scenarios:
Relationship Types
- One-to-Many (1:M):
||--o{
syntax Directly supported - Many-to-One (M:1):
}o--||
syntax Directly supported (inverse of one-to-many) - Many-to-Many (M:M): NOT directly supported - Use explicit junction tables instead
- Self-Referencing: Supported - Tables with relationships to themselves
Relationship Implementation
- One-to-Many: Directly supported with Dataverse lookup fields
- Many-to-Many: Must be implemented using an explicit junction table with two one-to-many relationships
- Junction Tables: Must be explicitly defined in the ERD with foreign keys to both related entities
Important: Direct many-to-many syntax like
}o--o{
is not supported. Always use explicit junction tables for many-to-many relationships.
Data Flow (please use CTRL + or CMD +) 🙈
Permission Model
Setup Time Permissions (Temporary)
Who: PowerShell script user (DevOps/Admin)
When: During initial setup and configuration
Duration: One-time setup
All authentication is handled through managed identity and federated credentials - no secrets or manual role assignments are required.
Runtime Permissions (Permanent)
Who: Managed Identity (App Service)
When: Application runtime
Duration: Permanent (for application lifetime)
// Managed Identity configuration for Dataverse access
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: 'id-${appName}'
location: location
}
Environment Variables
Production (Azure App Service):
TENANT_ID=your-tenant-id
CLIENT_ID=your-app-registration-id
MANAGED_IDENTITY_CLIENT_ID=your-managed-identity-id
PORT=8080
Local Development:
# Local .env file (development only)
DATAVERSE_URL=https://yourorg.crm.dynamics.com
TENANT_ID=your-tenant-id
CLIENT_ID=your-app-registration-id
MANAGED_IDENTITY_CLIENT_ID=your-managed-identity-id
CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
MANAGED_IDENTITY_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
TENANT_ID=your-tenant-id
SOLUTION_NAME=MermaidSolution
Field Type Mapping
Supported Mermaid Types → Dataverse Types
Mermaid Type | Dataverse Type | Notes |
---|---|---|
string | StringAttributeMetadata | Single line text (255 chars) |
integer , int | IntegerAttributeMetadata | Whole number |
decimal | DecimalAttributeMetadata | Decimal number with precision |
boolean | BooleanAttributeMetadata | Yes/No field |
datetime | DateTimeAttributeMetadata | Date and time |
Constraint Handling
Constraint | Implementation | Dataverse Behavior |
---|---|---|
PK | Primary key | Creates GUID primary key + name field |
FK | Foreign key | Creates lookup relationship |
Schema Generation Logic
function generateColumnMetadata(attribute, publisherPrefix) {
const baseMetadata = {
LogicalName: `${publisherPrefix.toLowerCase()}_${attribute.name.toLowerCase()}`,
DisplayName: { LocalizedLabels: [{ Label: attribute.displayName, LanguageCode: 1033 }] },
RequiredLevel: { Value: attribute.isRequired ? 'ApplicationRequired' : 'None' }
};
switch (attribute.type.toLowerCase()) {
case 'string':
return {
'@odata.type': 'Microsoft.Dynamics.CRM.StringAttributeMetadata',
...baseMetadata,
AttributeType: 'String',
MaxLength: 255
};
// ... other types
}
}