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.
This commit is contained in:
padreug 2025-09-08 12:03:28 +02:00
parent 670a42dd9b
commit a373fa714d
5 changed files with 620 additions and 515 deletions

22
docs/.obsidian/graph.json vendored Normal file
View file

@ -0,0 +1,22 @@
{
"collapse-filter": true,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"collapse-display": true,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": true,
"centerStrength": 0.518713248970312,
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 0.6488873738523617,
"close": false
}

View file

@ -13,12 +13,12 @@
"state": {
"type": "markdown",
"state": {
"file": "04-migrations/dependency-injection-migration.md",
"file": "01-architecture/modular-design.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "dependency-injection-migration"
"title": "modular-design"
}
}
]
@ -170,7 +170,16 @@
},
"active": "fe085d296b05d361",
"lastOpenFiles": [
"06-deployment/index.md",
"04-migrations/dependency-injection-migration.md",
"01-architecture/modular-design.md",
"01-architecture/index.md",
"01-architecture/authentication-architecture.md",
"01-architecture/modular-design.md.tmp.1581693.1757246120074",
"01-architecture/modular-design.md.tmp.1581693.1757246069013",
"01-architecture/modular-design.md.tmp.1581693.1757245931642",
"03-core-services/authentication.md.tmp.1581693.1757245911412",
"03-core-services/authentication.md.tmp.1581693.1757245834001",
"00-overview/index.md"
]
}

View file

