install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/feature-module-architect" ~/.claude/skills/majiayu000-claude-skill-registry-feature-module-architect && rm -rf "$T"
manifest:
skills/data/feature-module-architect/SKILL.mdsource content
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
with index.tscomponents/ - Add
with index.ts (if needed)hooks/ - Add
with index.tsservices/ - Add
with index.tstypes/ - Add
with index.ts (if needed)utils/ - Create root
with public API exportsindex.ts - 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
- Reference implementationssrc/features/