Skip to content

ozmenfurkan/vibe-coding-craftgate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

17 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Craftgate Payment System - Full Stack

Production-ready payment system with Craftgate integration, built with DDD Architecture (Backend) and Modern React (Frontend).

πŸ—οΈ Architecture Overview

πŸ“¦ Project Root
β”œβ”€β”€ πŸ”™ backend/          # Spring Boot + DDD
β”‚   β”œβ”€β”€ domain/         # Pure business logic
β”‚   β”œβ”€β”€ application/    # Use cases
β”‚   β”œβ”€β”€ infrastructure/ # Craftgate, JPA
β”‚   └── interface/      # REST API
β”‚
└── 🎨 frontend/         # React + TypeScript
    β”œβ”€β”€ components/     # UI Components
    β”œβ”€β”€ hooks/          # Custom hooks
    β”œβ”€β”€ lib/            # Utilities
    └── types/          # TypeScript types

✨ Features

Backend (Spring Boot)

  • βœ… DDD Architecture - Clean separation of concerns
  • βœ… Multi-Gateway Support - Akbank POS & Craftgate integration
  • βœ… User Points System - Loyalty points management
  • βœ… Idempotency - Duplicate payment prevention
  • βœ… PCI-DSS Compliant - Secure card handling
  • βœ… BigDecimal - No floating-point errors
  • βœ… PostgreSQL - Production-ready database
  • βœ… Flyway Migration - Database versioning
  • βœ… Global Error Handling - RFC 7807 Problem Details

Frontend (React)

  • βœ… TypeScript Strict Mode - Full type safety
  • βœ… Zod Validation - Luhn algorithm for cards
  • βœ… Auto Card Formatting - Spaces every 4 digits
  • βœ… TanStack Query - Server state management
  • βœ… React Hook Form - Performant forms
  • βœ… TailwindCSS - Modern, responsive UI
  • βœ… Currency Formatting - Intl.NumberFormat

πŸš€ Quick Start

Prerequisites

  • Java 17+
  • Node.js 18+
  • PostgreSQL 14+
  • Maven 3.8+
  • Craftgate Account (Sandbox)

1. Database Setup

# Create database
psql -U postgres
CREATE DATABASE payment_db_dev;
\q

2. Backend Setup

cd backend

# Configure environment
cp .env.example .env
# Edit .env with your Craftgate credentials

# Run application
mvn clean install
mvn spring-boot:run -Dspring-boot.run.profiles=dev

Backend will start on http://localhost:8080

3. Frontend Setup

cd frontend

# Install dependencies
npm install

# Configure environment
cp .env.example .env

# Start development server
npm run dev

Frontend will start on http://localhost:3000

πŸ§ͺ Testing

Test Card Numbers (Craftgate Sandbox)

βœ… Success:    5400010000000004
❌ Decline:    5400010000000012
πŸ”’ 3D Secure:  5400010000000020

Test Payment

  1. Open http://localhost:3000
  2. Enter amount and select currency
  3. Use test card: 5400010000000004
  4. Expire: 12/2030, CVV: 123
  5. Click "Pay Now"

πŸ“‘ API Documentation

Payment API

Create Payment

POST /api/v1/payments
Content-Type: application/json
Idempotency-Key: unique-key-123

{
  "conversationId": "ORDER-12345",
  "amount": 100.50,
  "currency": "TRY",
  "buyerId": "buyer-123",
  "cardInfo": {
    "cardHolderName": "JOHN DOE",
    "cardNumber": "5400010000000004",
    "expireMonth": "12",
    "expireYear": "2030",
    "cvv": "123"
  }
}

Response (Success)

{
  "id": "uuid",
  "conversationId": "ORDER-12345",
  "amount": 100.50,
  "currency": "TRY",
  "status": "SUCCESS",
  "buyerId": "buyer-123",
  "createdAt": "2024-01-15T10:30:00",
  "externalPaymentId": "12345678"
}

Response (Failed)

{
  "id": "uuid",
  "conversationId": "ORDER-12345",
  "amount": 100.50,
  "currency": "TRY",
  "status": "FAILED",
  "buyerId": "buyer-123",
  "createdAt": "2024-01-15T10:30:00",
  "errorCode": "INSUFFICIENT_FUNDS",
  "errorMessage": "Insufficient funds"
}

User Points API

Get User Points

GET /api/v1/user-points/{userId}

Response:

{
  "userId": "user123",
  "totalPoints": 150.00,
  "availablePoints": 120.00,
  "lockedPoints": 30.00,
  "createdAt": "2024-01-15T10:30:00",
  "lastUpdated": "2024-01-20T14:45:00"
}

Earn Points

POST /api/v1/user-points/earn
Content-Type: application/json

{
  "userId": "user123",
  "points": 50.00,
  "reason": "Payment completed successfully"
}

Spend Points

POST /api/v1/user-points/spend
Content-Type: application/json

{
  "userId": "user123",
  "points": 20.00,
  "reason": "Used in payment"
}

Check Points Availability

GET /api/v1/user-points/{userId}/check/{requiredPoints}

Response: true or false

πŸ“š Detailed Documentation: See USER_POINTS_API.md

πŸ§ͺ Testing

Backend includes comprehensive test coverage:

  • βœ… Unit Tests (UT): Domain logic, business rules (95% coverage)
  • βœ… Integration Tests (IT): Repository, database with TestContainers
  • βœ… Functional Tests (FT): End-to-end API tests with real PostgreSQL

Running Tests

# Run all tests
mvn clean test

# Run specific test types
mvn test -Dtest="*Test"   # Unit tests only
mvn test -Dtest="*IT"     # Integration tests only
mvn test -Dtest="*FT"     # Functional tests only

