Files
payguard-poc/EXPLAIN.md
T
John Patrick TeruelandCopilot 215c15a494 Add comprehensive system architecture documentation with Mermaid diagrams
- Detailed explanation of all 5 Docker containers
- Data flow diagrams (Mermaid) for complete transaction journey
- Network architecture and startup sequence visualizations
- Container dependencies, communication paths, and resource usage
- Happy path and fraud detection flow examples
- Service name resolution and listener configuration explanations

Co-authored-by: Copilot <[email protected]>
2026-04-24 21:37:32 +08:00

22 KiB

System Architecture Explanation - PayGuard Fraud Detection

Docker Containers Overview

The PayGuard fraud detection system uses 5 Docker containers working together on a shared Docker network.

graph TB
    subgraph docker["Docker Network: payguard-network"]
        ZK["🔹 Zookeeper<br/>Port: 2181"]
        KAFKA["🔹 Kafka<br/>Port: 29092/9092"]
        REDIS["🔹 Redis<br/>Port: 6379"]
        API["🔹 API<br/>Port: 8000"]
        FE["🔹 Frontend<br/>Port: 3000"]
    end
    
    ZK -->|coordinates| KAFKA
    KAFKA -->|stores messages| REDIS
    API -->|publishes to| KAFKA
    FE -->|calls| API
    REDIS -->|stores results| REDIS
    
    style docker fill:#f0f0f0
    style ZK fill:#4CAF50
    style KAFKA fill:#2196F3
    style REDIS fill:#FF9800
    style API fill:#9C27B0
    style FE fill:#F44336

Container 1: Zookeeper

Overview

Coordination Service for Kafka - Manages Kafka broker state and configuration

Configuration

Image: confluentinc/cp-zookeeper:7.5.0
Port: 2181
Network: payguard-network
Environment:
  ZOOKEEPER_CLIENT_PORT: 2181
  ZOOKEEPER_TICK_TIME: 2000

Purpose in This Project

  • Manages Kafka State: Tracks broker health, configuration, and metadata
  • Leader Election: Ensures cluster stability
  • Configuration Storage: Maintains topic and permission info
  • Broker Discovery: Keeps track of which brokers are available

Responsibilities

graph LR
    ZK["Zookeeper<br/>(Port 2181)"]
    
    ZK -->|Monitors| BH["Broker Health"]
    ZK -->|Manages| TC["Topic Config"]
    ZK -->|Tracks| PA["Partition<br/>Assignment"]
    ZK -->|Handles| LE["Leader<br/>Election"]
    
    style ZK fill:#4CAF50
    style BH fill:#E8F5E9
    style TC fill:#E8F5E9
    style PA fill:#E8F5E9
    style LE fill:#E8F5E9

Why It's Needed

  • Kafka requires Zookeeper to function
  • Without Zookeeper, Kafka can't coordinate
  • Single instance fine for development
  • Production would use Zookeeper cluster for HA

Startup

  • Starts first (no dependencies)
  • Other containers wait for it to be ready

Container 2: Kafka

Overview

Asynchronous Message Broker - Queues transactions for processing

Configuration

Image: confluentinc/cp-kafka:7.5.0
Ports:
  - 9092:9092        (external: localhost:9092)
  - 29092 (internal) (inside Docker: kafka:29092)
Network: payguard-network
Broker ID: 1
Topic: transactions (auto-created)

Message Flow Through Kafka

sequenceDiagram
    actor User as User<br/>(Browser)
    participant FE as Frontend<br/>:3000
    participant API as API<br/>:8000
    participant KAFKA as Kafka<br/>:29092
    participant CONSUMER as Consumer<br/>(Your Mac)
    participant REDIS as Redis<br/>:6379

    User->>FE: 1. Submit Transaction
    FE->>API: 2. POST /transaction
    API->>KAFKA: 3. Publish to "transactions"
    API-->>FE: 4. Return 200 OK (immediately)
    FE-->>User: 5. "Transaction accepted!"
    
    CONSUMER->>KAFKA: 6. Subscribe to topic
    KAFKA->>CONSUMER: 7. Deliver message
    CONSUMER->>CONSUMER: 8. ML Processing (6 steps)
    CONSUMER->>REDIS: 9. Store result
    CONSUMER->>CONSUMER: 10. Done

Data Structure in Kafka

Topic: "transactions"
Message: {
  "user_id": "user_123",
  "amount": 75.50,
  "merchant": "Starbucks Coffee",
  "description": "Morning coffee",
  "currency": "USD",
  "timestamp": "2026-04-24T21:30:00Z"
}

