- Change the active file in workspace.json to point to the new modular-design.md. - Revise modular-design.md to enhance clarity and structure, including a new table of contents and updated sections on design philosophy, architecture components, and service abstractions. - Remove outdated content and improve the overall presentation of modular design patterns and best practices. These updates aim to streamline the documentation for better accessibility and understanding of the modular architecture.
391 lines
No EOL
12 KiB
Markdown
391 lines
No EOL
12 KiB
Markdown
# 🔧 Modular Design Patterns
|
|
|
|
> **Plugin-based architecture** enabling scalable, maintainable, and extensible feature development with dependency injection, service abstractions, and clean modular boundaries.
|
|
|
|
## Table of Contents
|
|
|
|
- [[#Design Philosophy]]
|
|
- [[#Architecture Components]]
|
|
- [[#Service Abstractions]]
|
|
- [[#Module Development]]
|
|
- [[#Implementation Patterns]]
|
|
- [[#Benefits & Trade-offs]]
|
|
|
|
## Design Philosophy
|
|
|
|
### **Separation of Concerns**
|
|
Each module owns its complete domain logic, from data models to UI components, ensuring clear boundaries and reducing coupling between features.
|
|
|
|
### **Dependency Injection**
|
|
Services communicate through well-defined interfaces using a centralized DI container, enabling loose coupling and testability.
|
|
|
|
### **Plugin-Based Development**
|
|
Features are implemented as self-contained modules that can be independently developed, tested, and deployed.
|
|
|
|
### **Reactive Architecture**
|
|
Services integrate Vue's reactivity system to provide automatic UI updates and consistent state management.
|
|
|
|
---
|
|
|
|
## Architecture Components
|
|
|
|
### **Plugin Manager**
|
|
Orchestrates module loading, dependency resolution, and lifecycle management:
|
|
|
|
```typescript
|
|
class PluginManager {
|
|
async loadModules(modules: ModulePlugin[]): Promise<void>
|
|
getDependencyGraph(): Map<string, string[]>
|
|
validateDependencies(modules: ModulePlugin[]): void
|
|
}
|
|
```
|
|
|
|
### **Dependency Injection Container**
|
|
Manages service registration, injection, and lifecycle:
|
|
|
|
```typescript
|
|
// Service registration
|
|
container.provide(SERVICE_TOKENS.RELAY_HUB, relayHub)
|
|
|
|
// Service consumption
|
|
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
|
```
|
|
|
|
### **BaseService Architecture**
|
|
Abstract foundation providing common patterns for all services:
|
|
|
|
```typescript
|
|
abstract class BaseService {
|
|
protected readonly metadata: ServiceMetadata
|
|
protected dependencies = new Map<string, any>()
|
|
|
|
abstract initialize(): Promise<void>
|
|
abstract dispose(): Promise<void>
|
|
}
|
|
```
|
|
|
|
### **Module Plugin Interface**
|
|
Standardized contract for all feature modules:
|
|
|
|
```typescript
|
|
interface ModulePlugin {
|
|
name: string
|
|
version: string
|
|
dependencies: string[]
|
|
|
|
install(app: App, options?: ModuleConfig): Promise<void>
|
|
routes?: RouteRecordRaw[]
|
|
components?: Record<string, Component>
|
|
}
|
|
```
|
|
|
|
## Service Abstractions
|
|
|
|
### **Core Infrastructure Services**
|
|
|
|
#### **AuthService** - User Identity Management
|
|
- **Purpose**: Centralized authentication with Nostr key handling
|
|
- **Features**: Session management, profile updates, secure key storage
|
|
- **Pattern**: BaseService with reactive state management
|
|
|
|
#### **RelayHub** - Nostr Connection Management
|
|
- **Purpose**: Centralized relay connections and event processing
|
|
- **Features**: Connection pooling, automatic reconnection, event deduplication
|
|
- **Pattern**: Service singleton with connection state management
|
|
|
|
#### **InvoiceService** - Lightning Payment Processing
|
|
- **Purpose**: Unified Lightning Network integration
|
|
- **Features**: Invoice creation, payment monitoring, QR code generation
|
|
- **Pattern**: BaseService with LNBits API integration
|
|
|
|
#### **ToastService** - User Notifications
|
|
- **Purpose**: Consistent notification system across modules
|
|
- **Features**: Context-specific messages, accessibility support
|
|
- **Pattern**: Service with method categorization by context
|
|
|
|
#### **StorageService** - User-Scoped Data Persistence
|
|
- **Purpose**: Secure, user-isolated local storage operations
|
|
- **Features**: Encryption, type safety, reactive storage
|
|
- **Pattern**: Service with automatic user prefixing
|
|
|
|
### **Shared Composables**
|
|
|
|
#### **useAuth()** - Authentication Access
|
|
```typescript
|
|
const auth = useAuth()
|
|
const { isAuthenticated, currentUser, login, logout } = auth
|
|
```
|
|
|
|
#### **useToast()** - Notification Access
|
|
```typescript
|
|
const toast = useToast()
|
|
toast.success('Operation completed!')
|
|
toast.error('Operation failed')
|
|
```
|
|
|
|
#### **useStorage()** - Storage Access
|
|
```typescript
|
|
const storage = useStorage()
|
|
const userData = storage.getUserData('preferences', defaultPrefs)
|
|
```
|
|
|
|
## Module Development
|
|
|
|
### **Module Structure Pattern**
|
|
Each module follows a consistent directory structure:
|
|
|
|
```
|
|
src/modules/[module-name]/
|
|
├── index.ts # Module plugin definition
|
|
├── components/ # Module-specific UI components
|
|
├── composables/ # Module composables and hooks
|
|
├── services/ # Business logic services
|
|
├── stores/ # Module-specific Pinia stores
|
|
├── types/ # TypeScript type definitions
|
|
└── views/ # Page components and routes
|
|
```
|
|
|
|
### **Service Development Pattern**
|
|
Services extend BaseService for consistent lifecycle management:
|
|
|
|
```typescript
|
|
export class MyService extends BaseService {
|
|
protected readonly metadata = {
|
|
name: 'MyService',
|
|
dependencies: ['AuthService', 'RelayHub']
|
|
}
|
|
|
|
constructor() {
|
|
super()
|
|
}
|
|
|
|
async initialize(): Promise<void> {
|
|
await super.initialize() // Initialize dependencies
|
|
// Service-specific initialization
|
|
this.isInitialized.value = true
|
|
}
|
|
|
|
async dispose(): Promise<void> {
|
|
// Cleanup logic
|
|
this.isDisposed.value = true
|
|
}
|
|
}
|
|
```
|
|
|
|
### **Module Registration Pattern**
|
|
Standardized module plugin structure:
|
|
|
|
```typescript
|
|
export const myModule: ModulePlugin = {
|
|
name: 'my-module',
|
|
version: '1.0.0',
|
|
dependencies: ['base'],
|
|
|
|
async install(app: App, options?: MyModuleConfig) {
|
|
// 1. Create and register services
|
|
const myService = new MyService()
|
|
container.provide(SERVICE_TOKENS.MY_SERVICE, myService)
|
|
|
|
// 2. Register global components
|
|
app.component('MyGlobalComponent', MyGlobalComponent)
|
|
|
|
// 3. Initialize services
|
|
await myService.initialize()
|
|
},
|
|
|
|
routes: [
|
|
{
|
|
path: '/my-feature',
|
|
component: () => import('./views/MyFeatureView.vue')
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### **Dependency Declaration**
|
|
Services declare dependencies through metadata:
|
|
|
|
```typescript
|
|
protected readonly metadata = {
|
|
name: 'ChatService',
|
|
dependencies: ['AuthService', 'RelayHub', 'StorageService']
|
|
}
|
|
|
|
// Access injected dependencies
|
|
private get authService(): AuthService {
|
|
return this.dependencies.get('AuthService') as AuthService
|
|
}
|
|
```
|
|
|
|
## Implementation Patterns
|
|
|
|
### **Cross-Module Communication**
|
|
|
|
#### **Service Dependencies**
|
|
For required functionality between modules:
|
|
```typescript
|
|
// ✅ Correct: Use dependency injection
|
|
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
|
|
|
// ❌ Wrong: Direct import breaks modularity
|
|
import { relayHub } from '../base/services/relay-hub'
|
|
```
|
|
|
|
#### **Event Bus Communication**
|
|
For optional cross-module notifications:
|
|
```typescript
|
|
// Publishing events
|
|
eventBus.emit('user:authenticated', { userId: user.pubkey })
|
|
eventBus.emit('payment:received', { amount: 1000, invoiceId: 'abc123' })
|
|
|
|
// Subscribing to events
|
|
eventBus.on('chat:message-received', (message) => {
|
|
// Handle cross-module events
|
|
})
|
|
```
|
|
|
|
#### **Shared Components**
|
|
Modules can export components for reuse:
|
|
```typescript
|
|
// In module plugin definition
|
|
export const chatModule: ModulePlugin = {
|
|
components: {
|
|
'ChatAvatar': () => import('./components/ChatAvatar.vue'),
|
|
'MessageBubble': () => import('./components/MessageBubble.vue')
|
|
}
|
|
}
|
|
|
|
// Usage in other modules
|
|
<ChatAvatar :pubkey="user.pubkey" :size="32" />
|
|
```
|
|
|
|
### **State Management Patterns**
|
|
|
|
#### **Service-Based State**
|
|
Core state managed by services:
|
|
```typescript
|
|
// AuthService manages authentication state
|
|
export class AuthService extends BaseService {
|
|
public isAuthenticated = ref(false)
|
|
public user = ref<User | null>(null)
|
|
|
|
// Computed properties for components
|
|
public userDisplay = computed(() => this.user.value?.name || 'Anonymous')
|
|
}
|
|
```
|
|
|
|
#### **Module-Specific Stores**
|
|
Complex state handled by Pinia stores:
|
|
```typescript
|
|
// Market module store
|
|
export const useMarketStore = defineStore('market', () => {
|
|
const products = ref<Product[]>([])
|
|
const cartItems = ref<CartItem[]>([])
|
|
|
|
// Access shared services
|
|
const auth = useAuth()
|
|
const toast = useToast()
|
|
|
|
return { products, cartItems }
|
|
})
|
|
```
|
|
|
|
### **Error Handling Patterns**
|
|
|
|
#### **Service-Level Error Handling**
|
|
Centralized error handling in services:
|
|
```typescript
|
|
export class MyService extends BaseService {
|
|
protected handleError(error: Error, context: string) {
|
|
console.error(`[${this.metadata.name}] ${context}:`, error)
|
|
|
|
// Use toast service for user notifications
|
|
const toast = injectService(SERVICE_TOKENS.TOAST_SERVICE)
|
|
toast.error(`${context} failed: ${error.message}`)
|
|
}
|
|
}
|
|
```
|
|
|
|
#### **Component-Level Error Handling**
|
|
Consistent error display in components:
|
|
```vue
|
|
<script setup lang="ts">
|
|
const { error, isLoading, execute } = useAsyncOperation()
|
|
|
|
const handleAction = () => execute(async () => {
|
|
await myService.performAction()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<button @click="handleAction" :disabled="isLoading">
|
|
{{ isLoading ? 'Loading...' : 'Perform Action' }}
|
|
</button>
|
|
<div v-if="error" class="error">{{ error }}</div>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
## Benefits & Trade-offs
|
|
|
|
### **Achieved Benefits**
|
|
|
|
#### **Development Velocity**
|
|
- **Consistent Patterns** - Standardized development approaches across modules
|
|
- **Reusable Services** - Shared infrastructure reduces implementation time
|
|
- **Type Safety** - Dependency injection eliminates `as any` casting
|
|
- **Clear Boundaries** - Module separation simplifies feature development
|
|
|
|
#### **Maintainability**
|
|
- **Single Source of Truth** - Centralized services eliminate duplication
|
|
- **Dependency Visibility** - Clear service relationships and requirements
|
|
- **Testability** - Isolated modules and mockable dependencies
|
|
- **Extensibility** - Easy to add new modules without affecting existing ones
|
|
|
|
#### **User Experience**
|
|
- **Consistent Interface** - Unified patterns across all features
|
|
- **Reliable Performance** - Optimized shared services
|
|
- **Progressive Loading** - Lazy-loaded modules for faster initial load
|
|
- **Error Recovery** - Consistent error handling and user feedback
|
|
|
|
### **Architectural Trade-offs**
|
|
|
|
#### **Complexity vs. Flexibility**
|
|
- **Increased Initial Setup** - More boilerplate for dependency injection
|
|
- **Enhanced Flexibility** - Easy to swap implementations and add features
|
|
- **Learning Curve** - Developers need to understand DI patterns
|
|
- **Long-term Benefits** - Reduced complexity as application grows
|
|
|
|
#### **Performance Considerations**
|
|
- **Service Initialization** - Dependency resolution overhead at startup
|
|
- **Memory Efficiency** - Singleton services reduce memory usage
|
|
- **Bundle Optimization** - Module-based code splitting improves loading
|
|
- **Runtime Performance** - Optimized shared services benefit all modules
|
|
|
|
### **Best Practices Established**
|
|
|
|
1. **Always use dependency injection** for cross-module service access
|
|
2. **Extend BaseService** for all business logic services
|
|
3. **Declare dependencies explicitly** in service metadata
|
|
4. **Use reactive state** for UI-affecting service properties
|
|
5. **Handle errors consistently** through standardized patterns
|
|
6. **Test modules in isolation** with mocked dependencies
|
|
|
|
## See Also
|
|
|
|
### Architecture Documentation
|
|
- **[[index|🏗️ Architecture Overview]]** - System design principles
|
|
- **[[dependency-injection|⚙️ Dependency Injection]]** - DI container system
|
|
- **[[authentication-architecture|🔐 Authentication Architecture]]** - Auth service patterns
|
|
|
|
### Development Guides
|
|
- **[[../04-development/index|💻 Development Guide]]** - Module development workflows
|
|
- **[[../02-modules/index|📦 Module System]]** - Individual module documentation
|
|
- **[[../03-core-services/index|⚙️ Core Services]]** - Infrastructure service details
|
|
|
|
---
|
|
|
|
**Tags:** #architecture #modular-design #dependency-injection #plugin-system
|
|
**Last Updated:** 2025-09-07
|
|
**Author:** Development Team |