diff --git a/CLAUDE.md b/CLAUDE.md index 9d106b1..185930d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -342,6 +342,46 @@ const onSubmit = form.handleSubmit(async (values) => { 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]/ @@ -357,58 +397,147 @@ src/modules/[module-name]/ ``` **Service Implementation Pattern:** + +**⚠️ CRITICAL SERVICE REQUIREMENTS - MUST FOLLOW EXACTLY:** + ```typescript -// Always extend BaseService for services +// ✅ 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: [] // List service dependencies + dependencies: ['PaymentService', 'AuthService'] // List ALL service dependencies by name } + // 2. REQUIRED: DO NOT manually inject services in onInitialize protected async onInitialize(): Promise { - // Service-specific initialization + // ❌ 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 { + // Restore connections, refresh data when app becomes visible + await this.checkConnectionHealth() + await this.refreshData() + } + + private async onPause(): Promise { + // 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() - const config = appConfig.modules.myModule.config - this.baseUrl = config.apiConfig.baseUrl + // ❌ 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 - + dependencies: ['base'], // ALWAYS depend on 'base' for core infrastructure + async install(app: App, options?: { config?: MyModuleConfig }) { - // 1. Create service instances + // 1. REQUIRED: Create service instances const myService = new MyModuleService() const myAPI = new MyModuleAPI() - - // 2. Register in DI container + + // 2. REQUIRED: Register in DI container BEFORE initialization container.provide(SERVICE_TOKENS.MY_SERVICE, myService) container.provide(SERVICE_TOKENS.MY_API, myAPI) - - // 3. Initialize services + + // 3. CRITICAL: Initialize services with proper options await myService.initialize({ - waitForDependencies: true, - maxRetries: 3 + waitForDependencies: true, // REQUIRED: Wait for dependencies + maxRetries: 3, // RECOMMENDED: Retry on failure + timeout: 5000 // OPTIONAL: Timeout for initialization }) - - // 4. Register components if needed + + // 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 + } + } + } } } ```