Create comprehensive Obsidian-style documentation structure
- Reorganize all markdown documentation into structured docs/ folder - Create 7 main documentation categories (00-overview through 06-deployment) - Add comprehensive index files for each category with cross-linking - Implement Obsidian-compatible [[link]] syntax throughout - Move legacy/deprecated documentation to archive folder - Establish documentation standards and maintenance guidelines - Provide complete coverage of modular architecture, services, and deployment - Enable better navigation and discoverability for developers and contributors 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
46856134ef
commit
cdf099e45f
29 changed files with 3733 additions and 0 deletions
496
docs/03-core-services/index.md
Normal file
496
docs/03-core-services/index.md
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
# ⚙️ Core Services Overview
|
||||
|
||||
> **Shared infrastructure services** providing foundational functionality across all modules with reactive architecture, dependency injection, and lifecycle management.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [[#Service Architecture]]
|
||||
- [[#Available Services]]
|
||||
- [[#Service Lifecycle]]
|
||||
- [[#Dependency Injection]]
|
||||
- [[#Service Development]]
|
||||
- [[#Testing Services]]
|
||||
|
||||
## Service Architecture
|
||||
|
||||
### **BaseService Foundation**
|
||||
All core services extend the `BaseService` abstract class which provides:
|
||||
|
||||
- **Reactive State Management** - Integration with Vue's reactivity system
|
||||
- **Lifecycle Management** - Standardized initialization and disposal
|
||||
- **Error Handling** - Consistent error patterns across services
|
||||
- **Type Safety** - Full TypeScript support with strict typing
|
||||
|
||||
```typescript
|
||||
abstract class BaseService {
|
||||
protected isInitialized = ref(false)
|
||||
protected isDisposed = ref(false)
|
||||
|
||||
abstract initialize(): Promise<void>
|
||||
abstract dispose(): Promise<void>
|
||||
|
||||
// Reactive state helpers
|
||||
protected createReactiveState<T>(initialValue: T): Ref<T>
|
||||
protected createComputedState<T>(getter: () => T): ComputedRef<T>
|
||||
}
|
||||
```
|
||||
|
||||
### **Service Registration Pattern**
|
||||
Services are registered in the dependency injection container during module installation:
|
||||
|
||||
```typescript
|
||||
// Service registration (in base module)
|
||||
container.provide(SERVICE_TOKENS.RELAY_HUB, relayHub)
|
||||
container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService)
|
||||
container.provide(SERVICE_TOKENS.STORAGE_SERVICE, storageService)
|
||||
|
||||
// Service consumption (anywhere in app)
|
||||
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
||||
const auth = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
```
|
||||
|
||||
## Available Services
|
||||
|
||||
### **AuthService** 🔐
|
||||
**Purpose:** User authentication and identity management
|
||||
**Location:** `src/modules/base/auth/auth-service.ts`
|
||||
**Token:** `SERVICE_TOKENS.AUTH_SERVICE`
|
||||
|
||||
**Key Features:**
|
||||
- **Key Management** - Secure generation, import, and storage of Nostr keys
|
||||
- **User Sessions** - Persistent authentication with encrypted storage
|
||||
- **Profile Management** - User profile creation and updates
|
||||
- **Security** - Client-side key handling with no server storage
|
||||
|
||||
**Reactive State:**
|
||||
```typescript
|
||||
interface AuthService {
|
||||
user: Ref<NostrUser | null> // Current authenticated user
|
||||
isAuthenticated: ComputedRef<boolean> // Authentication status
|
||||
isLoading: Ref<boolean> // Loading state
|
||||
loginError: Ref<string | null> // Login error message
|
||||
}
|
||||
```
|
||||
|
||||
**Key Methods:**
|
||||
- `generateKeyPair()` - Create new Nostr key pair
|
||||
- `loginWithPrivateKey(privateKey: string)` - Authenticate with existing key
|
||||
- `logout()` - Clear session and user data
|
||||
- `updateProfile(profile: UserMetadata)` - Update user profile
|
||||
|
||||
**See:** [[authentication|📖 Authentication Service Documentation]]
|
||||
|
||||
### **RelayHub** 🌐
|
||||
**Purpose:** Centralized Nostr relay connection management
|
||||
**Location:** `src/modules/base/nostr/relay-hub.ts`
|
||||
**Token:** `SERVICE_TOKENS.RELAY_HUB`
|
||||
|
||||
**Key Features:**
|
||||
- **Connection Management** - Automatic connection, reconnection, and failover
|
||||
- **Event Publishing** - Reliable event publishing across multiple relays
|
||||
- **Subscription Management** - Efficient event subscriptions with deduplication
|
||||
- **Performance Monitoring** - Relay latency and success rate tracking
|
||||
|
||||
**Reactive State:**
|
||||
```typescript
|
||||
interface RelayHub {
|
||||
connectedRelays: Ref<string[]> // Currently connected relays
|
||||
connectionStatus: ComputedRef<ConnectionStatus> // Overall connection status
|
||||
relayStats: Ref<Map<string, RelayStats>> // Per-relay statistics
|
||||
isConnecting: Ref<boolean> // Connection in progress
|
||||
}
|
||||
```
|
||||
|
||||
**Key Methods:**
|
||||
- `connect(relays: string[])` - Connect to relay URLs
|
||||
- `publishEvent(event: NostrEvent)` - Publish event to all connected relays
|
||||
- `subscribe(filters: Filter[], callback: EventCallback)` - Subscribe to events
|
||||
- `getRelayInfo(url: string)` - Get relay connection information
|
||||
|
||||
**See:** [[../01-architecture/relay-hub|📖 Relay Hub Architecture Documentation]]
|
||||
|
||||
### **StorageService** 💾
|
||||
**Purpose:** User-scoped local storage operations
|
||||
**Location:** `src/core/services/StorageService.ts`
|
||||
**Token:** `SERVICE_TOKENS.STORAGE_SERVICE`
|
||||
|
||||
**Key Features:**
|
||||
- **User-Scoped Storage** - Automatic key prefixing per authenticated user
|
||||
- **Type-Safe Operations** - Strongly typed get/set operations with JSON serialization
|
||||
- **Reactive Updates** - Optional reactive storage with Vue refs
|
||||
- **Migration Support** - Data migration between storage schema versions
|
||||
|
||||
**Key Methods:**
|
||||
```typescript
|
||||
interface StorageService {
|
||||
setUserData<T>(key: string, data: T): void
|
||||
getUserData<T>(key: string, defaultValue?: T): T | undefined
|
||||
removeUserData(key: string): void
|
||||
clearUserData(): void
|
||||
|
||||
// Reactive variants
|
||||
getReactiveUserData<T>(key: string, defaultValue: T): Ref<T>
|
||||
setReactiveUserData<T>(key: string, ref: Ref<T>): void
|
||||
}
|
||||
```
|
||||
|
||||
**Storage Patterns:**
|
||||
- User-specific keys: `user:{pubkey}:settings`
|
||||
- Global application keys: `app:theme`
|
||||
- Module-specific keys: `user:{pubkey}:chat:contacts`
|
||||
|
||||
**See:** [[storage-service|📖 Storage Service Documentation]]
|
||||
|
||||
### **ToastService** 📢
|
||||
**Purpose:** Application-wide notifications and user feedback
|
||||
**Location:** `src/core/services/ToastService.ts`
|
||||
**Token:** `SERVICE_TOKENS.TOAST_SERVICE`
|
||||
|
||||
**Key Features:**
|
||||
- **Context-Specific Methods** - Pre-configured toasts for common scenarios
|
||||
- **Consistent Messaging** - Standardized success, error, and info messages
|
||||
- **Accessibility** - Screen reader compatible notifications
|
||||
- **Customizable** - Support for custom toast content and actions
|
||||
|
||||
**Organized by Context:**
|
||||
```typescript
|
||||
interface ToastService {
|
||||
// Authentication context
|
||||
auth: {
|
||||
loginSuccess(): void
|
||||
loginError(error?: string): void
|
||||
logoutSuccess(): void
|
||||
keyGenerated(): void
|
||||
}
|
||||
|
||||
// Payment context
|
||||
payment: {
|
||||
invoiceCreated(): void
|
||||
paymentReceived(): void
|
||||
paymentFailed(error?: string): void
|
||||
}
|
||||
|
||||
// Clipboard operations
|
||||
clipboard: {
|
||||
copied(item?: string): void
|
||||
copyFailed(): void
|
||||
}
|
||||
|
||||
// General operations
|
||||
operation: {
|
||||
success(message: string): void
|
||||
error(message: string): void
|
||||
info(message: string): void
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**See:** [[toast-service|📖 Toast Service Documentation]]
|
||||
|
||||
### **EventBus** 📡
|
||||
**Purpose:** Inter-module communication and event coordination
|
||||
**Location:** `src/core/services/EventBus.ts`
|
||||
**Token:** `SERVICE_TOKENS.EVENT_BUS`
|
||||
|
||||
**Key Features:**
|
||||
- **Type-Safe Events** - Strongly typed event payloads
|
||||
- **Module Isolation** - Clean communication between modules
|
||||
- **Event Namespacing** - Organized event names by domain
|
||||
- **Subscription Management** - Easy subscribe/unsubscribe patterns
|
||||
|
||||
**Event Categories:**
|
||||
```typescript
|
||||
interface EventBusEvents {
|
||||
// User events
|
||||
'user:authenticated': { userId: string, profile: UserMetadata }
|
||||
'user:profile-updated': { userId: string, changes: Partial<UserMetadata> }
|
||||
'user:logout': { userId: string }
|
||||
|
||||
// Chat events
|
||||
'chat:message-received': { messageId: string, from: string, content: string }
|
||||
'chat:typing-start': { from: string, chatId: string }
|
||||
|
||||
// Payment events
|
||||
'payment:invoice-created': { invoiceId: string, amount: number }
|
||||
'payment:received': { invoiceId: string, amount: number }
|
||||
|
||||
// Relay events
|
||||
'relay:connected': { url: string }
|
||||
'relay:disconnected': { url: string, reason?: string }
|
||||
}
|
||||
```
|
||||
|
||||
**See:** [[../01-architecture/event-bus|📖 Event Bus Communication Documentation]]
|
||||
|
||||
## Service Lifecycle
|
||||
|
||||
### **Initialization Phase**
|
||||
Services are initialized in dependency order during application startup:
|
||||
|
||||
```typescript
|
||||
// 1. Base services (no dependencies)
|
||||
await authService.initialize()
|
||||
await storageService.initialize()
|
||||
|
||||
// 2. Infrastructure services (depend on base services)
|
||||
await relayHub.initialize()
|
||||
await toastService.initialize()
|
||||
|
||||
// 3. Feature services (depend on infrastructure)
|
||||
await chatService.initialize()
|
||||
await eventsService.initialize()
|
||||
```
|
||||
|
||||
### **Service Dependencies**
|
||||
Services declare their dependencies through constructor injection:
|
||||
|
||||
```typescript
|
||||
class ChatService extends BaseService {
|
||||
constructor(
|
||||
private auth = injectService(SERVICE_TOKENS.AUTH_SERVICE),
|
||||
private relayHub = injectService(SERVICE_TOKENS.RELAY_HUB),
|
||||
private storage = injectService(SERVICE_TOKENS.STORAGE_SERVICE),
|
||||
private eventBus = injectService(SERVICE_TOKENS.EVENT_BUS)
|
||||
) {
|
||||
super()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Disposal Phase**
|
||||
Services are disposed in reverse dependency order during application shutdown:
|
||||
|
||||
```typescript
|
||||
async dispose(): Promise<void> {
|
||||
// Clean up subscriptions
|
||||
this.subscriptions.forEach(sub => sub.close())
|
||||
|
||||
// Save persistent state
|
||||
await this.storage.setUserData('chat:messages', this.messages.value)
|
||||
|
||||
// Mark as disposed
|
||||
this.isDisposed.value = true
|
||||
}
|
||||
```
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
### **Service Tokens**
|
||||
Type-safe service tokens prevent runtime errors and enable proper TypeScript inference:
|
||||
|
||||
```typescript
|
||||
export const SERVICE_TOKENS = {
|
||||
AUTH_SERVICE: Symbol('AUTH_SERVICE') as InjectionKey<AuthService>,
|
||||
RELAY_HUB: Symbol('RELAY_HUB') as InjectionKey<RelayHub>,
|
||||
STORAGE_SERVICE: Symbol('STORAGE_SERVICE') as InjectionKey<StorageService>,
|
||||
TOAST_SERVICE: Symbol('TOAST_SERVICE') as InjectionKey<ToastService>,
|
||||
} as const
|
||||
```
|
||||
|
||||
### **Service Registration**
|
||||
Services are registered during module installation:
|
||||
|
||||
```typescript
|
||||
// In base module installation
|
||||
export async function installBaseModule(app: App) {
|
||||
// Create service instances
|
||||
const authService = new AuthService()
|
||||
const relayHub = new RelayHub()
|
||||
const storageService = new StorageService()
|
||||
|
||||
// Register in container
|
||||
container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService)
|
||||
container.provide(SERVICE_TOKENS.RELAY_HUB, relayHub)
|
||||
container.provide(SERVICE_TOKENS.STORAGE_SERVICE, storageService)
|
||||
|
||||
// Initialize services
|
||||
await authService.initialize()
|
||||
await relayHub.initialize()
|
||||
}
|
||||
```
|
||||
|
||||
### **Service Consumption**
|
||||
Services are injected where needed using type-safe injection:
|
||||
|
||||
```typescript
|
||||
// In composables
|
||||
export function useAuth() {
|
||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
|
||||
return {
|
||||
user: authService.user,
|
||||
login: authService.login,
|
||||
logout: authService.logout
|
||||
}
|
||||
}
|
||||
|
||||
// In components
|
||||
<script setup>
|
||||
const toast = injectService(SERVICE_TOKENS.TOAST_SERVICE)
|
||||
const handleSuccess = () => toast.operation.success('Action completed!')
|
||||
</script>
|
||||
```
|
||||
|
||||
## Service Development
|
||||
|
||||
### **Creating a New Service**
|
||||
|
||||
#### 1. Service Class Implementation
|
||||
```typescript
|
||||
// src/core/services/MyService.ts
|
||||
export class MyService extends BaseService {
|
||||
// Reactive state
|
||||
private readonly _data = ref<MyData[]>([])
|
||||
private readonly _isLoading = ref(false)
|
||||
|
||||
// Public readonly access to state
|
||||
public readonly data = readonly(this._data)
|
||||
public readonly isLoading = readonly(this._isLoading)
|
||||
|
||||
constructor(
|
||||
private dependency = injectService(SERVICE_TOKENS.DEPENDENCY)
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
// Initialization logic
|
||||
await this.loadInitialData()
|
||||
this.isInitialized.value = true
|
||||
}
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
// Cleanup logic
|
||||
this._data.value = []
|
||||
this.isDisposed.value = true
|
||||
}
|
||||
|
||||
// Public methods
|
||||
async createItem(item: CreateItemRequest): Promise<MyData> {
|
||||
this._isLoading.value = true
|
||||
try {
|
||||
const newItem = await this.dependency.create(item)
|
||||
this._data.value.push(newItem)
|
||||
return newItem
|
||||
} finally {
|
||||
this._isLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Service Token Registration
|
||||
```typescript
|
||||
// Add to SERVICE_TOKENS
|
||||
export const SERVICE_TOKENS = {
|
||||
// ... existing tokens
|
||||
MY_SERVICE: Symbol('MY_SERVICE') as InjectionKey<MyService>,
|
||||
} as const
|
||||
```
|
||||
|
||||
#### 3. Service Registration in Module
|
||||
```typescript
|
||||
// In module installation
|
||||
const myService = new MyService()
|
||||
container.provide(SERVICE_TOKENS.MY_SERVICE, myService)
|
||||
await myService.initialize()
|
||||
```
|
||||
|
||||
### **Service Best Practices**
|
||||
|
||||
#### **Reactive State Management**
|
||||
- Use `ref()` for mutable state, `readonly()` for public access
|
||||
- Provide computed properties for derived state
|
||||
- Use `watch()` and `watchEffect()` for side effects
|
||||
|
||||
#### **Error Handling**
|
||||
- Throw descriptive errors with proper types
|
||||
- Use try/catch blocks with proper cleanup
|
||||
- Log errors appropriately for debugging
|
||||
|
||||
#### **Performance Optimization**
|
||||
- Implement proper subscription cleanup in `dispose()`
|
||||
- Use debouncing for frequent operations
|
||||
- Cache expensive computations with `computed()`
|
||||
|
||||
## Testing Services
|
||||
|
||||
### **Service Unit Tests**
|
||||
```typescript
|
||||
// tests/unit/services/MyService.test.ts
|
||||
describe('MyService', () => {
|
||||
let service: MyService
|
||||
let mockDependency: MockType<DependencyService>
|
||||
|
||||
beforeEach(() => {
|
||||
// Setup mocks
|
||||
mockDependency = createMockService()
|
||||
|
||||
// Create service with mocks
|
||||
service = new MyService(mockDependency)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await service.dispose()
|
||||
})
|
||||
|
||||
it('should initialize correctly', async () => {
|
||||
await service.initialize()
|
||||
|
||||
expect(service.isInitialized.value).toBe(true)
|
||||
expect(service.data.value).toEqual([])
|
||||
})
|
||||
|
||||
it('should create items', async () => {
|
||||
await service.initialize()
|
||||
|
||||
const item = await service.createItem({ name: 'test' })
|
||||
|
||||
expect(service.data.value).toContain(item)
|
||||
expect(mockDependency.create).toHaveBeenCalledWith({ name: 'test' })
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### **Integration Tests**
|
||||
```typescript
|
||||
// tests/integration/services/ServiceIntegration.test.ts
|
||||
describe('Service Integration', () => {
|
||||
let container: DIContainer
|
||||
|
||||
beforeEach(async () => {
|
||||
container = createTestContainer()
|
||||
await installTestServices(container)
|
||||
})
|
||||
|
||||
it('should handle cross-service communication', async () => {
|
||||
const authService = container.get(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
const chatService = container.get(SERVICE_TOKENS.CHAT_SERVICE)
|
||||
|
||||
await authService.login('test-key')
|
||||
const message = await chatService.sendMessage('Hello')
|
||||
|
||||
expect(message.author).toBe(authService.user.value?.pubkey)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
### Service Documentation
|
||||
- **[[authentication|🔐 Authentication Service]]** - User identity and session management
|
||||
- **[[storage-service|💾 Storage Service]]** - User-scoped data persistence
|
||||
- **[[toast-service|📢 Toast Service]]** - User notifications and feedback
|
||||
- **[[visibility-service|👁️ Visibility Service]]** - Dynamic UI component control
|
||||
|
||||
### Architecture References
|
||||
- **[[../01-architecture/dependency-injection|⚙️ Dependency Injection]]** - DI container system
|
||||
- **[[../01-architecture/event-bus|📡 Event Bus Communication]]** - Inter-service messaging
|
||||
- **[[../02-modules/index|📦 Module System]]** - How services integrate with modules
|
||||
- **[[../04-development/testing|🧪 Testing Guide]]** - Service testing patterns
|
||||
|
||||
---
|
||||
|
||||
**Tags:** #services #architecture #dependency-injection #reactive-state
|
||||
**Last Updated:** 2025-09-06
|
||||
**Author:** Development Team
|
||||
Loading…
Add table
Add a link
Reference in a new issue