数据库
ShipAny 目前使用 Supabase 作为数据库。用于存储登录用户 / 支付订单等数据。
其他数据库,如 MySQL / PostgreSQL 等,后续会逐步支持。
为完整运行 ShipAny 的功能,请参考以下步骤配置数据库。
数据库配置
-
登录 Supabase 官网,创建一个 Supabase 数据库实例
-
进入创建好的 Supabase 数据库实例,获取 API 访问凭证
- 填写环境配置文件里面的数据库配置信息
你可以为开发环境 / 生产环境创建不同的 Supabase 数据库实例,分别填入到
.env.development
和.env.production
文件中。
.env.development
SUPABASE_URL = "https://xxx.supabase.co"
SUPABASE_ANON_KEY = "eyxxx.eyxxx.qhxxx"
SUPABASE_ANON_KEY
和SUPABASE_SERVICE_ROLE_KEY
二选一填写。为了数据安全性,建议在生产环境使用SUPABASE_SERVICE_ROLE_KEY
。
.env.production
SUPABASE_URL = "https://xxx.supabase.co"
SUPABASE_SERVICE_ROLE_KEY = "eyxxx.eyxxx.qhxxx"
创建数据表
- 复制 ShipAny 模板代码下
data/install.sql
里面的 SQL 语句
data/install.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
uuid VARCHAR(255) UNIQUE NOT NULL,
email VARCHAR(255) NOT NULL,
created_at timestamptz,
nickname VARCHAR(255),
avatar_url VARCHAR(255),
locale VARCHAR(50),
signin_type VARCHAR(50),
signin_ip VARCHAR(255),
signin_provider VARCHAR(50),
signin_openid VARCHAR(255),
UNIQUE (email, signin_provider)
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
order_no VARCHAR(255) UNIQUE NOT NULL,
created_at timestamptz,
user_uuid VARCHAR(255) NOT NULL DEFAULT '',
user_email VARCHAR(255) NOT NULL DEFAULT '',
amount INT NOT NULL,
interval VARCHAR(50),
expired_at timestamptz,
status VARCHAR(50) NOT NULL,
stripe_session_id VARCHAR(255),
credits INT NOT NULL,
currency VARCHAR(50),
sub_id VARCHAR(255),
sub_interval_count int,
sub_cycle_anchor int,
sub_period_end int,
sub_period_start int,
sub_times int,
product_id VARCHAR(255),
product_name VARCHAR(255),
valid_months int,
order_detail TEXT,
paid_at timestamptz,
paid_email VARCHAR(255),
paid_detail TEXT
);
- 在 Supabase 实例运行 SQL 语句,创建数据表
等配置好用户登录和支付功能后,用户数据和支付数据就会自动写入 users
和 orders
表中。
可以在 Supabase 实例控制台管理相关数据。
数据 CURD
可以参考 ShipAny 模板下 models
目录下 user.ts
和 order.ts
操作数据的逻辑。
使用 @supabase/supabase-js SDK 实现数据增删改查。
models/user.ts
import { User } from "@/types/user";
import { getSupabaseClient } from "./db";
export async function insertUser(user: User) {
const supabase = getSupabaseClient();
const { data, error } = await supabase.from("users").insert(user);
if (error) {
throw error;
}
return data;
}
export async function findUserByEmail(
email: string,
signin_provider: string
): Promise<User | undefined> {
const supabase = getSupabaseClient();
const { data, error } = await supabase
.from("users")
.select("*")
.eq("email", email)
.eq("signin_provider", signin_provider)
.single();
if (error) {
return undefined;
}
return data;
}