Midtrans-Middleware/docs/tech-spec.md

1379 lines
40 KiB
Markdown

# core-midtrans-cifo - Technical Specification
**Author:** BMad
**Date:** 2025-11-25
**Project Level:** Quick-Flow (2 Stories)
**Change Type:** UX Enhancement + Bug Fix
**Development Context:** Brownfield - Payment Flow Improvements
---
## Context
### Available Documents
**Loaded Documents:**
-**Problem-Solution Analysis** (`problem-solution-2025-11-25.md`) - Comprehensive problem analysis by Dr. Quinn identifying 3 interconnected payment flow issues with systematic root cause analysis and 15 evaluated solutions
-**Project Codebase** - Existing React + TypeScript + Midtrans integration
**Project Type:** Brownfield - Existing functional payment application
**Key Context:**
- Target users: Non-tech-savvy customers (ibu-ibu awam)
- Platform: Mobile-first web application
- Payment Gateway: Midtrans (1 VA per transaction constraint)
- Current Issues: Duplicate VA generation, poor post-payment UX, inadequate error handling
### Project Stack
**Frontend Stack:**
- **React** 19.1.1 - Latest React with modern hooks and concurrent features
- **TypeScript** 5.9.3 - Type-safe development
- **Vite** 7.1.7 - Fast build tool and dev server
- **React Router DOM** 7.9.5 - Client-side routing
- **TailwindCSS** 4.1.17 - Utility-first CSS framework
- **Framer Motion** 12.23.24 - Animation library
- **React Hook Form** 7.66.0 - Form state management
- **TanStack React Query** 5.90.7 - Server state management and data fetching
- **Axios** 1.13.2 - HTTP client
**Backend Stack:**
- **Express** 5.1.0 - Node.js web framework
- **Midtrans Client** 1.4.3 - Official Midtrans SDK for payment processing
- **CORS** 2.8.5 - Cross-origin resource sharing
- **dotenv** 17.2.3 - Environment variable management
**Development Tools:**
- **ESLint** 9.36.0 - Code linting
- **Prettier** 3.6.2 - Code formatting
- **TypeScript ESLint** 8.45.0 - TypeScript-specific linting rules
**Project Type:** Vite + React + TypeScript SPA with Express backend
### Existing Codebase Structure
**Directory Organization:**
```
src/
├── features/ (16 feature modules) - Feature-based architecture
├── pages/ (6 pages) - Route-level components
├── components/ (3 shared components) - Reusable UI components
├── services/ (API services) - Backend communication layer
├── lib/ (utilities) - Helper functions and utilities
└── app/ (app config) - Application configuration
```
**Architecture Pattern:** Feature-based modular architecture
- Each feature is self-contained with its own components, hooks, and logic
- Shared components in `/components` for cross-feature reusability
- Centralized API services in `/services`
- Utility functions in `/lib`
**Styling Approach:** TailwindCSS utility classes
- Responsive mobile-first design
- Custom design system via `tailwind.config.ts`
**State Management:**
- React Query for server state
- React Hook Form for form state
- React hooks (useState, useEffect) for local component state
---
## The Change
### Problem Statement
**Core Problem:** Mobile-first payment application untuk non-tech-savvy users (ibu-ibu awam) mengalami critical UX failures dan poor state management yang menyebabkan:
1. **Duplicate VA Generation** - Users click generate VA button multiple times during 3-5 second delay, triggering HTTP 409 errors with technical error messages
2. **Post-Payment Confusion** - After successful payment, users are redirected to status page with no clear next steps, causing them to press back button which triggers invalid transaction states
3. **Poor Error Handling** - HTTP errors (409, 404) displayed as technical messages; invalid states show "Rp 0" instead of helpful recovery options
**Business Impact:**
- Abandoned transactions → lost revenue
- High support ticket volume
- User frustration and distrust
- Poor mobile UX for primary user demographic
**Root Causes Identified:**
1. Lack of defensive UX design patterns (no loading states, no button disable)
2. Poor React lifecycle management (useEffect re-triggering on navigation)
3. Missing error handling framework (no user-friendly messages, no recovery paths)
### Proposed Solution
**Phase 1: Quick Wins Bundle** - Implement 5 high-impact, low-risk solutions organized into 2 user stories:
**Story 1: Prevent Duplicate VA Generation & Improve Feedback**
- Solution #1: Button State Management - Disable button during processing
- Solution #2: Request Debouncing - 500ms debounce on VA generation
- Solution #3: User-Friendly Error Messages - Map HTTP codes to bahasa Indonesia
- Solution #4: Loading Overlay - Full-screen overlay with clear messaging
**Story 2: Improve Post-Payment UX**
- Solution #5: Auto-Redirect After Success - 5-second countdown with clear CTA
**Expected Impact:** Solves 70-80% of payment flow issues with minimal risk
### Scope
**In Scope:**
**Story 1: Prevent Duplicate VA Generation & Improve Feedback**
1. Implement button disable/enable logic on VA generation button
2. Add loading spinner to button during processing
3. Implement 500ms debounce on VA generation function
4. Create full-screen loading overlay component
5. Map HTTP 409 → "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat"
6. Map HTTP 404 → "Terjadi kesalahan. Silakan coba lagi"
7. Add "Coba Lagi" recovery button on error states
8. Add "Lihat Kode Pembayaran" button on 409 errors
**Story 2: Improve Post-Payment UX**
1. Implement 5-second countdown timer on payment success page
2. Add "Anda akan diarahkan ke dashboard dalam X detik..." message
3. Add "Kembali Sekarang" button for impatient users
4. Implement auto-redirect logic to dashboard/home after countdown
**Cross-Story Requirements**
1. Mobile-first responsive design (primary focus)
2. Bahasa Indonesia for all user-facing text
3. Consistent with existing TailwindCSS design system
4. Accessible (keyboard navigation, screen reader friendly)
**Out of Scope:**
**Phase 2 Solutions** (future work):
- Navigation guards (useEffect cleanup)
- Modal-based success page
- Progressive loading states
- Transaction state machine
- Idempotency key implementation
**Backend Changes:**
- Midtrans API modifications
- Database schema changes
- Backend validation logic
**Complete Redesign:**
- Single-page payment flow
- Optimistic UI patterns
- Guided tour/onboarding
---
## Implementation Details
### Source Tree Changes
**Files to CREATE:**
1. **`src/components/LoadingOverlay.tsx`** - NEW
- Full-screen loading overlay component
- Props: `isLoading: boolean`, `message: string`
- Semi-transparent backdrop with centered spinner and message
2. **`src/components/CountdownRedirect.tsx`** - NEW
- Countdown timer component for auto-redirect
- Props: `seconds: number`, `onComplete: () => void`, `destination: string`
- Display countdown with "Kembali Sekarang" button
3. **`src/lib/errorMessages.ts`** - NEW
- Error message mapping utility
- Function: `mapErrorToUserMessage(error: AxiosError): string`
- Maps HTTP status codes to user-friendly Indonesian messages
4. **`src/lib/debounce.ts`** - NEW
- Debounce utility function
- Function: `debounce<T>(func: T, delay: number): T`
- Generic debounce implementation for click handlers
**Files to MODIFY:**
1. **`src/features/payment/components/PaymentMethodSelector.tsx`** (or equivalent)
- ADD: Button disable logic (disabled state during VA generation)
- ADD: Loading spinner on button
- ADD: Debounce wrapper on generateVA handler
- ADD: LoadingOverlay integration
- MODIFY: Error handling to use mapErrorToUserMessage
2. **`src/features/payment/pages/PaymentSuccessPage.tsx`** (or equivalent)
- ADD: CountdownRedirect component
- ADD: Auto-redirect logic after 5 seconds
- MODIFY: Layout to include countdown timer and CTA button
3. **`src/features/payment/hooks/useGenerateVA.ts`** (or create if doesn't exist)
- ADD: Loading state management
- ADD: Error state with user-friendly messages
- ADD: Button disable logic
- MODIFY: Error handling to use mapErrorToUserMessage
**Files to ADD TESTS:**
1. **`src/components/__tests__/LoadingOverlay.test.tsx`** - CREATE
2. **`src/components/__tests__/CountdownRedirect.test.tsx`** - CREATE
3. **`src/lib/__tests__/errorMessages.test.ts`** - CREATE
4. **`src/lib/__tests__/debounce.test.ts`** - CREATE
### Technical Approach
**1. Button State Management (Solution #1)**
**Approach:** Use React state to track loading status and disable button during API call
```typescript
const [isGenerating, setIsGenerating] = useState(false);
const handleGenerateVA = async () => {
setIsGenerating(true);
try {
await generateVAAPI();
} finally {
setIsGenerating(false);
}
};
<button disabled={isGenerating}>
{isGenerating ? <Spinner /> : 'Generate VA'}
</button>
```
**Why:** Simple, effective, uses existing React patterns
---
**2. Request Debouncing (Solution #2)**
**Approach:** Wrap VA generation handler with debounce utility (500ms delay)
```typescript
import { debounce } from '@/lib/debounce';
const debouncedGenerateVA = useMemo(
() => debounce(handleGenerateVA, 500),
[]
);
```
**Why:** Prevents rapid successive clicks, complements button disable
---
**3. User-Friendly Error Messages (Solution #3)**
**Approach:** Create error mapping utility that translates HTTP codes to Indonesian
```typescript
// src/lib/errorMessages.ts
export const mapErrorToUserMessage = (error: AxiosError): string => {
if (error.response?.status === 409) {
return "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat";
}
if (error.response?.status === 404) {
return "Terjadi kesalahan. Silakan coba lagi";
}
return "Terjadi kesalahan. Silakan coba lagi";
};
```
**Why:** Centralized error handling, easy to maintain and extend
---
**4. Loading Overlay (Solution #4)**
**Approach:** Create reusable LoadingOverlay component with Framer Motion animations
```typescript
// src/components/LoadingOverlay.tsx
export const LoadingOverlay = ({ isLoading, message }) => {
if (!isLoading) return null;
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
>
<div className="bg-white p-6 rounded-lg">
<Spinner />
<p>{message}</p>
</div>
</motion.div>
);
};
```
**Why:** Prevents interaction during processing, clear visual feedback
---
**5. Auto-Redirect After Success (Solution #5)**
**Approach:** Use countdown timer with useEffect and setTimeout
```typescript
// src/components/CountdownRedirect.tsx
export const CountdownRedirect = ({ seconds, onComplete, destination }) => {
const [countdown, setCountdown] = useState(seconds);
useEffect(() => {
if (countdown === 0) {
onComplete();
return;
}
const timer = setTimeout(() => {
setCountdown(c => c - 1);
}, 1000);
return () => clearTimeout(timer);
}, [countdown, onComplete]);
return (
<div>
<p>Anda akan diarahkan ke {destination} dalam {countdown} detik...</p>
<button onClick={onComplete}>Kembali Sekarang</button>
</div>
);
};
```
**Why:** Clear user guidance, option for impatient users, prevents back button confusion
### Existing Patterns to Follow
**React Patterns:**
- Functional components with hooks (no class components)
- Custom hooks for reusable logic (e.g., `useGenerateVA`)
- TypeScript for type safety
- Props interfaces defined with `interface` keyword
**Styling Patterns:**
- TailwindCSS utility classes
- Responsive design with mobile-first breakpoints (`sm:`, `md:`, `lg:`)
- Custom colors and spacing from `tailwind.config.ts`
- Framer Motion for animations (already in use)
**State Management Patterns:**
- React Query for API calls and server state
- React Hook Form for form state
- Local useState for component-specific state
**Error Handling Patterns:**
- Try-catch blocks for async operations
- Error states in components
- User-friendly error messages (to be improved by this change)
**File Naming Conventions:**
- PascalCase for components: `LoadingOverlay.tsx`
- camelCase for utilities: `errorMessages.ts`
- Test files: `ComponentName.test.tsx`
### Integration Points
**1. Midtrans API Integration**
- **Location:** `src/services/midtrans.ts` (or similar)
- **Integration:** VA generation API call
- **Changes:** Wrap with loading state, error handling, debounce
**2. React Query Integration**
- **Usage:** Manage VA generation API state
- **Pattern:** Use `useMutation` for VA generation
- **Changes:** Add onMutate (loading), onError (error messages), onSuccess (redirect)
**3. React Router Integration**
- **Usage:** Navigate to success page, auto-redirect after payment
- **Pattern:** Use `useNavigate` hook
- **Changes:** Implement programmatic navigation in CountdownRedirect
**4. TailwindCSS Design System**
- **Integration:** All new components use Tailwind classes
- **Consistency:** Match existing color scheme, spacing, typography
- **Responsive:** Mobile-first breakpoints
**5. Framer Motion Animations**
- **Usage:** LoadingOverlay fade-in animation
- **Pattern:** `motion.div` with initial/animate props
- **Consistency:** Match existing animation timing and easing
---
## Development Context
### Relevant Existing Code
**Payment Feature Module:**
- **Location:** `src/features/payment/` (assumed based on feature-based architecture)
- **Components:** PaymentMethodSelector, PaymentSuccessPage (names may vary)
- **Hooks:** Likely has custom hooks for payment logic
- **Services:** API calls to Midtrans via backend
**Reference Patterns:**
- Check existing components in `src/components/` for styling patterns
- Review existing API calls in `src/services/` for error handling patterns
- Look at existing hooks for state management patterns
**Key Files to Review Before Implementation:**
1. Payment method selection component (where VA generation button lives)
2. Payment success/status page component
3. Existing API service layer for Midtrans calls
4. Existing error handling utilities (if any)
### Dependencies
**Framework/Libraries:**
**Production Dependencies (Already Installed):**
- `react@19.1.1` - Core React library
- `react-dom@19.1.1` - React DOM rendering
- `react-router-dom@7.9.5` - Routing
- `@tanstack/react-query@5.90.7` - Server state management
- `axios@1.13.2` - HTTP client
- `framer-motion@12.23.24` - Animations
- `tailwindcss@4.1.17` - Styling
- `clsx@2.1.1` - Conditional class names
- `tailwind-merge@3.3.1` - Merge Tailwind classes
**Development Dependencies (Already Installed):**
- `typescript@5.9.3` - TypeScript compiler
- `vite@7.1.7` - Build tool
- `eslint@9.36.0` - Linting
- `prettier@3.6.2` - Code formatting
**No New Dependencies Required** - All solutions use existing stack
### Internal Modules
**Modules to Create:**
- `@/components/LoadingOverlay` - Loading overlay component
- `@/components/CountdownRedirect` - Countdown redirect component
- `@/lib/errorMessages` - Error message mapping utility
- `@/lib/debounce` - Debounce utility function
**Modules to Import:**
- `@/services/midtrans` (or equivalent) - Midtrans API service
- `react-router-dom` - useNavigate hook
- `@tanstack/react-query` - useMutation hook
- `framer-motion` - motion components
- `clsx` or `tailwind-merge` - Conditional styling
### Configuration Changes
**No Configuration Changes Required**
All solutions work within existing configuration:
- ✅ No new environment variables
- ✅ No Vite config changes
- ✅ No TailwindCSS config changes
- ✅ No ESLint/Prettier config changes
- ✅ No package.json changes (no new dependencies)
### Existing Conventions (Brownfield)
**Code Style:**
- **TypeScript:** Strict mode enabled
- **Quotes:** Single quotes (based on Prettier config)
- **Semicolons:** Yes (TypeScript default)
- **Indentation:** 2 spaces
- **Line Length:** 80-100 characters (Prettier default)
**Component Patterns:**
- Functional components with TypeScript interfaces for props
- Named exports preferred
- Props interface named `ComponentNameProps`
**Import Organization:**
- React imports first
- Third-party libraries second
- Internal imports last
- Absolute imports using `@/` alias
**Error Handling:**
- Try-catch for async operations
- Error boundaries for component errors (if implemented)
- User-friendly error messages (to be improved)
**Testing:**
- Test files co-located with components in `__tests__/` folder
- File naming: `ComponentName.test.tsx`
- Framework: Likely Vitest (Vite's test framework) or Jest
### Test Framework & Standards
**Test Framework:** Vitest (recommended for Vite projects) or Jest
**Test File Patterns:**
- Location: `src/components/__tests__/` or `src/lib/__tests__/`
- Naming: `ComponentName.test.tsx` or `utilityName.test.ts`
- Structure: Describe blocks for component/function, it blocks for test cases
**Testing Strategy:**
- Unit tests for utilities (`debounce`, `errorMessages`)
- Component tests for UI components (`LoadingOverlay`, `CountdownRedirect`)
- Integration tests for payment flow (optional, recommended)
**Coverage Requirements:**
- Aim for 80%+ coverage on new code
- All utility functions must have tests
- All new components must have basic render tests
---
## Implementation Stack
**Runtime Environment:**
- Node.js 20.x (recommended for Express 5.x)
- Browser: Modern browsers with ES2020+ support
**Frontend Stack:**
- React 19.1.1
- TypeScript 5.9.3
- Vite 7.1.7
- TailwindCSS 4.1.17
- Framer Motion 12.23.24
- React Router DOM 7.9.5
- TanStack React Query 5.90.7
- Axios 1.13.2
**Backend Stack:**
- Express 5.1.0
- Midtrans Client 1.4.3
**Development Tools:**
- ESLint 9.36.0
- Prettier 3.6.2
- TypeScript ESLint 8.45.0
**Testing:**
- Vitest (recommended) or Jest
- React Testing Library (for component tests)
---
## Technical Details
### Story 1: Prevent Duplicate VA Generation & Improve Feedback
**Technical Implementation Details:**
**1. Button Disable Logic**
- State variable: `isGenerating: boolean`
- Set to `true` on button click, `false` on API response (success or error)
- Button `disabled` attribute bound to `isGenerating`
- Visual feedback: Show spinner when `isGenerating === true`
**2. Debounce Implementation**
- Debounce delay: 500ms
- Implementation: Custom debounce utility using setTimeout
- Applied to: VA generation click handler
- Edge case: Clear timeout on component unmount
**3. Error Message Mapping**
- HTTP 409 → "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat"
- HTTP 404 → "Terjadi kesalahan. Silakan coba lagi"
- HTTP 500 → "Terjadi kesalahan server. Silakan coba lagi nanti"
- Network error → "Tidak dapat terhubung ke server. Periksa koneksi internet Anda"
- Default → "Terjadi kesalahan. Silakan coba lagi"
**4. Loading Overlay**
- Z-index: 50 (above all content)
- Backdrop: Semi-transparent black (`bg-black/50`)
- Content: White card with spinner and message
- Animation: Fade in (200ms) using Framer Motion
- Message: "Sedang membuat kode pembayaran..."
- Accessibility: Focus trap, ESC key to cancel (optional)
**5. Recovery Buttons**
- "Coba Lagi" button on all errors → Retry VA generation
- "Lihat Kode Pembayaran" button on 409 error → Navigate to existing VA view
- "Kembali" button on errors → Navigate back to payment method selection
### Story 2: Improve Post-Payment UX
**Technical Implementation Details:**
**1. Countdown Timer**
- Initial value: 5 seconds
- Update interval: 1 second (1000ms)
- Implementation: useEffect with setTimeout
- Cleanup: Clear timeout on unmount
- Display format: "Anda akan diarahkan ke dashboard dalam {X} detik..."
**2. Auto-Redirect**
- Trigger: When countdown reaches 0
- Destination: Dashboard or home page (configurable)
- Method: `useNavigate()` from react-router-dom
- Fallback: Manual "Kembali Sekarang" button
**3. Manual Redirect Button**
- Label: "Kembali Sekarang"
- Action: Immediately navigate to destination (skip countdown)
- Styling: Primary button style (prominent, easy to find)
- Position: Below countdown message
**Performance Considerations:**
- Debounce prevents excessive API calls
- Loading overlay prevents UI interaction during processing
- Countdown timer uses single setTimeout (not setInterval) for better performance
**Security Considerations:**
- No sensitive data in error messages
- Error messages don't reveal system internals
- Rate limiting handled by backend (out of scope)
**Accessibility Considerations:**
- Loading overlay has proper ARIA labels
- Countdown timer announced by screen readers
- Buttons have clear labels and keyboard navigation
- Focus management during loading states
---
## Development Setup
**Prerequisites:**
- Node.js 20.x installed
- npm or yarn package manager
- Git for version control
**Initial Setup (if not already done):**
```bash
# 1. Clone repository (if not already cloned)
git clone <repository-url>
cd core-midtrans-cifo
# 2. Install dependencies
npm install
# 3. Set up environment variables
cp .env.example .env
# Edit .env with your Midtrans credentials
# 4. Start development server
npm run dev
# 5. Start backend server (in separate terminal)
npm run server
```
**Development Workflow:**
```bash
# Start Vite dev server (frontend)
npm run dev
# Access at http://localhost:5173
# Start Express server (backend)
npm run server
# Access at http://localhost:3000 (or configured port)
# Run linter
npm run lint
# Run tests (when implemented)
npm test
# Build for production
npm run build
# Preview production build
npm run preview
```
**Environment Variables Required:**
- `VITE_MIDTRANS_CLIENT_KEY` - Midtrans client key
- `MIDTRANS_SERVER_KEY` - Midtrans server key (backend)
- `MIDTRANS_IS_PRODUCTION` - true/false for sandbox vs production
---
## Implementation Guide
### Setup Steps
**Pre-Implementation Checklist:**
1. ✅ Create feature branch
```bash
git checkout -b feature/payment-ux-improvements
```
2. ✅ Verify development environment running
- Frontend dev server: `npm run dev`
- Backend server: `npm run server`
- Both running without errors
3. ✅ Review existing payment flow code
- Locate payment method selection component
- Locate payment success page component
- Locate Midtrans API service layer
- Understand current error handling
4. ✅ Set up test environment (if not already)
- Install Vitest or Jest
- Configure test runner
- Create test file structure
### Implementation Steps
**Story 1: Prevent Duplicate VA Generation & Improve Feedback**
**Phase 1: Create Utility Functions (30 minutes)**
1. Create `src/lib/debounce.ts`
- Implement generic debounce function
- Add TypeScript types
- Write unit tests
2. Create `src/lib/errorMessages.ts`
- Implement error mapping function
- Map all HTTP status codes
- Add recovery action suggestions
- Write unit tests
**Phase 2: Create UI Components (1 hour)**
3. Create `src/components/LoadingOverlay.tsx`
- Implement overlay with backdrop
- Add Framer Motion animations
- Add spinner and message
- Make responsive for mobile
- Write component tests
**Phase 3: Modify Payment Method Component (1.5 hours)**
4. Locate and modify payment method selection component
- Add `isGenerating` state
- Wrap VA generation handler with debounce
- Add button disable logic
- Add loading spinner to button
- Integrate LoadingOverlay
- Update error handling to use `mapErrorToUserMessage`
- Add recovery buttons based on error type
**Phase 4: Testing & Refinement (1 hour)**
5. Manual testing
- Test duplicate click prevention
- Test loading overlay display
- Test error messages for different error types
- Test recovery buttons
- Test on mobile devices
6. Fix any issues found during testing
**Story 2: Improve Post-Payment UX**
**Phase 1: Create Countdown Component (45 minutes)**
1. Create `src/components/CountdownRedirect.tsx`
- Implement countdown timer with useEffect
- Add auto-redirect logic
- Add manual redirect button
- Make responsive for mobile
- Write component tests
**Phase 2: Modify Payment Success Page (45 minutes)**
2. Locate and modify payment success page component
- Integrate CountdownRedirect component
- Configure redirect destination
- Update layout for mobile-first
- Add clear success messaging
**Phase 3: Testing & Refinement (30 minutes)**
3. Manual testing
- Test countdown timer accuracy
- Test auto-redirect functionality
- Test manual redirect button
- Test on mobile devices
- Verify no back button issues
4. Fix any issues found during testing
### Testing Strategy
**Unit Tests:**
1. **`debounce.test.ts`**
- Test debounce delays function execution
- Test multiple rapid calls only execute once
- Test cleanup on unmount
2. **`errorMessages.test.ts`**
- Test HTTP 409 maps to correct message
- Test HTTP 404 maps to correct message
- Test default error message
- Test network error message
**Component Tests:**
3. **`LoadingOverlay.test.tsx`**
- Test renders when isLoading=true
- Test doesn't render when isLoading=false
- Test displays correct message
- Test animation
4. **`CountdownRedirect.test.tsx`**
- Test countdown decrements every second
- Test onComplete called when countdown reaches 0
- Test manual redirect button works
- Test cleanup on unmount
**Integration Tests (Recommended):**
5. **Payment Flow Integration Test**
- Test full VA generation flow with loading states
- Test error handling and recovery
- Test success flow with auto-redirect
**Manual Testing Checklist:**
- [ ] Click VA generation button multiple times rapidly → Only one request sent
- [ ] Loading overlay appears during VA generation
- [ ] Error 409 shows user-friendly message with "Lihat Kode" button
- [ ] Error 404 shows user-friendly message with "Coba Lagi" button
- [ ] Payment success page shows countdown timer
- [ ] Auto-redirect works after 5 seconds
- [ ] Manual "Kembali Sekarang" button works immediately
- [ ] All flows work on mobile devices (Chrome, Safari)
- [ ] All text is in Bahasa Indonesia
- [ ] Keyboard navigation works
- [ ] Screen reader announces loading states and countdown
### Acceptance Criteria
**Story 1: Prevent Duplicate VA Generation & Improve Feedback**
**AC1: Button Disable During Processing**
- GIVEN user clicks "Generate VA" button
- WHEN API request is in progress
- THEN button is disabled and shows loading spinner
- AND user cannot click button again
- AND loading overlay appears with message "Sedang membuat kode pembayaran..."
**AC2: Debounce Prevents Rapid Clicks**
- GIVEN user clicks "Generate VA" button multiple times within 500ms
- WHEN debounce is active
- THEN only one API request is sent
- AND subsequent clicks within 500ms are ignored
**AC3: User-Friendly Error Messages**
- GIVEN VA generation fails with HTTP 409
- WHEN error is displayed to user
- THEN message shows "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat"
- AND "Lihat Kode Pembayaran" button is displayed
- AND clicking button navigates to existing VA view
**AC4: Error Recovery Options**
- GIVEN VA generation fails with any error
- WHEN error is displayed to user
- THEN "Coba Lagi" button is displayed
- AND clicking button retries VA generation
- AND "Kembali" button is displayed
- AND clicking button returns to payment method selection
**AC5: Loading Overlay Prevents Interaction**
- GIVEN VA generation is in progress
- WHEN loading overlay is displayed
- THEN user cannot interact with page content
- AND overlay shows clear message in Bahasa Indonesia
- AND overlay is responsive on mobile devices
**Story 2: Improve Post-Payment UX**
**AC6: Countdown Timer Display**
- GIVEN user completes payment successfully
- WHEN payment success page loads
- THEN countdown timer shows "Anda akan diarahkan ke dashboard dalam 5 detik..."
- AND countdown decrements every second (5, 4, 3, 2, 1)
- AND timer is visible and readable on mobile devices
**AC7: Auto-Redirect After Countdown**
- GIVEN countdown timer reaches 0
- WHEN timer completes
- THEN user is automatically redirected to dashboard/home page
- AND redirect happens smoothly without errors
**AC8: Manual Redirect Button**
- GIVEN countdown timer is active
- WHEN user clicks "Kembali Sekarang" button
- THEN user is immediately redirected to dashboard/home page
- AND countdown is cancelled
**AC9: Mobile-First Responsive Design**
- GIVEN user accesses payment flow on mobile device
- WHEN any new UI element is displayed
- THEN all elements are properly sized and positioned for mobile
- AND all text is readable without zooming
- AND all buttons are easily tappable (minimum 44x44px)
**AC10: Bahasa Indonesia Throughout**
- GIVEN user interacts with any new UI element
- WHEN text is displayed
- THEN all text is in Bahasa Indonesia
- AND language is appropriate for non-tech-savvy users (ibu-ibu awam)
- AND no technical jargon is used
---
## Developer Resources
### File Paths Reference
**New Files to Create:**
- `src/components/LoadingOverlay.tsx`
- `src/components/CountdownRedirect.tsx`
- `src/lib/errorMessages.ts`
- `src/lib/debounce.ts`
- `src/components/__tests__/LoadingOverlay.test.tsx`
- `src/components/__tests__/CountdownRedirect.test.tsx`
- `src/lib/__tests__/errorMessages.test.ts`
- `src/lib/__tests__/debounce.test.ts`
**Existing Files to Modify:**
- `src/features/payment/components/PaymentMethodSelector.tsx` (or equivalent)
- `src/features/payment/pages/PaymentSuccessPage.tsx` (or equivalent)
- `src/features/payment/hooks/useGenerateVA.ts` (or create if doesn't exist)
**Configuration Files (No Changes):**
- `package.json` - No new dependencies
- `vite.config.ts` - No changes
- `tailwind.config.ts` - No changes
- `tsconfig.json` - No changes
### Key Code Locations
**Payment Feature Module:**
- **Location:** `src/features/payment/` (assumed)
- **Key Components:**
- Payment method selection component (contains VA generation button)
- Payment success/status page component
- **Key Hooks:**
- VA generation hook (may need to create)
- **Key Services:**
- Midtrans API service (`src/services/midtrans.ts` or similar)
**Shared Components:**
- **Location:** `src/components/`
- **New Components:**
- LoadingOverlay
- CountdownRedirect
**Utilities:**
- **Location:** `src/lib/`
- **New Utilities:**
- errorMessages
- debounce
**Important Functions to Locate:**
1. VA generation API call function
2. Payment success navigation logic
3. Error handling in payment flow
4. Existing loading state management (if any)
### Testing Locations
**Unit Tests:**
- `src/lib/__tests__/` - Utility function tests
- `debounce.test.ts`
- `errorMessages.test.ts`
**Component Tests:**
- `src/components/__tests__/` - Component tests
- `LoadingOverlay.test.tsx`
- `CountdownRedirect.test.tsx`
**Integration Tests (Recommended):**
- `src/features/payment/__tests__/` - Payment flow integration tests
- `PaymentFlow.integration.test.tsx`
**Test Configuration:**
- `vitest.config.ts` or `jest.config.js` (if exists)
- Test setup file (if exists)
### Documentation to Update
**Code Documentation:**
- [ ] Add JSDoc comments to all new functions and components
- [ ] Add inline comments for complex logic (debounce, countdown timer)
- [ ] Add TypeScript interfaces with descriptions
**Project Documentation:**
- [ ] Update `README.md` with new features (optional)
- [ ] Update API documentation if error responses changed (unlikely)
- [ ] Add this tech-spec to `docs/` folder for future reference
**User Documentation (Optional):**
- [ ] Update user guide with new payment flow behavior
- [ ] Update FAQ with error message explanations
- [ ] Create internal documentation for support team
---
## UX/UI Considerations
**UI Components Affected:**
**Story 1:**
1. **VA Generation Button**
- MODIFY: Add disabled state styling
- MODIFY: Add loading spinner
- ENSURE: Button remains accessible (keyboard, screen reader)
2. **Loading Overlay** (NEW)
- CREATE: Full-screen overlay component
- DESIGN: Semi-transparent backdrop, centered content
- ANIMATION: Fade in/out with Framer Motion
- MOBILE: Full viewport coverage, readable text
3. **Error Display** (MODIFY)
- MODIFY: Replace technical errors with user-friendly messages
- ADD: Recovery action buttons
- DESIGN: Clear, non-threatening, helpful tone
**Story 2:**
1. **Payment Success Page**
- ADD: Countdown timer component
- ADD: Manual redirect button
- MODIFY: Layout to accommodate new elements
- MOBILE: Ensure all elements visible without scrolling
**UX Flow Changes:**
**Current Flow:**
1. User selects payment method
2. User clicks "Generate VA"
3. (3-5 second delay with no feedback)
4. VA displayed OR error shown
5. After payment: Success page with no clear next step
6. User presses back → Invalid state
**New Flow:**
1. User selects payment method
2. User clicks "Generate VA"
3. **Button disables, loading overlay appears**
4. **"Sedang membuat kode pembayaran..." message shown**
5. VA displayed OR **user-friendly error with recovery options**
6. After payment: Success page with **countdown timer**
7. **Auto-redirect after 5 seconds** OR **user clicks "Kembali Sekarang"**
8. User lands on dashboard (no back button confusion)
**Visual/Interaction Patterns:**
**Loading States:**
- Spinner: Use existing spinner component or create simple CSS spinner
- Color: Match primary brand color
- Size: Appropriate for mobile (not too small)
- Animation: Smooth, not distracting
**Error States:**
- Color: Warning yellow or soft red (not harsh)
- Icon: Information icon (not scary error icon)
- Tone: Helpful, not blaming user
- Actions: Clear buttons with action verbs
**Success States:**
- Color: Success green
- Icon: Checkmark
- Tone: Positive, reassuring
- Actions: Clear next step
**Responsive Design:**
- Mobile-first: Design for 320px width minimum
- Breakpoints: Use TailwindCSS defaults (sm: 640px, md: 768px, lg: 1024px)
- Touch targets: Minimum 44x44px for buttons
- Text size: Minimum 16px for body text (prevents zoom on iOS)
**Accessibility:**
**Keyboard Navigation:**
- All interactive elements focusable
- Logical tab order
- Visible focus indicators
- ESC key to dismiss overlay (optional)
**Screen Reader:**
- ARIA labels for loading states
- ARIA live regions for countdown timer
- Descriptive button labels
- Alt text for icons
**Color Contrast:**
- WCAG AA compliance minimum
- Text on overlay readable
- Error messages high contrast
**User Feedback:**
**Loading Feedback:**
- Visual: Spinner + overlay
- Text: Clear message in Bahasa Indonesia
- Duration: Show immediately, hide on response
**Error Feedback:**
- Visual: Error message + icon
- Text: User-friendly explanation + recovery action
- Persistence: Stay until user takes action
**Success Feedback:**
- Visual: Success message + checkmark
- Text: Countdown timer with destination
- Action: Auto-redirect + manual option
---
## Testing Approach
**Test Framework:** Vitest (recommended for Vite) or Jest
**Testing Pyramid:**
- 70% Unit Tests (utilities, hooks)
- 20% Component Tests (UI components)
- 10% Integration Tests (full flows)
**Unit Tests:**
1. **`debounce.test.ts`**
```typescript
describe('debounce', () => {
it('delays function execution', () => {
// Test implementation
});
it('only executes once for multiple rapid calls', () => {
// Test implementation
});
it('clears timeout on cleanup', () => {
// Test implementation
});
});
```
2. **`errorMessages.test.ts`**
```typescript
describe('mapErrorToUserMessage', () => {
it('maps HTTP 409 to user-friendly message', () => {
// Test implementation
});
it('maps HTTP 404 to user-friendly message', () => {
// Test implementation
});
it('returns default message for unknown errors', () => {
// Test implementation
});
});
```
**Component Tests:**
3. **`LoadingOverlay.test.tsx`**
```typescript
describe('LoadingOverlay', () => {
it('renders when isLoading is true', () => {
// Test implementation
});
it('does not render when isLoading is false', () => {
// Test implementation
});
it('displays the provided message', () => {
// Test implementation
});
});
```
4. **`CountdownRedirect.test.tsx`**
```typescript
describe('CountdownRedirect', () => {
it('decrements countdown every second', () => {
// Test implementation with fake timers
});
it('calls onComplete when countdown reaches 0', () => {
// Test implementation
});
it('redirects immediately when button clicked', () => {
// Test implementation
});
});
```
**Integration Tests (Recommended):**
5. **Payment Flow Integration Test**
```typescript
describe('Payment Flow', () => {
it('prevents duplicate VA generation', () => {
// Test full flow with multiple clicks
});
it('shows user-friendly error on 409', () => {
// Test error handling
});
it('auto-redirects after payment success', () => {
// Test success flow
});
});
```
**Coverage Goals:**
- Overall: 80%+
- New utilities: 100%
- New components: 90%+
- Modified components: 80%+
**Manual Testing Checklist:**
- [ ] Desktop Chrome
- [ ] Desktop Firefox
- [ ] Desktop Safari
- [ ] Mobile Chrome (Android)
- [ ] Mobile Safari (iOS)
- [ ] Tablet (iPad)
- [ ] Slow 3G network simulation
- [ ] Offline scenario
- [ ] Keyboard-only navigation
- [ ] Screen reader (NVDA/JAWS/VoiceOver)
---
## Deployment Strategy
### Deployment Steps
**Pre-Deployment:**
1. **Code Review**
- Create pull request from feature branch
- Request review from team lead
- Address all review comments
- Ensure all tests pass
2. **QA Testing**
- Deploy to staging environment
- QA team tests all acceptance criteria
- Fix any bugs found
- Re-test until all criteria pass
3. **Merge to Main**
```bash
git checkout main
git merge feature/payment-ux-improvements
git push origin main
```
**Deployment to Production:**
4. **Build Production Bundle**
```bash
npm run build
```
5. **Deploy Frontend**
- Upload `dist/` folder to hosting (Vercel, Netlify, or custom server)
- Verify environment variables are set
- Test production build locally with `npm run preview`
6. **Deploy Backend (if changes)**
- No backend changes in Phase 1
- Backend deployment not required
7. **Verify Deployment**
- Test VA generation on production
- Test error scenarios
- Test payment success flow
- Monitor for errors
**Post-Deployment:**
8. **Monitor**
- Watch error logs for 24 hours
- Monitor user behavior analytics
- Check support ticket volume
- Gather user feedback
9. **Iterate**
- Address any issues found
- Plan Phase 2 improvements based on data
### Rollback Plan
**If Critical Issues Found:**
1. **Immediate Rollback**
```bash
# Revert to previous commit
git revert HEAD
git push origin main
# Rebuild and redeploy
npm run build
# Deploy dist/ folder
```
2. **Verify Rollback**
- Test that old behavior is restored
- Confirm no errors in logs
- Notify users if necessary
3. **Post-Mortem**
- Identify what went wrong
- Fix issues in feature branch
- Re-test thoroughly
- Re-deploy when ready
**Rollback Triggers:**
- Critical bug preventing payments
- Widespread errors (>5% of transactions)
- Security vulnerability discovered
- Performance degradation (>2s load time increase)
### Monitoring
**Metrics to Monitor:**
**User Behavior:**
- VA generation success rate (target: >95%)
- Error rate (target: <5%)
- Payment completion rate (target: increase by 10%+)
- Time on payment success page (target: decrease by 50%)
- Back button usage after payment (target: decrease by 80%)
**Technical Metrics:**
- API response time (target: <3 seconds)
- Frontend load time (target: <2 seconds)
- Error logs (target: <1% error rate)
- 409 error frequency (target: near zero)
**Business Metrics:**
- Abandoned transaction rate (target: decrease by 20%+)
- Support ticket volume (target: decrease by 30%+)
- User satisfaction score (target: increase)
**Monitoring Tools:**
- Google Analytics for user behavior
- Sentry or similar for error tracking
- Server logs for API monitoring
- User feedback surveys
**Alert Thresholds:**
- Error rate >10% → Immediate alert
- API response time >5s → Warning alert
- Payment success rate <90% Critical alert
---
**End of Technical Specification**
This tech-spec provides a comprehensive guide for implementing Phase 1 Quick Wins Bundle (2 stories, 5 solutions) to improve payment flow UX for non-tech-savvy users in a brownfield Midtrans payment application.