# How the Trade Matching System Uses Supabase Edge Functions to Find Trading Partners

> Discover how our trade matching system uses Supabase Edge Functions to find ideal trading partners by analyzing card ownership and preferences for better matches. Get ranked suggestions now.

- Repository: [Marcel Panse/tcg-pocket-collection-tracker](https://github.com/marcelpanse/tcg-pocket-collection-tracker)
- Tags: how-to-guide
- Published: 2026-03-06

---

**The trade matching system leverages a Supabase Edge Function named `get-trading-partners` to execute SQL queries that calculate compatibility scores between users based on card ownership, rarity preferences, and active trading status, returning ranked partner suggestions to the frontend.**

The marcelpanse/tcg-pocket-collection-tracker repository implements a serverless trade matching architecture that uses Supabase edge functions to identify potential trading partners. This approach offloads computationally intensive collection comparisons to the edge, keeping the React frontend lightweight while maintaining secure database access.

## Architecture Overview: Edge Functions and Frontend Integration

The system splits responsibilities between a **Supabase Edge Function** (server-side) and a **frontend service** (client-side). This separation ensures complex SQL joins and aggregations run close to the database in [`supabase/functions/get-trading-partners/index.ts`](https://github.com/marcelpanse/tcg-pocket-collection-tracker/blob/main/supabase/functions/get-trading-partners/index.ts), minimizing latency for users.

The frontend abstraction lives in [`frontend/src/services/trade/tradeService.ts`](https://github.com/marcelpanse/tcg-pocket-collection-tracker/blob/main/frontend/src/services/trade/tradeService.ts) and provides a typed wrapper around the edge function invocation. This pattern allows the single-page application to request trading partner suggestions via HTTP POST without exposing database credentials or handling raw SQL.

## The `get-trading-partners` Edge Function Implementation

Located at [`supabase/functions/get-trading-partners/index.ts`](https://github.com/marcelpanse/tcg-pocket-collection-tracker/blob/main/supabase/functions/get-trading-partners/index.ts), the edge function establishes a PostgreSQL connection pool using the `SUPABASE_DB_URL` environment variable. It dynamically selects between two query strategies based on whether the user searches for general partners or targets a specific card.

### Database Connection and Query Execution

The function initializes a `postgres.Pool` connection and prepares parameterized queries. After executing the appropriate SQL via `connection.queryObject`, it serializes the rows—converting `trade_matches` to numeric values—and returns JSON with CORS headers to allow cross-origin requests from the frontend.

```typescript
// Conceptual flow from supabase/functions/get-trading-partners/index.ts
const connection = await pool.connect();
const result = await connection.queryObject(sqlQuery);
// Rows processed and returned as JSON with CORS headers

```

### The All-Matches Query for General Partner Discovery

When invoked without a `card_id` parameter, the function executes **`all_matches_query`**. This query scans the 50 most recently updated public accounts that have active trading enabled. For each candidate, it calculates:

- **`num_to_give`**: Cards the user owns in surplus that the partner needs
- **`num_to_get`**: Cards the partner owns in surplus that the user needs
- **`trade_matches`**: The summed minimum of give/get counts per rarity, filtered by `trade_rarity_settings`

The query returns `friend_id`, `username`, and the aggregated compatibility score, sorted by highest match potential.

### The Single-Card Query for Targeted Trading

When a `card_id` is provided via the request body, the function switches to **`single_card_query`**. This optimized path filters exclusively for partners with complementary surplus/deficit relationships for that specific card's rarity. This targeted approach reduces database load and returns only relevant partners for users seeking particular cards to complete their collections.

## Frontend Integration via [`tradeService.ts`](https://github.com/marcelpanse/tcg-pocket-collection-tracker/blob/main/tradeService.ts)

The frontend service exposes `getTradingPartners(email, cardId?)`, a typed wrapper that invokes the edge function using the Supabase JavaScript client.

```typescript
// From frontend/src/services/trade/tradeService.ts
const { data, error } = await supabase.functions.invoke('get-trading-partners', {
  method: 'POST',
  body: { email, card_id: cardId },
});

```

The function returns `TradePartners[]` data for UI rendering. Errors are caught and re-thrown to allow components to display user-friendly messages in modals or notification systems.

### Practical Usage Examples

```typescript
import { getTradingPartners } from '@/services/trade/tradeService'

// Find general trading partners
async function showPartners(email: string) {
  try {
    const partners = await getTradingPartners(email)
    console.log('Suggested partners:', partners)
  } catch (e) {
    console.error('Failed to fetch partners', e)
  }
}

// Find partners for a specific card
async function showCardPartners(email: string, cardId: number) {
  try {
    const partners = await getTradingPartners(email, cardId)
    console.log(`Partners for card ${cardId}:`, partners)
  } catch (e) {
    console.error('Failed to fetch card-specific partners', e)
  }
}

```

## Database Schema and Trade Compatibility Logic

The matching algorithm joins four core tables in the Supabase PostgreSQL database:

- **`accounts`**: Stores user profiles, privacy settings, and active trading status
- **`card_amounts`**: Tracks individual card ownership quantities per user
- **`cards_list`**: Contains card metadata including rarity classifications
- **`trade_rarity_settings`**: Defines which rarities users are willing to trade

The edge function queries these tables to compute compatibility by comparing ownership amounts against rarity-specific trade preferences. Public accounts with recent collection updates receive priority in the results, ensuring suggestions remain current and actionable.

## Summary

- The **`get-trading-partners`** edge function in [`supabase/functions/get-trading-partners/index.ts`](https://github.com/marcelpanse/tcg-pocket-collection-tracker/blob/main/supabase/functions/get-trading-partners/index.ts) executes SQL queries that calculate trade compatibility scores between users based on their collections.
- Two query modes exist: **`all_matches_query`** for general partner discovery across all cards, and **`single_card_query`** for targeted trading of specific cards.
- The frontend invokes the function via **`supabase.functions.invoke()`** in [`frontend/src/services/trade/tradeService.ts`](https://github.com/marcelpanse/tcg-pocket-collection-tracker/blob/main/frontend/src/services/trade/tradeService.ts), passing the user's email and optional `card_id`.
- Compatibility scores derive from comparing `num_to_give` and `num_to_get` values filtered by `trade_rarity_settings` across the `accounts`, `card_amounts`, and `cards_list` tables.
- CORS-enabled JSON responses ensure the edge function integrates securely with the React frontend while keeping database credentials protected server-side.

## Frequently Asked Questions

### How does the edge function calculate trade compatibility scores?

The function calculates `trade_matches` by summing the minimum values of `num_to_give` and `num_to_get` for each rarity tier, respecting each user's `trade_rarity_settings`. This represents the maximum number of mutually beneficial trades possible between two users based on current inventories and stated preferences for specific card rarities.

### What is the difference between the all-matches and single-card queries?

**`all_matches_query`** scans the 50 most recently updated public accounts with active trading enabled, evaluating compatibility across the entire collection to find partners with the highest overall trade potential. **`single_card_query`** filters exclusively for partners who can provide or accept a specific `card_id`, optimizing for targeted searches when users need particular cards.

### How does the frontend invoke the Supabase edge function?

The frontend uses the `getTradingPartners` function from [`frontend/src/services/trade/tradeService.ts`](https://github.com/marcelpanse/tcg-pocket-collection-tracker/blob/main/frontend/src/services/trade/tradeService.ts), which calls `supabase.functions.invoke('get-trading-partners', { method: 'POST', body: { email, card_id: cardId } })`. This approach provides TypeScript safety through the `TradePartners` interface and centralizes error handling for consistent UI feedback.

### What database tables power the trade matching algorithm?

The algorithm queries four primary tables: `accounts` (for user profiles and trading preferences), `card_amounts` (for ownership quantities), `cards_list` (for card metadata and rarities), and `trade_rarity_settings` (for rarity-specific trading rules). The edge function joins these tables to identify surplus/deficit relationships and calculate optimal trading partner suggestions.