Guide for developing new features in the DEVS platform following the modular feature architecture. Use this when asked to add a new feature, create a feature module, or understand the feature structure.
Features in DEVS are self-contained modules that encapsulate related functionality. Each feature has its own components, hooks, stores, and logic.
src/features/{feature-name}/
├── index.ts # Public exports
├── components/ # Feature-specific components
│ ├── FeatureComponent.tsx
│ └── index.ts
├── hooks/ # Feature-specific hooks
│ ├── useFeatureHook.ts
│ └── index.ts
├── stores/ # Feature-specific stores (if needed)
│ └── featureStore.ts
├── lib/ # Feature-specific utilities
│ └── feature-utils.ts
├── types/ # Feature-specific types
│ └── index.ts
└── README.md # Feature documentation
| Feature | Directory | Description |
| ------------ | ---------------------------- | ----------------------------------- |
| Connectors | src/features/connectors/ | OAuth integrations (Google, Notion) |
| Live | src/features/live/ | Real-time collaboration |
| Sync | src/features/sync/ | P2P data synchronization via Yjs |
| Traces | src/features/traces/ | LLM observability and analytics |
| Local Backup | src/features/local-backup/ | File system sync |
mkdir -p src/features/my-feature/{components,hooks,lib,types}
// src/features/my-feature/types/index.ts
export interface MyFeatureConfig {
enabled: boolean
option1: string
option2: number
}
export interface MyFeatureState {
isActive: boolean
data: MyFeatureData[]
}
export interface MyFeatureData {
id: string
name: string
createdAt: Date
}
// src/features/my-feature/stores/myFeatureStore.ts
import { create } from 'zustand'
import type { MyFeatureState, MyFeatureData } from '../types'
interface MyFeatureActions {
initialize: () => Promise<void>
addData: (data: MyFeatureData) => void
clear: () => void
}
export const useMyFeatureStore = create<MyFeatureState & MyFeatureActions>(
(set) => ({
isActive: false,
data: [],
initialize: async () => {
// Initialize feature
set({ isActive: true })
},
addData: (data) => {
set((state) => ({ data: [...state.data, data] }))
},
clear: () => {
set({ data: [], isActive: false })
},
}),
)
// src/features/my-feature/components/MyFeaturePanel.tsx
import { Card, CardBody, Button } from '@heroui/react'
import { useTranslation } from 'react-i18next'
import { useMyFeatureStore } from '../stores/myFeatureStore'
export function MyFeaturePanel() {
const { t } = useTranslation()
const { isActive, data, initialize } = useMyFeatureStore()
if (!isActive) {
return (
<Card>
<CardBody>
<Button onPress={initialize}>
{t('myFeature.activate')}
</Button>
</CardBody>
</Card>
)
}
return (
<Card>
<CardBody>
<h2>{t('myFeature.title')}</h2>
{data.map((item) => (
<div key={item.id}>{item.name}</div>
))}
</CardBody>
</Card>
)
}
// src/features/my-feature/hooks/useMyFeature.ts
import { useCallback, useEffect } from 'react'
import { useMyFeatureStore } from '../stores/myFeatureStore'
export function useMyFeature() {
const store = useMyFeatureStore()
useEffect(() => {
// Setup on mount
return () => {
// Cleanup on unmount
}
}, [])
const handleAction = useCallback(async () => {
// Feature-specific logic
}, [])
return {
...store,
handleAction,
}
}
// src/features/my-feature/index.ts
export { MyFeaturePanel } from './components/MyFeaturePanel'
export { useMyFeature } from './hooks/useMyFeature'
export { useMyFeatureStore } from './stores/myFeatureStore'
export type { MyFeatureConfig, MyFeatureState, MyFeatureData } from './types'
<!-- src/features/my-feature/README.md -->
# My Feature
Brief description of what this feature does.
## Usage
\`\`\`tsx
import { MyFeaturePanel, useMyFeature } from '@/features/my-feature'
function App() {
const { isActive, handleAction } = useMyFeature()
return <MyFeaturePanel />
}
\`\`\`
## Configuration
Describe configuration options...
## API Reference
### Components
- `MyFeaturePanel` - Main UI component
### Hooks
- `useMyFeature()` - Primary hook for feature functionality
### Store
- `useMyFeatureStore` - Zustand store for feature state
// In relevant page or layout
import { MyFeaturePanel } from '@/features/my-feature'
function MyPage() {
return (
<div>
<MyFeaturePanel />
</div>
)
}
For features that need to be toggleable:
// src/features/my-feature/lib/feature-flags.ts
export function isMyFeatureEnabled(): boolean {
// Check user settings, environment, etc.
return localStorage.getItem('myFeature.enabled') === 'true'
}
// Add to src/i18n/locales/en.ts
export default {
// ... existing translations
myFeature: {
title: 'My Feature',
activate: 'Activate Feature',
description: 'Feature description',
},
}
// src/test/features/my-feature/MyFeaturePanel.test.tsx
import { render, screen } from '@testing-library/react'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { MyFeaturePanel } from '@/features/my-feature'
import { useMyFeatureStore } from '@/features/my-feature/stores/myFeatureStore'
vi.mock('react-i18next', () => ({
useTranslation: () => ({ t: (key: string) => key }),
}))
describe('MyFeaturePanel', () => {
beforeEach(() => {
useMyFeatureStore.setState({ isActive: false, data: [] })
})
it('shows activate button when inactive', () => {
render(<MyFeaturePanel />)
expect(screen.getByText('myFeature.activate')).toBeInTheDocument()
})
it('shows data when active', () => {
useMyFeatureStore.setState({
isActive: true,
data: [{ id: '1', name: 'Test', createdAt: new Date() }],
})
render(<MyFeaturePanel />)
expect(screen.getByText('Test')).toBeInTheDocument()
})
})
index.tsnpx skills add codename-co/feature-development下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer