- 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>
14 KiB
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
- #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
# 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
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
# 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
- setup - Detailed setup instructions
- coding-standards - Comprehensive style guide
- testing - Testing frameworks and patterns
- debugging - Advanced debugging strategies
Architecture References
- ../02-modules/index - Plugin-based architecture
- ../03-core-services/index - Service development patterns
- ../01-architecture/dependency-injection - DI container usage
Tags: #development #workflow #standards #testing #debugging
Last Updated: 2025-09-06
Author: Development Team