Add module development checklist and critical requirements to CLAUDE.md
- 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.
This commit is contained in:
parent
453bb53282
commit
c064b0b40d
1 changed files with 147 additions and 18 deletions
165
CLAUDE.md
165
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
|
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
|
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:**
|
**Required Module Structure:**
|
||||||
```
|
```
|
||||||
src/modules/[module-name]/
|
src/modules/[module-name]/
|
||||||
|
|
@ -357,58 +397,147 @@ src/modules/[module-name]/
|
||||||
```
|
```
|
||||||
|
|
||||||
**Service Implementation Pattern:**
|
**Service Implementation Pattern:**
|
||||||
|
|
||||||
|
**⚠️ CRITICAL SERVICE REQUIREMENTS - MUST FOLLOW EXACTLY:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Always extend BaseService for services
|
// ✅ CORRECT: Proper BaseService implementation
|
||||||
export class MyModuleService extends BaseService {
|
export class MyModuleService extends BaseService {
|
||||||
|
// 1. REQUIRED: Declare metadata with dependencies
|
||||||
protected readonly metadata = {
|
protected readonly metadata = {
|
||||||
name: 'MyModuleService',
|
name: 'MyModuleService',
|
||||||
version: '1.0.0',
|
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<void> {
|
protected async onInitialize(): Promise<void> {
|
||||||
// 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<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
|
// API services for LNbits integration
|
||||||
export class MyModuleAPI extends BaseService {
|
export class MyModuleAPI extends BaseService {
|
||||||
private baseUrl: string
|
private baseUrl: string
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
const config = appConfig.modules.myModule.config
|
// ❌ WRONG: Direct config import
|
||||||
this.baseUrl = config.apiConfig.baseUrl
|
// import { config } from '@/lib/config'
|
||||||
|
|
||||||
|
// ✅ CORRECT: Use module configuration
|
||||||
|
const moduleConfig = appConfig.modules.myModule.config
|
||||||
|
this.baseUrl = moduleConfig.apiConfig.baseUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
// API methods here
|
// 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:**
|
**Module Plugin Pattern:**
|
||||||
|
|
||||||
|
**⚠️ CRITICAL MODULE INSTALLATION REQUIREMENTS:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export const myModule: ModulePlugin = {
|
export const myModule: ModulePlugin = {
|
||||||
name: 'my-module',
|
name: 'my-module',
|
||||||
version: '1.0.0',
|
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 }) {
|
async install(app: App, options?: { config?: MyModuleConfig }) {
|
||||||
// 1. Create service instances
|
// 1. REQUIRED: Create service instances
|
||||||
const myService = new MyModuleService()
|
const myService = new MyModuleService()
|
||||||
const myAPI = new MyModuleAPI()
|
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_SERVICE, myService)
|
||||||
container.provide(SERVICE_TOKENS.MY_API, myAPI)
|
container.provide(SERVICE_TOKENS.MY_API, myAPI)
|
||||||
|
|
||||||
// 3. Initialize services
|
// 3. CRITICAL: Initialize services with proper options
|
||||||
await myService.initialize({
|
await myService.initialize({
|
||||||
waitForDependencies: true,
|
waitForDependencies: true, // REQUIRED: Wait for dependencies
|
||||||
maxRetries: 3
|
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)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue