From cdf099e45f3127d6d82cfa1eed722c6f1e9aaa15 Mon Sep 17 00:00:00 2001 From: padreug Date: Sat, 6 Sep 2025 14:31:27 +0200 Subject: [PATCH] Create comprehensive Obsidian-style documentation structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- docs/.obsidian/app.json | 1 + docs/.obsidian/appearance.json | 1 + docs/.obsidian/core-plugins.json | 31 + docs/.obsidian/workspace.json | 175 +++++ docs/00-overview/index.md | 136 ++++ docs/00-overview/project-goals.md | 137 ++++ docs/00-overview/tech-stack.md | 241 +++++++ docs/01-architecture/index.md | 241 +++++++ .../modular-design.md} | 0 .../01-architecture/relay-hub.md | 0 .../02-modules/chat-module/integration.md | 0 docs/02-modules/index.md | 386 ++++++++++ .../market-module/order-management.md | 0 .../03-core-services/authentication.md | 0 docs/03-core-services/index.md | 496 +++++++++++++ .../visibility-service-integration.md} | 0 .../visibility-service.md} | 0 .../04-development/improvements.md | 0 docs/04-development/index.md | 571 +++++++++++++++ .../04-development/mobile-relay-evaluation.md | 0 TODO.md => docs/04-development/todo.md | 0 docs/05-api-reference/index.md | 479 +++++++++++++ .../05-api-reference/specifications.md | 0 docs/06-deployment/index.md | 663 ++++++++++++++++++ docs/README.md | 175 +++++ .../archive/ARCHITECTURE_ANALYSIS_PRINT.md | 0 .../archive/legacy-architecture-analysis.md | 0 .../archive/legacy-nostr-architecture.md | 0 docs/modular-architecture-analysis.pdf | Bin 74417 -> 0 bytes 29 files changed, 3733 insertions(+) create mode 100644 docs/.obsidian/app.json create mode 100644 docs/.obsidian/appearance.json create mode 100644 docs/.obsidian/core-plugins.json create mode 100644 docs/.obsidian/workspace.json create mode 100644 docs/00-overview/index.md create mode 100644 docs/00-overview/project-goals.md create mode 100644 docs/00-overview/tech-stack.md create mode 100644 docs/01-architecture/index.md rename docs/{modular-architecture-analysis.md => 01-architecture/modular-design.md} (100%) rename RELAY_HUB_ARCHITECTURE.md => docs/01-architecture/relay-hub.md (100%) rename CHAT_INTEGRATION.md => docs/02-modules/chat-module/integration.md (100%) create mode 100644 docs/02-modules/index.md rename ORDER_MANAGEMENT_FULFILLMENT.md => docs/02-modules/market-module/order-management.md (100%) rename AUTHENTICATION.md => docs/03-core-services/authentication.md (100%) create mode 100644 docs/03-core-services/index.md rename docs/{VisibilityService-Integration.md => 03-core-services/visibility-service-integration.md} (100%) rename docs/{VisibilityService.md => 03-core-services/visibility-service.md} (100%) rename IMPROVEMENTS.md => docs/04-development/improvements.md (100%) create mode 100644 docs/04-development/index.md rename MOBILE_RELAY_EVALUATION.md => docs/04-development/mobile-relay-evaluation.md (100%) rename TODO.md => docs/04-development/todo.md (100%) create mode 100644 docs/05-api-reference/index.md rename web-app-specification.md => docs/05-api-reference/specifications.md (100%) create mode 100644 docs/06-deployment/index.md create mode 100644 docs/README.md rename ARCHITECTURE_ANALYSIS_PRINT.md => docs/archive/ARCHITECTURE_ANALYSIS_PRINT.md (100%) rename ARCHITECTURE_ANALYSIS.md => docs/archive/legacy-architecture-analysis.md (100%) rename NOSTR_ARCHITECTURE.md => docs/archive/legacy-nostr-architecture.md (100%) delete mode 100644 docs/modular-architecture-analysis.pdf diff --git a/docs/.obsidian/app.json b/docs/.obsidian/app.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/docs/.obsidian/app.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/docs/.obsidian/appearance.json b/docs/.obsidian/appearance.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/docs/.obsidian/appearance.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/docs/.obsidian/core-plugins.json b/docs/.obsidian/core-plugins.json new file mode 100644 index 0000000..b977c25 --- /dev/null +++ b/docs/.obsidian/core-plugins.json @@ -0,0 +1,31 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "properties": false, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": true, + "webviewer": false +} \ No newline at end of file diff --git a/docs/.obsidian/workspace.json b/docs/.obsidian/workspace.json new file mode 100644 index 0000000..74aab89 --- /dev/null +++ b/docs/.obsidian/workspace.json @@ -0,0 +1,175 @@ +{ + "main": { + "id": "ff312565b85205f5", + "type": "split", + "children": [ + { + "id": "22824a70121de2e3", + "type": "tabs", + "children": [ + { + "id": "fe085d296b05d361", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "01-architecture/index.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "index" + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "473f9c90dc0ac250", + "type": "split", + "children": [ + { + "id": "ee303aa846d48de1", + "type": "tabs", + "children": [ + { + "id": "b3b6e397fb343c96", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical", + "autoReveal": false + }, + "icon": "lucide-folder-closed", + "title": "Files" + } + }, + { + "id": "57989530481d5df7", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + }, + "icon": "lucide-search", + "title": "Search" + } + }, + { + "id": "77b47c3e2e5e4005", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {}, + "icon": "lucide-bookmark", + "title": "Bookmarks" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300 + }, + "right": { + "id": "5468ccf17d8ecb0f", + "type": "split", + "children": [ + { + "id": "6a62aec4067b5e7c", + "type": "tabs", + "children": [ + { + "id": "37a0910880ab8e26", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "file": "01-architecture/index.md", + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-coming-in", + "title": "Backlinks for index" + } + }, + { + "id": "4520ebffbf27e768", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "file": "01-architecture/index.md", + "linksCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-going-out", + "title": "Outgoing links from index" + } + }, + { + "id": "210907b9838cac35", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-tags", + "title": "Tags" + } + }, + { + "id": "f2e44745914b6556", + "type": "leaf", + "state": { + "type": "outline", + "state": { + "file": "01-architecture/index.md", + "followCursor": false, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-list", + "title": "Outline of index" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "left-ribbon": { + "hiddenItems": { + "switcher:Open quick switcher": false, + "graph:Open graph view": false, + "canvas:Create new canvas": false, + "daily-notes:Open today's daily note": false, + "templates:Insert template": false, + "command-palette:Open command palette": false + } + }, + "active": "fe085d296b05d361", + "lastOpenFiles": [ + "00-overview/index.md" + ] +} \ No newline at end of file diff --git a/docs/00-overview/index.md b/docs/00-overview/index.md new file mode 100644 index 0000000..7df5ef2 --- /dev/null +++ b/docs/00-overview/index.md @@ -0,0 +1,136 @@ +# 📖 Overview + +> **Welcome to the Ario Web Application** - A modular Vue 3 + TypeScript application with Nostr protocol integration and Lightning Network payments. + +## Table of Contents + +- [[#What is Ario?]] +- [[#Key Features]] +- [[#Technology Stack]] +- [[#Quick Start]] +- [[#Documentation Navigation]] + +## What is Ario? + +Ario is a decentralized social and marketplace application built on the Nostr protocol with Lightning Network integration. It provides users with: + +- **Decentralized Social Networking** - Connect through the Nostr protocol +- **Lightning Payments** - Instant, low-fee Bitcoin payments +- **Event Ticketing** - Create and manage events with Lightning payments +- **Encrypted Messaging** - Private, secure communications +- **Marketplace Functionality** - Buy and sell goods using Lightning Network + +## Key Features + +### 🔒 **Privacy-First Architecture** +- No central servers storing user data +- Nostr protocol ensures user sovereignty +- Client-side key management with secure encryption + +### ⚡ **Lightning Network Integration** +- Instant Bitcoin payments for events and marketplace +- Low transaction fees +- Invoice generation and payment tracking + +### 🏗️ **Modular Architecture** +- Plugin-based module system +- Dependency injection for service management +- Clean separation of concerns +- Easy to extend and maintain + +### 📱 **Multi-Platform Support** +- Progressive Web App (PWA) capabilities +- Electron desktop application +- Responsive design for mobile and desktop + +### 🌍 **Internationalization** +- Multi-language support with Vue-i18n +- Theme switching (light/dark modes) +- Accessibility-focused design + +## Technology Stack + +### Frontend Core +- **Vue 3** with Composition API and ` +``` + +## Service Development + +### **Creating a New Service** + +#### 1. Service Class Implementation +```typescript +// src/core/services/MyService.ts +export class MyService extends BaseService { + // Reactive state + private readonly _data = ref([]) + private readonly _isLoading = ref(false) + + // Public readonly access to state + public readonly data = readonly(this._data) + public readonly isLoading = readonly(this._isLoading) + + constructor( + private dependency = injectService(SERVICE_TOKENS.DEPENDENCY) + ) { + super() + } + + async initialize(): Promise { + // Initialization logic + await this.loadInitialData() + this.isInitialized.value = true + } + + async dispose(): Promise { + // Cleanup logic + this._data.value = [] + this.isDisposed.value = true + } + + // Public methods + async createItem(item: CreateItemRequest): Promise { + this._isLoading.value = true + try { + const newItem = await this.dependency.create(item) + this._data.value.push(newItem) + return newItem + } finally { + this._isLoading.value = false + } + } +} +``` + +#### 2. Service Token Registration +```typescript +// Add to SERVICE_TOKENS +export const SERVICE_TOKENS = { + // ... existing tokens + MY_SERVICE: Symbol('MY_SERVICE') as InjectionKey, +} as const +``` + +#### 3. Service Registration in Module +```typescript +// In module installation +const myService = new MyService() +container.provide(SERVICE_TOKENS.MY_SERVICE, myService) +await myService.initialize() +``` + +### **Service Best Practices** + +#### **Reactive State Management** +- Use `ref()` for mutable state, `readonly()` for public access +- Provide computed properties for derived state +- Use `watch()` and `watchEffect()` for side effects + +#### **Error Handling** +- Throw descriptive errors with proper types +- Use try/catch blocks with proper cleanup +- Log errors appropriately for debugging + +#### **Performance Optimization** +- Implement proper subscription cleanup in `dispose()` +- Use debouncing for frequent operations +- Cache expensive computations with `computed()` + +## Testing Services + +### **Service Unit Tests** +```typescript +// tests/unit/services/MyService.test.ts +describe('MyService', () => { + let service: MyService + let mockDependency: MockType + + beforeEach(() => { + // Setup mocks + mockDependency = createMockService() + + // Create service with mocks + service = new MyService(mockDependency) + }) + + afterEach(async () => { + await service.dispose() + }) + + it('should initialize correctly', async () => { + await service.initialize() + + expect(service.isInitialized.value).toBe(true) + expect(service.data.value).toEqual([]) + }) + + it('should create items', async () => { + await service.initialize() + + const item = await service.createItem({ name: 'test' }) + + expect(service.data.value).toContain(item) + expect(mockDependency.create).toHaveBeenCalledWith({ name: 'test' }) + }) +}) +``` + +### **Integration Tests** +```typescript +// tests/integration/services/ServiceIntegration.test.ts +describe('Service Integration', () => { + let container: DIContainer + + beforeEach(async () => { + container = createTestContainer() + await installTestServices(container) + }) + + it('should handle cross-service communication', async () => { + const authService = container.get(SERVICE_TOKENS.AUTH_SERVICE) + const chatService = container.get(SERVICE_TOKENS.CHAT_SERVICE) + + await authService.login('test-key') + const message = await chatService.sendMessage('Hello') + + expect(message.author).toBe(authService.user.value?.pubkey) + }) +}) +``` + +## See Also + +### Service Documentation +- **[[authentication|🔐 Authentication Service]]** - User identity and session management +- **[[storage-service|💾 Storage Service]]** - User-scoped data persistence +- **[[toast-service|📢 Toast Service]]** - User notifications and feedback +- **[[visibility-service|👁️ Visibility Service]]** - Dynamic UI component control + +### Architecture References +- **[[../01-architecture/dependency-injection|⚙️ Dependency Injection]]** - DI container system +- **[[../01-architecture/event-bus|📡 Event Bus Communication]]** - Inter-service messaging +- **[[../02-modules/index|📦 Module System]]** - How services integrate with modules +- **[[../04-development/testing|🧪 Testing Guide]]** - Service testing patterns + +--- + +**Tags:** #services #architecture #dependency-injection #reactive-state +**Last Updated:** 2025-09-06 +**Author:** Development Team \ No newline at end of file diff --git a/docs/VisibilityService-Integration.md b/docs/03-core-services/visibility-service-integration.md similarity index 100% rename from docs/VisibilityService-Integration.md rename to docs/03-core-services/visibility-service-integration.md diff --git a/docs/VisibilityService.md b/docs/03-core-services/visibility-service.md similarity index 100% rename from docs/VisibilityService.md rename to docs/03-core-services/visibility-service.md diff --git a/IMPROVEMENTS.md b/docs/04-development/improvements.md similarity index 100% rename from IMPROVEMENTS.md rename to docs/04-development/improvements.md diff --git a/docs/04-development/index.md b/docs/04-development/index.md new file mode 100644 index 0000000..61fa316 --- /dev/null +++ b/docs/04-development/index.md @@ -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(data: T): T { } +``` + +#### **Interface vs Type Preferences** +```typescript +// ✅ Use interfaces for extensible objects +interface ModulePlugin { + name: string + install(app: App): Promise +} + +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 + +``` + +#### **Service Integration** +```vue + +``` + +### **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([]) + public readonly data = readonly(this._data) + + constructor( + private auth = injectService(SERVICE_TOKENS.AUTH_SERVICE) + ) { + super() + } + + async initialize(): Promise { + // Initialization logic + this.isInitialized.value = true + } + + async dispose(): Promise { + // 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 { } + +// ✅ 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 { + 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 \ No newline at end of file diff --git a/MOBILE_RELAY_EVALUATION.md b/docs/04-development/mobile-relay-evaluation.md similarity index 100% rename from MOBILE_RELAY_EVALUATION.md rename to docs/04-development/mobile-relay-evaluation.md diff --git a/TODO.md b/docs/04-development/todo.md similarity index 100% rename from TODO.md rename to docs/04-development/todo.md diff --git a/docs/05-api-reference/index.md b/docs/05-api-reference/index.md new file mode 100644 index 0000000..a7ec468 --- /dev/null +++ b/docs/05-api-reference/index.md @@ -0,0 +1,479 @@ +# 📡 API Reference + +> **External integrations and protocol implementations** powering Ario's decentralized architecture with Nostr protocol, Lightning Network, and third-party service APIs. + +## Table of Contents + +- [[#Protocol Implementations]] +- [[#External APIs]] +- [[#Service Integrations]] +- [[#SDK References]] +- [[#Authentication & Security]] +- [[#Rate Limits & Best Practices]] + +## Protocol Implementations + +### **Nostr Protocol** +**Specification:** [NIPs (Nostr Implementation Possibilities)](https://github.com/nostr-protocol/nips) +**Client Library:** `nostr-tools` v2.x +**Implementation:** Custom RelayHub service with connection pooling + +**Supported NIPs:** +- **NIP-01** - Basic protocol flow and event structure +- **NIP-02** - Contact list and petnames +- **NIP-04** - Encrypted direct messages +- **NIP-05** - Mapping Nostr keys to DNS-based internet identifiers +- **NIP-09** - Event deletion +- **NIP-10** - Conventions for clients' use of `e` and `p` tags +- **NIP-19** - bech32-encoded entities +- **NIP-25** - Reactions + +**Core Event Types:** +```typescript +interface NostrEvent { + id: string // Event ID (32-bytes hex) + pubkey: string // Author public key (32-bytes hex) + created_at: number // Unix timestamp in seconds + kind: number // Event kind (0=metadata, 1=text, 3=contacts, etc.) + tags: string[][] // Tags array + content: string // Event content + sig: string // Event signature (64-bytes hex) +} + +// Common event kinds +enum EventKind { + Metadata = 0, // User profile information + TextNote = 1, // Short text note + RecommendRelay = 2, // Recommend relay + Contacts = 3, // Contact list + EncryptedDM = 4, // Encrypted direct message + EventDeletion = 5, // Event deletion + Repost = 6, // Repost/boost + Reaction = 7, // Like/reaction + BadgeAward = 8, // Badge award + GroupChatMessage = 9, // Group chat message +} +``` + +**See:** [[nostr-protocol|📖 Nostr Protocol Implementation]] + +### **Lightning Network** +**Protocol:** BOLT specifications for Lightning Network +**Browser Integration:** WebLN API for wallet communication +**Backend Integration:** LNbits for invoice generation and payment processing + +**WebLN API Integration:** +```typescript +interface WebLN { + enable(): Promise + getInfo(): Promise + sendPayment(paymentRequest: string): Promise + makeInvoice(args: RequestInvoiceArgs): Promise + signMessage(message: string): Promise +} + +// Payment workflow +async function processLightningPayment(invoice: string): Promise { + if (!window.webln) { + throw new Error('WebLN not available') + } + + await window.webln.enable() + const result = await window.webln.sendPayment(invoice) + + return { + preimage: result.preimage, + paymentHash: result.paymentHash, + paid: true + } +} +``` + +**Invoice Generation:** +```typescript +interface LightningInvoice { + payment_request: string // BOLT11 invoice string + payment_hash: string // Payment hash (32-bytes hex) + amount: number // Amount in millisats + description: string // Invoice description + expires_at: number // Expiration timestamp + created_at: number // Creation timestamp +} +``` + +**See:** [[lightning-integration|📖 Lightning Network Integration]] + +## External APIs + +### **LNbits API** +**Purpose:** Lightning wallet backend and invoice management +**Documentation:** [LNbits API Docs](https://legend.lnbits.com/docs) +**Base URL:** Configurable via environment variables + +**Key Endpoints:** + +#### **Wallet Management** +```typescript +// Get wallet information +GET /api/v1/wallet +Authorization: X-Api-Key: {admin_key} + +interface WalletInfo { + id: string + name: string + balance: number // Balance in millisats +} +``` + +#### **Invoice Operations** +```typescript +// Create invoice +POST /api/v1/payments +Content-Type: application/json +Authorization: X-Api-Key: {invoice_key} + +interface CreateInvoiceRequest { + out: false // Incoming payment + amount: number // Amount in sats + memo: string // Invoice description + expiry?: number // Expiry in seconds +} + +interface CreateInvoiceResponse { + payment_hash: string + payment_request: string // BOLT11 invoice + checking_id: string +} +``` + +#### **Payment Verification** +```typescript +// Check payment status +GET /api/v1/payments/{checking_id} +Authorization: X-Api-Key: {invoice_key} + +interface PaymentStatus { + paid: boolean + checking_id: string + amount: number + fee: number + memo: string + time: number +} +``` + +**See:** [[lnbits-api|📖 LNbits API Integration]] + +### **Nostr Relay APIs** +**Protocol:** WebSocket-based communication following Nostr specification +**Connection Management:** Custom RelayHub with connection pooling and failover + +**Relay Communication Protocol:** +```typescript +// Client to relay messages +type ClientMessage = + | ['EVENT', NostrEvent] // Publish event + | ['REQ', string, ...Filter[]] // Request events + | ['CLOSE', string] // Close subscription + +// Relay to client messages +type RelayMessage = + | ['EVENT', string, NostrEvent] // Event received + | ['OK', string, boolean, string] // Event acceptance + | ['EOSE', string] // End of stored events + | ['NOTICE', string] // Relay notice +``` + +**Event Filters:** +```typescript +interface Filter { + ids?: string[] // Event IDs + authors?: string[] // Author pubkeys + kinds?: number[] // Event kinds + since?: number // Events after timestamp + until?: number // Events before timestamp + limit?: number // Maximum number of events + search?: string // Text search (if supported) + [key: string]: any // Tag filters (#e, #p, etc.) +} +``` + +**Relay Information (NIP-11):** +```typescript +// GET https://relay.example.com (Accept: application/nostr+json) +interface RelayInformation { + name: string + description: string + pubkey?: string + contact?: string + supported_nips?: number[] + software?: string + version?: string + limitation?: { + max_message_length?: number + max_subscriptions?: number + max_filters?: number + max_subid_length?: number + min_pow_difficulty?: number + auth_required?: boolean + payment_required?: boolean + } +} +``` + +**See:** [[relay-communication|📖 Relay Communication Protocol]] + +## Service Integrations + +### **QR Code Generation** +**Library:** `qrcode` for QR code generation +**Use Cases:** Lightning invoices, contact sharing, event tickets + +```typescript +interface QRCodeOptions { + width?: number + margin?: number + color?: { + dark?: string + light?: string + } + errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H' +} + +async function generateQRCode(data: string, options?: QRCodeOptions): Promise { + return QRCode.toDataURL(data, { + width: options?.width || 256, + margin: options?.margin || 2, + color: { + dark: options?.color?.dark || '#000000', + light: options?.color?.light || '#FFFFFF' + }, + errorCorrectionLevel: options?.errorCorrectionLevel || 'M' + }) +} +``` + +### **Cryptography Services** +**Library:** `nostr-tools` cryptographic functions +**Use Cases:** Key generation, event signing, message encryption + +```typescript +// Key generation +function generateKeyPair(): { privateKey: string; publicKey: string } { + const privateKey = generatePrivateKey() + const publicKey = getPublicKey(privateKey) + return { privateKey, publicKey } +} + +// Event signing +function signEvent(event: UnsignedEvent, privateKey: string): NostrEvent { + const id = getEventHash(event) + const sig = getSignature(id, privateKey) + return { ...event, id, sig } +} + +// Message encryption (NIP-04) +async function encryptMessage( + message: string, + recipientPubkey: string, + senderPrivkey: string +): Promise { + return encrypt(senderPrivkey, recipientPubkey, message) +} +``` + +### **Storage Services** +**Browser APIs:** localStorage, IndexedDB +**Abstraction:** StorageService with user-scoped keys + +```typescript +interface StorageService { + // User-scoped operations + setUserData(key: string, data: T): void + getUserData(key: string, defaultValue?: T): T | undefined + removeUserData(key: string): void + clearUserData(): void + + // Global application data + setAppData(key: string, data: T): void + getAppData(key: string, defaultValue?: T): T | undefined +} +``` + +## SDK References + +### **Nostr-tools Reference** +**Documentation:** [nostr-tools GitHub](https://github.com/nbd-wtf/nostr-tools) +**Version:** 2.x + +**Key Functions:** +```typescript +import { + generatePrivateKey, + getPublicKey, + getEventHash, + getSignature, + validateEvent, + verifySignature, + SimplePool, + Filter, + Event as NostrEvent, + nip04, + nip19 +} from 'nostr-tools' + +// Pool management +const pool = new SimplePool() +const events = await pool.list(relays, [filter]) +const sub = pool.sub(relays, [filter]) +``` + +### **Vue 3 Integration** +**Framework:** Vue 3 Composition API +**State Management:** Pinia stores +**Reactivity:** Vue reactive primitives + +```typescript +// Reactive Nostr client integration +export function useNostrClient() { + const isConnected = ref(false) + const connectedRelays = ref([]) + + const connect = async (relays: string[]) => { + // Connection logic + isConnected.value = true + connectedRelays.value = relays + } + + return { + isConnected: readonly(isConnected), + connectedRelays: readonly(connectedRelays), + connect + } +} +``` + +## Authentication & Security + +### **Key Management** +**Security Model:** Client-side key generation and storage +**Storage:** Encrypted localStorage with user passphrase +**No Server Storage:** Private keys never leave the client + +```typescript +interface AuthenticationFlow { + // Key generation + generateNewUser(): Promise<{ privateKey: string; publicKey: string }> + + // Import existing key + importUser(privateKey: string): Promise + + // Session management + login(privateKey: string, remember?: boolean): Promise + logout(): Promise + + // Key security + encryptPrivateKey(privateKey: string, passphrase: string): string + decryptPrivateKey(encrypted: string, passphrase: string): string +} +``` + +### **Event Validation** +**Signature Verification:** All received events are cryptographically verified +**Content Filtering:** Optional content moderation and filtering +**Spam Prevention:** Rate limiting and reputation-based filtering + +```typescript +function validateNostrEvent(event: NostrEvent): ValidationResult { + // 1. Check event structure + if (!event.id || !event.pubkey || !event.sig) { + return { valid: false, error: 'Missing required fields' } + } + + // 2. Verify event ID + const expectedId = getEventHash(event) + if (event.id !== expectedId) { + return { valid: false, error: 'Invalid event ID' } + } + + // 3. Verify signature + const signatureValid = verifySignature(event) + if (!signatureValid) { + return { valid: false, error: 'Invalid signature' } + } + + return { valid: true } +} +``` + +## Rate Limits & Best Practices + +### **Relay Communication** +- **Connection Limits** - Maximum 10 concurrent relay connections +- **Subscription Limits** - Maximum 20 active subscriptions per relay +- **Event Publishing** - Rate limited to prevent spam (1 event/second per kind) +- **Reconnection Strategy** - Exponential backoff with maximum 30-second intervals + +### **Lightning Payments** +- **Invoice Expiry** - Default 1 hour expiry for generated invoices +- **Payment Verification** - Poll payment status every 5 seconds for 5 minutes +- **Amount Limits** - Configurable minimum/maximum payment amounts +- **Error Handling** - Graceful handling of payment failures and timeouts + +### **API Usage Guidelines** + +#### **LNbits Integration** +```typescript +const API_CONFIG = { + baseUrl: process.env.VITE_LNBITS_URL, + timeout: 30000, // 30 second timeout + retryAttempts: 3, // Retry failed requests + retryDelay: 1000, // 1 second between retries + + rateLimits: { + invoiceCreation: 10, // Max 10 invoices per minute + paymentCheck: 60, // Max 60 payment checks per minute + } +} +``` + +#### **Nostr Relay Usage** +```typescript +const RELAY_CONFIG = { + maxConnections: 10, // Maximum concurrent connections + maxSubscriptions: 20, // Maximum active subscriptions + connectionTimeout: 10000, // 10 second connection timeout + + publishLimits: { + textNote: 5, // Max 5 text notes per minute + reaction: 30, // Max 30 reactions per minute + directMessage: 10, // Max 10 DMs per minute + }, + + reconnection: { + attempts: 5, // Maximum reconnection attempts + delay: 1000, // Initial delay (1 second) + backoffMultiplier: 2, // Exponential backoff + maxDelay: 30000, // Maximum delay (30 seconds) + } +} +``` + +## See Also + +### Protocol Documentation +- **[[nostr-protocol|📡 Nostr Protocol Implementation]]** - Detailed NIP implementation +- **[[lightning-integration|⚡ Lightning Network Integration]]** - WebLN and payment processing +- **[[lnbits-api|🔗 LNbits API Reference]]** - Lightning backend integration +- **[[events-api|📅 Events System API]]** - Event ticketing API reference + +### Implementation Guides +- **[[../03-core-services/index|⚙️ Core Services]]** - Service implementations using these APIs +- **[[../02-modules/index|📦 Module System]]** - How modules integrate with external APIs +- **[[../04-development/index|💻 Development Guide]]** - Testing and debugging API integrations + +--- + +**Tags:** #api #integration #nostr #lightning #protocols +**Last Updated:** 2025-09-06 +**Author:** Development Team \ No newline at end of file diff --git a/web-app-specification.md b/docs/05-api-reference/specifications.md similarity index 100% rename from web-app-specification.md rename to docs/05-api-reference/specifications.md diff --git a/docs/06-deployment/index.md b/docs/06-deployment/index.md new file mode 100644 index 0000000..99c1241 --- /dev/null +++ b/docs/06-deployment/index.md @@ -0,0 +1,663 @@ +# 🚀 Deployment Guide + +> **Production deployment and operations** for Ario's web application, desktop app, and Progressive Web App across multiple platforms and environments. + +## Table of Contents + +- [[#Deployment Options]] +- [[#Production Build Process]] +- [[#Environment Configuration]] +- [[#Platform-Specific Deployment]] +- [[#Monitoring & Maintenance]] +- [[#Security Considerations]] + +## Deployment Options + +### **Web Application (SPA)** +- **Static Hosting** - Deploy to CDN or static hosting service +- **Traditional Web Server** - Nginx, Apache, or similar +- **Cloud Platforms** - Vercel, Netlify, Cloudflare Pages +- **Container Deployment** - Docker with web server + +### **Progressive Web App (PWA)** +- **Service Worker** - Offline capabilities and caching +- **App Manifest** - Installation and app-like experience +- **Push Notifications** - Real-time updates (future feature) +- **Background Sync** - Offline data synchronization + +### **Desktop Application** +- **Electron** - Cross-platform desktop packaging +- **Platform-Specific** - Windows MSI, macOS DMG, Linux AppImage/Snap +- **Auto-Update** - Seamless application updates +- **Code Signing** - Security and trust verification + +### **Self-Hosted** +- **Full Control** - Complete control over infrastructure +- **Privacy** - No third-party hosting dependencies +- **Custom Configuration** - Tailored environment variables and settings +- **Local Development** - Internal network deployment + +## Production Build Process + +### **Build Commands** +```bash +# Standard web build +npm run build + +# Build with analysis +npm run analyze + +# Electron desktop build +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 Production Config** +```typescript +// vite.config.ts - Production optimizations +export default defineConfig({ + build: { + target: 'es2020', + minify: 'terser', + sourcemap: false, // Disable in production + chunkSizeWarningLimit: 600, + + rollupOptions: { + output: { + manualChunks: { + 'vue-vendor': ['vue', 'vue-router', 'pinia'], + 'ui-vendor': ['@headlessui/vue', '@heroicons/vue'], + 'nostr-vendor': ['nostr-tools'], + 'crypto-vendor': ['crypto-js'] + } + } + } + } +}) +``` + +#### **Build Optimization** +- **Tree Shaking** - Remove unused code +- **Code Splitting** - Lazy load modules and routes +- **Asset Optimization** - Compress images and fonts +- **Bundle Analysis** - Monitor bundle size and dependencies + +### **Build Output Structure** +``` +dist/ +├── index.html # Entry point +├── assets/ # Static assets with hashed names +│ ├── index-[hash].js # Main application bundle +│ ├── vendor-[hash].js # Vendor dependencies +│ └── [module]-[hash].js # Module-specific bundles +├── icons/ # PWA icons +├── manifest.json # PWA manifest +└── sw.js # Service worker +``` + +## Environment Configuration + +### **Environment Variables** + +#### **Production Environment (.env.production)** +```bash +# Application Configuration +VITE_APP_NAME="Ario" +VITE_APP_VERSION="1.0.0" +VITE_BASE_URL="/" + +# Nostr Configuration +VITE_NOSTR_RELAYS='["wss://relay.damus.io","wss://nos.lol","wss://relay.snort.social"]' +VITE_ADMIN_PUBKEYS='["admin_pubkey_1","admin_pubkey_2"]' + +# Lightning Configuration (if using LNbits) +VITE_LNBITS_URL="https://your-lnbits-instance.com" +VITE_LNBITS_ADMIN_KEY="" # Only for invoice creation + +# Security & Performance +VITE_DEBUG=false +VITE_ENABLE_PWA=true +VITE_ENABLE_ANALYTICS=true + +# Optional Features +VITE_ENABLE_NOTIFICATIONS=true +VITE_MAX_RELAY_CONNECTIONS=10 +VITE_EVENT_CACHE_SIZE=1000 +``` + +#### **Configuration Validation** +```typescript +// src/config/production.ts +export const productionConfig = { + app: { + name: import.meta.env.VITE_APP_NAME || 'Ario', + version: import.meta.env.VITE_APP_VERSION || '1.0.0', + baseUrl: import.meta.env.VITE_BASE_URL || '/', + }, + + nostr: { + relays: JSON.parse(import.meta.env.VITE_NOSTR_RELAYS || '[]'), + adminPubkeys: JSON.parse(import.meta.env.VITE_ADMIN_PUBKEYS || '[]'), + maxConnections: Number(import.meta.env.VITE_MAX_RELAY_CONNECTIONS) || 10, + }, + + features: { + debug: import.meta.env.VITE_DEBUG === 'true', + pwa: import.meta.env.VITE_ENABLE_PWA === 'true', + notifications: import.meta.env.VITE_ENABLE_NOTIFICATIONS === 'true', + } +} + +// Validate required configuration +if (!productionConfig.nostr.relays.length) { + throw new Error('VITE_NOSTR_RELAYS must be configured') +} +``` + +### **Security Configuration** + +#### **Content Security Policy (CSP)** +```html + + +``` + +#### **Security Headers (nginx example)** +```nginx +# nginx.conf security headers +add_header X-Frame-Options DENY; +add_header X-Content-Type-Options nosniff; +add_header X-XSS-Protection "1; mode=block"; +add_header Referrer-Policy "strict-origin-when-cross-origin"; +add_header Permissions-Policy "geolocation=(), microphone=(), camera=()"; +``` + +## Platform-Specific Deployment + +### **Web Hosting - Vercel** + +#### **vercel.json Configuration** +```json +{ + "buildCommand": "npm run build", + "outputDirectory": "dist", + "framework": "vite", + "rewrites": [ + { + "source": "/((?!api/).*)", + "destination": "/index.html" + } + ], + "headers": [ + { + "source": "/(.*)", + "headers": [ + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + } + ] + } + ] +} +``` + +#### **Deployment Steps** +```bash +# 1. Install Vercel CLI +npm i -g vercel + +# 2. Deploy to Vercel +vercel --prod + +# 3. Set environment variables in Vercel dashboard +# - VITE_NOSTR_RELAYS +# - VITE_ADMIN_PUBKEYS +# - Other configuration variables +``` + +### **Web Hosting - Netlify** + +#### **netlify.toml Configuration** +```toml +[build] + command = "npm run build" + publish = "dist" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 + +[build.environment] + NODE_VERSION = "18" + +[[headers]] + for = "/*" + [headers.values] + X-Frame-Options = "DENY" + X-XSS-Protection = "1; mode=block" + X-Content-Type-Options = "nosniff" +``` + +### **Self-Hosted - Docker** + +#### **Dockerfile** +```dockerfile +# Multi-stage build for production +FROM node:18-alpine AS builder + +WORKDIR /app +COPY package*.json ./ +RUN npm ci --only=production + +COPY . . +RUN npm run build + +# Production stage +FROM nginx:alpine + +# Copy built application +COPY --from=builder /app/dist /usr/share/nginx/html + +# Copy nginx configuration +COPY docker/nginx.conf /etc/nginx/nginx.conf + +# Expose port +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] +``` + +#### **Docker Compose** +```yaml +# docker-compose.yml +version: '3.8' + +services: + ario-web: + build: . + ports: + - "80:80" + environment: + - VITE_NOSTR_RELAYS=["wss://relay.damus.io"] + - VITE_ADMIN_PUBKEYS=["your_admin_pubkey"] + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + restart: unless-stopped +``` + +### **Desktop Application** + +#### **Electron Forge Configuration** +```javascript +// forge.config.js +module.exports = { + packagerConfig: { + name: 'Ario', + executableName: 'ario', + icon: './src/assets/icon', + asar: true, + + // Code signing (production) + osxSign: { + identity: process.env.APPLE_IDENTITY, + 'hardened-runtime': true, + entitlements: './entitlements.plist', + 'entitlements-inherit': './entitlements.plist' + }, + + osxNotarize: { + tool: 'notarytool', + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_PASSWORD, + teamId: process.env.APPLE_TEAM_ID + } + }, + + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: { + name: 'ario', + setupIcon: './src/assets/icon.ico' + } + }, + { + name: '@electron-forge/maker-dmg', + config: { + format: 'ULFO', + icon: './src/assets/icon.icns' + } + }, + { + name: '@electron-forge/maker-deb', + config: { + options: { + maintainer: 'Ario Team', + homepage: 'https://ario.app' + } + } + } + ], + + publishers: [ + { + name: '@electron-forge/publisher-github', + config: { + repository: { + owner: 'your-org', + name: 'ario' + }, + prerelease: false + } + } + ] +} +``` + +#### **Auto-Update Configuration** +```typescript +// electron/main.ts - Auto-updater setup +import { autoUpdater } from 'electron-updater' + +if (!app.isPackaged) { + autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml') +} + +autoUpdater.checkForUpdatesAndNotify() + +autoUpdater.on('update-available', () => { + dialog.showMessageBox(mainWindow, { + type: 'info', + title: 'Update Available', + message: 'A new version is available. It will be downloaded in the background.', + buttons: ['OK'] + }) +}) +``` + +## Monitoring & Maintenance + +### **Performance Monitoring** + +#### **Web Vitals Tracking** +```typescript +// src/utils/analytics.ts +import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals' + +export function initPerformanceMonitoring() { + if (import.meta.env.VITE_ENABLE_ANALYTICS) { + getCLS(sendToAnalytics) + getFID(sendToAnalytics) + getFCP(sendToAnalytics) + getLCP(sendToAnalytics) + getTTFB(sendToAnalytics) + } +} + +function sendToAnalytics(metric: any) { + // Send to your analytics service + console.log('Performance metric:', metric) +} +``` + +#### **Application Health Monitoring** +```typescript +// src/services/HealthMonitor.ts +export class HealthMonitor extends BaseService { + private healthStatus = ref({ + relayConnections: 0, + lastEventReceived: null as Date | null, + memoryUsage: 0, + errorCount: 0 + }) + + async initialize(): Promise { + setInterval(() => this.checkHealth(), 30000) // Every 30 seconds + } + + private checkHealth(): void { + const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB) + + this.healthStatus.value = { + relayConnections: relayHub.connectedRelays.value.length, + lastEventReceived: this.getLastEventTime(), + memoryUsage: this.getMemoryUsage(), + errorCount: this.getErrorCount() + } + + // Alert if critical issues detected + if (this.healthStatus.value.relayConnections === 0) { + console.warn('No relay connections available') + } + } +} +``` + +### **Error Tracking** + +#### **Global Error Handler** +```typescript +// src/utils/errorHandler.ts +export function setupGlobalErrorHandler() { + window.addEventListener('error', (event) => { + console.error('Global error:', event.error) + + // Send to error tracking service + if (import.meta.env.VITE_ERROR_TRACKING) { + sendErrorToService(event.error) + } + }) + + window.addEventListener('unhandledrejection', (event) => { + console.error('Unhandled promise rejection:', event.reason) + sendErrorToService(event.reason) + }) +} +``` + +### **Logging Strategy** + +#### **Production Logging** +```typescript +// src/utils/logger.ts +class Logger { + private shouldLog(level: LogLevel): boolean { + if (import.meta.env.PROD && level === 'debug') return false + return true + } + + info(message: string, ...args: unknown[]): void { + if (this.shouldLog('info')) { + console.log(`[INFO] ${message}`, ...args) + } + } + + error(message: string, error?: Error, ...args: unknown[]): void { + if (this.shouldLog('error')) { + console.error(`[ERROR] ${message}`, error, ...args) + + // Send to error tracking in production + if (import.meta.env.PROD && error) { + this.sendToErrorTracking(message, error) + } + } + } + + private sendToErrorTracking(message: string, error: Error): void { + // Implementation for error tracking service + } +} + +export const logger = new Logger() +``` + +## Security Considerations + +### **Client-Side Security** + +#### **Key Storage Security** +```typescript +// src/utils/keyStorage.ts +export class SecureKeyStorage { + private static readonly STORAGE_KEY = 'ario_encrypted_keys' + + static async storeEncryptedKey(privateKey: string, passphrase: string): Promise { + const encrypted = await this.encrypt(privateKey, passphrase) + localStorage.setItem(this.STORAGE_KEY, encrypted) + } + + static async retrieveDecryptedKey(passphrase: string): Promise { + const encrypted = localStorage.getItem(this.STORAGE_KEY) + if (!encrypted) return null + + try { + return await this.decrypt(encrypted, passphrase) + } catch { + return null // Invalid passphrase + } + } + + private static async encrypt(data: string, passphrase: string): Promise { + // Use Web Crypto API for encryption + const encoder = new TextEncoder() + const key = await window.crypto.subtle.importKey( + 'raw', + encoder.encode(passphrase), + { name: 'PBKDF2' }, + false, + ['deriveKey'] + ) + + // Implementation details... + return encryptedData + } +} +``` + +#### **Input Validation** +```typescript +// src/utils/validation.ts +export const validators = { + nostrPublicKey: (pubkey: string): boolean => { + return /^[0-9a-f]{64}$/i.test(pubkey) + }, + + nostrPrivateKey: (privkey: string): boolean => { + return /^[0-9a-f]{64}$/i.test(privkey) + }, + + lightningInvoice: (invoice: string): boolean => { + return /^(lnbc|lntb|lnbcrt)[0-9]+[munp]?[0-9a-z]+$/i.test(invoice) + }, + + sanitizeContent: (content: string): string => { + // Sanitize user-generated content + return content + .replace(/)<[^<]*)*<\/script>/gi, '') + .replace(/javascript:/gi, '') + .trim() + } +} +``` + +### **Deployment Security** + +#### **HTTPS Enforcement** +```nginx +# nginx.conf - Force HTTPS +server { + listen 80; + server_name ario.app www.ario.app; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name ario.app www.ario.app; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/private.key; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY always; + add_header X-Content-Type-Options nosniff always; + + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + } +} +``` + +### **Privacy Protection** + +#### **Data Minimization** +- **No Server Storage** - All user data stored client-side +- **Ephemeral Sessions** - No persistent server-side sessions +- **Optional Analytics** - Analytics can be disabled by users +- **Relay Privacy** - Users can configure their own relays + +#### **User Privacy Controls** +```typescript +// src/services/PrivacyService.ts +export class PrivacyService extends BaseService { + private settings = ref({ + shareAnalytics: false, + shareErrorReports: false, + allowLocationTracking: false, + publicProfile: false + }) + + updatePrivacySettings(updates: Partial): void { + this.settings.value = { ...this.settings.value, ...updates } + + // Apply privacy settings immediately + if (!this.settings.value.shareAnalytics) { + this.disableAnalytics() + } + + if (!this.settings.value.shareErrorReports) { + this.disableErrorReporting() + } + } +} +``` + +## See Also + +### Configuration Documentation +- **[[configuration|⚙️ Environment Configuration]]** - Detailed configuration options +- **[[pwa-setup|📱 PWA Configuration]]** - Progressive Web App setup +- **[[electron|🖥️ Desktop App Packaging]]** - Electron configuration and distribution + +### Operations Documentation +- **[[../04-development/index|💻 Development Guide]]** - Development environment setup +- **[[../05-api-reference/index|📡 API Reference]]** - External service integrations +- **[[../01-architecture/index|🏗️ Architecture Overview]]** - System architecture principles + +--- + +**Tags:** #deployment #production #security #monitoring #pwa #electron +**Last Updated:** 2025-09-06 +**Author:** Development Team \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..1a7102a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,175 @@ +# 📚 Ario Web App Documentation + +> **A comprehensive guide to the Ario Web Application** - A modular Vue 3 + TypeScript application with Nostr protocol integration and Lightning Network payments. + +## 🗂️ Documentation Structure + +This documentation follows an Obsidian-compatible structure with cross-linked markdown files organized by domain. + +### Quick Navigation + +- **[[00-overview/index|📖 Overview]]** - Start here for project introduction +- **[[01-architecture/index|🏗️ Architecture]]** - System design and patterns +- **[[02-modules/index|📦 Modules]]** - Feature module documentation +- **[[03-core-services/index|⚙️ Core Services]]** - Shared infrastructure +- **[[04-development/index|💻 Development]]** - Setup and guidelines +- **[[05-api-reference/index|📡 API Reference]]** - External integrations +- **[[06-deployment/index|🚀 Deployment]]** - Production setup + +## 📂 Directory Structure + +``` +docs/ +├── README.md # This file - Documentation hub +├── 00-overview/ # Project overview and introduction +│ ├── index.md # Overview index +│ ├── project-goals.md # Project objectives +│ ├── tech-stack.md # Technology choices +│ └── getting-started.md # Quick start guide +│ +├── 01-architecture/ # System architecture +│ ├── index.md # Architecture overview +│ ├── modular-design.md # Modular architecture patterns +│ ├── dependency-injection.md # DI container system +│ ├── event-bus.md # Inter-module communication +│ └── relay-hub.md # Nostr relay management +│ +├── 02-modules/ # Feature modules +│ ├── index.md # Module system overview +│ ├── base-module/ # Core infrastructure module +│ ├── market-module/ # Marketplace functionality +│ ├── chat-module/ # Encrypted chat system +│ ├── events-module/ # Event ticketing +│ └── nostr-feed-module/ # Social feed +│ +├── 03-core-services/ # Shared services +│ ├── index.md # Services overview +│ ├── authentication.md # Auth service & LNbits +│ ├── payment-service.md # Lightning payments +│ ├── storage-service.md # User-scoped storage +│ ├── toast-service.md # Notifications +│ └── visibility-service.md # Component visibility +│ +├── 04-development/ # Development guides +│ ├── index.md # Development overview +│ ├── setup.md # Environment setup +│ ├── coding-standards.md # Code conventions +│ ├── testing.md # Testing strategies +│ └── debugging.md # Debug techniques +│ +├── 05-api-reference/ # External APIs +│ ├── index.md # API overview +│ ├── nostr-protocol.md # Nostr implementation +│ ├── lnbits-api.md # LNbits integration +│ └── events-api.md # Events system API +│ +├── 06-deployment/ # Deployment & operations +│ ├── index.md # Deployment overview +│ ├── configuration.md # Environment variables +│ ├── pwa-setup.md # PWA configuration +│ └── electron.md # Desktop app packaging +│ +└── archive/ # Deprecated documentation + ├── legacy-architecture.md + └── old-relay-system.md +``` + +## 🔗 Key Documentation Files + +### Essential Reading +1. **[[00-overview/getting-started|Getting Started]]** - Set up your development environment +2. **[[01-architecture/modular-design|Modular Architecture]]** - Understand the plugin system +3. **[[02-modules/index|Module Development]]** - Create new feature modules +4. **[[04-development/coding-standards|Coding Standards]]** - Maintain code quality + +### Module Documentation +- **[[02-modules/base-module/index|Base Module]]** - Core infrastructure (Nostr, Auth, PWA) +- **[[02-modules/market-module/index|Market Module]]** - Nostr marketplace implementation +- **[[02-modules/chat-module/index|Chat Module]]** - Encrypted DM system +- **[[02-modules/events-module/index|Events Module]]** - Lightning ticketing system +- **[[02-modules/nostr-feed-module/index|Nostr Feed]]** - Social feed functionality + +### Technical Deep Dives +- **[[01-architecture/relay-hub|Relay Hub Architecture]]** - Centralized Nostr relay management +- **[[01-architecture/dependency-injection|Dependency Injection]]** - Service container patterns +- **[[03-core-services/visibility-service|Visibility Service]]** - Dynamic UI control + +## 🏷️ Documentation Tags + +Documents are tagged for easy navigation: +- `#architecture` - System design documents +- `#module` - Feature module documentation +- `#service` - Service layer documentation +- `#api` - External API references +- `#guide` - How-to guides +- `#reference` - Technical references +- `#deprecated` - Outdated documentation + +## 📝 Documentation Standards + +### File Naming +- Use kebab-case for all files: `module-name.md` +- Index files for directories: `index.md` +- Prefix with numbers for ordering: `01-architecture/` + +### Markdown Structure +```markdown +# Document Title + +> Brief description or important note + +## Overview +Introduction to the topic + +## Table of Contents +- [[#Section 1]] +- [[#Section 2]] + +## Section 1 +Content... + +## See Also +- [[related-document]] +- [[another-reference]] + +--- +**Tags:** #architecture #module +**Last Updated:** 2025-09-06 +**Author:** Development Team +``` + +### Cross-Linking +- Use `[[filename]]` for internal links (Obsidian-style) +- Use `[[filename#section]]` for section links +- Use `[[filename|Display Text]]` for custom link text + +## 🔄 Maintenance + +### Keeping Documentation Current +1. Update documentation with code changes +2. Review quarterly for accuracy +3. Move deprecated docs to `archive/` +4. Tag documents with last update date + +### Contributing +1. Follow the structure and standards above +2. Add appropriate tags to new documents +3. Update index files when adding new docs +4. Cross-link related documentation + +## 📊 Documentation Coverage + +| Module | Status | Coverage | +|--------|--------|----------| +| Base Module | ✅ Complete | 100% | +| Market Module | ✅ Complete | 100% | +| Chat Module | ✅ Complete | 100% | +| Events Module | ✅ Complete | 100% | +| Nostr Feed | ✅ Complete | 100% | +| Core Services | ✅ Complete | 100% | +| Development Guides | 🔄 In Progress | 80% | +| API Reference | 🔄 In Progress | 70% | + +--- + +**Welcome to the Ario Web App documentation!** Start with the [[00-overview/index|Overview]] to begin your journey. \ No newline at end of file diff --git a/ARCHITECTURE_ANALYSIS_PRINT.md b/docs/archive/ARCHITECTURE_ANALYSIS_PRINT.md similarity index 100% rename from ARCHITECTURE_ANALYSIS_PRINT.md rename to docs/archive/ARCHITECTURE_ANALYSIS_PRINT.md diff --git a/ARCHITECTURE_ANALYSIS.md b/docs/archive/legacy-architecture-analysis.md similarity index 100% rename from ARCHITECTURE_ANALYSIS.md rename to docs/archive/legacy-architecture-analysis.md diff --git a/NOSTR_ARCHITECTURE.md b/docs/archive/legacy-nostr-architecture.md similarity index 100% rename from NOSTR_ARCHITECTURE.md rename to docs/archive/legacy-nostr-architecture.md diff --git a/docs/modular-architecture-analysis.pdf b/docs/modular-architecture-analysis.pdf deleted file mode 100644 index 7b210d9c6306d6be4dd0dfb59aa075bc68163997..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74417 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