web-app/docs/01-architecture/modular-design.md
padreug a373fa714d Update modular design documentation and workspace configuration
- 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.
2025-09-08 12:03:28 +02:00

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