Midtrans-Middleware/docs/tech-spec.md

40 KiB

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

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)

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

// 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

// 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

// 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):

# 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:

# 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

    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)

  1. 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)

  1. 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)

  1. Manual testing

    • Test duplicate click prevention
    • Test loading overlay display
    • Test error messages for different error types
    • Test recovery buttons
    • Test on mobile devices
  2. 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)

  1. 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)

  1. Manual testing

    • Test countdown timer accuracy
    • Test auto-redirect functionality
    • Test manual redirect button
    • Test on mobile devices
    • Verify no back button issues
  2. 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:

  1. LoadingOverlay.test.tsx

    • Test renders when isLoading=true
    • Test doesn't render when isLoading=false
    • Test displays correct message
    • Test animation
  2. 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):

  1. 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

    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

    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:

  1. LoadingOverlay.test.tsx

    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
      });
    });
    
  2. CountdownRedirect.test.tsx

    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):

  1. Payment Flow Integration Test
    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

    git checkout main
    git merge feature/payment-ux-improvements
    git push origin main
    

Deployment to Production:

  1. Build Production Bundle

    npm run build
    
  2. 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
  3. Deploy Backend (if changes)

    • No backend changes in Phase 1
    • Backend deployment not required
  4. Verify Deployment

    • Test VA generation on production
    • Test error scenarios
    • Test payment success flow
    • Monitor for errors

Post-Deployment:

  1. Monitor

    • Watch error logs for 24 hours
    • Monitor user behavior analytics
    • Check support ticket volume
    • Gather user feedback
  2. Iterate

    • Address any issues found
    • Plan Phase 2 improvements based on data

Rollback Plan

If Critical Issues Found:

  1. Immediate Rollback

    # 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.