# Run with coverage report
mvn clean verify
# Report: target/site/jacoco/index.html

Test Examples

Domain Layer - Unit Test:

@Test
@DisplayName("Should earn points successfully")
void shouldEarnPointsSuccessfully() {
    UserPoints userPoints = new UserPoints("user123");
    userPoints.earnPoints(new BigDecimal("50.00"));
    
    assertThat(userPoints.getTotalPoints())
        .isEqualByComparingTo(new BigDecimal("50.00"));
}

Infrastructure Layer - Integration Test with TestContainers:

@DataJpaTest
@Testcontainers
@DisplayName("JPA UserPoints Repository Integration Tests")
class JpaUserPointsRepositoryIT {
    @Container
    static PostgreSQLContainer<?> postgres = 
        new PostgreSQLContainer<>("postgres:14-alpine");
    
    // Tests with real database...
}

Interfaces Layer - Functional Test:

@Test
@DisplayName("Should get user points successfully")
void shouldGetUserPointsSuccessfully() {
    given()
    .when()
        .get("/api/v1/user-points/user123")
    .then()
        .statusCode(200)
        .body("userId", equalTo("user123"));
}

πŸ“š Testing Rules: See .cursor/rules/06-backend-testing/RULE.mdc

πŸ”’ Security Rules

❌ NEVER DO THIS:

// ❌ Don't log sensitive data
logger.info("Card: " + cardNumber);  // WRONG!

// ❌ Don't use float/double for money
double amount = 100.50;  // WRONG!

// ❌ Don't trust frontend input
String amount = request.getAmount();  // WRONG! Validate!

βœ… DO THIS INSTEAD:

// βœ… Log only safe information
logger.info("Processing payment. ConversationId: {}", conversationId);

// βœ… Use BigDecimal for money
BigDecimal amount = new BigDecimal("100.50");

// βœ… Validate everything at API boundary
@Valid @RequestBody CreatePaymentRequest request

πŸ’° Money Handling

Backend (Java)

// βœ… CORRECT
Money money = new Money(new BigDecimal("100.50"), Currency.TRY);

// ❌ WRONG
double amount = 100.50;  // Causes rounding errors!

Frontend (TypeScript)

// βœ… CORRECT
formatCurrency(100.50, 'TRY')  // "β‚Ί100,50"

// ❌ WRONG
`${amount} TL`  // Don't manipulate strings!

πŸ“Š Project Statistics

Backend:
  - 30+ Java classes
  - 4 DDD layers
  - 100% type-safe
  - Zero tolerance for sensitive data logging

Frontend:
  - 15+ React components
  - Full TypeScript strict mode
  - Luhn validation
  - Auto card formatting
  - Currency formatting with Intl API

🎯 Multi-Gateway Support

Supported Payment Providers

  • βœ… Craftgate - Turkish payment gateway
  • βœ… Akbank Sanal POS - Real bank integration with 3D Secure
  • βž• Easy to add more!

Example: Payment with Akbank

curl -X POST http://localhost:8080/api/v1/payments \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "AKBANK",
    "amount": 100.50,
    "currency": "TRY",
    ...
  }'

🏭 Production Deployment

Backend

# Build
mvn clean package -DskipTests

# Run with production profile
java -jar payment-interfaces/target/payment-interfaces-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod

Frontend

# Build
npm run build

# Deploy dist/ folder to CDN or web server

πŸ“š Documentation

  • Backend: See backend/README.md
  • Frontend: See frontend/README.md
  • API Docs: See docs/api-specs.md (if exists)
  • DDD Rules: See 02-backend-ddd/RULE.md
  • Security Rules: See 01-global-security/RULE.md

πŸ”„ Development Workflow

1. Backend Changes

cd backend
# Make changes
mvn clean install
mvn spring-boot:run -Dspring-boot.run.profiles=dev

2. Frontend Changes

cd frontend
# Make changes
npm run dev
# Changes hot-reload automatically

3. Full Stack Testing

  1. Start backend (port 8080)
  2. Start frontend (port 3000)
  3. Frontend proxies API calls to backend
  4. Test payment flow end-to-end

🐳 Docker Support

# Start PostgreSQL
docker-compose up -d postgres

# Or start everything
docker-compose up -d

🀝 Contributing

Rules

  1. βœ… Code & commits in English
  2. βœ… Turkish comments only for complex business logic
  3. βœ… Never log sensitive data
  4. βœ… Use BigDecimal for money (backend)
  5. βœ… Use Intl.NumberFormat for currency (frontend)
  6. βœ… Follow DDD layers (backend)
  7. βœ… Feature-based folders (frontend)
  8. βœ… No any type (TypeScript)

Before Committing

# Backend
mvn clean test
mvn clean verify

# Frontend
npm run type-check
npm run lint

πŸ“„ License

Proprietary - All rights reserved

πŸ†˜ Support

Common Issues

Issue: Backend won't start

  • Solution: Check if PostgreSQL is running and database exists

Issue: Frontend can't connect to backend

  • Solution: Ensure backend is running on port 8080

Issue: Payment fails with "CRAFTGATE_ERROR"

  • Solution: Verify Craftgate API keys in .env

Issue: CORS errors

  • Solution: Frontend dev server has proxy configured, use it

Contact

For issues related to:

  • Architecture: Review DDD rules in /rules
  • Security: Review security rules in /rules
  • Craftgate API: See Craftgate Docs

Built with ❀️ using DDD, Spring Boot, React, and TypeScript

πŸ”’ PCI-DSS Compliant | βœ“ Luhn Validated | πŸ’³ Idempotent | πŸš€ Production Ready

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages