# How the Paid Community System Handles Alipay Onboarding in Awesome GPT Image 2

> Discover how the paid community system handles Alipay onboarding in Awesome GPT Image 2. Learn about the four-stage serverless pipeline for seamless user registration and payment.

- Repository: [苍何/awesome-gpt-image-2](https://github.com/freestylefly/awesome-gpt-image-2)
- Tags: how-to-guide
- Published: 2026-08-31

---

**The paid community system uses a four-stage serverless pipeline to onboard users via Alipay, creating pending orders in Supabase, generating signed payment forms, and confirming completion through both synchronous polling and asynchronous webhook notifications.**

The paid community feature in the `freestylefly/awesome-gpt-image-2` repository provides a complete Alipay integration for monetizing community access. Built on Vercel serverless functions and Supabase, this system orchestrates order creation, payment processing, and access provisioning through a tightly coupled sequence of API handlers and database operations.

## The Four-Stage Onboarding Flow

The **Alipay onboarding flow** is deterministic and server-driven, splitting the payment journey into four distinct stages that ensure idempotency and security.

### Stage 1: Creating or Reusing an Order

The process begins when the client sends a **POST** request to `/api/community/alipay/checkout`. The handler in [`api/community/alipay/checkout.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/community/alipay/checkout.js) first authenticates the user and applies rate limiting through `applyCommunityRateLimit` with a strict 10 requests per minute threshold.

The system checks the `COMMUNITY_PAYMENT_ENABLED` environment variable to ensure payments are currently accepted. It then calls the Supabase RPC function `create_or_reuse_community_order` to either fetch an existing *PENDING* order or insert a new row into the `community_orders` table. This prevents duplicate charges when users refresh the payment page.

**Key implementation details:**
- Rate limiting uses `communityRequestRateKey` for per-user buckets
- Order status must be *PENDING* for reuse; paid or closed orders trigger new rows
- Default price is set via `COMMUNITY_PRICE_CENTS = 990` (¥9.90)

### Stage 2: Building the Alipay Payment Request

Once an order exists, the [`checkout.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/checkout.js) handler invokes `getAlipayClient` to instantiate the Alipay SDK. It constructs a **FAST_INSTANT_TRADE_PAY** request containing:

- `out_trade_no`: The order UUID from Supabase
- `total_amount`: ¥9.90 (990 cents converted to yuan)
- `subject`: Community access description
- `timeout_express`: 30 minutes expiration
- `return_url`: Front-end result page (`/community/result`)
- `notify_url`: Server webhook endpoint (`/api/community/alipay/notify`)

The SDK returns an HTML `<form>` that auto-submits the browser to Alipay's payment gateway. The client receives this HTML in the `paymentHtml` response field and injects it directly into the DOM to redirect the user.

### Stage 3: User Payment and Redirect

After the user completes payment on Alipay's site, Alipay redirects the browser to the `return_url` with the `order_id` query parameter appended. The front-end route `/community/result` extracts this ID and initiates polling by calling the **GET** endpoint `/api/community/alipay/query`.

The [`query.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/query.js) handler implements synchronous status checking:
- Validates the order belongs to the authenticated user
- Calls Alipay's query API to verify current `trade_status`
- Returns JSON with `paid` boolean and full order object
- Implements 30 requests per minute rate limiting

The client polls every 2 seconds until receiving `paid: true` or detecting a closed order.

### Stage 4: Asynchronous Notification and Confirmation

Independently of the browser flow, Alipay sends a server-to-server **POST** to the `notify_url` defined by `COMMUNITY_ALIPAY_NOTIFY_URL`. The [`api/community/alipay/notify.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/community/alipay/notify.js) handler processes this callback:

1. Parses the form-encoded body using `sanitizeAlipayNotifyParams`
2. Validates the RSA2 signature against Alipay's public key
3. Confirms `app_id` and `seller_id` match runtime configuration
4. Checks `trade_status` for **TRADE_SUCCESS** or **TRADE_FINISHED**
5. Calls `markCommunityOrderPaid` to update the order to `PAID` status
6. For **TRADE_CLOSED** status on *PENDING* orders, invokes `closeCommunityOrderAtAlipay`

This dual-path confirmation (browser polling + server webhook) ensures the order state remains consistent even if the user closes their browser immediately after payment.

## Core Implementation Details

### Environment Configuration and Security

The system relies on Vercel environment variables for sensitive credentials. **Never commit these to the repository:**

- `ALIPAY_APP_ID`: Application identifier
- `ALIPAY_PRIVATE_KEY`: RSA2 signing key
- `ALIPAY_PUBLIC_KEY`: Alipay's verification key
- `ALIPAY_SELLER_ID`: Merchant account ID

Public configuration (price, support contact, terms version) is exposed through `communityPublicConfig()` in [`api/_lib/community.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/community.js). The `validateSameOrigin` helper ensures all requests originate from the configured `APP_URL` or same host, preventing CSRF attacks on payment endpoints.

### Rate Limiting and Request Validation

Every endpoint enforces user-specific rate limiting via `applyCommunityRateLimit`:
- **Checkout endpoint**: 10 requests per minute
- **Query endpoint**: 30 requests per minute

The system uses Redis-backed buckets keyed by `communityRequestRateKey` to track usage. Additionally, `validateSameOrigin` checks the `Origin` header against `APP_URL` before processing payment-sensitive operations.

### Order Lifecycle Management

Orders progress through a strict state machine defined in `COMMUNITY_ORDER_STATUSES`:

- `PENDING`: Order created, awaiting payment
- `PAID`: Payment confirmed, access granted
- `CLOSED`: Expired or manually cancelled
- `REFUNDED`: Payment reversed post-completion
- `REVOKED`: Access rescinded

The `shouldExpireCommunityOrder` utility automatically closes *PENDING* orders after 30 minutes, invoking `closeCommunityOrderAtAlipay` to call Alipay's native close API and prevent late payments.

### Database Schema

Supabase stores community data in two primary tables defined in [`supabase/migrations/20260722090000_paid_community.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260722090000_paid_community.sql):

- **`community_orders`**: Tracks payment state, user ID, amount, terms acceptance, and Alipay metadata
- **`community_group_qr_assets`**: Stores protected QR images unlocked upon payment

The `create_or_reuse_community_order` RPC handles atomic insertion with conflict resolution based on user ID and pending status.

## Code Implementation Examples

### Initiating Checkout from the Client

```javascript
async function startAlipayCheckout() {
  const resp = await fetch('/api/community/alipay/checkout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    credentials: 'same-origin',
    body: JSON.stringify({ 
      acceptedTerms: true, 
      termsVersion: '2026-07-22' 
    })
  });
  
  const data = await resp.json();
  if (!data.ok) throw new Error(data.error);
  
  // Inject auto-submitting form to redirect to Alipay
  document.body.innerHTML = data.paymentHtml;
}

```

This implementation references the handler logic in [`api/community/alipay/checkout.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/community/alipay/checkout.js) at lines 55-63, where the server validates the terms version before generating the payment form.

### Polling for Payment Status

On the return page (`/community/result`), extract the order ID and poll until completion:

```javascript
const url = new URL(window.location.href);
const orderId = url.searchParams.get('order_id');

async function pollPaymentStatus() {
  try {
    const response = await fetch(
      `/api/community/alipay/query?orderId=${orderId}`
    );
    const { paid, order } = await response.json();
    
    if (paid) {
      // Render QR code or success message
      displayCommunityAccess(order);
    } else if (order.status === 'CLOSED') {
      showPaymentExpiredMessage();
    } else {
      setTimeout(pollPaymentStatus, 2000);
    }
  } catch (err) {
    console.error('Polling failed:', err);
  }
}

pollPaymentStatus();

```

The [`query.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/query.js) handler validates user ownership of the order before returning status, preventing information leakage between users.

### Handling Server-Side Notifications

While the client polls, the server must handle Alipay's asynchronous callback. The [`notify.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/notify.js) handler processes form-encoded POST data:

```javascript
// Validation and processing flow in notify.js
const safeParams = sanitizeAlipayNotifyParams(req.body);
const isValid = validateAlipaySignature(safeParams);

if (isValid && 
    safeParams.app_id === process.env.ALIPAY_APP_ID &&
    ['TRADE_SUCCESS', 'TRADE_FINISHED'].includes(safeParams.trade_status)) {
  
  await markCommunityOrderPaid(client, order, safeParams, {
    notifyId: safeParams.notify_id,
    notifyPayload: safeParams
  });
  
  res.status(200).send('success');
}

```

The code validates RSA2 signatures, matches seller credentials, and only then updates the order status to `PAID`, ensuring webhook authenticity before granting community access.

## Summary

- The **Alipay onboarding flow** consists of four stages: order creation, payment form generation, user redirection with polling, and asynchronous webhook confirmation
- **Rate limiting** protects endpoints at 10 req/min (checkout) and 30 req/min (query) using Redis-backed buckets
- **Security measures** include RSA2 signature validation, same-origin checks, and environment variable isolation of Alipay credentials
- **Database operations** use Supabase RPC functions like `create_or_reuse_community_order` to maintain idempotency
- **Order expiration** occurs automatically after 30 minutes via `shouldExpireCommunityOrder` and `closeCommunityOrderAtAlipay`
- Key files include [`api/community/alipay/checkout.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/community/alipay/checkout.js), [`query.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/query.js), [`notify.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/notify.js), and [`api/_lib/community.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/community.js)

## Frequently Asked Questions

### How does the system prevent duplicate orders?

The `create_or_reuse_community_order` RPC function in Supabase checks for existing *PENDING* orders for the authenticated user before creating new rows. If a pending order exists from a previous session, the system returns that order ID instead of creating a duplicate charge. This ensures users never pay twice for the same community access, even if they refresh the checkout page multiple times.

### What security measures protect the Alipay integration?

The system implements multiple layers: **RSA2 signature validation** on all incoming notifications, **same-origin validation** via `validateSameOrigin`, **environment variable isolation** (credentials stored in Vercel, never in the repo), and **strict rate limiting** to prevent brute force attacks. Additionally, `sanitizeAlipayNotifyParams` removes unexpected fields before persistence, preventing injection attacks through webhook payloads.

### How long do users have to complete payment?

Users have **30 minutes** to complete payment after initiating checkout. This timeout is enforced through the `timeout_express` parameter in the Alipay SDK request and the `shouldExpireCommunityOrder` utility function. After expiration, the system calls `closeCommunityOrderAtAlipay` to cancel the order at both Supabase and Alipay, requiring the user to restart the checkout process if they wish to purchase access.

### Can the system handle payment notifications if the user closes the browser?

Yes. The architecture uses a **dual-path confirmation** strategy. While the front-end polls the query endpoint for immediate feedback, the [`notify.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/notify.js) handler receives asynchronous server-to-server notifications from Alipay regardless of browser state. The `markCommunityOrderPaid` function updates the database when the webhook arrives, ensuring users receive access even if they close the browser immediately after completing the Alipay payment flow.