# How to Implement Paid Community Features with QR Codes and Refunds

> Learn to implement paid community features using QR codes and refunds. Integrate Alipay, Supabase, and webhooks to manage access and payments seamlessly.

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

---

**To implement paid community features with QR codes and refunds, configure Alipay Web-Pay for ¥9.90 transactions, persist order states in Supabase, store protected QR images in a dedicated table, and process asynchronous payment notifications via webhooks to dynamically toggle access eligibility.**

The `freestylefly/awesome-gpt-image-2` repository provides a production-ready implementation of a paid community feature that operates independently from existing membership or credit systems. This architecture uses Alipay for payment processing, Supabase for state management, and atomic database operations to ensure QR codes remain secure while supporting full refund lifecycles. Below is a complete technical breakdown of how to implement paid community features with QR codes and refunds, referencing the actual source code and database schema.

## Architecture Overview

The system decouples payment processing from community access through a state-machine-driven flow. According to the source code in [`docs/paid-community.md`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/docs/paid-community.md), the implementation follows this sequence:

1. **Frontend Initiation**: Users navigate to `/community` to view the QR code page or `/community/result` for payment outcomes.
2. **Alipay Integration**: The backend calls `alipay.trade.page.pay` to create a ¥9.90 (990¢) order.
3. **State Persistence**: The `community_orders` table tracks status transitions from **PENDING** to **PAID**, and finally to terminal states like **REFUNDED**, **CLOSED**, or **REVOKED**.
4. **Access Control**: The `community_qr` table stores the protected image as a `bytea` blob, with access granted only when a user's latest order status equals **PAID** (or **PROCESSING** during active refunds).
5. **Asynchronous Updates**: Alipay webhooks push final status updates to `POST /api/community/alipay/notify`.

## Database Schema Design

### The community_orders Table

Located in [`supabase/migrations/20260722090000_paid_community.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260722090000_paid_community.sql), this table links payments to Supabase user IDs:

- `status` column manages the lifecycle: **PENDING** → **PAID** → **REFUNDED**/**CLOSED**/**REVOKED**
- Foreign key relationships ensure each order maps to a specific user
- The table supports idempotent updates to handle duplicate Alipay notifications safely

### The community_qr Table

QR images are stored as binary blobs with strict size limits (PNG/JPEG/WebP ≤ 2MB). The schema enforces atomic replacement operations through RPC transactions, ensuring the old image is disabled before the new one becomes live. This prevents race conditions where users might access outdated or revoked community codes.

## Implementing the Payment Flow

### Checkout Initiation

The frontend initiates payments via `POST /api/community/alipay/checkout`. In [`api/_lib/alipay.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/alipay.js), the server generates an Alipay order and returns a redirect URL:

```javascript
// Start an Alipay checkout (frontend)
async function startCheckout() {
  const res = await fetch('/api/community/alipay/checkout', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({amount: 990})   // fixed amount in cents
  });
  const {checkoutUrl} = await res.json();
  window.location = checkoutUrl;           // redirects to Alipay
}

```

### Webhook Handling

The `POST /api/community/alipay/notify` endpoint processes Alipay server-to-server notifications. As implemented in the API layer, this webhook updates the `community_orders` table status and handles idempotent processing:

```javascript
// Alipay webhook (server side) – records payment status
import {recordAlipayNotification} from '../_lib/alipay.js';
export default async function handler(req, res) {
  if (req.method !== 'POST') return res.status(405).end();
  await recordAlipayNotification(req.body); // updates `community_orders`
  res.status(200).json({ok: true});
}

```

### Status Polling and Eligibility

The `GET /api/community/status` endpoint aggregates payment state, QR availability, and user eligibility. The frontend uses this to conditionally render the protected QR code:

```javascript
// Get community status (frontend)
fetch('/api/community/status')
  .then(r => r.json())
  .then(({eligible, qrReady, order}) => {
    if (!eligible) return alert('Purchase required.');
    if (qrReady) showQrImage();               // renders the protected QR
    else console.log('QR not yet uploaded.');
  });

```