Purpose in This Project

  • Decouples API from Consumer: API doesn't wait for fraud detection
  • Handles High Throughput: Can queue thousands of transactions
  • Persistence: Transactions survive crashes
  • Scalability: Multiple consumers can process same topic

Listener Configuration

graph TB
    CLIENT1["API Container<br/>(inside Docker)"]
    CLIENT2["Consumer<br/>(on Mac)"]
    KAFKA["Kafka Broker"]
    
    CLIENT1 -->|Uses:<br/>kafka:29092| INTERNAL["PLAINTEXT<br/>Listener:29092"]
    CLIENT2 -->|Uses:<br/>localhost:9092| EXTERNAL["PLAINTEXT_HOST<br/>Listener:9092"]
    
    INTERNAL --> KAFKA
    EXTERNAL --> KAFKA
    
    style KAFKA fill:#2196F3
    style CLIENT1 fill:#9C27B0
    style CLIENT2 fill:#FF9800
    style INTERNAL fill:#81C784
    style EXTERNAL fill:#81C784

Common Issues

  • API error 503: Kafka not ready when API starts
  • Consumer can't connect: Using wrong address (kafka:29092 from Mac won't work)
  • Messages not persisting: Volume issue or broker crash

Container 3: Redis

Overview

In-Memory Cache & Result Storage - Stores transaction fraud detection results

Configuration

Image: redis:7.2-alpine
Port: 6379
Network: payguard-network
Volume: redis_data
Health Check: redis-cli ping

Data Flow to Redis

graph LR
    CONSUMER["Consumer<br/>(Your Mac)"]
    ML["ML Pipeline<br/>(6 Steps)"]
    RESULT["Result:<br/>fraud_score: 0.72<br/>decision: FRAUD_DETECTED"]
    REDIS["Redis<br/>:6379"]
    STORE["Key: transaction:txn_123<br/>Value: JSON Result"]
    
    CONSUMER -->|Process| ML
    ML -->|Generate| RESULT
    RESULT -->|Store in| REDIS
    REDIS -->|Persist| STORE
    
    style CONSUMER fill:#FF9800
    style ML fill:#FF9800
    style RESULT fill:#FFE0B2
    style REDIS fill:#FF9800
    style STORE fill:#FFE0B2

Result Data Structure

Key: transaction:txn_abc123

Value: {
  "transaction_id": "txn_abc123",
  "user_id": "user_xyz",
  "amount": 75.50,
  "merchant": "Starbucks Coffee",
  "fraud_score": 0.12,
  "decision": "APPROVED",
  "risk_level": "LOW",
  "timestamp": "2026-04-24T21:30:00Z",
  "features": {
    "amount_std_dev": 0.8,
    "velocity": 0.1,
    "geographic_score": 0.0,
    "time_of_day": 0.05
  }
}

Use Cases in System

graph TB
    CONSUMER["Consumer Writes"]
    API_READ["API Reads<br/>(optional)"]
    SESSION["Session Cache<br/>(optional)"]
    REDIS["Redis"]
    
    CONSUMER -->|Store Result| REDIS
    API_READ -->|Get Result| REDIS
    SESSION -->|Cache Data| REDIS
    
    style REDIS fill:#FF9800
    style CONSUMER fill:#4CAF50
    style API_READ fill:#2196F3
    style SESSION fill:#9C27B0

Why It's Needed

  • Performance: Instant result lookups (microseconds vs milliseconds)
  • Scalability: Multiple API instances can share results
  • TTL Support: Auto-expire old transactions
  • No Database: Simpler architecture for POC
  • Pub/Sub: Can notify about suspicious transactions

Persistence

  • Data persists to /data volume
  • Survives container restart
  • RDB snapshots and AOF (append-only file)

Container 4: API (FastAPI)

Overview

Transaction Intake & Validation Engine - REST API for transaction submission

Configuration

Build:
  context: .
  dockerfile: api/Dockerfile
Base Image: python:3.11-slim
Port: 8000
Network: payguard-network
Framework: FastAPI
Language: Python

Complete Transaction Flow Through API

