web-app/docs/04-development/index.md
padreug cdf099e45f 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>
2025-09-06 14:31:27 +02:00

14 KiB

💻 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

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

# 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

# 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

  • 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

# 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

# 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

# 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

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

# 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

// ✅ 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

// ✅ 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

<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

<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

// ✅ 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

// ✅ 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

// ✅ 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

// ✅ 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

// 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

// 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

# Development server (with HMR)
npm run dev

# Development build (for debugging)
npm run build:dev

Production Builds

# Full production build
npm run build

# Preview production build locally
npm run preview

# Bundle analysis
npm run analyze

Electron Builds

# 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

// 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

// 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

// 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

# 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

// ❌ Incorrect relative import
import { MyService } from '../../services/MyService'

// ✅ Use absolute imports with @ alias
import { MyService } from '@/services/MyService'

Dependency Injection Issues

// ❌ 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

Architecture References


Tags: #development #workflow #standards #testing #debugging
Last Updated: 2025-09-06
Author: Development Team