167 lines
4.8 KiB
Plaintext
167 lines
4.8 KiB
Plaintext
---
|
|
alwaysApply: true
|
|
description: Enforce business logic separation between frontend and backend
|
|
---
|
|
|
|
# Business Logic Separation Rules
|
|
|
|
## Core Principle: NO Business Logic in Frontend
|
|
|
|
All business logic, data processing, and domain rules MUST be implemented in the backend services layer. The frontend is purely for presentation and user interaction.
|
|
|
|
## ✅ ALLOWED in Frontend ([src/components/](mdc:src/components/), [src/hooks/](mdc:src/hooks/), [src/clients/](mdc:src/clients/))
|
|
|
|
### Components
|
|
- UI rendering and presentation logic
|
|
- Form validation (UI-level only, not business rules)
|
|
- User interaction handling (clicks, inputs, navigation)
|
|
- Visual state management (loading, errors, UI states)
|
|
- Data formatting for display purposes only
|
|
|
|
### Hooks
|
|
- React state management
|
|
- API call orchestration (using clients)
|
|
- UI-specific logic (modals, forms, animations)
|
|
- Data fetching and caching coordination
|
|
|
|
### Clients
|
|
- HTTP requests to API routes
|
|
- Request/response transformation (serialization only)
|
|
- Error handling and retry logic
|
|
- Authentication token management
|
|
|
|
## ❌ FORBIDDEN in Frontend
|
|
|
|
### Business Rules
|
|
```typescript
|
|
// ❌ BAD: Business logic in component
|
|
const TaskCard = ({ task }) => {
|
|
const canEdit = task.status === 'open' && task.assignee === currentUser.id;
|
|
const priority = task.dueDate < new Date() ? 'high' : 'normal';
|
|
// This is business logic!
|
|
}
|
|
|
|
// ✅ GOOD: Get computed values from backend
|
|
const TaskCard = ({ task }) => {
|
|
const { canEdit, priority } = task; // Computed by backend service
|
|
}
|
|
```
|
|
|
|
### Data Processing
|
|
```typescript
|
|
// ❌ BAD: Data transformation in frontend
|
|
const processJiraTasks = (tasks) => {
|
|
return tasks.map(task => ({
|
|
...task,
|
|
normalizedStatus: mapJiraStatus(task.status),
|
|
estimatedHours: calculateEstimate(task.storyPoints)
|
|
}));
|
|
}
|
|
|
|
// ✅ GOOD: Data already processed by backend service
|
|
const { processedTasks } = await tasksClient.getTasks();
|
|
```
|
|
|
|
### Domain Logic
|
|
```typescript
|
|
// ❌ BAD: Domain calculations in frontend
|
|
const calculateTeamVelocity = (sprints) => {
|
|
// Complex business calculation
|
|
}
|
|
|
|
// ✅ GOOD: Domain logic in service
|
|
// This belongs in services/team-analytics.ts
|
|
```
|
|
|
|
## ✅ REQUIRED in Backend ([src/services/](mdc:src/services/), [src/app/api/](mdc:src/app/api/))
|
|
|
|
### Services Layer
|
|
- All business rules and domain logic
|
|
- Data validation and processing
|
|
- Integration with external APIs (Jira, macOS Reminders)
|
|
- Complex calculations and algorithms
|
|
- Data aggregation and analytics
|
|
- Permission and authorization logic
|
|
|
|
### API Routes
|
|
- Input validation and sanitization
|
|
- Service orchestration
|
|
- Response formatting
|
|
- Error handling and logging
|
|
- Authentication and authorization
|
|
|
|
## Implementation Pattern
|
|
|
|
### ✅ Correct Flow
|
|
```
|
|
User Action → Component → Client → API Route → Service → Database
|
|
↑ ↓
|
|
Pure UI Logic Business Logic
|
|
```
|
|
|
|
### ❌ Incorrect Flow
|
|
```
|
|
User Action → Component with Business Logic → Database
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Task Status Management
|
|
```typescript
|
|
// ❌ BAD: In component
|
|
const updateTaskStatus = (taskId, newStatus) => {
|
|
if (newStatus === 'done' && !task.hasAllSubtasks) {
|
|
throw new Error('Cannot complete task with pending subtasks');
|
|
}
|
|
// Business rule in frontend!
|
|
}
|
|
|
|
// ✅ GOOD: In services/task-processor.ts
|
|
export const updateTaskStatus = async (taskId: string, newStatus: TaskStatus) => {
|
|
const task = await getTask(taskId);
|
|
|
|
// Business rules in service
|
|
if (newStatus === 'done' && !await hasAllSubtasksCompleted(taskId)) {
|
|
throw new BusinessError('Cannot complete task with pending subtasks');
|
|
}
|
|
|
|
return await updateTask(taskId, { status: newStatus });
|
|
}
|
|
```
|
|
|
|
### Team Analytics
|
|
```typescript
|
|
// ❌ BAD: In component
|
|
const TeamDashboard = () => {
|
|
const calculateBurndown = (tasks) => {
|
|
// Complex business calculation in component
|
|
}
|
|
}
|
|
|
|
// ✅ GOOD: In services/team-analytics.ts
|
|
export const getTeamBurndown = async (teamId: string, sprintId: string) => {
|
|
// All calculation logic in service
|
|
const tasks = await getSprintTasks(sprintId);
|
|
return calculateBurndownMetrics(tasks);
|
|
}
|
|
```
|
|
|
|
## Enforcement
|
|
|
|
When reviewing code:
|
|
1. **Components**: Should only contain JSX, event handlers, and UI state
|
|
2. **Hooks**: Should only orchestrate API calls and manage React state
|
|
3. **Clients**: Should only make HTTP requests and handle responses
|
|
4. **Services**: Should contain ALL business logic and data processing
|
|
5. **API Routes**: Should validate input and call appropriate services
|
|
|
|
## Red Flags
|
|
|
|
Watch for these patterns that indicate business logic in frontend:
|
|
- Complex calculations in components/hooks
|
|
- Business rule validation in forms
|
|
- Data transformation beyond display formatting
|
|
- Domain-specific constants and rules
|
|
- Integration logic with external systems
|
|
|
|
Remember: **The frontend is a thin presentation layer. All intelligence lives in the backend.** |