2025-09-17 18:43:43 +09:00
# Design Document
## Overview
This design document outlines a comprehensive refactoring strategy to transform the current customer portal codebase into a modern, maintainable, and scalable architecture. The refactoring will eliminate redundancies, establish consistent patterns, and improve developer experience while maintaining existing functionality.
## Architecture
### High-Level Structure
The refactored architecture will follow a feature-driven, layered approach:
```
apps/portal/src/
├── app/ # Next.js App Router pages
├── components/ # Shared UI components (Design System)
│ ├── ui/ # Base UI components (atoms)
│ ├── layout/ # Layout components (organisms)
│ └── common/ # Shared business components (molecules)
├── features/ # Feature-specific modules
│ ├── auth/ # Authentication feature
│ ├── dashboard/ # Dashboard feature
│ ├── billing/ # Billing feature
│ ├── subscriptions/ # Subscriptions feature
│ ├── catalog/ # Product catalog feature
│ └── support/ # Support feature
├── lib/ # Core utilities and services
│ ├── api/ # API client and services
│ ├── auth/ # Authentication logic
│ ├── hooks/ # Shared React hooks
│ ├── stores/ # State management
│ ├── types/ # Shared TypeScript types
│ └── utils/ # Utility functions
├── providers/ # React context providers
└── styles/ # Global styles and design tokens
```
### Design Principles
1. **Feature-First Organization** : Group related functionality together
2. **Atomic Design** : Build UI components in a hierarchical manner
3. **Separation of Concerns** : Separate business logic from presentation
4. **Single Responsibility** : Each module has one clear purpose
5. **Dependency Inversion** : Depend on abstractions, not concretions
## Components and Interfaces
### Design System Architecture
#### Atomic Design Structure
```typescript
// Base UI Components (Atoms)
components/ui/
├── Button/
│ ├── Button.tsx
│ ├── Button.stories.tsx
│ ├── Button.test.tsx
│ └── index.ts
├── Input/
├── Badge/
└── ...
// Composite Components (Molecules)
components/common/
├── DataTable/
├── SearchBar/
├── StatusIndicator/
└── ...
// Layout Components (Organisms)
components/layout/
├── DashboardLayout/
├── AuthLayout/
├── PageLayout/
└── ...
```
#### Component Interface Standards
```typescript
// Base component props interface
interface BaseComponentProps {
className?: string;
children?: React.ReactNode;
testId?: string;
}
// Variant-based component pattern
interface ButtonProps extends BaseComponentProps {
2025-09-26 17:02:36 +09:00
variant?: "primary" | "secondary" | "outline" | "ghost";
size?: "sm" | "md" | "lg";
2025-09-17 18:43:43 +09:00
disabled?: boolean;
loading?: boolean;
onClick?: () => void;
}
```
### Feature Module Structure
Each feature will follow a consistent internal structure:
```typescript
features/[feature-name]/
├── components/ # Feature-specific components
│ ├── [Component]/
│ │ ├── Component.tsx
│ │ ├── Component.test.tsx
│ │ └── index.ts
│ └── index.ts
├── hooks/ # Feature-specific hooks
│ ├── use[Feature].ts
│ └── index.ts
├── services/ # Feature business logic
│ ├── [feature].service.ts
│ └── index.ts
├── types/ # Feature-specific types
│ ├── [feature].types.ts
│ └── index.ts
├── utils/ # Feature utilities
└── index.ts # Feature public API
```
### API Service Layer
```typescript
// Centralized API service structure
lib/api/
├── client.ts # Base API client
├── types.ts # API response types
├── services/
│ ├── auth.service.ts
│ ├── billing.service.ts
│ ├── subscriptions.service.ts
│ └── index.ts
└── index.ts
// Service interface pattern
interface ApiService< T > {
getAll(params?: QueryParams): Promise< T [ ] > ;
getById(id: string): Promise< T > ;
create(data: CreateT): Promise< T > ;
update(id: string, data: UpdateT): Promise< T > ;
delete(id: string): Promise< void > ;
}
```
## Data Models
### Centralized Type Definitions
```typescript
// lib/types/index.ts - Centralized type exports
2025-09-26 17:02:36 +09:00
export * from "./api.types";
export * from "./auth.types";
export * from "./billing.types";
export * from "./subscription.types";
export * from "./common.types";
2025-09-17 18:43:43 +09:00
// Common base types
interface BaseEntity {
id: string;
createdAt: string;
updatedAt: string;
}
interface PaginatedResponse< T > {
data: T[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
// Feature-specific type extensions
interface Subscription extends BaseEntity {
userId: string;
planId: string;
status: SubscriptionStatus;
// ... other properties
}
```
### State Management Pattern
```typescript
// Zustand store pattern for each feature
interface FeatureStore {
// State
data: FeatureData[];
loading: boolean;
error: string | null;
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
// Actions
fetchData: () => Promise< void > ;
updateItem: (id: string, data: Partial< FeatureData > ) => Promise< void > ;
reset: () => void;
}
// React Query integration for server state
const useFeatureQuery = (params?: QueryParams) => {
return useQuery({
2025-09-26 17:02:36 +09:00
queryKey: ["feature", params],
2025-09-17 18:43:43 +09:00
queryFn: () => featureService.getAll(params),
staleTime: 5 * 60 * 1000, // 5 minutes
});
};
```
## Error Handling
### Centralized Error Management
```typescript
// lib/errors/index.ts
export class AppError extends Error {
constructor(
message: string,
public code: string,
public statusCode?: number
) {
super(message);
2025-09-26 17:02:36 +09:00
this.name = "AppError";
2025-09-17 18:43:43 +09:00
}
}
// Error boundary component
export function ErrorBoundary({ children }: { children: React.ReactNode }) {
// Implementation with error logging and user-friendly fallbacks
}
// API error handling
export function handleApiError(error: unknown): AppError {
if (error instanceof ApiError) {
return new AppError(error.message, error.code, error.status);
}
2025-09-26 17:02:36 +09:00
return new AppError("An unexpected error occurred", "UNKNOWN_ERROR");
2025-09-17 18:43:43 +09:00
}
```
### Error Display Strategy
```typescript
// Consistent error display components
interface ErrorStateProps {
error: AppError;
onRetry?: () => void;
2025-09-26 17:02:36 +09:00
variant?: "page" | "inline" | "toast";
2025-09-17 18:43:43 +09:00
}
2025-09-26 17:02:36 +09:00
export function ErrorState({ error, onRetry, variant = "page" }: ErrorStateProps) {
2025-09-17 18:43:43 +09:00
// Render appropriate error UI based on variant
}
```
## Testing Strategy
### Testing Architecture
```typescript
// Test utilities and setup
__tests__/
├── setup.ts # Test environment setup
├── utils/
│ ├── render.tsx # Custom render with providers
│ ├── mocks/ # API and service mocks
│ └── factories/ # Test data factories
└── fixtures/ # Test data fixtures
// Component testing pattern
describe('Button Component', () => {
it('renders with correct variant styles', () => {
render(< Button variant = "primary" > Click me< / Button > );
expect(screen.getByRole('button')).toHaveClass('bg-blue-600');
});
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
it('handles click events', async () => {
const handleClick = jest.fn();
render(< Button onClick = {handleClick} > Click me< / Button > );
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
await user.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
});
```
### Integration Testing
```typescript
// Feature integration tests
describe('Dashboard Feature', () => {
beforeEach(() => {
// Setup mocks and test data
mockApiService.dashboard.getSummary.mockResolvedValue(mockDashboardData);
});
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
it('displays user dashboard with correct data', async () => {
render(< DashboardPage / > );
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
await waitFor(() => {
expect(screen.getByText('Active Subscriptions')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
});
});
});
```
## Performance Optimization
### Code Splitting Strategy
```typescript
// Feature-based code splitting
2025-09-26 17:02:36 +09:00
const DashboardPage = lazy(() => import("@/features/dashboard/pages/DashboardPage "));
const BillingPage = lazy(() => import("@/features/billing/pages/BillingPage "));
2025-09-17 18:43:43 +09:00
// Component-level splitting for heavy components
2025-09-26 17:02:36 +09:00
const DataVisualization = lazy(() => import("@/components/common/DataVisualization "));
2025-09-17 18:43:43 +09:00
```
### Bundle Optimization
```typescript
// Tree-shakeable exports
// Instead of: export * from './components';
// Use specific exports:
2025-09-26 17:02:36 +09:00
export { Button } from "./Button";
export { Input } from "./Input";
export type { ButtonProps, InputProps } from "./types";
2025-09-17 18:43:43 +09:00
// Dynamic imports for heavy dependencies
2025-09-26 17:02:36 +09:00
const heavyLibrary = await import("heavy-library");
2025-09-17 18:43:43 +09:00
```
### Caching Strategy
```typescript
// React Query configuration
const queryClient = new QueryClient({
defaultOptions: {
queries: {
2025-09-26 17:02:36 +09:00
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes
2025-09-17 18:43:43 +09:00
retry: (failureCount, error) => {
if (error.status === 404) return false;
return failureCount < 3 ;
},
},
},
});
```
## Migration Strategy
### Phase 1: Foundation (Weeks 1-2)
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
- Set up new folder structure
- Create base UI components (Button, Input, etc.)
- Establish design tokens and styling system
- Set up centralized API client
### Phase 2: Core Features (Weeks 3-4)
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
- Refactor authentication module
- Migrate dashboard feature
- Consolidate layout components
- Implement error handling system
### Phase 3: Business Features (Weeks 5-6)
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
- Migrate billing feature
- Refactor subscriptions feature
- Consolidate catalog functionality
- Implement testing framework
### Phase 4: Optimization (Weeks 7-8)
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
- Performance optimization
- Bundle analysis and splitting
- Documentation and cleanup
- Final testing and validation
## Risk Mitigation
### Backward Compatibility
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
- Maintain existing API contracts during migration
- Use feature flags for gradual rollout
- Keep old components until migration is complete
### Testing Coverage
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
- Maintain existing functionality through comprehensive testing
- Implement visual regression testing
- Set up automated testing pipeline
### Performance Monitoring
2025-09-26 17:02:36 +09:00
2025-09-17 18:43:43 +09:00
- Implement bundle size monitoring
- Set up performance metrics tracking
2025-09-26 17:02:36 +09:00
- Monitor Core Web Vitals during migration