Where everything lives and why.
src/
├── main.jsx # Entry point: providers, React DOM render
├── App.jsx # Router, layout shell, error boundaries
├── index.css # Tailwind directives + global styles
│
├── contexts/ # React Context providers
│ ├── ThemeContext.jsx # Light/dark mode
│ └── ToastContext.jsx # Toast notifications
│ # At scale: +ToolContext, SearchContext, SidebarContext, ScrollContainerContext
│
├── components/
│ ├── shared/ # Reusable UI components (30+)
│ │ ├── Button.jsx
│ │ ├── Card.jsx
│ │ └── ...
│ ├── layout/ # App-level layout components
│ │ └── FeatureLayout.jsx # Standard feature page wrapper
│ └── features/ # Feature-specific subcomponents (optional)
│ └── MyFeature/
│ ├── MyFeatureChart.jsx
│ └── MyFeatureTable.jsx
│
├── hooks/ # Custom hooks
│ ├── useLocalStorage.js # General-purpose (shared)
│ ├── useDebounce.js
│ └── useMyFeature.js # Feature-specific (named after feature)
│
├── utils/ # Pure utility functions (no React)
│ ├── formatters.js
│ ├── validators.js
│ └── ...
│
├── core/ # Pure processing functions (no React/DOM) -- at scale
│ ├── registry.js # Core function registration (separate from UI registry)
│ ├── types.js # MIME-like type system constants and helpers
│ ├── typeGraph.js # Type compatibility engine and suggestion ranking
│ ├── normalizeInput.js # Input normalization (Blob -> canonical pipeline types)
│ └── tools/ # One file per chainable feature core
│ ├── case-converter.js
│ └── ...
│
├── batch/ # Pipeline execution engine (Worker-capable) -- at scale
│ └── executePipeline.js # Sequential pipeline runner
│
├── data/
│ ├── routeManifest.js # Lightweight routing data (in main bundle)
│ ├── registry.js # Full metadata (lazy-loaded)
│ └── seoData.js # Per-feature SEO titles, descriptions, FAQs -- at scale
│
├── pages/
│ ├── Home.jsx # Landing page with feature grid
│ ├── NotFound.jsx # 404 page
│ └── features/ # One file per feature
│ ├── CounterPage.jsx
│ └── FileProcessorPage.jsx
│
└── test-utils/
└── render.jsx # Test helpers (renderWithProviders)
| Type | Convention | Example |
|---|---|---|
| Feature pages | PascalCase + Page suffix |
CounterPage.jsx |
| Shared components | PascalCase |
Button.jsx, Card.jsx |
| Hooks | camelCase with use prefix |
useLocalStorage.js |
| Utilities | camelCase |
formatters.js, validators.js |
| Data files | camelCase |
routeManifest.js, registry.js |
| CSS | Only index.css (Tailwind handles the rest) |
index.css |
"I'm building a new feature"
- Create
src/pages/features/MyFeaturePage.jsx - Create
src/hooks/useMyFeature.js(if the feature has logic) - Add entries to
routeManifest.jsandregistry.js
"I need a subcomponent for my feature"
- If used only by this feature:
src/components/features/MyFeature/SubComponent.jsx - If used by 3+ features:
src/components/shared/SubComponent.jsx
"I wrote a utility function"
- If pure JavaScript (no React):
src/utils/myModule.js - If it uses React hooks:
src/hooks/useMyHook.js
"I need shared state"
- If theme/toast/app-level:
src/contexts/MyContext.jsx - If feature-specific persistence:
useLocalStorageinside a feature hook
- Don't create one-off CSS files. Use Tailwind classes.
- Don't put feature logic in page components. Extract to hooks.
- Don't import between feature pages. Extract shared logic to
hooks/orutils/. - Don't import
registry.jsin eagerly-loaded modules. UserouteManifest.js.