Merge remote-tracking branch 'origin/main' into cloudflare

This commit is contained in:
javayhu 2025-07-20 14:44:58 +08:00
commit 313c783dbd
8 changed files with 1952 additions and 10 deletions

View File

@ -0,0 +1,17 @@
CREATE INDEX "account_user_id_idx" ON "account" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "account_account_id_idx" ON "account" USING btree ("account_id");--> statement-breakpoint
CREATE INDEX "account_provider_id_idx" ON "account" USING btree ("provider_id");--> statement-breakpoint
CREATE INDEX "credit_transaction_user_id_idx" ON "credit_transaction" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "credit_transaction_type_idx" ON "credit_transaction" USING btree ("type");--> statement-breakpoint
CREATE INDEX "payment_type_idx" ON "payment" USING btree ("type");--> statement-breakpoint
CREATE INDEX "payment_price_id_idx" ON "payment" USING btree ("price_id");--> statement-breakpoint
CREATE INDEX "payment_user_id_idx" ON "payment" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "payment_customer_id_idx" ON "payment" USING btree ("customer_id");--> statement-breakpoint
CREATE INDEX "payment_status_idx" ON "payment" USING btree ("status");--> statement-breakpoint
CREATE INDEX "payment_subscription_id_idx" ON "payment" USING btree ("subscription_id");--> statement-breakpoint
CREATE INDEX "session_token_idx" ON "session" USING btree ("token");--> statement-breakpoint
CREATE INDEX "session_user_id_idx" ON "session" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "user_id_idx" ON "user" USING btree ("id");--> statement-breakpoint
CREATE INDEX "user_customer_id_idx" ON "user" USING btree ("customer_id");--> statement-breakpoint
CREATE INDEX "user_role_idx" ON "user" USING btree ("role");--> statement-breakpoint
CREATE INDEX "user_credit_user_id_idx" ON "user_credit" USING btree ("user_id");

View File

@ -0,0 +1,2 @@
ALTER TABLE "payment" ADD COLUMN "session_id" text;--> statement-breakpoint
CREATE INDEX "payment_session_id_idx" ON "payment" USING btree ("session_id");

View File