@ -1,419 +1,391 @@
# Modular Architecture Analysis & Infrastructure Abstractions
# 🔧 Modular Design Patterns
**Project**: Ario Web Application
**Date**: September 5, 2025
**Scope**: Analysis of modular plugin architecture for centralization opportunities
> **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.
---
## Executive Summary
## Architecture Components
The Ario web application demonstrates a well-architected modular system using Vue 3, TypeScript, and dependency injection. After comprehensive analysis of all modules, we've identified **significant opportunities for code consolidation** that could reduce duplication by 30-40% while improving maintainability, type safety, and development velocity.
### **Plugin Manager**
Orchestrates module loading, dependency resolution, and lifecycle management:
**Key Findings**:
- **16+ duplicate patterns** across modules requiring abstraction
- **Common async operation pattern** found in 12+ files
- **Service dependency injection** pattern duplicated in 7+ services
- **Payment processing logic** duplicated between market and events modules
- **User-scoped storage** pattern repeated across multiple stores
**Recent Progress (September 6, 2025)**:
- ✅ **Legacy relay infrastructure cleanup completed**
- ✅ Removed redundant NostrclientHub service
- ✅ Removed legacy NostrStore Pinia store
- ✅ Standardized on RelayHub service for all Nostr operations
- ✅ Updated dependency injection to remove unused tokens
---
## Current Module Structure
### Base Module (`src/modules/base/`)
- **Purpose**: Core infrastructure (Nostr, Auth, PWA)
- **Key Services**: Authentication, Relay Hub, Payment Service, Visibility Service
- **Status**: Well-established foundation with recent cleanup of legacy relay infrastructure
### Chat Module (`src/modules/chat/`)
- **Purpose**: Encrypted Nostr chat functionality
- **Key Features**: NIP-04 encryption, DM handling, peer management
- **Dependencies**: Base module services
### Events Module (`src/modules/events/`)
- **Purpose**: Event ticketing with Lightning payments
- **Key Features**: Ticket purchase, Lightning integration, QR codes
- **Dependencies**: Base module, payment processing
### Market Module (`src/modules/market/`)
- **Purpose**: Nostr marketplace with order management
- **Key Features**: Product catalog, order processing, payment handling
- **Dependencies**: Base module, payment processing, storage
### Nostr Feed Module (`src/modules/nostr-feed/`)
- **Purpose**: Social feed functionality
- **Key Features**: Note filtering, admin posts, real-time updates
- **Dependencies**: Base module services
---
## Identified Duplicate Patterns
### 1. Async Operation Pattern ⭐ **HIGH PRIORITY**
**Occurrences**: Found in **12+ files** across all modules
**Current Implementation**:
```typescript
// Repeated in every composable/component
const isLoading = ref(false)
const error = ref<string | null>(null)
const data = ref<T | null>(null)
try {
isLoading.value = true
// operation
} catch (err) {
error.value = err.message
} finally {
isLoading.value = false
class PluginManager {
async loadModules(modules: ModulePlugin[]): Promise<void>
getDependencyGraph(): Map<string, string[]>
validateDependencies(modules: ModulePlugin[]): void
}
```
**Impact**:
- 200+ lines of duplicate code
- Inconsistent error handling
- Manual loading state management
### **Dependency Injection Container**
Manages service registration, injection, and lifecycle:
### 2. Service Dependency Injection ⭐ **HIGH PRIORITY**
**Occurrences**: Found in **7+ service files**
**Current Implementation**:
```typescript
// Repeated in every service
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB) as any
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
// Service registration
container.provide(SERVICE_TOKENS.RELAY_HUB, relayHub)
if (!relayHub) {
throw new Error('RelayHub not available')
// 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>
}
```
**Impact**:
- Type safety issues (`as any` casting)
- Duplicate dependency checking
- Inconsistent error messages
### **Module Plugin Interface**
Standardized contract for all feature modules:
### 3. Payment Processing Logic ⭐ **HIGH PRIORITY**
**Occurrences**: Duplicated between market and events modules
**Current Implementation**:
```typescript
// Similar logic in both modules
const payInvoiceWithWallet = async (bolt11: string) => {
// Lightning payment logic
// QR code generation
// Success/error handling
// Toast notifications
interface ModulePlugin {
name: string
version: string
dependencies: string[]
install(app: App, options?: ModuleConfig): Promise<void>
routes?: RouteRecordRaw[]
components?: Record<string, Component>
}
```
**Impact**:
- 150+ lines of duplicate payment logic
- Inconsistent payment UX
- Duplicate error handling
## Service Abstractions
### 4. User-Scoped Storage Pattern
### **Core Infrastructure Services**
**Occurrences**: Found in market store, chat service
#### **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
**Current Implementation**:
#### **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
// Pattern repeated across modules
const getUserStorageKey = (baseKey: string) => {
const userPubkey = auth.currentUser?.value?.pubkey
return userPubkey ? `${baseKey}_${userPubkey}` : baseKey
}
const auth = useAuth()
const { isAuthenticated, currentUser, login, logout } = auth
```
**Impact**:
- Duplicate storage key logic
- Potential data consistency issues
### 5. Module Registration Pattern
**Occurrences**: Every module (`index.ts` files)
**Current Implementation**:
#### **useToast()** - Notification Access
```typescript
// Identical structure in every module
export const modulePlugin: ModulePlugin = {
name: 'module-name',
install(app: App, options) {
// Service registration
// Component registration
// Route registration
// Event setup
},
uninstall() {
// Cleanup logic
}
}
```
**Impact**:
- Boilerplate code in every module
- Inconsistent registration patterns
### 6. Toast Notification Pattern
**Occurrences**: Found in 4+ files
**Current Implementation**:
```typescript
// Inconsistent usage across modules
toast.success('Operation successful!')
const toast = useToast()
toast.success('Operation completed!')
toast.error('Operation failed')
```
**Impact**:
- Inconsistent notification styling
- Duplicate notification logic
---
## Recommended Abstractions
### 1. Core Infrastructure Abstractions
#### A. `useAsyncOperation` Composable
**Location**: `src/core/composables/useAsyncOperation.ts`
#### **useStorage()** - Storage Access
```typescript
export function useAsyncOperation<T>() {
const isLoading = ref(false)
const error = ref<string | null>(null)
const data = ref<T | null>(null)
const execute = async (operation: () => Promise<T>, options?: {
successMessage?: string
errorMessage?: string
showToast?: boolean
}) => {
// Standardized loading/error/success handling
}
return { isLoading, error, data, execute, reset }
}
const storage = useStorage()
const userData = storage.getUserData('preferences', defaultPrefs)
```
**Benefits**:
- ✅ Eliminates 200+ lines of duplicate code
- ✅ Consistent error handling across all modules
- ✅ Standardized loading states
- ✅ Optional toast notification integration
## Module Development
#### B. `BaseService` Abstract Class
**Location**: `src/core/base/BaseService.ts`
### **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 abstract class BaseService {
protected relayHub: any
protected authService: any
export class MyService extends BaseService {
protected readonly metadata = {
name: 'MyService',
dependencies: ['AuthService', 'RelayHub']
}
constructor() {
// Proper dependency injection with type safety
super()
}
protected async initialize(): Promise<void> {
await this.waitForDependencies()
await this.onInitialize()
async initialize(): Promise<void> {
await super.initialize() // Initialize dependencies
// Service-specific initialization
this.isInitialized.value = true
}
protected requireAuth() {
// Centralized auth requirement checking
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) {
// Standardized error handling and reporting
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}`)
}
}
```
**Benefits**:
- ✅ Eliminates `as any` type casting
- ✅ Consistent dependency management
- ✅ Standardized service lifecycle
- ✅ Better error handling and debugging
#### **Component-Level Error Handling**
Consistent error display in components:
```vue
<script setup lang="ts">
const { error, isLoading, execute } = useAsyncOperation()
#### C. `PaymentService` Centralization
**Location**: `src/core/services/PaymentService.ts`
const handleAction = () => execute(async () => {
await myService.performAction()
})
</script>
```typescript
export class PaymentService extends BaseService {
async processLightningPayment(bolt11: string, orderId?: string): Promise<PaymentResult>
async generateQRCode(paymentRequest: string): Promise<string>
async monitorPaymentStatus(paymentHash: string): Promise<void>
}
<template>
<div>
<button @click="handleAction" :disabled="isLoading">
{{ isLoading ? 'Loading...' : 'Perform Action' }}
</button>
<div v-if="error" class="error">{{ error }}</div>
</div>
</template>
```
**Benefits**:
- ✅ Eliminates 150+ lines of duplicate payment logic
- ✅ Consistent payment UX across market and events
- ✅ Centralized payment monitoring and error handling
- ✅ Single source of truth for Lightning integration
## Benefits & Trade-offs
#### D. `StorageService` Abstraction
**Location**: `src/core/services/StorageService.ts`
### **Achieved Benefits**
```typescript
export class StorageService {
setUserData<T>(key: string, data: T): void
getUserData<T>(key: string, defaultValue?: T): T | undefined
clearUserData(key: string): void
}
```
#### **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
**Benefits**:
- ✅ User-scoped storage abstraction
- ✅ Type-safe storage operations
- ✅ Consistent data isolation between users
#### **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
### 2. UI/UX Standardization
#### **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
#### A. Notification Service
**Location**: `src/core/services/NotificationService.ts`
### **Architectural Trade-offs**
```typescript
export class NotificationService {
success(message: string, options?: NotificationOptions): void
error(message: string, options?: NotificationOptions): void
info(message: string, options?: NotificationOptions): void
}
```
#### **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
#### B. Module Registration Utilities
**Location**: `src/core/utils/moduleRegistration.ts`
#### **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
```typescript
export function createModulePlugin(config: ModuleConfig): ModulePlugin {
// Standardized module registration with error handling
}
```
### **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
---
## Implementation Roadmap
### Phase 1: High-Impact Core Abstractions (Week 1-2)
1. **Create `useAsyncOperation` composable**
- Implement core functionality
- Replace usage in 12+ files
- **Expected Impact**: 40% reduction in loading/error code
2. **Create `BaseService` abstract class**
- Implement dependency injection abstraction
- Migrate 7+ services to inherit from BaseService
- **Expected Impact**: Eliminate `as any` casting, improve type safety
### Phase 2: Service Consolidation (Week 3-4)
3. **Create `PaymentService` centralization**
- Consolidate market and events payment logic
- Implement centralized QR code generation
- **Expected Impact**: 30% reduction in payment-related code
4. **Create `StorageService` abstraction**
- Implement user-scoped storage
- Migrate existing storage patterns
- **Expected Impact**: Consistent data isolation
### Phase 3: UX Standardization (Week 5-6)
5. **Create `NotificationService`**
- Standardize toast notifications
- Implement consistent messaging
- **Expected Impact**: Unified notification experience
6. **Create module registration utilities**
- Simplify module creation process
- Standardize registration patterns
- **Expected Impact**: Faster module development
---
## Expected Benefits
### Development Velocity
- **40% faster module development** with reusable patterns
- **Reduced onboarding time** for new developers
- **Consistent development patterns** across team
### Code Quality
- **30-40% reduction in duplicate code**
- **Improved type safety** with proper service injection
- **Standardized error handling** across all modules
- **Better test coverage** of centralized functionality
### User Experience
- **Consistent loading states** across all features
- **Unified error messaging** and handling
- **Standardized payment flows** between market and events
- **Better performance** through optimized common operations
### Maintainability
- **Single source of truth** for common patterns
- **Easier debugging** with centralized error handling
- **Propagated improvements** - enhancements benefit all modules
- **Reduced technical debt** through consolidation
---
## Risk Assessment
### Low Risk
- **Backward compatibility**: New abstractions won't break existing functionality
- **Incremental adoption**: Can be implemented module by module
- **Fallback options**: Existing patterns remain functional during transition
### Medium Risk
- **TypeScript complexity**: Need careful typing for generic abstractions
- **Testing coverage**: Must ensure centralized code is thoroughly tested
### Mitigation Strategies
- **Comprehensive testing** of all abstracted functionality
- **Gradual migration** one module at a time
- **Maintain existing APIs** during transition period
---
## Success Metrics
### Quantitative Metrics
- **Lines of Code**: Target 30-40% reduction in common patterns
- **Type Safety**: Eliminate all `as any` casting in services
- **Test Coverage**: Achieve 90%+ coverage of centralized functionality
- **Build Performance**: Maintain sub-6s production build times
### Qualitative Metrics
- **Developer Experience**: Faster module development and onboarding
- **Code Consistency**: Uniform patterns across all modules
- **Error Handling**: Consistent error reporting and recovery
- **User Experience**: Uniform loading states and notifications
---
## Conclusion
The modular architecture analysis reveals a mature, well-structured codebase with **significant opportunities for optimization**. The identified abstractions will:
1. **Reduce code duplication** by 30-40% in common patterns
2. **Improve type safety** and eliminate `as any` casting
3. **Standardize user experience** across all modules
4. **Accelerate future development** through reusable patterns
**Recommendation**: Proceed with **Phase 1 implementation** starting with `useAsyncOperation` and `BaseService` abstractions, which will deliver immediate benefits with minimal risk.
The proposed changes align with the existing architectural principles while providing substantial improvements in maintainability, developer experience, and code quality.
---
*This analysis was conducted on September 5, 2025, based on the current state of the Ario web application modular architecture.*
**Tags:** #architecture #modular-design #dependency-injection #plugin-system
**Last Updated:** 2025-09-07
**Author:** Development Team

