> For the complete documentation index, see [llms.txt](https://crowdfunding-ugmbcc.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://crowdfunding-ugmbcc.gitbook.io/docs/architecture/data-flow.md).

# Data Flow

This document provides an in-depth analysis of how data flows through the CrowdFUNding platform, covering all major operations from campaign creation to fund withdrawal.

### Data Layer Overview

The platform uses a three-tier data architecture to balance blockchain transparency with query performance. Each layer serves a specific purpose in the overall data flow.

```mermaid
flowchart TB
    subgraph Layer1["Layer 1: Blockchain (Source of Truth)"]
        Contracts["Smart Contracts"]
        Events["Event Logs"]
    end

    subgraph Layer2["Layer 2: Indexer (Real-time Processing)"]
        Ponder["Ponder Indexer"]
        IndexerDB["Indexed Database"]
    end

    subgraph Layer3["Layer 3: Backend Cache (Fast Queries)"]
        Backend["Express Backend"]
        PostgreSQL["PostgreSQL Cache"]
    end

    Contracts --> |"Emit Events"| Events
    Events --> |"Subscribe"| Ponder
    Ponder --> |"Process & Store"| IndexerDB
    Backend --> |"Poll Every 30s"| IndexerDB
    Backend --> |"Cache Data"| PostgreSQL
```

The following table explains the purpose and characteristics of each data layer:

| Layer             | Technology                 | Purpose                            | Latency     |
| ----------------- | -------------------------- | ---------------------------------- | ----------- |
| **Blockchain**    | Base Sepolia               | Permanent storage, source of truth | \~2 seconds |
| **Indexer**       | Ponder + SQLite/PostgreSQL | Real-time event processing         | \~5 seconds |
| **Backend Cache** | PostgreSQL                 | Fast queries, join operations      | \~50 ms     |

***

### Campaign Data Flow

#### Campaign Creation

When a creator submits a new campaign, the data flows through the entire stack to ensure both on-chain permanence and fast queryability.

```mermaid
sequenceDiagram
    participant Creator
    participant Frontend
    participant Wallet
    participant Campaign as Campaign.sol
    participant Indexer as Ponder
    participant Backend
    participant DB as PostgreSQL

    Note over Creator,Frontend: Step 1: User Input
    Creator->>Frontend: Fill form (name, target, description)

    Note over Frontend,Wallet: Step 2: Transaction Signing
    Frontend->>Wallet: Request transaction signature
    Wallet->>Creator: Confirm transaction
    Creator->>Wallet: Approve

    Note over Wallet,Campaign: Step 3: On-chain Storage
    Wallet->>Campaign: createCampaign(name, creatorName, targetAmount)
    Campaign->>Campaign: Store CampaignStruct
    Campaign->>Campaign: Emit CampaignCreated event

    Note over Campaign,Indexer: Step 4: Event Indexing
    Campaign-->>Indexer: CampaignCreated(id, name, owner, target)
    Indexer->>Indexer: Insert into campaigns table

    Note over Backend,DB: Step 5: Cache Sync (every 30s)
    Backend->>Indexer: GET /api/campaigns
    Indexer-->>Backend: Campaign data
    Backend->>DB: UPSERT campaign record
```

**Key Points:**

* On-chain data includes: `name`, `creatorName`, `targetAmount`, `owner`, `creationTime`
* Off-chain data (description, images) is stored directly in PostgreSQL via backend API
* The campaign becomes queryable via backend API within 30 seconds

#### Campaign Data Structure

The campaign data is represented differently at each layer. This table shows the mapping:

| Field          | Blockchain | Indexer      | Backend Cache |
| -------------- | ---------- | ------------ | ------------- |
| `id`           | uint256    | integer (PK) | integer (PK)  |
| `name`         | string     | text         | varchar(255)  |
| `creatorName`  | string     | text         | varchar(255)  |
| `owner`        | address    | hex          | varchar(42)   |
| `balance`      | uint256    | bigint       | decimal(78,0) |
| `targetAmount` | uint256    | bigint       | decimal(78,0) |
| `creationTime` | uint256    | bigint       | timestamp     |
| `description`  | N/A        | N/A          | text          |
| `imageUrl`     | N/A        | N/A          | varchar(500)  |

***

### Donation Data Flow

#### Multi-Currency Donation with Auto-Swap

Users can donate using BASE (native token), USDC, or IDRX. When donating with non-IDRX currencies, the system automatically swaps to IDRX to ensure consistent campaign accounting.

```mermaid
sequenceDiagram
    participant Donor
    participant Frontend
    participant Campaign as Campaign.sol
    participant MockSwap as MockSwap.sol
    participant IDRX as IDRX Token
    participant Indexer as Ponder

    Note over Donor,Frontend: User selects currency and amount
    Donor->>Frontend: Select 0.01 ETH for Campaign #1

    Note over Frontend,Campaign: Native token donation
    Frontend->>Campaign: donate(1) with value: 0.01 ETH

    Note over Campaign,IDRX: Auto-swap process
    Campaign->>MockSwap: swapETHForToken{value: 0.01 ETH}(IDRX)
    MockSwap->>MockSwap: Calculate: 0.01 ETH × 268,400 = 2,684 IDRX
    MockSwap->>IDRX: Transfer 2,684 IDRX to Campaign

    Note over Campaign,Indexer: Update state and emit
    Campaign->>Campaign: campaigns[1].balance += 2,684 IDRX
    Campaign->>Indexer: Emit DonationReceived(1, donor, 2684)

    Note over Indexer: Index donation
    Indexer->>Indexer: Insert donation record
    Indexer->>Indexer: Update campaign balance
```

#### Token Swap Exchange Rates

The MockSwap contract maintains exchange rates for converting between tokens. These rates are defined in the contract's storage:

| Input      | Output per 1 ETH     | Calculation                  |
| ---------- | -------------------- | ---------------------------- |
| BASE (ETH) | 268,400 IDRX         | Direct rate to IDRX          |
| USDC       | 16,775 IDRX per USDC | USDC → ETH equivalent → IDRX |
| IDRX       | 1 IDRX               | No swap needed               |

#### Donation Record Structure

Each donation creates a record in the indexer with the following structure:

```mermaid
erDiagram
    DONATIONS {
        text id PK "txHash-logIndex"
        integer campaignId FK
        hex donor
        bigint amount
        bigint blockNumber
        bigint timestamp
        hex transactionHash
    }

    CAMPAIGNS {
        integer id PK
        text name
        bigint balance
    }

    CAMPAIGNS ||--o{ DONATIONS : "has many"
```

***

### Withdrawal Data Flow

#### Fund Withdrawal Process

Campaign owners can withdraw accumulated IDRX funds at any time. The contract validates ownership before transferring tokens.

```mermaid
sequenceDiagram
    participant Owner
    participant Frontend
    participant Campaign as Campaign.sol
    participant IDRX as IDRX Token
    participant Indexer as Ponder

    Note over Owner,Frontend: Owner requests withdrawal
    Owner->>Frontend: Request withdraw 100,000 IDRX from Campaign #1

    Note over Frontend,Campaign: Validate and execute
    Frontend->>Campaign: withdraw(1, 100000)
    Campaign->>Campaign: Verify msg.sender == campaign.owner
    Campaign->>Campaign: Verify balance >= 100000

    Note over Campaign,IDRX: Transfer funds
    Campaign->>Campaign: campaigns[1].balance -= 100000
    Campaign->>IDRX: safeTransfer(owner, 100000)
    IDRX->>Owner: 100,000 IDRX credited

    Note over Campaign,Indexer: Emit event
    Campaign->>Indexer: Emit FundWithdrawn(1, name, owner, creatorName, 100000)
    Indexer->>Indexer: Insert withdrawal record
```

**Security Checks:**

1. **Ownership**: Only the campaign creator can withdraw
2. **Balance**: Cannot withdraw more than available balance
3. **Reentrancy**: Protected by ReentrancyGuard modifier

***

### Authentication Data Flow

#### User Authentication Options

The platform supports dual authentication methods to accommodate both Web2 and Web3 users.

```mermaid
flowchart LR
    subgraph Methods["Authentication Methods"]
        Google["Google OAuth 2.0"]
        Wallet["Web3 Wallet\n(RainbowKit)"]
    end

    subgraph Backend["Backend Processing"]
        Passport["Passport.js\n(OAuth Strategy)"]
        JWT["JWT Generator"]
        Session["Session Store"]
    end

    subgraph Storage["User Storage"]
        PostgreSQL["PostgreSQL"]
    end

    Google --> Passport
    Wallet --> Passport
    Passport --> JWT
    JWT --> Session
    Passport --> PostgreSQL
```

#### Authentication Flow (Google OAuth 2.0)

For users who prefer social login, **Google OAuth 2.0** provides a familiar authentication experience handled entirely server-side for security.

```mermaid
sequenceDiagram
    participant User
    participant Frontend
    participant Google
    participant Backend
    participant DB as PostgreSQL

    User->>Frontend: Click "Sign in with Google"
    Frontend->>Backend: Redirect to /auth/google
    Backend->>Google: OAuth 2.0 request
    Google->>User: Show consent screen
    User->>Google: Grant permission
    Google->>Backend: Return user profile
    Backend->>DB: Create/update user record
    Backend->>Backend: Generate JWT token
    Backend->>Frontend: Set JWT cookie & redirect
    Frontend->>Frontend: Read session from cookie
```

**Key Points:**

* OAuth handled entirely on backend (Passport.js)
* JWT stored in httpOnly cookie (secure)
* User can optionally link Web3 wallet later
* No embedded wallet creation - users bring their own wallet

***

### Indexer Event Processing

#### Real-time Event Handling

The Ponder indexer subscribes to blockchain events and processes them in real-time. Each event type has a dedicated handler that transforms the event data into database records.

```mermaid
flowchart TB
    subgraph Blockchain["Blockchain Events"]
        E1["CampaignCreated"]
        E2["DonationReceived"]
        E3["FundWithdrawn"]
        E4["BadgeMinted"]
    end

    subgraph Handlers["Event Handlers"]
        H1["handleCampaignCreated"]
        H2["handleDonationReceived"]
        H3["handleFundWithdrawn"]
        H4["handleBadgeMinted"]
    end

    subgraph Operations["Database Operations"]
        O1["INSERT campaigns"]
        O2["INSERT donations\nUPDATE campaigns.balance"]
        O3["INSERT withdrawals\nUPDATE campaigns.balance"]
        O4["INSERT badges"]
    end

    E1 --> H1 --> O1
    E2 --> H2 --> O2
    E3 --> H3 --> O3
    E4 --> H4 --> O4
```

#### Event Handler Example

This code snippet shows how the DonationReceived event is processed:

```typescript
ponder.on("Campaign:DonationReceived", async ({ event, context }) => {
  const { db } = context;

  // Create unique ID from transaction hash and log index
  const donationId = `${event.transaction.hash}-${event.log.logIndex}`;

  // Insert donation record
  await db.donations.insert({
    id: donationId,
    campaignId: Number(event.args.id),
    donor: event.args.donor,
    amount: event.args.amount,
    blockNumber: event.block.number,
    timestamp: event.block.timestamp,
    transactionHash: event.transaction.hash,
  });

  // Update campaign balance
  await db.campaigns.update({
    id: Number(event.args.id),
    balance: (prev) => prev.balance + event.args.amount,
  });
});
```

***

### Backend Sync Process

#### Automatic Data Synchronization

The backend runs an auto-sync service that periodically fetches data from the Ponder indexer and updates the PostgreSQL cache.

```mermaid
sequenceDiagram
    participant Timer as "Interval Timer"
    participant Sync as "Sync Service"
    participant Ponder as "Ponder API"
    participant DB as "PostgreSQL"

    loop Every 30 seconds
        Timer->>Sync: Trigger sync

        Sync->>Ponder: GET /api/campaigns
        Ponder-->>Sync: Campaign list
        Sync->>DB: UPSERT campaigns

        Sync->>Ponder: GET /api/donations
        Ponder-->>Sync: Donation list
        Sync->>DB: UPSERT donations

        Sync->>Ponder: GET /api/badges
        Ponder-->>Sync: Badge list
        Sync->>DB: UPSERT badges

        Sync->>Sync: Log: "Synced X campaigns, Y donations, Z badges"
    end
```

#### Why Cache in PostgreSQL?

The backend maintains a PostgreSQL cache for several important reasons:

| Reason                | Explanation                                                 |
| --------------------- | ----------------------------------------------------------- |
| **Query Performance** | Complex JOINs are faster on PostgreSQL than on indexed data |
| **Off-chain Data**    | Store descriptions, images, and user preferences            |
| **Data Enrichment**   | Combine on-chain and off-chain data                         |
| **Reliability**       | Serve data even if Ponder is temporarily unavailable        |

***

### API Data Flow

#### REST API Request/Response Flow

When the frontend makes an API request, the data flows through multiple backend layers before returning to the client.

```mermaid
sequenceDiagram
    participant Client as "Frontend"
    participant Router as "Express Router"
    participant Middleware as "Auth Middleware"
    participant Controller as "Controller"
    participant Model as "Model"
    participant DB as "PostgreSQL"

    Client->>Router: GET /crowdfunding/vaults
    Router->>Middleware: Check authentication (if required)
    Middleware->>Middleware: Validate JWT
    Middleware->>Controller: getAllVaults()
    Controller->>Model: Vault.findAll()
    Model->>DB: SELECT * FROM vaults
    DB-->>Model: Result rows
    Model-->>Controller: Vault instances
    Controller-->>Router: JSON response
    Router-->>Client: { success: true, data: [...] }
```

#### API Response Format

All API responses follow a consistent format to simplify frontend handling:

```json
{
  "success": true,
  "data": {
    "campaigns": [
      {
        "id": 1,
        "name": "Save the Rainforest",
        "creatorName": "Green Foundation",
        "balance": "45000000",
        "targetAmount": "100000000",
        "owner": "0x1234...5678",
        "creationTime": "1706577600"
      }
    ]
  },
  "meta": {
    "total": 42,
    "page": 1,
    "limit": 10
  }
}
```

***

### Badge Minting Data Flow

#### Achievement Badge Creation

When a user earns an achievement (e.g., first donation), the backend triggers a badge mint on the blockchain.

```mermaid
sequenceDiagram
    participant User
    participant Backend
    participant Badge as Badge.sol
    participant Indexer as Ponder
    participant Frontend

    Note over User,Backend: User completes achievement
    User->>Backend: Action triggers achievement check
    Backend->>Backend: Verify eligibility

    Note over Backend,Badge: Mint badge NFT
    Backend->>Badge: mintBadge(userAddress, name, description)
    Badge->>Badge: _tokenIds++
    Badge->>Badge: _mint(userAddress, newTokenId)
    Badge->>Badge: Store BadgeInfo

    Note over Badge,Frontend: Event emission and display
    Badge->>Indexer: Emit BadgeMinted(tokenId, owner, name, description)
    Indexer->>Indexer: Insert badge record
    Frontend->>Indexer: Query user badges
    Indexer-->>Frontend: Badge list
    Frontend->>User: Display new badge
```

***

### Summary: Complete Data Journey

This diagram shows the complete journey of data through the CrowdFUNding platform, from user action to final storage.

```mermaid
flowchart LR
    subgraph UserActions["User Actions"]
        Create["Create Campaign"]
        Donate["Make Donation"]
        Withdraw["Withdraw Funds"]
    end

    subgraph OnChain["On-Chain"]
        SC["Smart Contracts"]
        Events["Event Logs"]
    end

    subgraph OffChain["Off-Chain"]
        Indexer["Ponder Indexer"]
        Backend["Express Backend"]
        DB["PostgreSQL"]
    end

    subgraph Clients["Clients"]
        Web["Web App"]
        API["API Consumers"]
    end

    UserActions --> SC
    SC --> Events
    Events --> Indexer
    Indexer --> Backend
    Backend --> DB
    DB --> Clients
```