sequenceDiagram
    actor User
    participant Browser as Browser<br/>localhost:3000
    participant API as API<br/>localhost:8000
    participant JWT as JWT<br/>Engine
    participant KAFKA as Kafka<br/>kafka:29092
    
    User->>Browser: Click "Generate Token"
    Browser->>API: POST /token?user_id=user_123
    API->>JWT: Create JWT (HS256)
    JWT-->>API: eyJh...
    API-->>Browser: {token, type: bearer}
    Browser-->>User: Display Token
    
    User->>Browser: Fill transaction form
    User->>Browser: Click Submit
    Browser->>API: POST /transaction<br/>Header: Authorization: Bearer eyJh...
    API->>JWT: Validate JWT
    JWT-->>API: Valid ✓
    API->>API: Validate schema
    API->>KAFKA: Publish message
    KAFKA-->>API: OK
    API-->>Browser: 200 OK
    API-->>Browser: {status: accepted, txn_id}
    Browser-->>User: "Transaction accepted!"

API Endpoints

graph TB
    FE["Frontend"]
    
    FE -->|POST /token<br/>?user_id=X| TOKEN["🔑 Token Generation<br/>Returns: JWT Token"]
    FE -->|POST /transaction<br/>+ JWT Header| TXN["💳 Transaction Submission<br/>Validates & Publishes to Kafka"]
    FE -->|GET /health| HEALTH["❤️ Health Check<br/>Returns: {status: healthy}"]
    
    style FE fill:#F44336
    style TOKEN fill:#4CAF50
    style TXN fill:#2196F3
    style HEALTH fill:#FF9800

Key Features

  • ✅ JWT Authentication: HS256 algorithm
  • ✅ CORS Enabled: Allows http://localhost:3000
  • ✅ Input Validation: Pydantic models
  • ✅ Async Publishing: Doesn't wait for consumer
  • ✅ Error Handling: 503 if Kafka unavailable
  • ✅ Logging: Structured JSON logs

Startup Dependencies

graph TD
    DOCKER["docker compose up"]
    DOCKER -->|Wait| KAFKA_HEALTH["Kafka Healthy?"]
    DOCKER -->|Wait| REDIS_HEALTH["Redis Healthy?"]
    KAFKA_HEALTH -->|Yes| API_START["Initialize API"]
    REDIS_HEALTH -->|Yes| API_START
    API_START -->|Create routes| ROUTES["Setup endpoints"]
    ROUTES -->|Setup| CORS["CORS middleware"]
    CORS -->|Start| UVICORN["Uvicorn on :8000"]
    UVICORN -->|Ready| DONE["✓ API Ready"]
    
    style DOCKER fill:#2196F3
    style KAFKA_HEALTH fill:#FF9800
    style REDIS_HEALTH fill:#FF9800
    style API_START fill:#4CAF50
    style DONE fill:#4CAF50

Container 5: Frontend (React)

Overview

User Interface - React web application for transaction submission

Configuration

Build:
  context: ./frontend
  dockerfile: Dockerfile
Base: node:18-alpine
Port: 3000
Network: payguard-network
Framework: React 18 + TypeScript
Build Tool: Vite
Server: serve

User Interaction Flow

graph TD
    USER["👤 User<br/>(on Mac)"]
    BROWSER["🌐 Browser<br/>localhost:3000"]
    FE["⚛️ React Frontend<br/>(in Docker)"]
    API["🔌 API<br/>:8000"]
    
    USER -->|Open| BROWSER
    BROWSER -->|Renders| FE
    USER -->|Click Generate| FE
    FE -->|POST /token| API
    API -->|Return JWT| FE
    FE -->|Display Token| USER
    USER -->|Fill Form| FE
    FE -->|POST /transaction| API
    API -->|Return 200| FE
    FE -->|Show Success| USER
    
    style USER fill:#FF5722
    style BROWSER fill:#FFF3E0
    style FE fill:#F44336
    style API fill:#9C27B0

Build Process

graph TB
    DOCKER["docker build"]
    
    DOCKER -->|Stage 1| BUILDER["📦 Builder<br/>node:18-alpine"]
    BUILDER -->|install| DEPS["npm install"]
    DEPS -->|build| BUILD["npm run build"]
    BUILD -->|produces| DIST["dist/<br/>optimized bundle"]
    
    DOCKER -->|Stage 2| RUNTIME["🚀 Runtime<br/>node:18-alpine"]
    RUNTIME -->|install| SERVE["npm install -g serve"]
    SERVE -->|copy| COPY["COPY dist/ from builder"]
    COPY -->|start| START["serve -s dist -l 3000"]
    START -->|port| PORT["0.0.0.0:3000"]
    PORT -->|ready| DONE["✓ Ready"]
    
    DIST -.->|reused in Stage 2| COPY
    
    style DOCKER fill:#2196F3
    style BUILDER fill:#4CAF50
    style RUNTIME fill:#2196F3
    style DONE fill:#4CAF50

