Modular Design
Date: 2025-22-09
Status: accepted
Current Architecture Analysis
The Vega web application is built with Remix (React Router v7) and follows a feature-based routing structure with the following characteristics:
Current Structure
services/remix/
├── app/
│ ├── components/ # Shared components
│ │ ├── ui/ # Design system components (shadcn/ui based)
│ │ ├── chat/ # Chat-related components
│ │ ├── forms/ # Form components
│ │ └── shared/ # Shared business components
│ ├── routes/ # Route-based organization
│ │ ├── alerts+/ # Alerts feature
│ │ ├── dashboards+/ # Dashboards feature
│ │ ├── detections+/ # Detections feature
│ │ ├── assessment+/ # Data assessment feature
│ │ ├── intel+/ # Intelligence feature
│ │ ├── notebooks+/ # Notebooks feature
│ │ ├── query+/ # Query feature
│ │ ├── settings+/ # Settings feature
│ │ └── _auth+/ # Authentication
│ ├── queries/ # GraphQL queries
│ ├── utils/ # Utility functions
│ └── transformations/ # Data transformations
Key Technologies
- Framework: Remix (React Router v7) with Vite
- UI Library: shadcn/ui components + Radix UI primitives
- State Management: Zustand + React Query
- Styling: Tailwind CSS
- Data Fetching: GraphQL with custom hooks
- Testing: Vitest + Playwright
Modular Design Pattern Migration
What is Modular Design?
Modular design breaks down the application into independent, reusable modules where each module encapsulates related functionality, data, and dependencies. Each module can be developed, tested, and deployed independently.
Migration Strategy
Phase 1: Identify Core Modules
Based on the current feature structure, identify these core modules:
-
Authentication Module
- User management
- SSO integration
- Session handling
-
Dashboard Module
- Dashboard creation/editing
- Widget management
- Grid layout system
-
Detection Module
- Detection creation/editing
- Detection library
- MITRE mapping
-
Query Module
- Query execution
- Natural language processing
- Query history
-
Intelligence Module
- Threat intelligence
- Article management
- Chat integration
-
Settings Module
- User settings
- Connector management
- Role management
-
Assessment Module
- Data discovery
- Schema exploration
- Query planning
-
Notebook Module
- Notebook management
- Cell execution
- Collaboration features
Phase 2: Module Structure Design
Each module should follow this structure:
modules/
├── auth/
│ ├── components/ # Module-specific components
│ ├── hooks/ # Module-specific hooks
│ ├── services/ # API calls and business logic
│ ├── stores/ # Module state management
│ ├── types/ # TypeScript definitions
│ ├── utils/ # Module utilities
│ ├── constants/ # Module constants
│ ├── index.ts # Public API exports
│ └── module.config.ts # Module configuration
├── dashboard/
│ ├── components/
│ ├── hooks/
│ ├── services/
│ ├── stores/
│ ├── types/
│ ├── utils/
│ ├── constants/
│ ├── index.ts
│ └── module.config.ts
└── ...
Phase 3: Implementation Steps
Step 1: Create Module Infrastructure
// modules/shared/types/module.ts
export interface ModuleConfig {
name: string;
version: string;
dependencies: string[];
routes: ModuleRoute[];
permissions: string[];
}
export interface ModuleRoute {
path: string;
component: React.ComponentType;
loader?: LoaderFunction;
action?: ActionFunction;
}
// modules/shared/core/module-registry.ts
export class ModuleRegistry {
private modules = new Map<string, ModuleConfig>();
register(module: ModuleConfig) {
this.modules.set(module.name, module);
}
getModule(name: string): ModuleConfig | undefined {
return this.modules.get(name);
}
getAllModules(): ModuleConfig[] {
return Array.from(this.modules.values());
}
}Step 2: Extract Authentication Module
// modules/auth/index.ts
export { AuthProvider } from './components/AuthProvider';
export { useAuth } from './hooks/useAuth';
export { authService } from './services/authService';
export { authStore } from './stores/authStore';
export type { User, AuthState } from './types';
// modules/auth/module.config.ts
export const authModule: ModuleConfig = {
name: 'auth',
version: '1.0.0',
dependencies: [],
routes: [
{
path: '/login',
component: LoginPage,
loader: loginLoader,
},
{
path: '/logout',
component: LogoutPage,
action: logoutAction,
},
],
permissions: ['auth:read', 'auth:write'],
};Step 3: Extract Dashboard Module
// modules/dashboard/index.ts
export { DashboardProvider } from './components/DashboardProvider';
export { DashboardGrid } from './components/DashboardGrid';
export { useDashboard } from './hooks/useDashboard';
export { dashboardService } from './services/dashboardService';
export { dashboardStore } from './stores/dashboardStore';
export type { Dashboard, Widget } from './types';
// modules/dashboard/components/DashboardProvider.tsx
export function DashboardProvider({ children }: { children: React.ReactNode }) {
const store = useDashboardStore();
return (
<DashboardContext.Provider value={store}>
{children}
</DashboardContext.Provider>
);
}Step 4: Update Route Configuration
// app/routes.ts
import { authModule } from '../modules/auth/module.config';
import { dashboardModule } from '../modules/dashboard/module.config';
import { detectionModule } from '../modules/detection/module.config';
// ... other modules
export default [
// Register modules
...authModule.routes,
...dashboardModule.routes,
...detectionModule.routes,
// ... other module routes
] satisfies RouteConfig;Step 5: Implement Module Communication
// modules/shared/core/event-bus.ts
export class ModuleEventBus {
private listeners = new Map<string, Function[]>();
emit(event: string, data: any) {
const eventListeners = this.listeners.get(event);
if (eventListeners) {
eventListeners.forEach(listener => listener(data));
}
}
on(event: string, listener: Function) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event)!.push(listener);
}
off(event: string, listener: Function) {
const eventListeners = this.listeners.get(event);
if (eventListeners) {
const index = eventListeners.indexOf(listener);
if (index > -1) {
eventListeners.splice(index, 1);
}
}
}
}
// Usage in modules
// modules/dashboard/hooks/useDashboard.ts
export function useDashboard() {
const eventBus = useEventBus();
const createDashboard = useCallback((data: CreateDashboardData) => {
return dashboardService.create(data).then(result => {
eventBus.emit('dashboard:created', result);
return result;
});
}, [eventBus]);
return { createDashboard };
}Phase 4: Benefits of Modular Design
- Independent Development: Teams can work on different modules simultaneously
- Reusability: Modules can be reused across different applications
- Testability: Each module can be tested in isolation
- Maintainability: Changes in one module don’t affect others
- Scalability: Easy to add new modules or remove existing ones
- Deployment: Modules can be deployed independently
Phase 5: Migration Timeline
Week 1-2: Setup module infrastructure and extract authentication module Week 3-4: Extract dashboard and detection modules Week 5-6: Extract query and intelligence modules Week 7-8: Extract remaining modules and integration testing Week 9-10: Performance optimization and documentation
Implementation Considerations
- Shared Dependencies: Create a shared module for common utilities, types, and components
- Module Communication: Implement event-driven communication between modules
- State Management: Each module should manage its own state with minimal global state
- Testing Strategy: Each module should have its own test suite
- Documentation: Each module should have clear documentation and API contracts
Potential Challenges
- Initial Complexity: Setting up the module infrastructure requires significant upfront work
- Module Dependencies: Managing dependencies between modules can be complex
- Performance: Module loading and initialization might impact performance
- Debugging: Debugging across modules can be more challenging
- Team Coordination: Requires clear communication and coordination between teams
Success Metrics
- Code Reusability: Percentage of code reused across modules
- Development Velocity: Time to implement new features
- Bug Isolation: Percentage of bugs contained within modules
- Team Productivity: Features delivered per team per sprint
- Deployment Frequency: Frequency of independent module deployments