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:

  1. Authentication Module

    • User management
    • SSO integration
    • Session handling
  2. Dashboard Module

    • Dashboard creation/editing
    • Widget management
    • Grid layout system
  3. Detection Module

    • Detection creation/editing
    • Detection library
    • MITRE mapping
  4. Query Module

    • Query execution
    • Natural language processing
    • Query history
  5. Intelligence Module

    • Threat intelligence
    • Article management
    • Chat integration
  6. Settings Module

    • User settings
    • Connector management
    • Role management
  7. Assessment Module

    • Data discovery
    • Schema exploration
    • Query planning
  8. 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

  1. Independent Development: Teams can work on different modules simultaneously
  2. Reusability: Modules can be reused across different applications
  3. Testability: Each module can be tested in isolation
  4. Maintainability: Changes in one module don’t affect others
  5. Scalability: Easy to add new modules or remove existing ones
  6. 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

  1. Shared Dependencies: Create a shared module for common utilities, types, and components
  2. Module Communication: Implement event-driven communication between modules
  3. State Management: Each module should manage its own state with minimal global state
  4. Testing Strategy: Each module should have its own test suite
  5. Documentation: Each module should have clear documentation and API contracts

Potential Challenges

  1. Initial Complexity: Setting up the module infrastructure requires significant upfront work
  2. Module Dependencies: Managing dependencies between modules can be complex
  3. Performance: Module loading and initialization might impact performance
  4. Debugging: Debugging across modules can be more challenging
  5. 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