feat: 账本域 billing_domain 与成员支付可见性收紧

三表增加账本域标签,成员支付参数改为同域透明、跨域隔离、未标域默认藏;管理面登记/筛选/行内编辑与文档中心同步对齐。
This commit is contained in:
2026-10-13 20:42:26 +08:00
parent 843ab4433a
commit b0e9ea750b
31 changed files with 1463 additions and 53 deletions
@@ -0,0 +1,3 @@
ALTER TABLE "api_keys" ADD COLUMN "billing_domain" text;--> statement-breakpoint
ALTER TABLE "subscriptions" ADD COLUMN "billing_domain" text;--> statement-breakpoint
ALTER TABLE "topups" ADD COLUMN "billing_domain" text;
File diff suppressed because it is too large Load Diff
+7
View File
@@ -8,6 +8,13 @@
"when": 1791551016051,
"tag": "0000_loose_goblin_queen",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1791878178512,
"tag": "0001_aromatic_hawkeye",
"breakpoints": true
}
]
}
+37 -4
View File
@@ -115,6 +115,7 @@ export function createRepos(db: Db) {
async listAll(filter?: {
member_id?: number | "unassigned";
status?: string;
billing_domain?: string | "none";
}): Promise<KeyListRow[]> {
const conds = [];
if (filter?.member_id === "unassigned") {
@@ -125,6 +126,11 @@ export function createRepos(db: Db) {
if (filter?.status) {
conds.push(eq(apiKeys.status, filter.status));
}
if (filter?.billing_domain === "none") {
conds.push(isNull(apiKeys.billing_domain));
} else if (filter?.billing_domain) {
conds.push(eq(apiKeys.billing_domain, filter.billing_domain));
}
const base = db
.select({
id: apiKeys.id,
@@ -132,6 +138,7 @@ export function createRepos(db: Db) {
key_ciphertext: apiKeys.key_ciphertext,
status: apiKeys.status,
member_id: apiKeys.member_id,
billing_domain: apiKeys.billing_domain,
registered_at: apiKeys.registered_at,
log_synced_at: apiKeys.log_synced_at,
usage_synced_at: apiKeys.usage_synced_at,
@@ -220,6 +227,7 @@ export function createRepos(db: Db) {
key_hash: string;
key_ciphertext: Uint8Array;
member_id: number | null;
billing_domain?: string | null;
token_name?: string;
}): Promise<ApiKeyRow> {
const [row] = await db
@@ -228,6 +236,7 @@ export function createRepos(db: Db) {
key_hash: values.key_hash,
key_ciphertext: values.key_ciphertext,
member_id: values.member_id,
billing_domain: values.billing_domain ?? null,
token_name: values.token_name ?? "",
})
.returning();
@@ -404,11 +413,23 @@ export function createRepos(db: Db) {
},
subscriptions: {
async listAll(): Promise<SubscriptionRow[]> {
return db
async listAll(filter?: {
billing_domain?: string | "none";
}): Promise<SubscriptionRow[]> {
const conds = [];
if (filter?.billing_domain === "none") {
conds.push(isNull(subscriptions.billing_domain));
} else if (filter?.billing_domain) {
conds.push(eq(subscriptions.billing_domain, filter.billing_domain));
}
const base = db
.select()
.from(subscriptions)
.orderBy(desc(subscriptions.period_start));
if (conds.length > 0) {
return base.where(and(...conds));
}
return base;
},
async findById(id: number): Promise<SubscriptionRow | null> {
const rows = await db
@@ -451,8 +472,20 @@ export function createRepos(db: Db) {
},
topups: {
async listAll(): Promise<TopupRow[]> {
return db.select().from(topups).orderBy(desc(topups.paid_at));
async listAll(filter?: {
billing_domain?: string | "none";
}): Promise<TopupRow[]> {
const conds = [];
if (filter?.billing_domain === "none") {
conds.push(isNull(topups.billing_domain));
} else if (filter?.billing_domain) {
conds.push(eq(topups.billing_domain, filter.billing_domain));
}
const base = db.select().from(topups).orderBy(desc(topups.paid_at));
if (conds.length > 0) {
return base.where(and(...conds));
}
return base;
},
async findById(id: number): Promise<TopupRow | null> {
const rows = await db
+3
View File
@@ -44,6 +44,7 @@ export const apiKeys = pgTable(
member_id: bigint("member_id", { mode: "number" }).references(
() => members.id,
),
billing_domain: text("billing_domain"),
registered_at: timestamp("registered_at", {
withTimezone: true,
mode: "date",
@@ -135,6 +136,7 @@ export const subscriptions = pgTable(
mode: "number",
}),
paid_at: timestamp("paid_at", { withTimezone: true, mode: "date" }),
billing_domain: text("billing_domain"),
remark: text("remark").notNull().default(""),
created_at: timestamp("created_at", {
withTimezone: true,
@@ -161,6 +163,7 @@ export const topups = pgTable("topups", {
payment_provider: text("payment_provider"),
status: text("status"),
paid_at: timestamp("paid_at", { withTimezone: true, mode: "date" }).notNull(),
billing_domain: text("billing_domain"),
remark: text("remark").notNull().default(""),
created_at: timestamp("created_at", {
withTimezone: true,