How Paid Community Access Is Implemented in GPT‑Image2: A Technical Deep Dive
GPT‑Image2 implements paid community access through a tightly‑coupled architecture of React, Vercel serverless functions, Supabase, and Alipay, using a state‑machine‑driven order flow that restricts QR code access until payment is server‑side verified.
The freestylefly/awesome-gpt-image-2 repository demonstrates a production‑grade monetization pattern for gated community content. This article examines how the codebase orchestrates frontend checkout, payment verification, and protected asset delivery without exposing sensitive group credentials.
Architecture Overview
The paid community system operates across three distinct layers. React handles the user interface and payment initiation, Vercel serverless functions process business logic and Alipay integrations, and Supabase persists order states and binary QR assets. The flow enforces a strict sequence: authenticated users create orders, complete Alipay transactions, and only then receive access to the community QR code.
Front‑End Payment Flow
The user journey begins at /community, managed by src/community.jsx. This component orchestrates the entire client‑side state machine.
Checkout Initiation
When a user accepts the ¥9.90 terms and clicks Pay, the frontend POSTs to /api/community/alipay/checkout. The server returns an HTML form that auto‑submits to Alipay’s gateway. If the user already has a PAID order, the UI skips payment and immediately fetches the QR code.
// src/community.jsx – trigger checkout
async function handleCheckout() {
if (!acceptedTerms || !session?.access_token) return;
const response = await fetch('/api/community/alipay/checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...authHeaders(session)
},
body: JSON.stringify({ acceptedTerms: true, termsVersion: TERMS_VERSION })
});
const { ok, paymentHtml, paid } = await response.json();
if (paid) await loadStatus(); // already paid
else submitPaymentForm(paymentHtml); // redirects to Alipay
}
Status Polling and QR Retrieval
After Alipay redirects to /community/result?order_id=…, the page polls /api/community/alipay/query until the order status becomes PAID. Only then does the client call /api/community/qr to retrieve the binary image. The QR is never cached client‑side; each request validates the user’s order status server‑side.
Serverless API Layer
The /api/community/* endpoints implement the business logic as discrete Vercel functions. Each endpoint has a single responsibility within the order lifecycle.
Order Status Management
The api/community/status.js endpoint returns the public configuration, payment enablement flags, and the user’s current order state. It checks canAccessCommunityQr to determine if the authenticated user should see the QR option.
// api/community/status.js – return order & QR readiness
export default async function handler(req, res) {
const auth = await getAuthContext(req, { allowAnonymous: true });
const publicConfig = communityPublicConfig();
const paymentEnabled = publicConfig.paymentEnabled && isAlipayConfigured();
if (!auth.user) return res.status(200).json({
ok: true, authenticated: false, eligible: false, qrReady: false,
paymentEnabled, order: null
});
const [order, qr] = await Promise.all([
getLatestCommunityOrder(auth.client, auth.user.id),
getCurrentCommunityQr(auth.client)
]);
res.status(200).json({
ok: true,
authenticated: true,
eligible: canAccessCommunityQr(order?.status),
qrReady: Boolean(qr),
paymentEnabled,
order: serializeCommunityOrder(order)
});
}
Payment Processing Pipeline
checkout.js– Creates a new row incommunity_ordersviacommunityOrderPayloadand returns the Alipay payment HTML.query.js– Polls Alipay’s API for trade status. Upon confirmation, it invokes themark_community_order_paidPostgreSQL RPC to atomically update the order toPAID.close.js– Allows users to cancel pending orders, setting status toCLOSED.
Protected Asset Delivery
The api/community/qr.js endpoint streams the binary QR image from Supabase storage. It strictly enforces canAccessCommunityQr(order.status) before returning any data, ensuring the QR code remains inaccessible to non‑paying users.
Core Business Logic and Validation
All shared constants, validation rules, and database helpers reside in api/_lib/community.js. This module centralizes the security model for paid community access.
Order Lifecycle Constants
The file defines COMMUNITY_PRICE_CENTS (990 for ¥9.90), COMMUNITY_QR_MAX_BYTES (2 MiB), and allowed order statuses (PENDING, PAID, CLOSED). The communityPublicConfig function exposes a toggle (COMMUNITY_PAYMENT_ENABLED) that can disable payments globally without redeploying.
Payment Verification Security
Server‑side validation prevents tampering with payment callbacks. The validateCommunityTradeResult function verifies Alipay’s signature, matches the out_trade_no against the order ID, validates the amount equals COMMUNITY_PRICE_CENTS, and confirms the currency.
// api/_lib/community.js – validate Alipay trade result
export function validateCommunityTradeResult(order, result) {
if (!order || !result) return { ok: false, error: 'ORDER_RESULT_REQUIRED' };
if (String(result.out_trade_no || '') !== order.id) return { ok: false, error: 'OUT_TRADE_NO_MISMATCH' };
const amountCents = parseAlipayAmount(result.total_amount);
if (amountCents !== Number(order.amount_cents) || amountCents !== COMMUNITY_PRICE_CENTS)
return { ok: false, error: 'AMOUNT_MISMATCH' };
if (String(order.currency || '').toUpperCase() !== COMMUNITY_CURRENCY) return { ok: false, error: 'CURRENCY_MISMATCH' };
if (!String(result.trade_no || '').trim()) return { ok: false, error: 'TRADE_NO_REQUIRED' };
return { ok: true, amountCents };
}
The validateCommunityQrUpload helper ensures uploaded QR images are PNG, JPEG, or WebP format and under the size limit before storage.
Database Schema and Security Model
Supabase Schema
The migration supabase/migrations/20260722090000_paid_community.sql creates two tables:
community_orders– Stores order ID, user reference, amount, currency, status, and timestamps.community_group_qr_assets– Stores the binary QR image asbyteawith a foreign key to the order.
The migration also defines RPCs (mark_community_order_paid, close_community_order) that atomically update order state and validate transitions to prevent race conditions.
Access Control and Rate Limiting
The security model relies on server‑side verification only. The frontend never trusts URL parameters for payment status. The applyCommunityRateLimit middleware protects the status and query endpoints against enumeration attacks. QR access requires both a valid session and a PAID order status check on every request.
Summary
- GPT‑Image2 implements paid community access using React, Vercel serverless functions, Supabase, and Alipay.
- The order flow is managed through
community_orderstable rows with strict status states (PENDING,PAID,CLOSED). - Server‑side validation in
api/_lib/community.jsverifies Alipay signatures, amounts, and trade numbers before marking orders paid. - The QR code is stored as a binary asset in Supabase and streamed only through
api/community/qr.jsaftercanAccessCommunityQrconfirms thePAIDstatus. - Rate limiting and atomic database RPCs prevent abuse and race conditions during payment confirmation.
Frequently Asked Questions
What payment gateway does GPT‑Image2 use for paid community access?
GPT‑Image2 integrates Alipay as its payment gateway. The backend generates an HTML form via api/community/alipay/checkout.js that submits directly to Alipay’s checkout page. After payment, Alipay redirects to the application, and api/community/alipay/query.js verifies the transaction server‑side using Alipay’s API before granting access.
How is the community QR code protected from unauthorized access?
The QR code is never stored or transmitted to unauthenticated users. It resides as a bytea binary in Supabase within community_group_qr_assets. The api/community/qr.js endpoint checks canAccessCommunityQr(order.status) on every request, ensuring only users with a PAID order status receive the image stream.
What database tables store the paid community order data?
The system uses two primary tables defined in supabase/migrations/20260722090000_paid_community.sql: community_orders stores the order metadata, status, and payment details, while community_group_qr_assets stores the actual binary QR image linked to valid orders.
How does the system handle pending or cancelled orders?
Pending orders remain in the PENDING state until the query.js endpoint confirms payment or the user invokes close.js to cancel. The close_community_order RPC updates the status to CLOSED, preventing future payment attempts. Expired or abandoned orders stay in PENDING until explicitly closed or successfully paid.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →