Best Practices
This guide provides best practices for building efficient, maintainable, and scalable dashboards with Veltix.
Dashboard Design
1. Layout Principles
Visual Hierarchy
- Place the most important information at the top-left (F-pattern reading)
- Use consistent spacing and alignment
- Group related components together
- Use visual weight to guide attention
// Good layout structure
function DashboardLayout() {
return (
<div className="dashboard">
{/* Header with title and controls */}
<header className="dashboard-header">
<h1>Sales Dashboard</h1>
<div className="controls">
<DatePicker />
<ThemeToggle />
</div>
</header>
{/* Main content area */}
<main className="dashboard-content">
{/* KPI row at top */}
<section className="kpi-section">
<KPICard title="Total Revenue" value="$1.2M" />
<KPICard title="Growth Rate" value="+12.5%" />
<KPICard title="Active Users" value="45.2K" />
</section>
{/* Charts in grid layout */}
<section className="charts-grid">
<BarChart data={salesData} />
<LineChart data={trendData} />
<PieChart data={categoryData} />
</section>
</main>
</div>
);
}Responsive Design
- Design for multiple screen sizes
- Use flexible layouts
- Test on different devices
- Consider mobile interactions
// Responsive component sizing
const responsiveConfig = {
mobile: {
columns: 1,
spacing: 8,
fontSize: 14
},
tablet: {
columns: 2,
spacing: 16,
fontSize: 16
},
desktop: {
columns: 3,
spacing: 24,
fontSize: 18
}
};2. Data Visualization
Chart Selection
- Use bar charts for categorical comparisons
- Use line charts for time series data
- Use pie charts for proportions (limit to 5-7 segments)
- Use scatter plots for correlations
- Use heatmaps for matrix data
// Appropriate chart selection
function ChartSelector({ data, type }) {
const getChartComponent = () => {
switch (type) {
case 'categorical':
return <BarChart data={data} />;
case 'time-series':
return <LineChart data={data} />;
case 'proportion':
return <PieChart data={data} />;
case 'correlation':
return <ScatterChart data={data} />;
default:
return <BarChart data={data} />;
}
};
return getChartComponent();
}Color Usage
- Use semantic colors consistently
- Ensure sufficient contrast ratios
- Consider color blindness
- Limit color palette to 5-7 colors
// Semantic color usage
const colorPalette = {
primary: '#1890ff',
success: '#52c41a',
warning: '#faad14',
error: '#f5222d',
neutral: '#8c8c8c'
};
// Color-blind friendly palette
const accessibleColors = [
'#1f77b4', // blue
'#ff7f0e', // orange
'#2ca02c', // green
'#d62728', // red
'#9467bd', // purple
'#8c564b', // brown
'#e377c2' // pink
];3. Performance Optimization
Data Management
- Implement efficient data structures
- Use pagination for large datasets
- Cache frequently accessed data
- Optimize data transformations
// Efficient data handling
function OptimizedDataComponent({ data }) {
// Memoize expensive calculations
const processedData = useMemo(() => {
return data.map(item => ({
...item,
normalizedValue: item.value / Math.max(...data.map(d => d.value))
}));
}, [data]);
// Use virtual scrolling for large lists
const VirtualizedList = memo(({ items }) => (
<VirtualList
height={400}
itemCount={items.length}
itemSize={50}
itemData={items}
>
{({ index, style, data }) => (
<div style={style}>
{data[index].name}
</div>
)}
</VirtualList>
));
return <VirtualizedList items={processedData} />;
}Component Optimization
- Use React.memo for expensive components
- Implement lazy loading
- Optimize re-render cycles
- Clean up event listeners
// Optimized component
const OptimizedChart = memo(({ data, config }) => {
const chartRef = useRef(null);
useEffect(() => {
const chart = chartRef.current;
// Setup chart
chart.setOption(config);
// Cleanup
return () => {
chart.dispose();
};
}, [config]);
return <div ref={chartRef} style={{ height: 300 }} />;
}, (prevProps, nextProps) => {
// Custom comparison for memo
return (
prevProps.data === nextProps.data &&
JSON.stringify(prevProps.config) === JSON.stringify(nextProps.config)
);
});Code Organization
1. Project Structure
Monorepo Organization
veltix/
├── apps/
│ ├── web/ # Main application
│ ├── api/ # Backend API
│ └── docs/ # Documentation
├── packages/
│ ├── charts/ # Chart components
│ ├── ui/ # UI components
│ ├── core/ # Core utilities
│ └── types/ # TypeScript types
└── shared/
├── constants/ # Shared constants
├── utils/ # Shared utilities
└── types/ # Shared typesComponent Organization
components/
├── charts/ # Chart components
│ ├── bar/
│ ├── line/
│ └── pie/
├── ui/ # UI components
│ ├── buttons/
│ ├── inputs/
│ └── layout/
└── dashboard/ # Dashboard components
├── header/
├── sidebar/
└── content/2. Code Standards
TypeScript Usage
- Use strict TypeScript configuration
- Define proper interfaces
- Avoid
anytype - Use generics for reusable components
// Proper TypeScript usage
interface ChartData {
id: string;
value: number;
category: string;
timestamp: Date;
}
interface ChartConfig {
type: 'bar' | 'line' | 'pie';
data: ChartData[];
options?: Partial<EChartsOption>;
}
const ChartComponent: React.FC<ChartConfig> = ({ type, data, options }) => {
// Component implementation
};Naming Conventions
- Use PascalCase for components
- Use camelCase for functions and variables
- Use kebab-case for CSS classes
- Use UPPER_CASE for constants
// Good naming conventions
const CHART_TYPES = {
BAR: 'bar',
LINE: 'line',
PIE: 'pie'
} as const;
const useChartData = (dataSource: string) => {
// Hook implementation
};
const ChartComponent: React.FC<ChartProps> = ({ data, config }) => {
// Component implementation
};3. State Management
Local State
- Use useState for simple state
- Use useReducer for complex state
- Keep state as close to usage as possible
- Avoid prop drilling
// Good state management
function Dashboard() {
const [components, setComponents] = useState<Component[]>([]);
const [selectedComponent, setSelectedComponent] = useState<string | null>(null);
const addComponent = useCallback((component: Component) => {
setComponents(prev => [...prev, component]);
}, []);
const updateComponent = useCallback((id: string, updates: Partial<Component>) => {
setComponents(prev =>
prev.map(comp =>
comp.id === id ? { ...comp, ...updates } : comp
)
);
}, []);
return (
<DashboardContext.Provider value={{ components, selectedComponent, addComponent, updateComponent }}>
<DashboardContent />
</DashboardContext.Provider>
);
}Global State
- Use Context for theme-wide state
- Use Zustand for complex state
- Keep state normalized
- Implement proper state persistence
// Global state with Zustand
interface DashboardStore {
components: Component[];
selectedComponent: string | null;
theme: Theme;
addComponent: (component: Component) => void;
updateComponent: (id: string, updates: Partial<Component>) => void;
setTheme: (theme: Theme) => void;
}
const useDashboardStore = create<DashboardStore>((set) => ({
components: [],
selectedComponent: null,
theme: 'light',
addComponent: (component) =>
set((state) => ({ components: [...state.components, component] })),
updateComponent: (id, updates) =>
set((state) => ({
components: state.components.map(comp =>
comp.id === id ? { ...comp, ...updates } : comp
)
})),
setTheme: (theme) => set({ theme })
}));Security Best Practices
1. Data Security
Input Validation
- Validate all user inputs
- Sanitize data before rendering
- Use TypeScript for type safety
- Implement proper error handling
// Input validation
const validateComponentConfig = (config: unknown): ComponentConfig => {
const schema = z.object({
id: z.string(),
type: z.enum(['chart', 'table', 'text']),
position: z.object({
x: z.number(),
y: z.number()
}),
size: z.object({
width: z.number().positive(),
height: z.number().positive()
})
});
return schema.parse(config);
};Data Sanitization
- Sanitize HTML content
- Escape special characters
- Validate URLs and file paths
- Use Content Security Policy
// Data sanitization
import DOMPurify from 'dompurify';
const sanitizeContent = (content: string): string => {
return DOMPurify.sanitize(content, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href', 'target']
});
};
const SafeTextComponent: React.FC<{ content: string }> = ({ content }) => {
const sanitizedContent = useMemo(() => sanitizeContent(content), [content]);
return <div dangerouslySetInnerHTML={{ __html: sanitizedContent }} />;
};2. API Security
Authentication
- Implement proper authentication
- Use JWT tokens
- Validate API keys
- Implement rate limiting
// API authentication
const apiClient = axios.create({
baseURL: process.env.REACT_APP_API_URL,
headers: {
'Authorization': `Bearer ${getToken()}`,
'Content-Type': 'application/json'
}
});
// Request interceptor
apiClient.interceptors.request.use((config) => {
const token = getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Response interceptor
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Handle unauthorized access
logout();
}
return Promise.reject(error);
}
);Data Encryption
- Use HTTPS for all communications
- Encrypt sensitive data
- Implement proper key management
- Use secure storage for tokens
// Data encryption utilities
import CryptoJS from 'crypto-js';
const encryptData = (data: string, key: string): string => {
return CryptoJS.AES.encrypt(data, key).toString();
};
const decryptData = (encryptedData: string, key: string): string => {
const bytes = CryptoJS.AES.decrypt(encryptedData, key);
return bytes.toString(CryptoJS.enc.Utf8);
};
// Secure storage
const secureStorage = {
set: (key: string, value: string) => {
const encrypted = encryptData(value, process.env.REACT_APP_ENCRYPTION_KEY!);
localStorage.setItem(key, encrypted);
},
get: (key: string): string | null => {
const encrypted = localStorage.getItem(key);
if (!encrypted) return null;
return decryptData(encrypted, process.env.REACT_APP_ENCRYPTION_KEY!);
}
};Testing Best Practices
1. Unit Testing
Component Testing
- Test component rendering
- Test user interactions
- Test prop changes
- Test error states
// Component testing
import { render, screen, fireEvent } from '@testing-library/react';
describe('ChartComponent', () => {
it('renders chart with data', () => {
const data = [{ category: 'A', value: 100 }];
render(<BarChart data={data} />);
expect(screen.getByRole('img')).toBeInTheDocument();
});
it('handles click events', () => {
const onClick = jest.fn();
const data = [{ category: 'A', value: 100 }];
render(<BarChart data={data} onClick={onClick} />);
fireEvent.click(screen.getByRole('img'));
expect(onClick).toHaveBeenCalled();
});
it('shows loading state', () => {
render(<BarChart data={[]} loading={true} />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
});
});Hook Testing
- Test hook logic
- Test state changes
- Test side effects
- Test error handling
// Hook testing
import { renderHook, act } from '@testing-library/react-hooks';
describe('useDataSource', () => {
it('loads data successfully', async () => {
const { result } = renderHook(() => useDataSource('test-data'));
expect(result.current.loading).toBe(true);
await act(async () => {
await result.current.refresh();
});
expect(result.current.loading).toBe(false);
expect(result.current.data).toBeDefined();
});
it('handles errors', async () => {
const { result } = renderHook(() => useDataSource('invalid-data'));
await act(async () => {
await result.current.refresh();
});
expect(result.current.error).toBeDefined();
});
});2. Integration Testing
Dashboard Testing
- Test complete workflows
- Test data flow
- Test component interactions
- Test theme switching
// Integration testing
describe('Dashboard Integration', () => {
it('creates and saves dashboard', async () => {
render(<Dashboard />);
// Add component
fireEvent.click(screen.getByText('Add Chart'));
fireEvent.click(screen.getByText('Bar Chart'));
// Configure component
fireEvent.change(screen.getByLabelText('Title'), {
target: { value: 'Sales Chart' }
});
// Save dashboard
fireEvent.click(screen.getByText('Save'));
expect(screen.getByText('Dashboard saved')).toBeInTheDocument();
});
it('switches themes', () => {
render(<Dashboard />);
const themeToggle = screen.getByRole('button', { name: /theme/i });
fireEvent.click(themeToggle);
expect(document.documentElement).toHaveAttribute('data-theme', 'dark');
});
});Performance Monitoring
1. Metrics Collection
Performance Metrics
- Monitor render times
- Track memory usage
- Measure API response times
- Monitor user interactions
// Performance monitoring
import { usePerformanceMonitor } from '@veltix/ui';
function DashboardWithMonitoring() {
const { metrics, alerts } = usePerformanceMonitor({
fps: true,
memory: true,
network: true,
renderTime: true
});
useEffect(() => {
// Log performance metrics
if (metrics.fps < 30) {
console.warn('Low FPS detected:', metrics.fps);
}
if (metrics.memory > 100 * 1024 * 1024) { // 100MB
console.warn('High memory usage:', metrics.memory);
}
}, [metrics]);
return <Dashboard />;
}Error Tracking
- Implement error boundaries
- Log errors to monitoring service
- Track user actions leading to errors
- Monitor API failures
// Error tracking
import * as Sentry from '@sentry/react';
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
environment: process.env.NODE_ENV,
integrations: [
new Sentry.BrowserTracing(),
new Sentry.Replay()
]
});
function ErrorBoundary({ children }) {
return (
<Sentry.ErrorBoundary
fallback={<div>Something went wrong</div>}
onError={(error, errorInfo) => {
console.error('Dashboard error:', error, errorInfo);
Sentry.captureException(error, { extra: errorInfo });
}}
>
{children}
</Sentry.ErrorBoundary>
);
}2. User Analytics
Usage Tracking
- Track component usage
- Monitor user interactions
- Analyze performance patterns
- Identify popular features
// Analytics tracking
import { useAnalytics } from '@veltix/ui';
function DashboardWithAnalytics() {
const { track } = useAnalytics();
const handleComponentAdd = (component) => {
track('component_added', {
component_type: component.type,
dashboard_id: dashboard.id
});
};
const handleThemeChange = (theme) => {
track('theme_changed', {
theme: theme,
user_id: user.id
});
};
return (
<Dashboard
onComponentAdd={handleComponentAdd}
onThemeChange={handleThemeChange}
/>
);
}Documentation Best Practices
1. Code Documentation
Component Documentation
- Document component props
- Provide usage examples
- Explain complex logic
- Include TypeScript types
/**
* BarChart component for displaying categorical data
*
* @example
* ```tsx
* <BarChart
* data={[{ category: 'A', value: 100 }]}
* xField="category"
* yField="value"
* height={300}
* />
* ```
*/
interface BarChartProps {
/** Chart data array */
data: ChartData[];
/** Field name for x-axis */
xField: string;
/** Field name for y-axis */
yField: string;
/** Chart height in pixels */
height?: number;
/** Chart color */
color?: string;
/** Enable animations */
animation?: boolean;
}
const BarChart: React.FC<BarChartProps> = ({
data,
xField,
yField,
height = 300,
color = '#1890ff',
animation = true
}) => {
// Component implementation
};API Documentation
- Document all public APIs
- Provide code examples
- Include error scenarios
- Explain return types
/**
* Hook for managing dashboard state
*
* @returns Dashboard state and actions
*
* @example
* ```tsx
* const { dashboard, addComponent, saveDashboard } = useDashboard();
*
* addComponent({
* type: 'chart',
* position: { x: 0, y: 0 },
* size: { width: 300, height: 200 }
* });
* ```
*/
export const useDashboard = () => {
// Hook implementation
};2. User Documentation
Getting Started
- Provide quick start guide
- Include common use cases
- Show best practices
- Include troubleshooting
API Reference
- Complete API documentation
- Interactive examples
- Type definitions
- Migration guides
Tutorials
- Step-by-step guides
- Video tutorials
- Sample projects
- Community examples
Deployment Best Practices
1. Build Optimization
Bundle Optimization
- Enable tree shaking
- Use code splitting
- Optimize images
- Minimize bundle size
// Webpack optimization
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
charts: {
test: /[\\/]packages[\\/]charts[\\/]/,
name: 'charts',
chunks: 'all'
}
}
}
}
};Environment Configuration
- Use environment variables
- Configure different environments
- Implement feature flags
- Set up monitoring
// Environment configuration
const config = {
api: {
url: process.env.REACT_APP_API_URL,
timeout: parseInt(process.env.REACT_APP_API_TIMEOUT || '5000')
},
features: {
realTimeUpdates: process.env.REACT_APP_REAL_TIME === 'true',
advancedCharts: process.env.REACT_APP_ADVANCED_CHARTS === 'true'
},
monitoring: {
enabled: process.env.NODE_ENV === 'production',
dsn: process.env.REACT_APP_SENTRY_DSN
}
};2. CI/CD Pipeline
Automated Testing
- Run tests on every commit
- Check code coverage
- Validate TypeScript types
- Test build process
# GitHub Actions workflow
name: CI/CD
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '18'
- run: pnpm install
- run: pnpm test
- run: pnpm type-check
- run: pnpm buildDeployment Strategy
- Use blue-green deployment
- Implement rollback strategy
- Monitor deployment health
- Set up staging environment
// Health check component
const HealthCheck: React.FC = () => {
const [health, setHealth] = useState('checking');
useEffect(() => {
fetch('/api/health')
.then(response => response.json())
.then(data => setHealth(data.status))
.catch(() => setHealth('error'));
}, []);
if (health === 'error') {
return <div>Service unavailable</div>;
}
return null;
};Conclusion
Following these best practices will help you build robust, maintainable, and scalable dashboards with Veltix. Remember to:
- Start Simple: Begin with basic functionality and iterate
- Test Early: Write tests as you develop features
- Monitor Performance: Keep an eye on performance metrics
- Document Everything: Maintain comprehensive documentation
- Stay Updated: Keep dependencies and practices current
- Get Feedback: Gather user feedback and iterate
- Plan for Scale: Design with future growth in mind
- Security First: Implement security measures from the start
By following these guidelines, you’ll create dashboards that are not only functional but also maintainable, performant, and user-friendly.