View file

@ -1,172 +1,261 @@
# Authentication System
# 🔐 Authentication Service
This web application now uses LNBits username/password authentication instead of Nostr keypairs.
> **User identity and session management** with Nostr key handling, dependency injection architecture, and secure client-side key management.
## Overview
## Table of Contents
The authentication system has been completely replaced with a traditional username/password system that integrates with LNBits. Users can now:
- [[#Service Overview]]
- [[#Architecture]]
- [[#Key Features]]
- [[#Usage Patterns]]
- [[#Authentication Flow]]
- [[#Security Considerations]]
- Register new accounts with username and password
- Login with username/email and password
- Manage their profile information
- Logout securely
## Service Overview
## Configuration
The `AuthService` is a core infrastructure service that manages user authentication, identity, and session state throughout the application. It provides secure Nostr key management with client-side encryption and reactive state management.
### Environment Variables
Create a `.env` file in the `web-app` directory with the following variables:
```env
# LNBits Base URL Configuration
# Set this to your LNBits instance base URL
# Example: http://localhost:5000 or https://your-lnbits-instance.com
VITE_LNBITS_BASE_URL=http://localhost:5000
# Enable debug logging for LNBits API calls
VITE_LNBITS_DEBUG=false
# App Configuration
VITE_APP_TITLE=Ario
VITE_APP_DESCRIPTION=Your secure platform for events and community management
```
### LNBits Setup
1. Ensure your LNBits instance is running and accessible
2. Make sure the username/password authentication method is enabled in LNBits
3. Configure CORS if your LNBits instance is on a different domain
## API Endpoints
The application uses the following LNBits API endpoints:
- `POST /api/v1/auth` - Login
- `POST /api/v1/auth/register` - Register new user
- `POST /api/v1/auth/logout` - Logout
- `GET /api/v1/auth` - Get current user
- `PUT /api/v1/auth/password` - Update password
- `PUT /api/v1/auth/update` - Update profile
## Components
### New Components
- `LoginDialog.vue` - Modal dialog for login/register
- `UserProfile.vue` - Display user information and logout
- `Login.vue` - Full-page login/register form
### Updated Components
- `App.vue` - Now uses new authentication system
- `Navbar.vue` - Shows user status and logout option
- `Home.vue` - Displays welcome message and user profile
## Authentication Flow
1. **App Initialization**: The app checks for existing authentication token on startup
2. **Route Protection**: Routes with `requiresAuth: true` redirect to login if not authenticated
3. **Login/Register**: Users can create accounts or login with existing credentials
4. **Token Management**: Access tokens are stored in localStorage and automatically included in API requests
5. **Logout**: Clears tokens and redirects to login page
## Security Features
- JWT tokens for session management
- Secure password handling (handled by LNBits)
- Automatic token refresh
- Route protection for authenticated pages
- Secure logout with token cleanup
**Service Token**: `SERVICE_TOKENS.AUTH_SERVICE`
**Location**: `src/modules/base/auth/auth-service.ts`
**Dependencies**: `LnbitsAPI` for backend integration
## Architecture
The authentication system uses a **dependency injection pattern** for clean modular architecture:
### Core Components
1. **AuthService** (`src/modules/base/auth/auth-service.ts`)
- Singleton service that manages authentication state
- Handles API calls to LNBits
- Provides reactive state management
2. **useAuthService** (`src/composables/useAuthService.ts`)
- Wrapper composable that provides unified access to AuthService
- Uses dependency injection to access the service
- Provides consistent API for all components
3. **Dependency Injection Container** (`src/core/di-container.ts`)
- Manages service registration and injection
- Ensures single source of truth across modules
### Usage Pattern
Components access authentication through the `useAuth()` composable:
### Dependency Injection Pattern
The authentication system uses dependency injection for clean, modular access:
```typescript
// Service registration (base module)
container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService)
// Service consumption (components)
const auth = useAuth() // Via composable wrapper
// Service consumption (other services)
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
```
### Reactive State Management
AuthService integrates Vue's reactivity system for automatic UI updates:
```typescript
export class AuthService extends BaseService {
public isAuthenticated = ref(false)
public user = ref<User | null>(null)
public isLoading = ref(false)
public error = ref<Error | null>(null)
// Computed properties for component compatibility
public currentUser = computed(() => this.user.value)
public userDisplay = computed(() => this.user.value?.name || 'Anonymous')
}
```
## Key Features
### 🔑 **Nostr Key Management**
- **Secure Key Generation** - Client-side key pair creation with proper entropy
- **Key Import/Export** - Support for existing Nostr keys (nsec/hex formats)
- **Encrypted Storage** - User keys encrypted with password-derived encryption
- **Key Recovery** - Secure key backup and restoration mechanisms
### 👤 **User Identity & Profiles**
- **Nostr Profile Management** - NIP-01 compatible user metadata
- **Profile Updates** - Real-time profile information synchronization
- **Display Name Handling** - Fallback from name → display_name → truncated pubkey
- **Avatar Support** - Profile picture URLs with fallback handling
### 🔒 **Session Management**
- **Persistent Sessions** - Secure localStorage-based session persistence
- **Auto-Initialization** - Automatic session restoration on app startup
- **Secure Logout** - Complete session cleanup and key removal
- **Token Management** - LNBits API token handling and refresh
### 🌐 **Backend Integration**
- **LNBits API** - Wallet integration for Lightning functionality
- **Event Publishing** - User profile publishing to Nostr relays
- **Real-time Updates** - Reactive profile updates across relays
## Usage Patterns
### Component Usage (Recommended)
```vue
<script setup lang="ts">
import { useAuth } from '@/composables/useAuthService'
export default defineComponent({
setup() {
const auth = useAuth()
// Access authentication state
const isAuthenticated = auth.isAuthenticated
const currentUser = auth.currentUser
// Call authentication methods
const login = (credentials) => auth.login(credentials)
const logout = () => auth.logout()
return {
isAuthenticated,
currentUser,
login,
logout
const auth = useAuth()
// Access reactive authentication state
const isAuthenticated = auth.isAuthenticated
const currentUser = auth.currentUser
const userDisplay = auth.userDisplay
// Authentication methods
const handleLogin = async (privateKey: string) => {
try {
await auth.login({ privateKey })
// Success handled automatically by service
} catch (error) {
// Error handling
console.error('Login failed:', error)
}
}
const handleLogout = () => auth.logout()
</script>
```
### Service Usage (Other Services)
```typescript
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
export class ChatService extends BaseService {
private get authService(): AuthService {
return this.dependencies.get('AuthService') as AuthService
}
async sendMessage(content: string) {
const user = this.authService.user.value
if (!user?.pubkey || !user?.prvkey) {
throw new Error('Authentication required')
}
// Use authenticated user data for message signing
}
}
```
### Store Integration
```typescript
// In Pinia stores
export const useMyStore = defineStore('myStore', () => {
const auth = useAuth()
// Reactive dependency on auth state
const userSpecificData = computed(() => {
if (!auth.isAuthenticated.value) return []
return loadDataForUser(auth.currentUser.value.pubkey)
})
return { userSpecificData }
})
```
## Authentication Flow
### 1. App Initialization
```typescript
// App startup sequence
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
await authService.initialize()
if (authService.isAuthenticated.value) {
// User has valid session - proceed to app
} else {
// Redirect to login/onboarding
}
```
### 2. User Login Process
1. **Key Input** - User provides private key (nsec, hex, or generates new)
2. **Key Validation** - Validate key format and derive public key
3. **Profile Loading** - Fetch existing Nostr profile if available
4. **Session Creation** - Encrypt and store keys securely
5. **Service Initialization** - Initialize user-scoped services
6. **UI Updates** - Reactive state triggers navigation/UI changes
### 3. Authentication Guards
```typescript
// Router guards use auth service
router.beforeEach((to, from, next) => {
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
if (to.meta.requiresAuth && !authService.isAuthenticated.value) {
next('/login')
} else {
next()
}
})
```
### Service Registration
### 4. Logout Process
1. **Session Cleanup** - Clear encrypted keys from storage
2. **Service Reset** - Reset all user-scoped service state
3. **Relay Cleanup** - Close user-specific Nostr subscriptions
4. **UI Reset** - Clear user data from stores and components
5. **Navigation** - Redirect to login/public areas
The AuthService is registered in the base module and made available through dependency injection:
## Security Considerations
### 🔐 **Client-Side Security**
- **No Server Keys** - Private keys never leave the client
- **Encrypted Storage** - Keys encrypted with user-provided password
- **Memory Management** - Secure key handling in memory
- **Input Validation** - Strict validation of key formats and data
### 🌐 **Network Security**
- **HTTPS Only** - All API calls over encrypted connections
- **Token Security** - LNBits tokens with appropriate scoping
- **Request Validation** - API request signature verification
- **Error Handling** - No sensitive data in error messages
### 🛡️ **Data Protection**
- **User-Scoped Storage** - Data isolation between users
- **Automatic Cleanup** - Session data cleared on logout
- **Profile Privacy** - Configurable profile information sharing
- **Key Rotation** - Support for updating authentication credentials
## API Reference
### AuthService Methods
```typescript
// In base module
container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService)
// In components
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
interface AuthService {
// Core authentication
login(credentials: LoginCredentials): Promise<void>
logout(): Promise<void>
initialize(): Promise<void>
// Key management
generateKeyPair(): Promise<{ pubkey: string, prvkey: string }>
importPrivateKey(key: string): Promise<void>
exportPrivateKey(): string | null
// Profile management
updateProfile(profile: UserMetadata): Promise<void>
publishProfile(): Promise<void>
// Reactive state (readonly)
readonly isAuthenticated: ComputedRef<boolean>
readonly currentUser: ComputedRef<User | null>
readonly userDisplay: ComputedRef<UserDisplay>
readonly isLoading: Ref<boolean>
readonly error: Ref<Error | null>
}
```
## Migration from Legacy Architecture
### LoginCredentials Interface
```typescript
interface LoginCredentials {
privateKey?: string // Existing key (nsec or hex)
generateNew?: boolean // Generate new key pair
password?: string // For key encryption
profile?: UserMetadata // Initial profile data
}
```
The following components have been updated:
## See Also
- **Legacy**: Global `useAuth.ts` composable → **Current**: `useAuthService.ts` with dependency injection
- **Legacy**: Direct service imports → **Current**: Dependency injection pattern
- **Legacy**: Dual authentication detection → **Current**: Single source of truth via AuthService
- `IdentityDialog.vue``LoginDialog.vue`
- `PasswordDialog.vue` → Integrated into `LoginDialog.vue`
- Nostr connection status → User authentication status
### Architecture Documentation
- **[[../01-architecture/authentication-architecture|🔐 Authentication Architecture]]** - Detailed architecture overview
- **[[../01-architecture/dependency-injection|⚙️ Dependency Injection]]** - Service container patterns
- **[[index|⚙️ Core Services Overview]]** - Related infrastructure services
## Development
### Module Documentation
- **[[../02-modules/base-module/index|🏗️ Base Module]]** - Authentication service registration
- **[[../04-development/security|🛡️ Security Guidelines]]** - Security best practices
To run the application with the new authentication system:
---
1. Set up your LNBits instance
2. Configure the environment variables
3. Run the development server: `npm run dev`
4. Access the application and test login/register functionality
## Troubleshooting
### Common Issues
1. **CORS Errors**: Ensure your LNBits instance allows requests from your frontend domain
2. **Authentication Failures**: Check that username/password auth is enabled in LNBits
3. **API Connection**: Verify the `VITE_LNBITS_BASE_URL` is correct and points to your LNBits instance (without /api/v1)
### Debug Mode
Enable debug logging by setting `VITE_LNBITS_DEBUG=true` to see detailed API request/response information in the browser console.
**Tags:** #authentication #security #services #nostr #dependency-injection
**Last Updated:** 2025-09-07
**Author:** Development Team

View file

@ -260,24 +260,37 @@ const invoiceService = injectService(SERVICE_TOKENS.INVOICE_SERVICE) as InvoiceS
const invoice = await invoiceService.createInvoice(order, adminKey)
```
### 🔄 In Progress
#### 2. NostrmarketService (Completed)
- **Status**: ✅ Successfully migrated
- **Token**: `SERVICE_TOKENS.NOSTRMARKET_SERVICE`
- **Registration**: Market module (`src/modules/market/index.ts`)
- **Usage**: Market module composables and stores
#### 2. NostrmarketService (Pending)
- **Status**: 🔄 Ready for migration
- **File**: `src/modules/market/services/nostrmarketService.ts`
- **Token**: Need to add `NOSTRMARKET_SERVICE`
- **Registration**: Market module
**Before:**
```typescript
// ❌ Legacy singleton pattern
import { nostrmarketService } from '@/modules/market/services/nostrmarketService'
await nostrmarketService.publishOrder(orderData)
```
#### 3. PaymentMonitorService (Partially Migrated)
- **Status**: 🔄 Token exists, needs completion
- **Token**: `SERVICE_TOKENS.PAYMENT_MONITOR` (already exists)
- **Registration**: Market module
**After:**
```typescript
// ✅ Dependency injection pattern
const nostrmarketService = injectService(SERVICE_TOKENS.NOSTRMARKET_SERVICE) as NostrmarketService
await nostrmarketService.publishOrder(orderData)
```
#### 4. LnbitsAPI (Pending)
- **Status**: 🔄 Ready for migration
- **File**: `src/lib/api/lnbits.ts`
- **Token**: Need to add `LNBITS_API`
- **Registration**: Base module
#### 3. PaymentMonitorService (Completed)
- **Status**: ✅ Successfully migrated
- **Token**: `SERVICE_TOKENS.PAYMENT_MONITOR`
- **Registration**: Market module (`src/modules/market/index.ts`)
- **Usage**: Market store for payment status monitoring
#### 4. LnbitsAPI (Completed)
- **Status**: ✅ Successfully migrated
- **Token**: `SERVICE_TOKENS.LNBITS_API`
- **Registration**: Base module (`src/modules/base/index.ts`)
- **Usage**: AuthService and events API integration
## Practical Example: Market Module Using InvoiceService