Frontend to API Communication

graph LR
    subgraph Frontend["🌐 React Frontend<br/>Browser Context"]
        FORM["Transaction Form"]
        STATE["React State"]
        AXIOS["Axios Client"]
    end
    
    subgraph API["🔌 FastAPI Backend<br/>Docker Container"]
        CORS["CORS Middleware"]
        VALIDATION["Validation"]
        KAFKA["Kafka Publish"]
    end
    
    FORM -->|Fill| STATE
    STATE -->|Submit| AXIOS
    AXIOS -->|POST http://localhost:8000| CORS
    CORS -->|Check origin| CORS
    CORS -->|Allow| VALIDATION
    VALIDATION -->|OK| KAFKA
    KAFKA -->|Publish| KAFKA
    KAFKA -->|Return 200| AXIOS
    AXIOS -->|Show result| FORM
    
    style Frontend fill:#F44336
    style API fill:#9C27B0
    style CORS fill:#4CAF50
    style KAFKA fill:#2196F3

Complete Data Flow: End-to-End

Full Journey of a Transaction

graph LR
    subgraph User["👤 You (Browser)"]
        BUY["Click Generate<br/>Token Button"]
    end
    
    subgraph Frontend_UI["⚛️ Frontend Container<br/>:3000"]
        FORM["Transaction Form"]
        STATE["React State<br/>with JWT"]
    end
    
    subgraph Backend["🔌 API Container<br/>:8000"]
        JWT_CHECK["Validate<br/>JWT"]
        VALIDATE["Validate<br/>Schema"]
    end
    
    subgraph MessageQueue["🔹 Kafka Container<br/>:29092"]
        QUEUE["Queue<br/>Message"]
    end
    
    subgraph Processing["🖥️ Consumer (Your Mac)"]
        EXTRACT["Feature<br/>Extraction"]
        ML1["ML Layer 1<br/>Score"]
        ML2["ML Layer 2<br/>Score"]
        DECISION["Decision<br/>Engine"]
    end
    
    subgraph Cache["🔹 Redis Container<br/>:6379"]
        STORE["Store<br/>Result"]
    end
    
    BUY -->|1. Request| Frontend_UI
    Frontend_UI -->|2. HTTP POST| Backend
    Backend -->|3. Validate| Backend
    Backend -->|4. Publish| MessageQueue
    MessageQueue -->|5. Queue| MessageQueue
    MessageQueue -->|6. Receive| Processing
    Processing -->|7. Process| Processing
    Processing -->|8. Store| Cache
    
    style BUY fill:#FF5722
    style Frontend_UI fill:#F44336
    style Backend fill:#9C27B0
    style MessageQueue fill:#2196F3
    style Processing fill:#FF9800
    style Cache fill:#FF9800

Happy Path: Normal Transaction

sequenceDiagram
    participant Browser
    participant Frontend
    participant API
    participant Kafka
    participant Consumer
    participant Redis

    Browser->>Frontend: 1. User submits transaction
    activate Frontend
    Frontend->>API: 2. POST /transaction (Amount: $75.50)
    activate API
    API->>API: 3. Validate JWT ✓
    API->>API: 4. Validate schema ✓
    API->>Kafka: 5. Publish to "transactions"
    activate Kafka
    API-->>Frontend: 6. Return 200 OK
    deactivate API
    Frontend-->>Browser: 7. Show "Accepted!"
    deactivate Frontend
    
    Kafka->>Consumer: 8. Deliver message
    deactivate Kafka
    activate Consumer
    Consumer->>Consumer: 9. Extract features
    Consumer->>Consumer: 10. Layer 1 score: 0.15
    Consumer->>Consumer: 11. Layer 2 score: 0.12
    Consumer->>Consumer: 12. Decision: APPROVED
    Consumer->>Redis: 13. Store result
    deactivate Consumer
    activate Redis
    Redis->>Redis: 14. Persist to disk
    deactivate Redis
    
    Note over Consumer,Redis: Fraud score < 0.3 = APPROVED ✓

Fraud Path: High-Value Transaction

