feature-module-architect
1
总安装量
1
周安装量
#51092
全站排名
安装命令
npx skills add https://github.com/d-oit/do-novelist-ai --skill feature-module-architect
Agent 安装分布
opencode
1
cursor
1
Skill 文档
Feature Module Architect
Quick Start
This skill scaffolds feature modules following project architecture:
- Feature structure: Standard directory layout with components, hooks, services, types, utils
- File size limit: 500 LOC maximum per file (hard limit)
- Colocation: Keep related code together within feature directory
- Public API: Export only what other features need via
index.ts
When to Use
- Creating new feature modules
- Refactoring files exceeding 500 LOC
- Organizing scattered feature code
- Need feature architecture guidance
Standard Feature Structure
src/features/{feature-name}/
âââ components/ # React components for this feature
â âââ FeatureComponent.tsx
â âââ FeatureComponent.test.tsx
â âââ index.ts
âââ hooks/ # Custom React hooks
â âââ useFeatureData.ts
â âââ useFeatureData.test.ts
â âââ index.ts
âââ services/ # Business logic and API calls
â âââ featureService.ts
â âââ featureService.test.ts
â âââ index.ts
âââ types/ # TypeScript interfaces and types
â âââ feature.types.ts
â âââ index.ts
âââ utils/ # Pure utility functions
â âââ featureUtils.ts
â âââ featureUtils.test.ts
â âââ index.ts
âââ index.ts # Public API (exports for other features)
Existing Feature Examples
AI Generation (src/features/ai-generation/):
- Components: GenerationForm, GenerationHistory
- Hooks: useGeneration, useAIProvider
- Services: generationService, aiGatewayClient
- Types: GenerationRequest, GenerationResponse
Project Management (src/features/project-management/):
- Components: ProjectCard, ProjectList, ProjectForm
- Hooks: useProjects, useProjectMutations
- Services: projectService
- Types: Project, ProjectMetadata
World Building (src/features/world-building/):
- Components: WorldMap, LocationEditor
- Hooks: useWorldState
- Services: worldService
- Types: WorldElement, Location
File Size Enforcement
Hard Limit: 500 LOC per file (from AGENTS.md)
Check file sizes:
# Count lines in all TypeScript files
wc -l src/features/**/*.ts src/features/**/*.tsx
# Find files exceeding 500 LOC
find src/features -name "*.ts" -o -name "*.tsx" | xargs wc -l | awk '$1 > 500'
Refactoring Strategy
When a file exceeds 500 LOC, split by responsibility:
Before (600 LOC component):
// ProjectDashboard.tsx (600 LOC) â
export const ProjectDashboard: React.FC = () => {
// 100 LOC of state/hooks
// 200 LOC of handlers
// 300 LOC of JSX
};
After (split into 3 files, each <200 LOC):
// useProjectDashboard.ts (100 LOC)
export function useProjectDashboard() {
// State and effects
}
// projectDashboardHandlers.ts (100 LOC)
export function createHandlers(projects: Project[]) {
// Event handlers
}
// ProjectDashboard.tsx (150 LOC)
export const ProjectDashboard: React.FC = () => {
const state = useProjectDashboard();
const handlers = createHandlers(state.projects);
return <div>{/* JSX */}</div>;
};
Colocation Principle
Keep related code together:
â Good – Feature-specific code within feature:
src/features/ai-generation/
âââ components/GenerationForm.tsx
âââ hooks/useGeneration.ts # Only used by GenerationForm
âââ types/generation.types.ts # Only used by this feature
â Bad – Scattered across global directories:
src/
âââ components/GenerationForm.tsx
âââ hooks/useGeneration.ts # Generic hooks directory
âââ types/generation.types.ts # Generic types directory
Public API Pattern
Each feature exports a public API via index.ts:
// src/features/ai-generation/index.ts
export { GenerationForm } from './components/GenerationForm';
export { useGeneration } from './hooks/useGeneration';
export type {
GenerationRequest,
GenerationResponse,
} from './types/generation.types';
// Keep internal utilities private (don't export)
Usage by other features:
// â
Import from feature public API
import { GenerationForm, useGeneration } from '@/features/ai-generation';
// â Import from internal paths (breaks encapsulation)
import { GenerationForm } from '@/features/ai-generation/components/GenerationForm';
Component Organization
Small Components (<100 LOC)
Keep component and styles together:
// Button.tsx (80 LOC)
export const Button: React.FC<ButtonProps> = ({ children, ...props }) => {
return (
<button
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
{...props}
>
{children}
</button>
);
};
Large Components (>100 LOC)
Extract hooks and handlers:
// useProjectForm.ts
export function useProjectForm(initialValues: Project) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const handleChange = (field: string, value: any) => {
setValues(prev => ({ ...prev, [field]: value }));
};
return { values, errors, handleChange };
}
// ProjectForm.tsx (<150 LOC)
export const ProjectForm: React.FC<ProjectFormProps> = ({ initialValues }) => {
const { values, errors, handleChange } = useProjectForm(initialValues);
return (
<form>
{/* JSX using values, errors, handleChange */}
</form>
);
};
Scaffolding Checklist
When creating a new feature:
- Create feature directory:
src/features/{feature-name}/ - Add
components/with index.ts - Add
hooks/with index.ts (if needed) - Add
services/with index.ts - Add
types/with index.ts - Add
utils/with index.ts (if needed) - Create root
index.tswith public API exports - Add test files next to implementation files
- Verify no file exceeds 500 LOC
- Update feature integration points
Common Patterns
Service Pattern
// src/features/projects/services/projectService.ts
import { db } from '@/lib/database';
import type { Project } from '../types/project.types';
export const projectService = {
async getAll(): Promise<Project[]> {
return db.select().from('projects');
},
async getById(id: string): Promise<Project | null> {
const result = await db.select().from('projects').where('id', id);
return result[0] ?? null;
},
async create(data: Omit<Project, 'id'>): Promise<Project> {
const id = crypto.randomUUID();
await db.insert({ id, ...data }).into('projects');
return { id, ...data };
},
};
Hook Pattern
// src/features/projects/hooks/useProjects.ts
import { useQuery } from '@tanstack/react-query';
import { projectService } from '../services/projectService';
export function useProjects() {
return useQuery({
queryKey: ['projects'],
queryFn: () => projectService.getAll(),
});
}
Type Pattern
// src/features/projects/types/project.types.ts
export interface Project {
id: string;
title: string;
description?: string;
genre: ProjectGenre;
createdAt: number;
updatedAt: number;
}
export type ProjectGenre = 'fantasy' | 'scifi' | 'mystery' | 'romance';
export interface ProjectMetadata {
wordCount: number;
chapterCount: number;
}
Success Criteria
- All files under 500 LOC
- Feature code colocated within feature directory
- Public API clearly defined in root
index.ts - Test files next to implementation files
- Consistent directory structure across features
- No cross-feature internal imports
References
- AGENTS.md – Colocation principle and file size limits
- Existing features in
src/features/– Reference implementations