@ -0,0 +1,896 @@
{
"id": "216af09b-e743-44ca-aacf-3426238ab2f2",
"prevId": "6ed4f085-66bb-42c4-a708-2e5d86438ca2",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.account": {
"name": "account",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"account_id": {
"name": "account_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"provider_id": {
"name": "provider_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"id_token": {
"name": "id_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"access_token_expires_at": {
"name": "access_token_expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"refresh_token_expires_at": {
"name": "refresh_token_expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"scope": {
"name": "scope",
"type": "text",
"primaryKey": false,
"notNull": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"account_user_id_idx": {
"name": "account_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"account_account_id_idx": {
"name": "account_account_id_idx",
"columns": [
{
"expression": "account_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"account_provider_id_idx": {
"name": "account_provider_id_idx",
"columns": [
{
"expression": "provider_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"account_user_id_user_id_fk": {
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.credit_transaction": {
"name": "credit_transaction",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"amount": {
"name": "amount",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"remaining_amount": {
"name": "remaining_amount",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"payment_id": {
"name": "payment_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"expiration_date": {
"name": "expiration_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"expiration_date_processed_at": {
"name": "expiration_date_processed_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"credit_transaction_user_id_idx": {
"name": "credit_transaction_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"credit_transaction_type_idx": {
"name": "credit_transaction_type_idx",
"columns": [
{
"expression": "type",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"credit_transaction_user_id_user_id_fk": {
"name": "credit_transaction_user_id_user_id_fk",
"tableFrom": "credit_transaction",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.payment": {
"name": "payment",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"price_id": {
"name": "price_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"interval": {
"name": "interval",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"customer_id": {
"name": "customer_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"subscription_id": {
"name": "subscription_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true
},
"period_start": {
"name": "period_start",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"period_end": {
"name": "period_end",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"cancel_at_period_end": {
"name": "cancel_at_period_end",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"trial_start": {
"name": "trial_start",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"trial_end": {
"name": "trial_end",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"payment_type_idx": {
"name": "payment_type_idx",
"columns": [
{
"expression": "type",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_price_id_idx": {
"name": "payment_price_id_idx",
"columns": [
{
"expression": "price_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_user_id_idx": {
"name": "payment_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_customer_id_idx": {
"name": "payment_customer_id_idx",
"columns": [
{
"expression": "customer_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_status_idx": {
"name": "payment_status_idx",
"columns": [
{
"expression": "status",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_subscription_id_idx": {
"name": "payment_subscription_id_idx",
"columns": [
{
"expression": "subscription_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"payment_user_id_user_id_fk": {
"name": "payment_user_id_user_id_fk",
"tableFrom": "payment",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.session": {
"name": "session",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"token": {
"name": "token",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"ip_address": {
"name": "ip_address",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_agent": {
"name": "user_agent",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"impersonated_by": {
"name": "impersonated_by",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"session_token_idx": {
"name": "session_token_idx",
"columns": [
{
"expression": "token",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"session_user_id_idx": {
"name": "session_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"session_user_id_user_id_fk": {
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"session_token_unique": {
"name": "session_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.user": {
"name": "user",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email_verified": {
"name": "email_verified",
"type": "boolean",
"primaryKey": false,
"notNull": true
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": false
},
"banned": {
"name": "banned",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"ban_reason": {
"name": "ban_reason",
"type": "text",
"primaryKey": false,
"notNull": false
},
"ban_expires": {
"name": "ban_expires",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"customer_id": {
"name": "customer_id",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"user_id_idx": {
"name": "user_id_idx",
"columns": [
{
"expression": "id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"user_customer_id_idx": {
"name": "user_customer_id_idx",
"columns": [
{
"expression": "customer_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"user_role_idx": {
"name": "user_role_idx",
"columns": [
{
"expression": "role",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"user_email_unique": {
"name": "user_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.user_credit": {
"name": "user_credit",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"current_credits": {
"name": "current_credits",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
},
"last_refresh_at": {
"name": "last_refresh_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"user_credit_user_id_idx": {
"name": "user_credit_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"user_credit_user_id_user_id_fk": {
"name": "user_credit_user_id_user_id_fk",
"tableFrom": "user_credit",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.verification": {
"name": "verification",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"identifier": {
"name": "identifier",
"type": "text",
"primaryKey": false,
"notNull": true
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@ -0,0 +1,917 @@
{
"id": "318baf42-b0f6-4288-807b-778767149685",
"prevId": "216af09b-e743-44ca-aacf-3426238ab2f2",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.account": {
"name": "account",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"account_id": {
"name": "account_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"provider_id": {
"name": "provider_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"id_token": {
"name": "id_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"access_token_expires_at": {
"name": "access_token_expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"refresh_token_expires_at": {
"name": "refresh_token_expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"scope": {
"name": "scope",
"type": "text",
"primaryKey": false,
"notNull": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"account_user_id_idx": {
"name": "account_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"account_account_id_idx": {
"name": "account_account_id_idx",
"columns": [
{
"expression": "account_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"account_provider_id_idx": {
"name": "account_provider_id_idx",
"columns": [
{
"expression": "provider_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"account_user_id_user_id_fk": {
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.credit_transaction": {
"name": "credit_transaction",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"amount": {
"name": "amount",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"remaining_amount": {
"name": "remaining_amount",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"payment_id": {
"name": "payment_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"expiration_date": {
"name": "expiration_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"expiration_date_processed_at": {
"name": "expiration_date_processed_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"credit_transaction_user_id_idx": {
"name": "credit_transaction_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"credit_transaction_type_idx": {
"name": "credit_transaction_type_idx",
"columns": [
{
"expression": "type",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"credit_transaction_user_id_user_id_fk": {
"name": "credit_transaction_user_id_user_id_fk",
"tableFrom": "credit_transaction",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.payment": {
"name": "payment",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"price_id": {
"name": "price_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"interval": {
"name": "interval",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"customer_id": {
"name": "customer_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"subscription_id": {
"name": "subscription_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"session_id": {
"name": "session_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true
},
"period_start": {
"name": "period_start",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"period_end": {
"name": "period_end",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"cancel_at_period_end": {
"name": "cancel_at_period_end",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"trial_start": {
"name": "trial_start",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"trial_end": {
"name": "trial_end",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"payment_type_idx": {
"name": "payment_type_idx",
"columns": [
{
"expression": "type",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_price_id_idx": {
"name": "payment_price_id_idx",
"columns": [
{
"expression": "price_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_user_id_idx": {
"name": "payment_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_customer_id_idx": {
"name": "payment_customer_id_idx",
"columns": [
{
"expression": "customer_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_status_idx": {
"name": "payment_status_idx",
"columns": [
{
"expression": "status",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_subscription_id_idx": {
"name": "payment_subscription_id_idx",
"columns": [
{
"expression": "subscription_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"payment_session_id_idx": {
"name": "payment_session_id_idx",
"columns": [
{
"expression": "session_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"payment_user_id_user_id_fk": {
"name": "payment_user_id_user_id_fk",
"tableFrom": "payment",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.session": {
"name": "session",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"token": {
"name": "token",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"ip_address": {
"name": "ip_address",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_agent": {
"name": "user_agent",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"impersonated_by": {
"name": "impersonated_by",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"session_token_idx": {
"name": "session_token_idx",
"columns": [
{
"expression": "token",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"session_user_id_idx": {
"name": "session_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"session_user_id_user_id_fk": {
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"session_token_unique": {
"name": "session_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.user": {
"name": "user",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email_verified": {
"name": "email_verified",
"type": "boolean",
"primaryKey": false,
"notNull": true
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": false
},
"banned": {
"name": "banned",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"ban_reason": {
"name": "ban_reason",
"type": "text",
"primaryKey": false,
"notNull": false
},
"ban_expires": {
"name": "ban_expires",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"customer_id": {
"name": "customer_id",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"user_id_idx": {
"name": "user_id_idx",
"columns": [
{
"expression": "id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"user_customer_id_idx": {
"name": "user_customer_id_idx",
"columns": [
{
"expression": "customer_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"user_role_idx": {
"name": "user_role_idx",
"columns": [
{
"expression": "role",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"user_email_unique": {
"name": "user_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.user_credit": {
"name": "user_credit",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"current_credits": {
"name": "current_credits",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
},
"last_refresh_at": {
"name": "last_refresh_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"user_credit_user_id_idx": {
"name": "user_credit_user_id_idx",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"user_credit_user_id_user_id_fk": {
"name": "user_credit_user_id_user_id_fk",
"tableFrom": "user_credit",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.verification": {
"name": "verification",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"identifier": {
"name": "identifier",
"type": "text",
"primaryKey": false,
"notNull": true
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@ -15,6 +15,20 @@
"when": 1751214200582,
"tag": "0001_woozy_jigsaw",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1752913862566,
"tag": "0002_left_grandmaster",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1752992749001,
"tag": "0003_loving_risque",
"breakpoints": true
}
]
}

View File

@ -1,4 +1,4 @@
import { boolean, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { boolean, integer, pgTable, text, timestamp, index } from "drizzle-orm/pg-core";
export const user = pgTable("user", {
id: text("id").primaryKey(),
@ -13,7 +13,11 @@ export const user = pgTable("user", {
banReason: text('ban_reason'),
banExpires: timestamp('ban_expires'),
customerId: text('customer_id'),
});
}, (table) => ({
userIdIdx: index("user_id_idx").on(table.id),
userCustomerIdIdx: index("user_customer_id_idx").on(table.customerId),
userRoleIdx: index("user_role_idx").on(table.role),
}));
export const session = pgTable("session", {
id: text("id").primaryKey(),
@ -25,7 +29,10 @@ export const session = pgTable("session", {
userAgent: text('user_agent'),
userId: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }),
impersonatedBy: text('impersonated_by')
});
}, (table) => ({
sessionTokenIdx: index("session_token_idx").on(table.token),
sessionUserIdIdx: index("session_user_id_idx").on(table.userId),
}));
export const account = pgTable("account", {
id: text("id").primaryKey(),
@ -41,7 +48,11 @@ export const account = pgTable("account", {
password: text('password'),
createdAt: timestamp('created_at').notNull(),
updatedAt: timestamp('updated_at').notNull()
});
}, (table) => ({
accountUserIdIdx: index("account_user_id_idx").on(table.userId),
accountAccountIdIdx: index("account_account_id_idx").on(table.accountId),
accountProviderIdIdx: index("account_provider_id_idx").on(table.providerId),
}));
export const verification = pgTable("verification", {
id: text("id").primaryKey(),
@ -60,6 +71,7 @@ export const payment = pgTable("payment", {
userId: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }),
customerId: text('customer_id').notNull(),
subscriptionId: text('subscription_id'),
sessionId: text('session_id'),
status: text('status').notNull(),
periodStart: timestamp('period_start'),
periodEnd: timestamp('period_end'),
@ -68,7 +80,15 @@ export const payment = pgTable("payment", {
trialEnd: timestamp('trial_end'),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
});
}, (table) => ({
paymentTypeIdx: index("payment_type_idx").on(table.type),
paymentPriceIdIdx: index("payment_price_id_idx").on(table.priceId),
paymentUserIdIdx: index("payment_user_id_idx").on(table.userId),
paymentCustomerIdIdx: index("payment_customer_id_idx").on(table.customerId),
paymentStatusIdx: index("payment_status_idx").on(table.status),
paymentSubscriptionIdIdx: index("payment_subscription_id_idx").on(table.subscriptionId),
paymentSessionIdIdx: index("payment_session_id_idx").on(table.sessionId),
}));
export const userCredit = pgTable("user_credit", {
id: text("id").primaryKey(),
@ -77,7 +97,9 @@ export const userCredit = pgTable("user_credit", {
lastRefreshAt: timestamp("last_refresh_at"),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow(),
});
}, (table) => ({
userCreditUserIdIdx: index("user_credit_user_id_idx").on(table.userId),
}));
export const creditTransaction = pgTable("credit_transaction", {
id: text("id").primaryKey(),
@ -91,4 +113,7 @@ export const creditTransaction = pgTable("credit_transaction", {
expirationDateProcessedAt: timestamp("expiration_date_processed_at"),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow(),
});
}, (table) => ({
creditTransactionUserIdIdx: index("credit_transaction_user_id_idx").on(table.userId),
creditTransactionTypeIdx: index("credit_transaction_type_idx").on(table.type),
}));

View File

@ -1,7 +1,12 @@
import { betterFetch } from '@better-fetch/fetch';
import createMiddleware from 'next-intl/middleware';
import { type NextRequest, NextResponse } from 'next/server';
import { LOCALES, routing } from './i18n/routing';
import {
DEFAULT_LOCALE,
LOCALES,
LOCALE_COOKIE_NAME,
routing,
} from './i18n/routing';
import type { Session } from './lib/auth-types';
import { getBaseUrl } from './lib/urls/urls';
import {
@ -23,9 +28,31 @@ const intlMiddleware = createMiddleware(routing);
* to handle redirection. To avoid blocking requests by making API or database calls.
*/
export default async function middleware(req: NextRequest) {
const { nextUrl, headers } = req;
const { nextUrl } = req;
console.log('>> middleware start, pathname', nextUrl.pathname);
// Handle internal docs link redirection for internationalization
// Check if this is a docs page without locale prefix
if (nextUrl.pathname.startsWith('/docs/') || nextUrl.pathname === '/docs') {
// Get the user's preferred locale from cookie
const localeCookie = req.cookies.get(LOCALE_COOKIE_NAME);
const preferredLocale = localeCookie?.value;
// If user has a non-default locale preference, redirect to localized version
if (
preferredLocale &&
preferredLocale !== DEFAULT_LOCALE &&
LOCALES.includes(preferredLocale)
) {
const localizedPath = `/${preferredLocale}${nextUrl.pathname}${nextUrl.search}${nextUrl.hash}`;
console.log(
'<< middleware end, redirecting docs link to preferred locale:',
localizedPath
);
return NextResponse.redirect(new URL(localizedPath, nextUrl));
}
}
// do not use getSession() here, it will cause error related to edge runtime
// const session = await getSession();
const { data: session } = await betterFetch<Session>(

View File

@ -748,9 +748,24 @@ export class StripeProvider implements PaymentProvider {
}
try {
const db = await getDb();
// Check if this session has already been processed to prevent duplicate processing
const existingPayment = await db
.select({ id: payment.id })
.from(payment)
.where(eq(payment.sessionId, session.id))
.limit(1);
if (existingPayment.length > 0) {
console.log(
'One-time payment session already processed: ' + session.id
);
return;
}
// Create a one-time payment record
const now = new Date();
const db = await getDb();
const result = await db
.insert(payment)
.values({
@ -759,6 +774,7 @@ export class StripeProvider implements PaymentProvider {
type: PaymentTypes.ONE_TIME,
userId: userId,
customerId: customerId,
sessionId: session.id, // Track the session ID
status: 'completed', // One-time payments are always completed
periodStart: now,
createdAt: now,
@ -833,6 +849,34 @@ export class StripeProvider implements PaymentProvider {
}
try {
// Check if this session has already been processed to prevent duplicate credit additions
const db = await getDb();
const existingPayment = await db
.select({ id: payment.id })
.from(payment)
.where(eq(payment.sessionId, session.id))
.limit(1);
if (existingPayment.length > 0) {
console.log('Credit purchase session already processed: ' + session.id);
return;
}
// Create payment record first to mark this session as processed
const now = new Date();
await db.insert(payment).values({
id: randomUUID(),
priceId: session.metadata?.priceId || '',
type: PaymentTypes.ONE_TIME,
userId: userId,
customerId: customerId,
sessionId: session.id, // Use sessionId to track processed sessions
status: 'completed',
periodStart: now,
createdAt: now,
updatedAt: now,
});
// add credits to user account
const amount = session.amount_total ? session.amount_total / 100 : 0;
await addCredits({