sequenceDiagram
    participant Browser
    participant Frontend
    participant API
    participant Kafka
    participant Consumer
    participant Redis

    Browser->>Frontend: 1. User submits transaction
    activate Frontend
    Frontend->>API: 2. POST /transaction (Amount: $5000)
    activate API
    API->>API: 3. Validate JWT ✓
    API->>API: 4. Validate schema ✓
    API->>Kafka: 5. Publish to "transactions"
    activate Kafka
    API-->>Frontend: 6. Return 200 OK (always)
    deactivate API
    Frontend-->>Browser: 7. Show "Accepted!"
    deactivate Frontend
    
    Kafka->>Consumer: 8. Deliver message
    deactivate Kafka
    activate Consumer
    Consumer->>Consumer: 9. Extract features
    Note over Consumer: ⚠️ ANOMALY: Amount spike!
    Consumer->>Consumer: 10. Layer 1 score: 0.68
    Consumer->>Consumer: 11. Layer 2 score: 0.72
    Consumer->>Consumer: 12. Decision: FRAUD_DETECTED
    Consumer->>Redis: 13. Store result
    deactivate Consumer
    activate Redis
    Redis->>Redis: 14. Persist to disk
    deactivate Redis
    
    Note over Consumer,Redis: Fraud score > 0.7 = FRAUD_DETECTED 🚨

Container Networking

Docker Network Architecture

graph TB
    subgraph Host["🖥️ Your Mac (Host Machine)"]
        PORT_MAPPING["Port Mapping:<br/>3000→3000<br/>8000→8000<br/>9092→9092<br/>6379→6379<br/>2181→2181"]
    end
    
    subgraph Docker["🐳 Docker Bridge Network<br/>payguard-network"]
        ZK["Zookeeper<br/>:2181"]
        KAFKA["Kafka<br/>:29092 (internal)<br/>:9092 (external)"]
        REDIS["Redis<br/>:6379"]
        API["API<br/>:8000"]
        FE["Frontend<br/>:3000"]
    end
    
    subgraph Consumer["🖥️ Your Mac<br/>Consumer Process"]
        CONS["Consumer<br/>localhost:9092"]
    end
    
    HOST_CONSUMER["Your Mac<br/>Browser"]
    
    HOST_CONSUMER -->|http://localhost:3000| FE
    HOST_CONSUMER -->|http://localhost:8000| API
    CONS -->|localhost:9092| KAFKA
    
    ZK -->|coordinates| KAFKA
    API -->|kafka:29092| KAFKA
    API -->|redis:6379| REDIS
    FE -->|localhost:8000| API
    
    style Docker fill:#E3F2FD
    style Host fill:#F3E5F5
    style Consumer fill:#FFF3E0
    style KAFKA fill:#2196F3
    style API fill:#9C27B0
    style REDIS fill:#FF9800
    style ZK fill:#4CAF50

Service Name Resolution

graph LR
    API_CODE["API Code:<br/>kafka:29092"]
    DNS["Docker DNS<br/>Resolver"]
    KAFKA_IP["Kafka Container IP<br/>172.19.0.3"]
    KAFKA["Kafka<br/>Listening on<br/>:29092"]
    
    API_CODE -->|Lookup| DNS
    DNS -->|Resolve| KAFKA_IP
    KAFKA_IP -->|Connect to| KAFKA
    KAFKA -->|Accept| KAFKA
    
    style API_CODE fill:#9C27B0
    style DNS fill:#4CAF50
    style KAFKA_IP fill:#2196F3
    style KAFKA fill:#2196F3

Startup Sequence

graph TD
    START["docker compose up -d --build"]
    
    START -->|1. No deps| ZK["Zookeeper Starts"]
    ZK -->|Ready| ZK_OK["✓ Zookeeper Ready<br/>:2181"]
    
    ZK_OK -->|2. Waits for| KAFKA["Kafka Starts"]
    KAFKA -->|Health check| KAFKA_HC["Kafka API Version OK?"]
    KAFKA_HC -->|Yes| KAFKA_OK["✓ Kafka Ready<br/>:29092"]
    
    KAFKA_OK -->|3. No deps| REDIS["Redis Starts"]
    REDIS -->|Health check| REDIS_HC["redis-cli ping?"]
    REDIS_HC -->|PONG| REDIS_OK["✓ Redis Ready<br/>:6379"]
    
    KAFKA_OK -->|4. Waits for| API["API Starts"]
    REDIS_OK -->|4. Waits for| API
    API -->|Initialize| API_INIT["Setup FastAPI"]
    API_INIT -->|Routes| API_READY["✓ API Ready<br/>:8000"]
    
    API_READY -->|5. Waits for| FE["Frontend Starts"]
    KAFKA_OK -->|5. Waits for| FE
    REDIS_OK -->|5. Waits for| FE
    FE -->|Build dist| FE_BUILD["npm run build"]
    FE_BUILD -->|Serve| FE_READY["✓ Frontend Ready<br/>:3000"]
    
    FE_READY -->|All Ready| DONE["🎉 System Ready!"]
    
    style START fill:#2196F3
    style DONE fill:#4CAF50
    style ZK_OK fill:#81C784
    style KAFKA_OK fill:#81C784
    style REDIS_OK fill:#81C784
    style API_READY fill:#81C784
    style FE_READY fill:#81C784

