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": { "state": {
"type": "markdown", "type": "markdown",
"state": { "state": {
"file": "04-migrations/dependency-injection-migration.md", "file": "01-architecture/modular-design.md",
"mode": "source", "mode": "source",
"source": false "source": false
}, },
"icon": "lucide-file", "icon": "lucide-file",
"title": "dependency-injection-migration" "title": "modular-design"
} }
} }
] ]
@ -170,7 +170,16 @@
}, },
"active": "fe085d296b05d361", "active": "fe085d296b05d361",
"lastOpenFiles": [ "lastOpenFiles": [
"06-deployment/index.md",
"04-migrations/dependency-injection-migration.md",
"01-architecture/modular-design.md",
"01-architecture/index.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" "00-overview/index.md"
] ]
} }

View file

@ -1,419 +1,391 @@
# Modular Architecture Analysis & Infrastructure Abstractions # 🔧 Modular Design Patterns
**Project**: Ario Web Application > **Plugin-based architecture** enabling scalable, maintainable, and extensible feature development with dependency injection, service abstractions, and clean modular boundaries.
**Date**: September 5, 2025
**Scope**: Analysis of modular plugin architecture for centralization opportunities ## 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 ```typescript
// Repeated in every composable/component class PluginManager {
const isLoading = ref(false) async loadModules(modules: ModulePlugin[]): Promise<void>
const error = ref<string | null>(null) getDependencyGraph(): Map<string, string[]>
const data = ref<T | null>(null) validateDependencies(modules: ModulePlugin[]): void
try {
isLoading.value = true
// operation
} catch (err) {
error.value = err.message
} finally {
isLoading.value = false
} }
``` ```
**Impact**: ### **Dependency Injection Container**
- 200+ lines of duplicate code Manages service registration, injection, and lifecycle:
- Inconsistent error handling
- Manual loading state management
### 2. Service Dependency Injection ⭐ **HIGH PRIORITY**
**Occurrences**: Found in **7+ service files**
**Current Implementation**:
```typescript ```typescript
// Repeated in every service // Service registration
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB) as any container.provide(SERVICE_TOKENS.RELAY_HUB, relayHub)
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
if (!relayHub) { // Service consumption
throw new Error('RelayHub not available') 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**: ### **Module Plugin Interface**
- Type safety issues (`as any` casting) Standardized contract for all feature modules:
- Duplicate dependency checking
- Inconsistent error messages
### 3. Payment Processing Logic ⭐ **HIGH PRIORITY**
**Occurrences**: Duplicated between market and events modules
**Current Implementation**:
```typescript ```typescript
// Similar logic in both modules interface ModulePlugin {
const payInvoiceWithWallet = async (bolt11: string) => { name: string
// Lightning payment logic version: string
// QR code generation dependencies: string[]
// Success/error handling
// Toast notifications install(app: App, options?: ModuleConfig): Promise<void>
routes?: RouteRecordRaw[]
components?: Record<string, Component>
} }
``` ```
**Impact**: ## Service Abstractions
- 150+ lines of duplicate payment logic
- Inconsistent payment UX
- Duplicate error handling
### 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 ```typescript
// Pattern repeated across modules const auth = useAuth()
const getUserStorageKey = (baseKey: string) => { const { isAuthenticated, currentUser, login, logout } = auth
const userPubkey = auth.currentUser?.value?.pubkey
return userPubkey ? `${baseKey}_${userPubkey}` : baseKey
}
``` ```
**Impact**: #### **useToast()** - Notification Access
- Duplicate storage key logic
- Potential data consistency issues
### 5. Module Registration Pattern
**Occurrences**: Every module (`index.ts` files)
**Current Implementation**:
```typescript ```typescript
// Identical structure in every module const toast = useToast()
export const modulePlugin: ModulePlugin = { toast.success('Operation completed!')
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!')
toast.error('Operation failed') toast.error('Operation failed')
``` ```
**Impact**: #### **useStorage()** - Storage Access
- Inconsistent notification styling
- Duplicate notification logic
---
## Recommended Abstractions
### 1. Core Infrastructure Abstractions
#### A. `useAsyncOperation` Composable
**Location**: `src/core/composables/useAsyncOperation.ts`
```typescript ```typescript
export function useAsyncOperation<T>() { const storage = useStorage()
const isLoading = ref(false) const userData = storage.getUserData('preferences', defaultPrefs)
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 }
}
``` ```
**Benefits**: ## Module Development
- ✅ Eliminates 200+ lines of duplicate code
- ✅ Consistent error handling across all modules
- ✅ Standardized loading states
- ✅ Optional toast notification integration
#### B. `BaseService` Abstract Class ### **Module Structure Pattern**
**Location**: `src/core/base/BaseService.ts` 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 ```typescript
export abstract class BaseService { export class MyService extends BaseService {
protected relayHub: any protected readonly metadata = {
protected authService: any name: 'MyService',
dependencies: ['AuthService', 'RelayHub']
}
constructor() { constructor() {
// Proper dependency injection with type safety super()
} }
protected async initialize(): Promise<void> { async initialize(): Promise<void> {
await this.waitForDependencies() await super.initialize() // Initialize dependencies
await this.onInitialize() // Service-specific initialization
this.isInitialized.value = true
} }
protected requireAuth() { async dispose(): Promise<void> {
// Centralized auth requirement checking // 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) { 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**: #### **Component-Level Error Handling**
- ✅ Eliminates `as any` type casting Consistent error display in components:
- ✅ Consistent dependency management ```vue
- ✅ Standardized service lifecycle <script setup lang="ts">
- ✅ Better error handling and debugging const { error, isLoading, execute } = useAsyncOperation()
#### C. `PaymentService` Centralization const handleAction = () => execute(async () => {
**Location**: `src/core/services/PaymentService.ts` await myService.performAction()
})
</script>
```typescript <template>
export class PaymentService extends BaseService { <div>
async processLightningPayment(bolt11: string, orderId?: string): Promise<PaymentResult> <button @click="handleAction" :disabled="isLoading">
async generateQRCode(paymentRequest: string): Promise<string> {{ isLoading ? 'Loading...' : 'Perform Action' }}
async monitorPaymentStatus(paymentHash: string): Promise<void> </button>
} <div v-if="error" class="error">{{ error }}</div>
</div>
</template>
``` ```
**Benefits**: ## Benefits & Trade-offs
- ✅ 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
#### D. `StorageService` Abstraction ### **Achieved Benefits**
**Location**: `src/core/services/StorageService.ts`
```typescript #### **Development Velocity**
export class StorageService { - **Consistent Patterns** - Standardized development approaches across modules
setUserData<T>(key: string, data: T): void - **Reusable Services** - Shared infrastructure reduces implementation time
getUserData<T>(key: string, defaultValue?: T): T | undefined - **Type Safety** - Dependency injection eliminates `as any` casting
clearUserData(key: string): void - **Clear Boundaries** - Module separation simplifies feature development
}
```
**Benefits**: #### **Maintainability**
- ✅ User-scoped storage abstraction - **Single Source of Truth** - Centralized services eliminate duplication
- ✅ Type-safe storage operations - **Dependency Visibility** - Clear service relationships and requirements
- ✅ Consistent data isolation between users - **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 ### **Architectural Trade-offs**
**Location**: `src/core/services/NotificationService.ts`
```typescript #### **Complexity vs. Flexibility**
export class NotificationService { - **Increased Initial Setup** - More boilerplate for dependency injection
success(message: string, options?: NotificationOptions): void - **Enhanced Flexibility** - Easy to swap implementations and add features
error(message: string, options?: NotificationOptions): void - **Learning Curve** - Developers need to understand DI patterns
info(message: string, options?: NotificationOptions): void - **Long-term Benefits** - Reduced complexity as application grows
}
```
#### B. Module Registration Utilities #### **Performance Considerations**
**Location**: `src/core/utils/moduleRegistration.ts` - **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 ### **Best Practices Established**
export function createModulePlugin(config: ModuleConfig): ModulePlugin {
// Standardized module registration with error handling 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 **Tags:** #architecture #modular-design #dependency-injection #plugin-system
**Last Updated:** 2025-09-07
### Phase 1: High-Impact Core Abstractions (Week 1-2) **Author:** Development Team
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.*

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 ## Service Overview
- Login with username/email and password
- Manage their profile information
- Logout securely
## 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 **Service Token**: `SERVICE_TOKENS.AUTH_SERVICE`
**Location**: `src/modules/base/auth/auth-service.ts`
Create a `.env` file in the `web-app` directory with the following variables: **Dependencies**: `LnbitsAPI` for backend integration
```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
## Architecture ## Architecture
The authentication system uses a **dependency injection pattern** for clean modular architecture: ### Dependency Injection Pattern
The authentication system uses dependency injection for clean, modular access:
### 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:
```typescript ```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' import { useAuth } from '@/composables/useAuthService'
export default defineComponent({ const auth = useAuth()
setup() {
const auth = useAuth()
// Access authentication state // Access reactive authentication state
const isAuthenticated = auth.isAuthenticated const isAuthenticated = auth.isAuthenticated
const currentUser = auth.currentUser const currentUser = auth.currentUser
const userDisplay = auth.userDisplay
// Call authentication methods // Authentication methods
const login = (credentials) => auth.login(credentials) const handleLogin = async (privateKey: string) => {
const logout = () => auth.logout() try {
await auth.login({ privateKey })
// Success handled automatically by service
} catch (error) {
// Error handling
console.error('Login failed:', error)
}
}
return { const handleLogout = () => auth.logout()
isAuthenticated, </script>
currentUser, ```
login,
logout ### 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 ```typescript
// In base module interface AuthService {
container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService) // Core authentication
login(credentials: LoginCredentials): Promise<void>
logout(): Promise<void>
initialize(): Promise<void>
// In components // Key management
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) 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 ### Architecture Documentation
- **Legacy**: Direct service imports → **Current**: Dependency injection pattern - **[[../01-architecture/authentication-architecture|🔐 Authentication Architecture]]** - Detailed architecture overview
- **Legacy**: Dual authentication detection → **Current**: Single source of truth via AuthService - **[[../01-architecture/dependency-injection|⚙️ Dependency Injection]]** - Service container patterns
- `IdentityDialog.vue``LoginDialog.vue` - **[[index|⚙️ Core Services Overview]]** - Related infrastructure services
- `PasswordDialog.vue` → Integrated into `LoginDialog.vue`
- Nostr connection status → User authentication status
## 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 **Tags:** #authentication #security #services #nostr #dependency-injection
2. Configure the environment variables **Last Updated:** 2025-09-07
3. Run the development server: `npm run dev` **Author:** Development Team
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.

View file

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