Behind this endpoint, [`api/_lib/community.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/community.js) provides helper functions including `canAccessCommunityQr`, `getCurrentCommunityQr`, and `getLatestCommunityOrder` to encapsulate the eligibility logic.

## QR Code Access Control

### Storage and Retrieval

Protected QR images are never served directly from static files. Instead, the system queries the `community_qr` table and streams the `bytea` blob only to eligible users. The [`src/community.jsx`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/community.jsx) and [`src/community.css`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/community.css) files handle the frontend rendering once access is verified.

### Atomic Replacement

Administrators rotate QR codes through admin-only endpoints (`/api/admin/...`). The `replaceCommunityQr` function executes an RPC transaction to swap images atomically:

```javascript
// Admin: Rotate QR code (server side)
import {replaceCommunityQr} from '../_lib/community.js';
export default async function handler(req, res) {
  const {qrFile} = req.body;               // binary image uploaded by admin
  await replaceCommunityQr(qrFile);        // RPC transaction, atomic swap
  res.json({ok: true});
}

```

This ensures zero-downtime rotation and immediate invalidation of previous codes.

## Handling Refunds and Revocation

Refund processing follows Alipay's refund API workflow. When an administrator issues a refund through the admin panel, the system calls the `createRefund` function from [`api/_lib/alipay.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/alipay.js) and immediately updates the corresponding order status to **REFUNDED** or **PROCESSING**:

```javascript
// Admin: Issue a refund (server side)
import {createRefund} from '../_lib/alipay.js';
export default async function handler(req, res) {
  const {orderId} = req.body;
  const result = await createRefund(orderId); // Alipay refund API call
  res.status(200).json(result);
}

```

Once the status transitions to **REFUNDED**, the `canAccessCommunityQr` helper returns false, instantly revoking QR code access without requiring manual intervention.

## Environment Configuration and Safety Flags

The implementation uses feature flags to prevent premature activation. The `COMMUNITY_PAYMENT_ENABLED` environment variable (default `false`) guards all payment endpoints until production acceptance testing completes. Additionally, `COMMUNITY_ALIPAY_NOTIFY_URL` defines the webhook endpoint for Alipay asynchronous notifications.

## Production Deployment Checklist

According to the paid-community runbook in [`docs/paid-community.md`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/docs/paid-community.md), deploy the feature using this verification sequence:

1. Deploy code with `COMMUNITY_PAYMENT_ENABLED=false`
2. Upload an initial QR image via admin endpoints
3. Enable the flag temporarily: `COMMUNITY_PAYMENT_ENABLED=true`
4. Execute a real ¥9.90 payment flow
5. Process a full-cycle refund and verify:
   - Alipay async notification and query APIs are idempotent
   - QR code becomes unavailable after successful refund
   - Order status correctly transitions through all states
6. If any step fails, immediately revert `COMMUNITY_PAYMENT_ENABLED` to `false`

## Summary

- **Alipay Web-Pay** handles ¥9.90 transactions through `alipay.trade.page.pay`, redirecting users to complete payment externally.
- **Supabase** stores order states in `community_orders` and protected images in `community_qr`, linking access to **PAID** status only.
- **API Layer** provides public endpoints for status checks and checkout initiation, with admin endpoints for QR rotation and refunds.
- **Idempotent Webhooks** ensure `POST /api/community/alipay/notify` safely processes duplicate notifications without corrupting order state.
- **Atomic Operations** in `replaceCommunityQr` prevent race conditions during QR code rotation.
- **Environment Flags** like `COMMUNITY_PAYMENT_ENABLED` provide circuit-breaker protection during deployment.

## Frequently Asked Questions

### How does the system prevent users from accessing QR codes after a refund?

When a refund is processed via `createRefund` in [`api/_lib/alipay.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/alipay.js), the order status updates to **REFUNDED** or **PROCESSING**. The `canAccessCommunityQr` helper function in [`api/_lib/community.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/community.js) checks this status and returns false for any non-**PAID** state, immediately blocking QR image retrieval.

### What happens if Alipay sends duplicate webhook notifications?

The `recordAlipayNotification` function implements idempotent updates. It checks the existing order state in the `community_orders` table before writing, ensuring duplicate notifications from Alipay do not create duplicate transactions or corrupt the payment status.

### Can administrators change the QR code without downtime?

Yes. The `replaceCommunityQr` function executes an RPC transaction that atomically disables the old image before enabling the new one. This approach, defined in [`api/_lib/community.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/community.js), ensures users never see a broken or outdated QR code during rotation.

### How is the payment amount fixed and protected?

The backend enforces the ¥9.90 (990 cents) amount in the `POST /api/community/alipay/checkout` handler. While the frontend may display the amount, the server validates or hardcodes the parameter when calling the Alipay SDK, preventing price tampering through client-side requests.