- Introduced a comprehensive module development checklist to ensure consistency and quality in module implementation. - Added critical service and module installation requirements, emphasizing proper service initialization, dependency management, and configuration usage. - Included common mistakes to avoid during module development to guide developers in best practices. These updates enhance the documentation for module development, promoting better adherence to standards and improving overall code quality.
600 lines
No EOL
21 KiB
Markdown
600 lines
No EOL
21 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Development Commands
|
|
|
|
**Development**
|
|
- `npm run dev` - Start development server with Vite (includes --host flag)
|
|
- `npm run build` - Build for production (includes TypeScript check with vue-tsc -b)
|
|
- `npm run preview` - Preview production build locally
|
|
- `npm run analyze` - Build with bundle analysis (opens visualization)
|
|
|
|
**Electron Development**
|
|
- `npm run electron:dev` - Run both Vite dev server and Electron concurrently
|
|
- `npm run electron:build` - Full build and package for Electron
|
|
- `npm run start` - Start Electron using Forge
|
|
- `npm run package` - Package Electron app with Forge
|
|
- `npm run make` - Create distributables with Electron Forge
|
|
|
|
## Architecture Overview
|
|
|
|
This is a modular Vue 3 + TypeScript + Vite application with Electron support, featuring a Nostr protocol client and Lightning Network integration for events/ticketing.
|
|
|
|
### **Modular Architecture**
|
|
|
|
The application uses a plugin-based modular architecture with dependency injection for service management:
|
|
|
|
**Core Modules:**
|
|
- **Base Module** (`src/modules/base/`) - Core infrastructure (Nostr, Auth, PWA)
|
|
- **Nostr Feed Module** (`src/modules/nostr-feed/`) - Social feed functionality
|
|
- **Chat Module** (`src/modules/chat/`) - Encrypted Nostr chat
|
|
- **Events Module** (`src/modules/events/`) - Event ticketing with Lightning payments
|
|
- **Market Module** (`src/modules/market/`) - Nostr marketplace functionality
|
|
|
|
**Module Configuration:**
|
|
- Modules are configured in `src/app.config.ts`
|
|
- Each module can be enabled/disabled and configured independently
|
|
- Modules have dependencies (e.g., all modules depend on 'base')
|
|
|
|
**Plugin Manager:**
|
|
- `src/core/plugin-manager.ts` handles module lifecycle
|
|
- Registers, installs, and manages module dependencies
|
|
- Handles route registration from modules
|
|
|
|
### **Dependency Injection Pattern**
|
|
|
|
**CRITICAL**: Always use the dependency injection pattern for accessing shared services:
|
|
|
|
**Service Registration (Base Module):**
|
|
```typescript
|
|
// src/modules/base/index.ts
|
|
import { container, SERVICE_TOKENS } from '@/core/di-container'
|
|
|
|
container.provide(SERVICE_TOKENS.RELAY_HUB, relayHub)
|
|
container.provide(SERVICE_TOKENS.AUTH_SERVICE, auth)
|
|
```
|
|
|
|
**Service Consumption (Other Modules):**
|
|
```typescript
|
|
// In any module's composables or services
|
|
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
|
|
|
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
|
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
|
```
|
|
|
|
**❌ NEVER do this:**
|
|
```typescript
|
|
// DON'T import services directly - breaks modular architecture
|
|
import { relayHubComposable } from '@/composables/useRelayHub'
|
|
```
|
|
|
|
**✅ Always do this:**
|
|
```typescript
|
|
// DO use dependency injection for loose coupling
|
|
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
|
```
|
|
|
|
**Available Services:**
|
|
- `SERVICE_TOKENS.RELAY_HUB` - Centralized Nostr relay management
|
|
- `SERVICE_TOKENS.AUTH_SERVICE` - Authentication services
|
|
- `SERVICE_TOKENS.VISIBILITY_SERVICE` - App visibility and connection management
|
|
|
|
**Core Stack:**
|
|
- Vue 3 with Composition API (`<script setup>` style)
|
|
- TypeScript throughout
|
|
- Vite build system with PWA support
|
|
- Electron for desktop app packaging
|
|
- Pinia for state management
|
|
- Vue Router for navigation
|
|
- TailwindCSS v4 with Shadcn/ui components
|
|
- Vue-i18n for internationalization
|
|
|
|
**Key Features:**
|
|
- Nostr protocol client for decentralized social networking
|
|
- Lightning Network integration for event ticketing
|
|
- PWA capabilities with service worker
|
|
- Theme switching and language switching
|
|
- Real-time connection status monitoring
|
|
|
|
**Directory Structure:**
|
|
- `src/components/` - Vue components organized by feature
|
|
- `ui/` - Shadcn/ui component library
|
|
- `nostr/` - Nostr-specific components
|
|
- `events/` - Event/ticketing components
|
|
- `layout/` - App layout components
|
|
- `src/composables/` - Vue composables for reusable logic
|
|
- `src/stores/` - Pinia stores for state management
|
|
- `src/lib/` - Core business logic
|
|
- `nostr/` - Nostr client implementation
|
|
- `api/` - API integrations
|
|
- `types/` - TypeScript type definitions
|
|
- `src/pages/` - Route pages
|
|
- `electron/` - Electron main process code
|
|
|
|
**Nostr Integration:**
|
|
The app connects to Nostr relays using a custom NostrClient class built on nostr-tools. Key files:
|
|
- `src/lib/nostr/client.ts` - Core Nostr client implementation
|
|
- `src/composables/useNostr.ts` - Vue composable for Nostr connection management
|
|
- `src/stores/nostr.ts` - Pinia store for Nostr state
|
|
|
|
## Development Guidelines
|
|
|
|
### **Modular Architecture Patterns**
|
|
|
|
**Module Structure:**
|
|
```
|
|
src/modules/[module-name]/
|
|
├── index.ts # Module plugin definition
|
|
├── components/ # Module-specific components
|
|
├── composables/ # Module composables
|
|
├── services/ # Module services
|
|
├── stores/ # Module-specific stores
|
|
├── types/ # Module type definitions
|
|
└── views/ # Module pages/views
|
|
```
|
|
|
|
**Module Plugin Pattern:**
|
|
```typescript
|
|
export const myModule: ModulePlugin = {
|
|
name: 'my-module',
|
|
version: '1.0.0',
|
|
dependencies: ['base'], // Always depend on base for core services
|
|
|
|
async install(app: App, options?: { config?: MyModuleConfig }) {
|
|
// Module installation logic
|
|
// Register components, initialize services, etc.
|
|
},
|
|
|
|
routes: [/* module routes */],
|
|
components: {/* exported components */},
|
|
composables: {/* exported composables */}
|
|
}
|
|
```
|
|
|
|
**Service Integration:**
|
|
- All modules MUST use dependency injection for shared services
|
|
- NEVER import services directly across module boundaries
|
|
- Base module provides core infrastructure services
|
|
- Modules can register their own services in the DI container
|
|
|
|
**⚠️ CRITICAL - WebSocket Connection Management:**
|
|
- **ALWAYS integrate with VisibilityService for any module that uses WebSocket connections**
|
|
- All services extending `BaseService` have automatic access to `this.visibilityService`
|
|
- Register visibility callbacks during service initialization: `this.visibilityService.registerService(name, onResume, onPause)`
|
|
- Implement proper connection recovery in `onResume()` handler (check health, reconnect if needed, restore subscriptions)
|
|
- Implement battery-conscious pausing in `onPause()` handler (stop heartbeats, queue operations)
|
|
- **Mobile browsers suspend WebSocket connections when app loses visibility** - visibility management is essential for reliable real-time features
|
|
- See `docs/VisibilityService.md` and `docs/VisibilityService-Integration.md` for comprehensive integration guides
|
|
- Future modules will likely ALL depend on WebSocket connections - plan for visibility management from the start
|
|
|
|
### **Centralized Infrastructure**
|
|
|
|
**Nostr Relay Management:**
|
|
- Single RelayHub manages all Nostr connections
|
|
- All modules use the same relay configuration from `VITE_NOSTR_RELAYS`
|
|
- No module should create separate relay connections
|
|
|
|
**Authentication:**
|
|
- Centralized auth service handles all authentication
|
|
- Modules access auth state through dependency injection
|
|
- Router guards use the shared auth service
|
|
|
|
**Configuration:**
|
|
- Environment variables prefixed with `VITE_`
|
|
- Module configs in `src/app.config.ts`
|
|
- Centralized config parsing and validation
|
|
|
|
### **Form Implementation Standards**
|
|
|
|
**CRITICAL: Always use Shadcn/UI Form Components with vee-validate**
|
|
|
|
All forms in the application MUST follow the official Shadcn Vue form implementation pattern:
|
|
|
|
**Required Form Setup:**
|
|
```typescript
|
|
import { useForm } from 'vee-validate'
|
|
import { toTypedSchema } from '@vee-validate/zod'
|
|
import * as z from 'zod'
|
|
import {
|
|
FormControl,
|
|
FormDescription,
|
|
FormField,
|
|
FormItem,
|
|
FormLabel,
|
|
FormMessage,
|
|
} from '@/components/ui/form'
|
|
|
|
// 1. Define Zod schema for validation
|
|
const formSchema = toTypedSchema(z.object({
|
|
name: z.string().min(1, "Name is required").max(100, "Name too long"),
|
|
email: z.string().email("Invalid email address").optional(),
|
|
items: z.array(z.string()).min(1, "Select at least one item"),
|
|
}))
|
|
|
|
// 2. Set up form with vee-validate
|
|
const form = useForm({
|
|
validationSchema: formSchema,
|
|
initialValues: {
|
|
name: '',
|
|
email: '',
|
|
items: []
|
|
}
|
|
})
|
|
|
|
// 3. Destructure form methods
|
|
const { setFieldValue, resetForm, values, meta } = form
|
|
|
|
// 4. Create form validation computed
|
|
const isFormValid = computed(() => meta.value.valid)
|
|
|
|
// 5. Create submit handler with form.handleSubmit
|
|
const onSubmit = form.handleSubmit(async (values) => {
|
|
console.log('Form submitted:', values)
|
|
// Handle form submission logic
|
|
})
|
|
```
|
|
|
|
**Required Form Template Structure:**
|
|
```vue
|
|
<template>
|
|
<!-- form.handleSubmit automatically prevents default submission -->
|
|
<form @submit="onSubmit" class="space-y-6">
|
|
<!-- Text Input Field -->
|
|
<FormField v-slot="{ componentField }" name="name">
|
|
<FormItem>
|
|
<FormLabel>Name *</FormLabel>
|
|
<FormControl>
|
|
<Input
|
|
placeholder="Enter name"
|
|
v-bind="componentField"
|
|
/>
|
|
</FormControl>
|
|
<FormDescription>Enter your full name</FormDescription>
|
|
<FormMessage />
|
|
</FormItem>
|
|
</FormField>
|
|
|
|
<!-- Multiple Checkbox Selection -->
|
|
<FormField name="items">
|
|
<FormItem>
|
|
<div class="mb-4">
|
|
<FormLabel class="text-base">Items *</FormLabel>
|
|
<FormDescription>Select one or more items</FormDescription>
|
|
</div>
|
|
<div v-for="item in availableItems" :key="item.id">
|
|
<FormField
|
|
v-slot="{ value, handleChange }"
|
|
type="checkbox"
|
|
:value="item.id"
|
|
:unchecked-value="false"
|
|
name="items"
|
|
>
|
|
<FormItem class="flex flex-row items-start space-x-3 space-y-0">
|
|
<FormControl>
|
|
<Checkbox
|
|
:model-value="value.includes(item.id)"
|
|
@update:model-value="handleChange"
|
|
/>
|
|
</FormControl>
|
|
<FormLabel class="font-normal">{{ item.name }}</FormLabel>
|
|
</FormItem>
|
|
</FormField>
|
|
</div>
|
|
<FormMessage />
|
|
</FormItem>
|
|
</FormField>
|
|
|
|
<!-- Submit Button -->
|
|
<Button
|
|
type="submit"
|
|
:disabled="isLoading || !isFormValid"
|
|
>
|
|
{{ isLoading ? 'Submitting...' : 'Submit' }}
|
|
</Button>
|
|
</form>
|
|
</template>
|
|
```
|
|
|
|
**Key Form Requirements:**
|
|
- ✅ **Form validation**: Use `@submit="onSubmit"` - form.handleSubmit automatically prevents page refresh
|
|
- ✅ **Button state**: Disable submit button with `!isFormValid` until all required fields are valid
|
|
- ✅ **Error display**: Use `<FormMessage />` for automatic error display
|
|
- ✅ **Field binding**: Use `v-bind="componentField"` for proper form field integration
|
|
- ✅ **Checkbox arrays**: Use nested FormField pattern for multiple checkbox selection
|
|
- ✅ **Type safety**: Zod schema provides full TypeScript type safety
|
|
|
|
**❌ NEVER do this:**
|
|
```vue
|
|
<!-- Wrong: Manual form handling without vee-validate -->
|
|
<form @submit.prevent="handleSubmit">
|
|
|
|
<!-- Wrong: Direct v-model bypasses form validation -->
|
|
<Input v-model="myValue" />
|
|
|
|
<!-- Wrong: Manual validation instead of using meta.valid -->
|
|
<Button :disabled="!name || !email">Submit</Button>
|
|
```
|
|
|
|
**✅ ALWAYS do this:**
|
|
```vue
|
|
<!-- Correct: Uses form.handleSubmit for proper form handling -->
|
|
<form @submit="onSubmit">
|
|
|
|
<!-- Correct: Uses FormField with componentField binding -->
|
|
<FormField v-slot="{ componentField }" name="fieldName">
|
|
<FormControl>
|
|
<Input v-bind="componentField" />
|
|
</FormControl>
|
|
</FormField>
|
|
|
|
<!-- Correct: Uses form meta for validation state -->
|
|
<Button :disabled="!isFormValid">Submit</Button>
|
|
```
|
|
|
|
### **Module Development Best Practices**
|
|
|
|
**Module Structure Requirements:**
|
|
1. **Independence**: Modules must be independent of each other - no direct imports between modules
|
|
2. **Base Dependency**: All modules should depend on 'base' module for core infrastructure
|
|
3. **Service Pattern**: All services should extend `BaseService` for standardized initialization
|
|
4. **API Isolation**: Module-specific API calls must be in the module's services folder
|
|
5. **Dependency Injection**: Cross-module communication only through DI container
|
|
|
|
### **📋 MODULE DEVELOPMENT CHECKLIST**
|
|
|
|
Before considering any module complete, verify ALL items:
|
|
|
|
**Service Implementation:**
|
|
- [ ] Service extends `BaseService`
|
|
- [ ] Has `metadata` with `name`, `version`, `dependencies`
|
|
- [ ] Dependencies listed in metadata match actual usage
|
|
- [ ] No manual `injectService()` calls in `onInitialize()`
|
|
- [ ] Registers with VisibilityService if has real-time features
|
|
- [ ] Implements `onResume()` and `onPause()` if using VisibilityService
|
|
- [ ] Uses module config, not direct config imports
|
|
|
|
**Module Plugin:**
|
|
- [ ] Depends on `'base'` module
|
|
- [ ] Creates service instances
|
|
- [ ] Registers services in DI container BEFORE initialization
|
|
- [ ] Calls `service.initialize()` with `waitForDependencies: true`
|
|
- [ ] Registers components AFTER service initialization
|
|
|
|
**Configuration:**
|
|
- [ ] Module added to `app.config.ts`
|
|
- [ ] Has `enabled` flag
|
|
- [ ] Has `config` object with necessary settings
|
|
- [ ] Uses `appConfig.modules.[moduleName].config` in services
|
|
|
|
**Forms (if applicable):**
|
|
- [ ] Uses Shadcn/UI form components
|
|
- [ ] Uses vee-validate with Zod schema
|
|
- [ ] Has proper validation messages
|
|
- [ ] Disables submit button until form is valid
|
|
- [ ] Uses `form.handleSubmit()` for submission
|
|
|
|
**Testing Checklist:**
|
|
- [ ] Service initializes without errors
|
|
- [ ] Dependencies are properly injected
|
|
- [ ] VisibilityService callbacks work (test by switching tabs)
|
|
- [ ] Configuration is properly loaded
|
|
- [ ] Module can be disabled via config
|
|
|
|
**Required Module Structure:**
|
|
```
|
|
src/modules/[module-name]/
|
|
├── index.ts # Module plugin definition (REQUIRED)
|
|
├── components/ # Module-specific components
|
|
├── composables/ # Module composables (use DI for services)
|
|
├── services/ # Module services (extend BaseService)
|
|
│ ├── [module]Service.ts # Core module service
|
|
│ └── [module]API.ts # LNbits API integration
|
|
├── stores/ # Module-specific Pinia stores
|
|
├── types/ # Module type definitions
|
|
└── views/ # Module pages/views
|
|
```
|
|
|
|
**Service Implementation Pattern:**
|
|
|
|
**⚠️ CRITICAL SERVICE REQUIREMENTS - MUST FOLLOW EXACTLY:**
|
|
|
|
```typescript
|
|
// ✅ CORRECT: Proper BaseService implementation
|
|
export class MyModuleService extends BaseService {
|
|
// 1. REQUIRED: Declare metadata with dependencies
|
|
protected readonly metadata = {
|
|
name: 'MyModuleService',
|
|
version: '1.0.0',
|
|
dependencies: ['PaymentService', 'AuthService'] // List ALL service dependencies by name
|
|
}
|
|
|
|
// 2. REQUIRED: DO NOT manually inject services in onInitialize
|
|
protected async onInitialize(): Promise<void> {
|
|
// ❌ WRONG: Manual injection
|
|
// this.paymentService = injectService(SERVICE_TOKENS.PAYMENT_SERVICE)
|
|
|
|
// ✅ CORRECT: BaseService auto-injects based on metadata.dependencies
|
|
// this.paymentService is already available here!
|
|
|
|
// 3. REQUIRED: Register with VisibilityService if you have ANY real-time features
|
|
if (this.hasRealTimeFeatures()) {
|
|
this.visibilityService.registerService(
|
|
this.metadata.name,
|
|
this.onResume.bind(this),
|
|
this.onPause.bind(this)
|
|
)
|
|
}
|
|
|
|
// 4. Initialize your module-specific logic
|
|
await this.loadInitialData()
|
|
}
|
|
|
|
// 5. REQUIRED: Implement visibility handlers for connection management
|
|
private async onResume(): Promise<void> {
|
|
// Restore connections, refresh data when app becomes visible
|
|
await this.checkConnectionHealth()
|
|
await this.refreshData()
|
|
}
|
|
|
|
private async onPause(): Promise<void> {
|
|
// Pause expensive operations for battery efficiency
|
|
this.pausePolling()
|
|
}
|
|
|
|
private hasRealTimeFeatures(): boolean {
|
|
// Return true if your service uses WebSockets, polling, or real-time updates
|
|
return true
|
|
}
|
|
}
|
|
|
|
// API services for LNbits integration
|
|
export class MyModuleAPI extends BaseService {
|
|
private baseUrl: string
|
|
|
|
constructor() {
|
|
super()
|
|
// ❌ WRONG: Direct config import
|
|
// import { config } from '@/lib/config'
|
|
|
|
// ✅ CORRECT: Use module configuration
|
|
const moduleConfig = appConfig.modules.myModule.config
|
|
this.baseUrl = moduleConfig.apiConfig.baseUrl
|
|
}
|
|
|
|
// API methods here
|
|
}
|
|
```
|
|
|
|
**❌ COMMON MISTAKES TO AVOID:**
|
|
1. **Manual service injection** in onInitialize - BaseService handles this
|
|
2. **Direct config imports** - Always use module configuration
|
|
3. **Missing metadata.dependencies** - Breaks automatic dependency injection
|
|
4. **No VisibilityService integration** - Causes connection issues on mobile
|
|
5. **Not using proper initialization options** - Miss dependency waiting
|
|
|
|
**Module Plugin Pattern:**
|
|
|
|
**⚠️ CRITICAL MODULE INSTALLATION REQUIREMENTS:**
|
|
|
|
```typescript
|
|
export const myModule: ModulePlugin = {
|
|
name: 'my-module',
|
|
version: '1.0.0',
|
|
dependencies: ['base'], // ALWAYS depend on 'base' for core infrastructure
|
|
|
|
async install(app: App, options?: { config?: MyModuleConfig }) {
|
|
// 1. REQUIRED: Create service instances
|
|
const myService = new MyModuleService()
|
|
const myAPI = new MyModuleAPI()
|
|
|
|
// 2. REQUIRED: Register in DI container BEFORE initialization
|
|
container.provide(SERVICE_TOKENS.MY_SERVICE, myService)
|
|
container.provide(SERVICE_TOKENS.MY_API, myAPI)
|
|
|
|
// 3. CRITICAL: Initialize services with proper options
|
|
await myService.initialize({
|
|
waitForDependencies: true, // REQUIRED: Wait for dependencies
|
|
maxRetries: 3, // RECOMMENDED: Retry on failure
|
|
timeout: 5000 // OPTIONAL: Timeout for initialization
|
|
})
|
|
|
|
// Initialize API service if it needs initialization
|
|
if (myAPI.initialize) {
|
|
await myAPI.initialize({
|
|
waitForDependencies: true,
|
|
maxRetries: 3
|
|
})
|
|
}
|
|
|
|
// 4. Register components AFTER services are initialized
|
|
app.component('MyComponent', MyComponent)
|
|
|
|
// 5. OPTIONAL: Export for testing/debugging
|
|
return {
|
|
service: myService,
|
|
api: myAPI
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**MODULE CONFIGURATION IN app.config.ts:**
|
|
```typescript
|
|
// REQUIRED: Add module configuration
|
|
export default {
|
|
modules: {
|
|
'my-module': {
|
|
enabled: true,
|
|
config: {
|
|
apiConfig: {
|
|
baseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000'
|
|
},
|
|
// Module-specific configuration
|
|
features: {
|
|
realTimeUpdates: true,
|
|
offlineSupport: false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Nostr Integration Rules:**
|
|
1. **NEVER create separate relay connections** - always use the central RelayHub
|
|
2. **Access RelayHub through DI**: `const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)`
|
|
3. **Use RelayHub methods** for all Nostr operations (subscribe, publish, etc.)
|
|
4. **Event kinds** should be module-specific and follow NIP specifications
|
|
|
|
**LNbits API Integration:**
|
|
1. **Create module-specific API service** in `services/[module]API.ts`
|
|
2. **Extend BaseService** for automatic dependency management
|
|
3. **Use authentication headers**: `X-Api-Key: walletKey`
|
|
4. **Base URL from config**: Use `appConfig.modules.[module].config.apiConfig.baseUrl`
|
|
5. **Error handling**: Implement proper error handling with user feedback
|
|
|
|
**Composables Best Practices:**
|
|
```typescript
|
|
export function useMyModule() {
|
|
// Always use DI for services
|
|
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
|
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
|
const myAPI = injectService(SERVICE_TOKENS.MY_API)
|
|
|
|
// Never import services directly
|
|
// ❌ import { relayHub } from '@/modules/base/nostr/relay-hub'
|
|
// ✅ const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
|
}
|
|
```
|
|
|
|
**WebSocket & Visibility Management:**
|
|
- Services with WebSocket connections MUST integrate with VisibilityService
|
|
- Register visibility callbacks: `this.visibilityService.registerService(name, onResume, onPause)`
|
|
- Handle connection recovery in `onResume()` callback
|
|
- Implement battery-conscious pausing in `onPause()` callback
|
|
|
|
### **Code Conventions:**
|
|
- Use TypeScript interfaces over types for extendability
|
|
- Prefer functional and declarative patterns over classes (except for services)
|
|
- Use Vue Composition API with `<script setup>` syntax
|
|
- Follow naming convention: lowercase-with-dashes for directories
|
|
- Leverage VueUse functions for enhanced reactivity
|
|
- Implement lazy loading for non-critical components
|
|
- Optimize images using WebP format with lazy loading
|
|
- **ALWAYS use dependency injection for cross-module service access**
|
|
- **ALWAYS use Shadcn Form components for all form implementations**
|
|
- **ALWAYS extend BaseService for module services**
|
|
- **NEVER create direct dependencies between modules**
|
|
|
|
**Build Configuration:**
|
|
- Vite config includes PWA, image optimization, and bundle analysis
|
|
- Manual chunking strategy for vendor libraries (vue-vendor, ui-vendor, shadcn)
|
|
- Electron Forge configured for cross-platform packaging
|
|
- TailwindCSS v4 integration via Vite plugin
|
|
|
|
**Environment:**
|
|
- Nostr relay configuration via `VITE_NOSTR_RELAYS` environment variable
|
|
- PWA manifest configured for standalone app experience
|
|
- Service worker with automatic updates every hour |