This document describes the architectural decisions and patterns used in the ABP React TanStack application.
The application is organized around features rather than technical layers. Each feature contains its own components, hooks, stores, and constants. This approach improves:
- Developer Experience: Developers can focus on a specific feature without navigating unrelated code
- Maintainability: Changes to one feature are less likely to affect others
- Scalability: New features can be added without disrupting existing code
src/
├── features/ # Feature-based modules
│ ├── auth/ # Authentication feature
│ ├── users/ # User management feature
│ ├── roles/ # Role management feature
│ ├── tenants/ # Tenant management feature
│ └── dashboard/ # Dashboard feature
├── shared/ # Shared code across features
│ ├── components/ # Reusable UI components
│ ├── hooks/ # Shared hooks
│ ├── stores/ # Shared stores
│ ├── utils/ # Utility functions
│ └── types/ # Shared types
├── infrastructure/ # Infrastructure concerns
│ ├── api/ # API client configuration
│ ├── auth/ # Authentication infrastructure
│ └── config/ # Configuration files
├── routes/ # Route definitions (TanStack Router file-based routing)
├── router.tsx # Router configuration
├── routeTree.gen.ts # Auto-generated route tree (gitignored)
├── constants.ts # Application constants
├── styles.css # Global styles
└── logo.svg # Application logo
Each feature follows this pattern:
feature-name/
├── components/ # Feature-specific components
│ ├── [Feature]List.tsx # Main list component
│ ├── [Feature]Form.tsx # Create/edit form
│ ├── [Feature]Modal.tsx # Feature-specific modals
│ ├── [Feature]Table.tsx # Table component (split from list)
│ └── [Feature]Header.tsx # Header component (split from list)
├── hooks/ # Feature-specific hooks
├── stores/ # Feature-specific stores
│ ├── [feature]-form-store.ts # Form state management
│ └── [feature]-modal-store.ts # Modal state management
└── constants.ts # Feature-specific constants
We use Zustand for state management with these patterns:
-
Base Store Pattern: Common store interfaces and actions extracted to base stores
BaseFormStore: For create/edit formsBaseModalStore: For modal components- Reusable actions:
setLoading,openCreateForm,openEditForm, etc.
-
Feature Stores: Extend base patterns with feature-specific state
- Form stores for managing create/edit state
- Modal stores for managing modal state
- Consistent naming:
[feature]-form-store,[feature]-modal-store
We use path aliases to simplify imports:
@/shared/*: Points to shared code@/features/*: Points to feature-specific code@/infrastructure/*: Points to infrastructure code
Large components (500+ lines) are split into smaller components:
- List Components: Main container with data fetching
- Table Components: Table display and pagination
- Header Components: Header with actions
- Form Components: Create/edit forms
- Modal Components: Feature-specific modals
- Scalability: New developers can quickly understand and work on specific features
- Maintainability: Reduced coupling between features makes maintenance easier
- Testability: Feature-specific tests are more focused and easier to write
- Code Reuse: Shared components reduce duplication
- Performance: Smaller components are easier to optimize and lazy load
- Create a new directory under
src/features/[feature-name]/ - Follow the established patterns for components, hooks, and stores
- Use base store patterns to reduce boilerplate
- Add feature-specific constants if needed
- Create a route file in
src/routes/[feature].tsx - Update navigation components to include the new feature
- Keep files under 500 lines (enforced by
check-file-sizescript) - Use TypeScript for type safety
- Follow existing naming conventions
- Add tests for new functionality
- Update documentation when adding features
- Use the defined path aliases for imports
- Import from feature-specific locations when possible
- Use shared components for common UI patterns
- Keep component dependencies explicit and minimal