Communication Paths

Valid Connections

graph TB
    subgraph INSIDE["Inside Docker Network"]
        API["API Container"]
        KAFKA["Kafka Container"]
        REDIS["Redis Container"]
    end
    
    subgraph OUTSIDE["Outside Docker Network"]
        MAC["Your Mac"]
        BROWSER["Browser"]
        CONSUMER["Consumer Process"]
    end
    
    API -->|✅ kafka:29092| KAFKA
    API -->|✅ redis:6379| REDIS
    BROWSER -->|✅ localhost:8000| API
    BROWSER -->|✅ localhost:3000| API
    CONSUMER -->|✅ localhost:9092| KAFKA
    
    API -.->|❌ localhost:9092| KAFKA
    MAC -.->|❌ kafka:29092| KAFKA
    
    style INSIDE fill:#E8F5E9
    style OUTSIDE fill:#FFF3E0
    style KAFKA fill:#2196F3
    style API fill:#9C27B0
    style REDIS fill:#FF9800

Resource Usage & Performance

Container Resource Estimates

graph TB
    TOTAL["Total System<br/>~1.5 GB RAM"]
    
    TOTAL --> ZK["Zookeeper<br/>100-200 MB"]
    TOTAL --> KAFKA["Kafka<br/>500-800 MB"]
    TOTAL --> REDIS["Redis<br/>50-100 MB"]
    TOTAL --> API["API<br/>200-300 MB"]
    TOTAL --> FE["Frontend<br/>50-100 MB"]
    
    style TOTAL fill:#FF6F00
    style ZK fill:#4CAF50
    style KAFKA fill:#2196F3
    style REDIS fill:#FF9800
    style API fill:#9C27B0
    style FE fill:#F44336

Typical Latency

graph LR
    USER["User<br/>Action"]
    API_CALL["API Call<br/>&lt;10ms"]
    KAFKA["Kafka<br/>Publish<br/>&lt;50ms"]
    CONSUMER["Consumer<br/>Receive<br/>&lt;100ms"]
    ML["ML<br/>Processing<br/>200-500ms"]
    REDIS["Redis<br/>Store<br/>&lt;10ms"]
    
    USER -->|⏱️| API_CALL
    API_CALL -->|⏱️| KAFKA
    KAFKA -->|⏱️| CONSUMER
    CONSUMER -->|⏱️| ML
    ML -->|⏱️| REDIS
    
    style USER fill:#FF5722
    style API_CALL fill:#4CAF50
    style KAFKA fill:#2196F3
    style CONSUMER fill:#FF9800
    style ML fill:#FF9800
    style REDIS fill:#FF9800

Summary Table

Container Image Port Purpose Depends On Status
Zookeeper confluentinc/cp-zookeeper 2181 Kafka coordination None Always up
Kafka confluentinc/cp-kafka 29092/9092 Message broker Zookeeper ✓ Healthy
Redis redis:alpine 6379 Result caching None Healthy
API python:3.11-slim 8000 Transaction intake Kafka, Redis ✓ Running
Frontend node:18-alpine 3000 User interface API ✓ Healthy

Key Concepts

Asynchronous Processing

The API returns immediately (200 OK) without waiting for fraud detection results. Consumer processes transactions asynchronously from Kafka queue.

Service Discovery

Docker's embedded DNS server resolves service names (kafka, redis, etc.) to container IPs on the payguard-network.

Port Mapping

Exposes container ports to host machine:

  • Internal communication: Container name + internal port (kafka:29092)
  • External access: localhost + exposed port (localhost:9092)

Health Checks

Each container declares how to verify it's healthy. Other containers wait for dependencies to be healthy before starting.

Data Persistence

Redis volume ensures results survive container restarts. Kafka and Zookeeper also persist their data.


This architecture enables: ✅ Scalability - Add more consumers for parallel processing ✅ Reliability - Kafka persists messages ✅ Performance - Async processing doesn't block frontend ✅ Testability - Each component can be tested independently ✅ Maintainability - Clear separation of concerns