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
169
docs/04-development/improvements.md
Normal file
169
docs/04-development/improvements.md
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
# Project Improvements
|
||||
|
||||
## Current Strengths 💪
|
||||
|
||||
### Project Structure
|
||||
- Clean, modular organization with separate directories for components, pages, i18n, etc.
|
||||
- Follows Vue 3 best practices with Composition API
|
||||
- Good separation of concerns between layout components and pages
|
||||
|
||||
### Internationalization
|
||||
- Type-safe i18n system
|
||||
- Lazy loading of language files
|
||||
- Persistent language preferences
|
||||
- Clean language switcher UI with Shadcn components
|
||||
|
||||
### Theming
|
||||
- Dark/light theme implementation with smooth transitions
|
||||
- Consistent theme colors using Tailwind's color system
|
||||
- Theme persistence
|
||||
- Proper theme-aware components
|
||||
|
||||
### Components
|
||||
- Shadcn components properly integrated
|
||||
- Reusable UI components in dedicated directories
|
||||
- TypeScript interfaces for props
|
||||
- Responsive design patterns
|
||||
|
||||
### Performance
|
||||
- PWA support with periodic updates
|
||||
- Code splitting configuration
|
||||
- Image optimization
|
||||
- Lazy loading implementation
|
||||
|
||||
## Planned Improvements 🎯
|
||||
|
||||
### 1. Testing Implementation
|
||||
- [ ] Set up Vitest for unit testing
|
||||
- [ ] Set up Cypress for E2E testing
|
||||
- [ ] Add @testing-library/vue for component testing
|
||||
- [ ] Write tests for critical components
|
||||
- [ ] Set up CI/CD pipeline for automated testing
|
||||
|
||||
### 2. Error Handling
|
||||
- [ ] Implement global error boundary
|
||||
```typescript
|
||||
app.config.errorHandler = (err, instance, info) => {
|
||||
// Log error to service
|
||||
console.error(err)
|
||||
}
|
||||
```
|
||||
- [ ] Add error states for async operations
|
||||
- [ ] Implement error logging service
|
||||
- [ ] Add retry mechanisms for failed API calls
|
||||
|
||||
### 3. Performance Monitoring
|
||||
- [ ] Implement Web Vitals monitoring
|
||||
```typescript
|
||||
import { onCLS, onFID, onLCP } from 'web-vitals'
|
||||
|
||||
function sendToAnalytics({ name, delta, id }) {
|
||||
// Send metrics to analytics
|
||||
}
|
||||
|
||||
onCLS(sendToAnalytics)
|
||||
onFID(sendToAnalytics)
|
||||
onLCP(sendToAnalytics)
|
||||
```
|
||||
- [ ] Set up performance budgets
|
||||
- [ ] Implement automated performance testing
|
||||
- [ ] Add bundle size monitoring
|
||||
|
||||
### 4. Documentation
|
||||
- [ ] Set up Storybook for component documentation
|
||||
- [ ] Implement TypeDoc for API documentation
|
||||
- [ ] Create comprehensive README
|
||||
- [ ] Add contribution guidelines
|
||||
- [ ] Document component usage examples
|
||||
- [ ] Add inline code documentation
|
||||
|
||||
### 5. SEO Optimization
|
||||
- [ ] Implement meta tags management
|
||||
- [ ] Add OpenGraph tags
|
||||
- [ ] Generate sitemap
|
||||
- [ ] Implement structured data
|
||||
- [ ] Add robots.txt configuration
|
||||
|
||||
### 6. Accessibility
|
||||
- [ ] Add missing ARIA labels
|
||||
- [ ] Implement keyboard navigation
|
||||
- [ ] Add skip links
|
||||
- [ ] Ensure proper color contrast
|
||||
- [ ] Add screen reader announcements
|
||||
- [ ] Test with screen readers
|
||||
|
||||
### 7. Type Safety Enhancements
|
||||
- [ ] Add comprehensive TypeScript interfaces for store state
|
||||
- [ ] Implement strict prop types for all components
|
||||
- [ ] Add runtime type checking for API responses
|
||||
- [ ] Enhance type safety in route definitions
|
||||
|
||||
### 8. Security
|
||||
- [ ] Implement CSP (Content Security Policy)
|
||||
- [ ] Add XSS protection
|
||||
- [ ] Set up security headers
|
||||
- [ ] Implement rate limiting
|
||||
- [ ] Add input sanitization
|
||||
|
||||
### 9. Build & Development
|
||||
- [ ] Optimize build configuration
|
||||
- [ ] Add development tools and utilities
|
||||
- [ ] Implement git hooks for code quality
|
||||
- [ ] Set up automated dependency updates
|
||||
- [ ] Add development environment documentation
|
||||
|
||||
## Priority Order 📋
|
||||
|
||||
1. **High Priority**
|
||||
- Testing Implementation
|
||||
- Error Handling
|
||||
- Security Improvements
|
||||
|
||||
2. **Medium Priority**
|
||||
- Documentation
|
||||
- Type Safety Enhancements
|
||||
- Accessibility Improvements
|
||||
|
||||
3. **Lower Priority**
|
||||
- Performance Monitoring
|
||||
- SEO Optimization
|
||||
- Build & Development Optimizations
|
||||
|
||||
## Getting Started 🚀
|
||||
|
||||
To begin implementing these improvements:
|
||||
|
||||
1. Start with testing setup:
|
||||
```bash
|
||||
# Install testing dependencies
|
||||
npm install -D vitest @testing-library/vue cypress
|
||||
```
|
||||
|
||||
2. Add error handling:
|
||||
```bash
|
||||
# Install error tracking
|
||||
npm install @sentry/vue
|
||||
```
|
||||
|
||||
3. Set up documentation:
|
||||
```bash
|
||||
# Install Storybook
|
||||
npx storybook@latest init
|
||||
```
|
||||
|
||||
## Contributing 🤝
|
||||
|
||||
When implementing these improvements:
|
||||
|
||||
1. Create a feature branch
|
||||
2. Follow the existing code style
|
||||
3. Add tests for new features
|
||||
4. Update documentation
|
||||
5. Submit a PR with a clear description
|
||||
|
||||
## Notes 📝
|
||||
|
||||
- Keep track of completed items by checking them off
|
||||
- Add new improvements as they are identified
|
||||
- Update priorities based on project needs
|
||||
- Document any technical decisions made during implementation
|
||||
571
docs/04-development/index.md
Normal file
571
docs/04-development/index.md
Normal file
|
|
@ -0,0 +1,571 @@
|
|||
# 💻 Development Guide
|
||||
|
||||
> **Development workflows and standards** for contributing to Ario's modular Vue 3 + TypeScript application with Nostr and Lightning Network integration.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [[#Development Environment]]
|
||||
- [[#Development Workflow]]
|
||||
- [[#Code Standards]]
|
||||
- [[#Testing Strategy]]
|
||||
- [[#Build & Deployment]]
|
||||
- [[#Debugging Guide]]
|
||||
|
||||
## Development Environment
|
||||
|
||||
### **Prerequisites**
|
||||
- **Node.js 18+** and npm for package management
|
||||
- **Git** for version control
|
||||
- **VS Code** (recommended) with Vue and TypeScript extensions
|
||||
- **Basic understanding** of Vue 3, TypeScript, and Nostr protocol
|
||||
|
||||
### **Quick Setup**
|
||||
```bash
|
||||
# Navigate to web app directory
|
||||
cd web-app/
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development server with hot reload
|
||||
npm run dev
|
||||
|
||||
# For desktop development
|
||||
npm run electron:dev
|
||||
```
|
||||
|
||||
### **Environment Configuration**
|
||||
```bash
|
||||
# Copy environment template
|
||||
cp .env.example .env
|
||||
|
||||
# Essential configuration
|
||||
VITE_NOSTR_RELAYS='["wss://relay.damus.io","wss://nos.lol"]'
|
||||
VITE_ADMIN_PUBKEYS='["admin_pubkey_hex"]'
|
||||
|
||||
# Optional configuration
|
||||
VITE_DEBUG=true
|
||||
VITE_APP_NAME="Ario Development"
|
||||
```
|
||||
|
||||
### **Development Tools**
|
||||
|
||||
#### **Recommended VS Code Extensions**
|
||||
- **Vue Language Features (Volar)** - Vue 3 support
|
||||
- **TypeScript Vue Plugin (Volar)** - TypeScript integration
|
||||
- **Tailwind CSS IntelliSense** - CSS class completion
|
||||
- **ESLint** - Code linting
|
||||
- **Prettier** - Code formatting
|
||||
- **Auto Rename Tag** - HTML tag synchronization
|
||||
|
||||
#### **Browser Extensions**
|
||||
- **Vue.js devtools** - Component inspection and debugging
|
||||
- **Lightning Network Browser Extension** - WebLN testing
|
||||
|
||||
### **Project Structure Overview**
|
||||
```
|
||||
web-app/
|
||||
├── src/
|
||||
│ ├── components/ # Reusable UI components
|
||||
│ ├── composables/ # Vue composables and hooks
|
||||
│ ├── core/ # Core architecture (DI, services)
|
||||
│ ├── lib/ # Utility functions and helpers
|
||||
│ ├── modules/ # Feature modules (plugin-based)
|
||||
│ ├── pages/ # Route pages
|
||||
│ ├── stores/ # Pinia state management
|
||||
│ └── types/ # TypeScript type definitions
|
||||
├── docs/ # Documentation (Obsidian-style)
|
||||
├── public/ # Static assets
|
||||
├── electron/ # Electron main process
|
||||
└── tests/ # Test files
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### **Feature Development Process**
|
||||
|
||||
#### **1. Planning & Design**
|
||||
- Review existing modules and services for reusable functionality
|
||||
- Design module interfaces and dependencies
|
||||
- Create or update relevant documentation
|
||||
|
||||
#### **2. Implementation**
|
||||
```bash
|
||||
# Create feature branch
|
||||
git checkout -b feature/my-new-feature
|
||||
|
||||
# Implement feature following modular architecture
|
||||
# - Create module plugin if needed
|
||||
# - Implement services with BaseService pattern
|
||||
# - Use dependency injection for service access
|
||||
# - Follow TypeScript and Vue 3 best practices
|
||||
|
||||
# Test implementation
|
||||
npm run dev
|
||||
npm run test:unit # If tests exist
|
||||
```
|
||||
|
||||
#### **3. Code Review & Testing**
|
||||
```bash
|
||||
# Run quality checks
|
||||
npm run build # Ensure TypeScript compilation
|
||||
npm run lint # Check code style
|
||||
npm run format # Auto-format code
|
||||
|
||||
# Test across platforms
|
||||
npm run preview # Test production build
|
||||
npm run electron:dev # Test desktop version
|
||||
```
|
||||
|
||||
#### **4. Documentation & Commit**
|
||||
```bash
|
||||
# Update relevant documentation
|
||||
# Add JSDoc comments for public APIs
|
||||
# Update CHANGELOG.md if applicable
|
||||
|
||||
# Commit with conventional commits
|
||||
git add .
|
||||
git commit -m "feat: add new feature functionality"
|
||||
```
|
||||
|
||||
### **Daily Development Tasks**
|
||||
|
||||
#### **Starting Development Session**
|
||||
```bash
|
||||
cd web-app/
|
||||
npm run dev # Starts Vite dev server on http://localhost:5173
|
||||
```
|
||||
|
||||
#### **Development Server Features**
|
||||
- **Hot Module Replacement (HMR)** - Instant updates without page reload
|
||||
- **TypeScript Checking** - Compile-time error detection
|
||||
- **Import Analysis** - Automatic dependency resolution
|
||||
- **Source Maps** - Debug original TypeScript code in browser
|
||||
|
||||
#### **Common Development Commands**
|
||||
```bash
|
||||
# Development
|
||||
npm run dev # Start dev server
|
||||
npm run dev:host # Dev server accessible on network
|
||||
|
||||
# Building
|
||||
npm run build # Production build with TypeScript check
|
||||
npm run preview # Preview production build locally
|
||||
|
||||
# Code Quality
|
||||
npm run lint # ESLint checking
|
||||
npm run lint:fix # Auto-fix linting issues
|
||||
npm run format # Prettier formatting
|
||||
|
||||
# Electron
|
||||
npm run electron:dev # Concurrent Vite + Electron development
|
||||
npm run electron:build # Package desktop application
|
||||
|
||||
# Analysis
|
||||
npm run analyze # Bundle analyzer
|
||||
```
|
||||
|
||||
## Code Standards
|
||||
|
||||
### **TypeScript Guidelines**
|
||||
|
||||
#### **Strict Type Checking**
|
||||
```typescript
|
||||
// ✅ Use explicit types for public APIs
|
||||
interface UserProfile {
|
||||
pubkey: string
|
||||
name?: string
|
||||
about?: string
|
||||
}
|
||||
|
||||
// ✅ Use type guards for runtime validation
|
||||
function isNostrEvent(obj: unknown): obj is NostrEvent {
|
||||
return typeof obj === 'object' && obj !== null && 'kind' in obj
|
||||
}
|
||||
|
||||
// ❌ Avoid 'any' type
|
||||
function processData(data: any): any { }
|
||||
|
||||
// ✅ Use proper generic constraints
|
||||
function processData<T extends NostrEvent>(data: T): T { }
|
||||
```
|
||||
|
||||
#### **Interface vs Type Preferences**
|
||||
```typescript
|
||||
// ✅ Use interfaces for extensible objects
|
||||
interface ModulePlugin {
|
||||
name: string
|
||||
install(app: App): Promise<void>
|
||||
}
|
||||
|
||||
interface MyModulePlugin extends ModulePlugin {
|
||||
customConfig?: MyConfig
|
||||
}
|
||||
|
||||
// ✅ Use type aliases for unions and computations
|
||||
type EventKind = 0 | 1 | 3 | 4 | 5 | 6 | 7
|
||||
type ServiceToken = keyof typeof SERVICE_TOKENS
|
||||
```
|
||||
|
||||
### **Vue 3 Patterns**
|
||||
|
||||
#### **Composition API with Script Setup**
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// ✅ Use <script setup> syntax
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
|
||||
// Props with TypeScript
|
||||
interface Props {
|
||||
userId: string
|
||||
initialData?: UserData
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// Reactive state
|
||||
const data = ref<UserData[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
// Computed properties
|
||||
const filteredData = computed(() =>
|
||||
data.value.filter(item => item.userId === props.userId)
|
||||
)
|
||||
|
||||
// Lifecycle hooks
|
||||
onMounted(async () => {
|
||||
await loadUserData()
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
#### **Service Integration**
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// ✅ Use dependency injection for services
|
||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
const toast = injectService(SERVICE_TOKENS.TOAST_SERVICE)
|
||||
|
||||
// ✅ Destructure reactive properties
|
||||
const { user, isAuthenticated } = authService
|
||||
|
||||
// ✅ Handle async operations properly
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
await authService.login(privateKey.value)
|
||||
toast.auth.loginSuccess()
|
||||
} catch (error) {
|
||||
toast.auth.loginError(error.message)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### **Module Development Standards**
|
||||
|
||||
#### **Module Structure**
|
||||
```typescript
|
||||
// ✅ Proper module plugin implementation
|
||||
export const myModule: ModulePlugin = {
|
||||
name: 'my-module',
|
||||
version: '1.0.0',
|
||||
dependencies: ['base'], // Always depend on base
|
||||
|
||||
async install(app: App, options?: MyModuleConfig) {
|
||||
// Register services
|
||||
const myService = new MyService()
|
||||
container.provide(SERVICE_TOKENS.MY_SERVICE, myService)
|
||||
|
||||
// Register components
|
||||
app.component('MyComponent', MyComponent)
|
||||
|
||||
// Initialize
|
||||
await myService.initialize()
|
||||
},
|
||||
|
||||
routes: [
|
||||
{
|
||||
path: '/my-feature',
|
||||
component: () => import('./views/MyFeatureView.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### **Service Development**
|
||||
```typescript
|
||||
// ✅ Extend BaseService for consistency
|
||||
export class MyService extends BaseService {
|
||||
private readonly _data = ref<MyData[]>([])
|
||||
public readonly data = readonly(this._data)
|
||||
|
||||
constructor(
|
||||
private auth = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
// Initialization logic
|
||||
this.isInitialized.value = true
|
||||
}
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
// Cleanup logic
|
||||
this.isDisposed.value = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Naming Conventions**
|
||||
|
||||
#### **Files and Directories**
|
||||
```
|
||||
# ✅ Use kebab-case for files and directories
|
||||
my-component.vue
|
||||
my-service.ts
|
||||
my-module-config.ts
|
||||
|
||||
# ✅ Component files use PascalCase base name
|
||||
UserProfileCard.vue
|
||||
EventTicketPurchase.vue
|
||||
```
|
||||
|
||||
#### **Variables and Functions**
|
||||
```typescript
|
||||
// ✅ Use camelCase for variables and functions
|
||||
const userName = ref('')
|
||||
const isAuthenticated = computed(() => !!user.value)
|
||||
|
||||
async function handleUserLogin(): Promise<void> { }
|
||||
|
||||
// ✅ Use PascalCase for classes and interfaces
|
||||
class AuthService extends BaseService { }
|
||||
interface UserProfile { }
|
||||
```
|
||||
|
||||
#### **Constants and Types**
|
||||
```typescript
|
||||
// ✅ Use SCREAMING_SNAKE_CASE for constants
|
||||
const MAX_MESSAGE_LENGTH = 1000
|
||||
const DEFAULT_RELAY_URLS = ['wss://relay.example.com']
|
||||
|
||||
// ✅ Use PascalCase for types and enums
|
||||
type NostrEventKind = 0 | 1 | 3 | 4
|
||||
enum ConnectionStatus { Connected, Connecting, Disconnected }
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### **Testing Philosophy**
|
||||
- **Unit Tests** - Test individual components and services in isolation
|
||||
- **Integration Tests** - Test service interactions and module integration
|
||||
- **E2E Tests** - Test complete user workflows (planned)
|
||||
- **Manual Testing** - Cross-platform testing and user experience validation
|
||||
|
||||
### **Unit Testing Setup**
|
||||
```typescript
|
||||
// tests/unit/services/MyService.test.ts
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { MyService } from '@/services/MyService'
|
||||
import { createMockDIContainer } from '@/tests/helpers'
|
||||
|
||||
describe('MyService', () => {
|
||||
let service: MyService
|
||||
let mockAuth: MockAuthService
|
||||
|
||||
beforeEach(() => {
|
||||
const container = createMockDIContainer()
|
||||
mockAuth = container.get(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
service = new MyService()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await service.dispose()
|
||||
})
|
||||
|
||||
it('should initialize correctly', async () => {
|
||||
await service.initialize()
|
||||
expect(service.isInitialized.value).toBe(true)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### **Component Testing**
|
||||
```typescript
|
||||
// tests/unit/components/MyComponent.test.ts
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createMockDIContainer } from '@/tests/helpers'
|
||||
import MyComponent from '@/components/MyComponent.vue'
|
||||
|
||||
describe('MyComponent', () => {
|
||||
it('should render correctly', () => {
|
||||
const wrapper = mount(MyComponent, {
|
||||
props: { userId: 'test-user' },
|
||||
global: {
|
||||
plugins: [createMockDIContainer()]
|
||||
}
|
||||
})
|
||||
|
||||
expect(wrapper.text()).toContain('test-user')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## Build & Deployment
|
||||
|
||||
### **Development Builds**
|
||||
```bash
|
||||
# Development server (with HMR)
|
||||
npm run dev
|
||||
|
||||
# Development build (for debugging)
|
||||
npm run build:dev
|
||||
```
|
||||
|
||||
### **Production Builds**
|
||||
```bash
|
||||
# Full production build
|
||||
npm run build
|
||||
|
||||
# Preview production build locally
|
||||
npm run preview
|
||||
|
||||
# Bundle analysis
|
||||
npm run analyze
|
||||
```
|
||||
|
||||
### **Electron Builds**
|
||||
```bash
|
||||
# Development
|
||||
npm run electron:dev
|
||||
|
||||
# Production packaging
|
||||
npm run electron:build
|
||||
|
||||
# Platform-specific builds
|
||||
npm run build:win # Windows
|
||||
npm run build:mac # macOS
|
||||
npm run build:linux # Linux
|
||||
```
|
||||
|
||||
### **Build Configuration**
|
||||
|
||||
#### **Vite Configuration** (`vite.config.ts`)
|
||||
- **TypeScript compilation** with vue-tsc
|
||||
- **Bundle optimization** with manual chunking
|
||||
- **PWA integration** with service worker
|
||||
- **Asset optimization** with image processing
|
||||
|
||||
#### **Electron Configuration** (`forge.config.js`)
|
||||
- **Cross-platform packaging** with Electron Forge
|
||||
- **Auto-updater integration** for seamless updates
|
||||
- **Code signing** for distribution (production)
|
||||
|
||||
## Debugging Guide
|
||||
|
||||
### **Development Debugging**
|
||||
|
||||
#### **Vue DevTools**
|
||||
- Install Vue DevTools browser extension
|
||||
- Inspect component state and props
|
||||
- Monitor Pinia store mutations
|
||||
- Track component lifecycle events
|
||||
|
||||
#### **Browser Developer Tools**
|
||||
- Use TypeScript source maps for original code debugging
|
||||
- Network tab for Nostr relay communication
|
||||
- Console tab for service logging
|
||||
- Application tab for localStorage inspection
|
||||
|
||||
#### **Service Debugging**
|
||||
```typescript
|
||||
// Add debug logging to services
|
||||
export class MyService extends BaseService {
|
||||
private debug = (message: string, ...args: unknown[]) => {
|
||||
if (import.meta.env.VITE_DEBUG) {
|
||||
console.log(`[MyService] ${message}`, ...args)
|
||||
}
|
||||
}
|
||||
|
||||
async performAction(): Promise<void> {
|
||||
this.debug('Performing action...')
|
||||
// Implementation
|
||||
this.debug('Action completed')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Nostr Debugging**
|
||||
|
||||
#### **Relay Communication**
|
||||
```typescript
|
||||
// Log Nostr events for debugging
|
||||
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
||||
|
||||
relayHub.subscribe(filters, (event) => {
|
||||
console.log('Received Nostr event:', event)
|
||||
})
|
||||
|
||||
// Debug relay connections
|
||||
console.log('Connected relays:', relayHub.connectedRelays.value)
|
||||
```
|
||||
|
||||
#### **Event Publishing**
|
||||
```typescript
|
||||
// Debug event publishing
|
||||
try {
|
||||
await relayHub.publishEvent(event)
|
||||
console.log('Event published successfully:', event)
|
||||
} catch (error) {
|
||||
console.error('Failed to publish event:', error)
|
||||
}
|
||||
```
|
||||
|
||||
### **Common Issues & Solutions**
|
||||
|
||||
#### **TypeScript Errors**
|
||||
```bash
|
||||
# Clear TypeScript cache
|
||||
rm -rf node_modules/.cache
|
||||
rm -rf dist
|
||||
|
||||
# Restart TypeScript language server in VS Code
|
||||
Cmd/Ctrl + Shift + P > "TypeScript: Restart TS Server"
|
||||
```
|
||||
|
||||
#### **Module Import Issues**
|
||||
```typescript
|
||||
// ❌ Incorrect relative import
|
||||
import { MyService } from '../../services/MyService'
|
||||
|
||||
// ✅ Use absolute imports with @ alias
|
||||
import { MyService } from '@/services/MyService'
|
||||
```
|
||||
|
||||
#### **Dependency Injection Issues**
|
||||
```typescript
|
||||
// ❌ Service not registered
|
||||
const service = injectService(SERVICE_TOKENS.MY_SERVICE) // Error!
|
||||
|
||||
// ✅ Ensure service is registered in module installation
|
||||
container.provide(SERVICE_TOKENS.MY_SERVICE, new MyService())
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
### Development Documentation
|
||||
- **[[setup|🛠️ Environment Setup]]** - Detailed setup instructions
|
||||
- **[[coding-standards|📋 Coding Standards]]** - Comprehensive style guide
|
||||
- **[[testing|🧪 Testing Guide]]** - Testing frameworks and patterns
|
||||
- **[[debugging|🐛 Debugging Techniques]]** - Advanced debugging strategies
|
||||
|
||||
### Architecture References
|
||||
- **[[../02-modules/index|📦 Module System]]** - Plugin-based architecture
|
||||
- **[[../03-core-services/index|⚙️ Core Services]]** - Service development patterns
|
||||
- **[[../01-architecture/dependency-injection|⚙️ Dependency Injection]]** - DI container usage
|
||||
|
||||
---
|
||||
|
||||
**Tags:** #development #workflow #standards #testing #debugging
|
||||
**Last Updated:** 2025-09-06
|
||||
**Author:** Development Team
|
||||
444
docs/04-development/mobile-relay-evaluation.md
Normal file
444
docs/04-development/mobile-relay-evaluation.md
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
# Mobile Relay Connection Management Evaluation
|
||||
|
||||
## Current Implementation Analysis
|
||||
|
||||
### ✅ **Strengths - What We're Doing Well**
|
||||
|
||||
#### 1. **Basic Mobile Visibility Handling**
|
||||
- **Page Visibility API**: Uses `document.visibilitychange` to detect when app goes to background/foreground
|
||||
- **Network Status Monitoring**: Listens for `online`/`offline` events
|
||||
- **Health Check Integration**: Performs health checks when page becomes visible
|
||||
|
||||
#### 2. **Automatic Reconnection Logic**
|
||||
- **Exponential Backoff**: Implements reconnection attempts with delays
|
||||
- **Max Attempts**: Prevents infinite reconnection loops (max 5 attempts)
|
||||
- **Health Monitoring**: 30-second intervals for connection health checks
|
||||
|
||||
#### 3. **Connection Pool Management**
|
||||
- **SimplePool Integration**: Uses `nostr-tools` SimplePool for efficient relay management
|
||||
- **Priority-based Connection**: Connects to relays in priority order
|
||||
- **Graceful Degradation**: Continues working with partial relay connections
|
||||
|
||||
### ⚠️ **Areas for Improvement - Mobile-Specific Issues**
|
||||
|
||||
#### 1. **WebSocket Lifecycle Management**
|
||||
```typescript
|
||||
// Current implementation in relayHub.ts:424-456
|
||||
private setupMobileVisibilityHandling(): void {
|
||||
if (typeof document !== 'undefined') {
|
||||
this.mobileVisibilityHandler = () => {
|
||||
if (document.hidden) {
|
||||
console.log('Page hidden, maintaining WebSocket connections')
|
||||
// ❌ PROBLEM: Just logs, doesn't optimize connections
|
||||
} else {
|
||||
console.log('Page visible, resuming normal WebSocket activity')
|
||||
this.performHealthCheck() // ✅ Good: Checks health on resume
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
- **No Connection Optimization**: When app goes to background, WebSockets remain fully active
|
||||
- **Battery Drain**: Maintains all subscriptions and connections in background
|
||||
- **No Smart Throttling**: Doesn't reduce activity when not visible
|
||||
|
||||
#### 2. **Mobile App State Handling**
|
||||
- **Missing PWA Support**: No handling for `beforeinstallprompt`, `appinstalled` events
|
||||
- **No Service Worker Integration**: Missing offline/background sync capabilities
|
||||
- **Limited Mobile-Specific Events**: Doesn't handle `pagehide`/`pageshow` for better mobile detection
|
||||
|
||||
#### 3. **Connection Resilience**
|
||||
- **Health Check Limitations**: Current health check only verifies relay presence, not actual WebSocket health
|
||||
- **No Ping/Pong**: Missing WebSocket-level health verification
|
||||
- **Subscription Recovery**: Subscriptions aren't automatically restored after reconnection
|
||||
|
||||
## 🔧 **Recommended Improvements**
|
||||
|
||||
### 1. **Enhanced Mobile Visibility Handling**
|
||||
|
||||
```typescript
|
||||
private setupMobileVisibilityHandling(): void {
|
||||
if (typeof document !== 'undefined') {
|
||||
this.mobileVisibilityHandler = () => {
|
||||
if (document.hidden) {
|
||||
console.log('Page hidden, optimizing WebSocket connections...')
|
||||
this.optimizeForBackground()
|
||||
} else {
|
||||
console.log('Page visible, restoring full WebSocket activity...')
|
||||
this.restoreFullActivity()
|
||||
}
|
||||
}
|
||||
|
||||
// Add mobile-specific events
|
||||
document.addEventListener('visibilitychange', this.mobileVisibilityHandler)
|
||||
window.addEventListener('pagehide', this.handlePageHide)
|
||||
window.addEventListener('pageshow', this.handlePageShow)
|
||||
}
|
||||
|
||||
// Handle network changes
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('online', this.handleNetworkOnline)
|
||||
window.addEventListener('offline', this.handleNetworkOffline)
|
||||
|
||||
// Add connection quality monitoring
|
||||
if ('connection' in navigator) {
|
||||
navigator.connection?.addEventListener('change', this.handleConnectionChange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private optimizeForBackground(): void {
|
||||
// Reduce WebSocket activity in background
|
||||
this.backgroundMode = true
|
||||
|
||||
// Keep only essential connections
|
||||
this.maintainEssentialConnections()
|
||||
|
||||
// Reduce health check frequency
|
||||
this.adjustHealthCheckInterval(60000) // 1 minute instead of 30 seconds
|
||||
|
||||
// Suspend non-critical subscriptions
|
||||
this.suspendNonCriticalSubscriptions()
|
||||
}
|
||||
|
||||
private restoreFullActivity(): void {
|
||||
this.backgroundMode = false
|
||||
|
||||
// Restore all connections
|
||||
this.restoreAllConnections()
|
||||
|
||||
// Resume normal health check frequency
|
||||
this.adjustHealthCheckInterval(30000)
|
||||
|
||||
// Restore all subscriptions
|
||||
this.restoreAllSubscriptions()
|
||||
|
||||
// Perform immediate health check
|
||||
this.performHealthCheck()
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **Smart Connection Management**
|
||||
|
||||
```typescript
|
||||
interface ConnectionStrategy {
|
||||
mode: 'foreground' | 'background' | 'critical'
|
||||
maxConnections: number
|
||||
healthCheckInterval: number
|
||||
subscriptionLimit: number
|
||||
}
|
||||
|
||||
private connectionStrategies: Map<string, ConnectionStrategy> = new Map([
|
||||
['foreground', { mode: 'foreground', maxConnections: 5, healthCheckInterval: 30000, subscriptionLimit: 20 }],
|
||||
['background', { mode: 'background', maxConnections: 2, healthCheckInterval: 60000, subscriptionLimit: 5 }],
|
||||
['critical', { mode: 'critical', maxConnections: 1, healthCheckInterval: 120000, subscriptionLimit: 2 }]
|
||||
])
|
||||
|
||||
private maintainEssentialConnections(): void {
|
||||
const strategy = this.connectionStrategies.get('background')!
|
||||
|
||||
// Keep only the most reliable relays
|
||||
const essentialRelays = this.getMostReliableRelays(strategy.maxConnections)
|
||||
|
||||
// Disconnect from non-essential relays
|
||||
this.disconnectNonEssentialRelays(essentialRelays)
|
||||
|
||||
// Maintain only critical subscriptions
|
||||
this.maintainCriticalSubscriptions(strategy.subscriptionLimit)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **Enhanced Health Checking**
|
||||
|
||||
```typescript
|
||||
private async performHealthCheck(): Promise<void> {
|
||||
if (!this._isConnected) return
|
||||
|
||||
console.log('Performing enhanced relay health check...')
|
||||
const disconnectedRelays: string[] = []
|
||||
const unhealthyRelays: string[] = []
|
||||
|
||||
for (const [url, relay] of this.connectedRelays) {
|
||||
try {
|
||||
// Test actual WebSocket health with ping/pong
|
||||
const isHealthy = await this.testRelayHealth(relay)
|
||||
|
||||
if (!isHealthy) {
|
||||
unhealthyRelays.push(url)
|
||||
}
|
||||
|
||||
// Update relay status
|
||||
this.updateRelayStatus(url, {
|
||||
lastSeen: Date.now(),
|
||||
latency: await this.measureRelayLatency(relay)
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.warn(`Health check failed for relay ${url}:`, error)
|
||||
disconnectedRelays.push(url)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle unhealthy relays
|
||||
unhealthyRelays.forEach(url => {
|
||||
console.log(`Relay ${url} is unhealthy, attempting reconnection...`)
|
||||
this.reconnectRelay(url)
|
||||
})
|
||||
|
||||
// Handle disconnected relays
|
||||
this.handleDisconnectedRelays(disconnectedRelays)
|
||||
}
|
||||
|
||||
private async testRelayHealth(relay: Relay): Promise<boolean> {
|
||||
try {
|
||||
// Send a ping event to test WebSocket health
|
||||
const pingEvent = { kind: 1, content: 'ping', created_at: Math.floor(Date.now() / 1000) }
|
||||
await relay.send(pingEvent)
|
||||
|
||||
// Wait for response or timeout
|
||||
return new Promise((resolve) => {
|
||||
const timeout = setTimeout(() => resolve(false), 5000)
|
||||
|
||||
const onMessage = (event: any) => {
|
||||
if (event.kind === 1 && event.content === 'pong') {
|
||||
clearTimeout(timeout)
|
||||
relay.off('message', onMessage)
|
||||
resolve(true)
|
||||
}
|
||||
}
|
||||
|
||||
relay.on('message', onMessage)
|
||||
})
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. **Subscription Recovery System**
|
||||
|
||||
```typescript
|
||||
interface SubscriptionState {
|
||||
id: string
|
||||
filters: Filter[]
|
||||
relays?: string[]
|
||||
onEvent?: (event: Event) => void
|
||||
onEose?: () => void
|
||||
onClose?: () => void
|
||||
isActive: boolean
|
||||
lastActivity: number
|
||||
}
|
||||
|
||||
private subscriptionStates: Map<string, SubscriptionState> = new Map()
|
||||
|
||||
subscribe(config: SubscriptionConfig): () => void {
|
||||
// Store subscription state for recovery
|
||||
this.subscriptionStates.set(config.id, {
|
||||
...config,
|
||||
isActive: true,
|
||||
lastActivity: Date.now()
|
||||
})
|
||||
|
||||
// Perform actual subscription
|
||||
const unsubscribe = this.performSubscription(config)
|
||||
|
||||
return () => {
|
||||
this.subscriptionStates.get(config.id)!.isActive = false
|
||||
unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
private restoreAllSubscriptions(): void {
|
||||
console.log('Restoring all subscriptions...')
|
||||
|
||||
for (const [id, state] of this.subscriptionStates) {
|
||||
if (state.isActive) {
|
||||
console.log(`Restoring subscription: ${id}`)
|
||||
this.performSubscription(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. **Mobile-Specific Event Handling**
|
||||
|
||||
```typescript
|
||||
private handlePageHide = (event: PageTransitionEvent): void => {
|
||||
// Handle mobile app backgrounding
|
||||
if (event.persisted) {
|
||||
console.log('Page is being cached (mobile background)')
|
||||
this.optimizeForBackground()
|
||||
} else {
|
||||
console.log('Page is being unloaded')
|
||||
this.prepareForUnload()
|
||||
}
|
||||
}
|
||||
|
||||
private handlePageShow = (event: PageTransitionEvent): void => {
|
||||
console.log('Page is being shown (mobile foreground)')
|
||||
|
||||
// Check if we need to reconnect
|
||||
if (!this._isConnected) {
|
||||
console.log('Reconnecting after page show...')
|
||||
this.connect()
|
||||
} else {
|
||||
this.restoreFullActivity()
|
||||
}
|
||||
}
|
||||
|
||||
private handleConnectionChange = (event: Event): void => {
|
||||
const connection = (event.target as any) as NetworkInformation
|
||||
|
||||
console.log(`Connection type changed: ${connection.effectiveType}`)
|
||||
|
||||
// Adjust connection strategy based on network quality
|
||||
if (connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g') {
|
||||
this.setConnectionStrategy('critical')
|
||||
} else if (connection.effectiveType === '3g') {
|
||||
this.setConnectionStrategy('background')
|
||||
} else {
|
||||
this.setConnectionStrategy('foreground')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📱 **Mobile-Specific Best Practices Implementation**
|
||||
|
||||
### 1. **Battery-Aware Connection Management**
|
||||
|
||||
```typescript
|
||||
private isLowBattery = false
|
||||
|
||||
private setupBatteryMonitoring(): void {
|
||||
if ('getBattery' in navigator) {
|
||||
navigator.getBattery().then(battery => {
|
||||
battery.addEventListener('levelchange', () => {
|
||||
this.isLowBattery = battery.level < 0.2
|
||||
this.adjustConnectionStrategy()
|
||||
})
|
||||
|
||||
battery.addEventListener('chargingchange', () => {
|
||||
this.adjustConnectionStrategy()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private adjustConnectionStrategy(): void {
|
||||
if (this.isLowBattery && !this.isCharging) {
|
||||
this.setConnectionStrategy('critical')
|
||||
} else {
|
||||
this.setConnectionStrategy(this.backgroundMode ? 'background' : 'foreground')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **Progressive Web App Support**
|
||||
|
||||
```typescript
|
||||
private setupPWASupport(): void {
|
||||
// Handle app installation
|
||||
window.addEventListener('beforeinstallprompt', (event) => {
|
||||
console.log('App can be installed')
|
||||
this.installPrompt = event
|
||||
})
|
||||
|
||||
// Handle app installation completion
|
||||
window.addEventListener('appinstalled', () => {
|
||||
console.log('App was installed')
|
||||
this.isInstalled = true
|
||||
})
|
||||
|
||||
// Handle app launch from installed state
|
||||
if (window.matchMedia('(display-mode: standalone)').matches) {
|
||||
console.log('App is running in standalone mode')
|
||||
this.isStandalone = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **Service Worker Integration**
|
||||
|
||||
```typescript
|
||||
// In service worker
|
||||
self.addEventListener('sync', (event) => {
|
||||
if (event.tag === 'relay-reconnect') {
|
||||
event.waitUntil(reconnectToRelays())
|
||||
}
|
||||
})
|
||||
|
||||
// In relay hub
|
||||
private scheduleBackgroundReconnect(): void {
|
||||
if ('serviceWorker' in navigator && 'sync' in window.ServiceWorkerRegistration.prototype) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.sync.register('relay-reconnect')
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 **Testing Recommendations**
|
||||
|
||||
### 1. **Mobile Device Testing**
|
||||
- Test on actual iOS/Android devices
|
||||
- Test background/foreground transitions
|
||||
- Test network switching (WiFi ↔ Cellular)
|
||||
- Test low battery scenarios
|
||||
|
||||
### 2. **Simulation Testing**
|
||||
```typescript
|
||||
// Test visibility changes
|
||||
document.dispatchEvent(new Event('visibilitychange'))
|
||||
|
||||
// Test network changes
|
||||
window.dispatchEvent(new Event('offline'))
|
||||
window.dispatchEvent(new Event('online'))
|
||||
|
||||
// Test page transitions
|
||||
window.dispatchEvent(new PageTransitionEvent('pagehide', { persisted: true }))
|
||||
window.dispatchEvent(new PageTransitionEvent('pageshow', { persisted: false }))
|
||||
```
|
||||
|
||||
### 3. **Performance Monitoring**
|
||||
```typescript
|
||||
// Monitor connection efficiency
|
||||
const connectionMetrics = {
|
||||
connectionAttempts: 0,
|
||||
successfulConnections: 0,
|
||||
failedConnections: 0,
|
||||
averageLatency: 0,
|
||||
batteryImpact: 'low' // 'low' | 'medium' | 'high'
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 **Current Implementation Score**
|
||||
|
||||
| Category | Score | Notes |
|
||||
|----------|-------|-------|
|
||||
| **Basic Mobile Support** | 6/10 | Has visibility API but limited optimization |
|
||||
| **Connection Resilience** | 7/10 | Good reconnection logic, needs better health checks |
|
||||
| **Battery Optimization** | 3/10 | No battery-aware connection management |
|
||||
| **Network Adaptation** | 5/10 | Basic online/offline handling |
|
||||
| **Subscription Recovery** | 4/10 | Subscriptions lost on reconnection |
|
||||
| **Mobile-Specific Events** | 4/10 | Missing key mobile lifecycle events |
|
||||
|
||||
**Overall Score: 4.8/10**
|
||||
|
||||
## 🎯 **Priority Implementation Order**
|
||||
|
||||
1. **High Priority**: Enhanced health checking and subscription recovery
|
||||
2. **Medium Priority**: Smart background/foreground connection management
|
||||
3. **Low Priority**: Battery monitoring and PWA support
|
||||
|
||||
## 🚀 **Next Steps**
|
||||
|
||||
1. Implement enhanced health checking with ping/pong
|
||||
2. Add subscription state persistence and recovery
|
||||
3. Implement smart connection optimization for background mode
|
||||
4. Add mobile-specific event handling
|
||||
5. Test thoroughly on mobile devices
|
||||
6. Monitor battery impact and connection efficiency
|
||||
|
||||
The current implementation provides a solid foundation but needs significant enhancement to meet mobile best practices for WebSocket management, battery optimization, and connection resilience.
|
||||
10
docs/04-development/todo.md
Normal file
10
docs/04-development/todo.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
● You're absolutely correct! The backend functionality is already there. We just need to add the UI components to interact with
|
||||
the existing social functions.
|
||||
|
||||
The main missing pieces are:
|
||||
1. Reply UI - buttons and forms to reply to notes
|
||||
2. Reaction buttons - like/emoji buttons on each note
|
||||
3. Note composition - form to write and publish new notes
|
||||
|
||||
Would you like me to start implementing these UI components? We could begin with adding reply and reaction buttons to the
|
||||
existing NostrFeed component since the backend functions are already available.
|
||||
Loading…
Add table
Add a link
Reference in a new issue