Site health/proxy, SiteAccount login state (challenge, lastLoginAt, lastError, userData), SiteUserData history table, SiteCredentialsBody by kind, refresh-login/health-check/user-data/delete endpoints, SitesSettings defaults. Co-Authored-By: Claude Opus 5.5 <[email protected]>
89 lines
3.2 KiB
TypeScript
89 lines
3.2 KiB
TypeScript
import type { Kysely } from "kysely";
|
|
import { entityTable, execDdl, oneOf } from "../src/migration-helpers.ts";
|
|
|
|
// W9-A 站点中心(docs/design/site-center.md §5):
|
|
// - site_account:登录状态加 challenge;账密登录名、TOTP / 会话 Cookie / passkey 的 secret 引用、UA、
|
|
// 上次登录、最近错误、最近一次用户数据;user_info.username 迁到 login_name。
|
|
// - site_user_data:用户数据按天一行(同日 upsert 取最新),随账号删除。
|
|
// - site:最近健康检测(结果 + 时间)、使用代理;deleted_at 软删除(source_release 外键 restrict,资源保留)。
|
|
|
|
const OLD_STATUS = ["unknown", "active", "invalid", "expired"];
|
|
const NEW_STATUS = [...OLD_STATUS, "challenge"];
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型
|
|
export async function up(db: Kysely<any>): Promise<void> {
|
|
await execDdl(
|
|
db,
|
|
`
|
|
alter table site_account drop constraint site_account_status_check;
|
|
alter table site_account add constraint site_account_status_check ${oneOf("status", NEW_STATUS)};
|
|
alter table site_account
|
|
add column login_name text,
|
|
add column totp_secret_ref uuid references secret (id) on delete set null,
|
|
add column session_secret_ref uuid references secret (id) on delete set null,
|
|
add column passkey_secret_ref uuid references secret (id) on delete set null,
|
|
add column user_agent text,
|
|
add column last_login_at timestamptz,
|
|
add column last_error jsonb,
|
|
add column user_data jsonb,
|
|
add column user_data_at timestamptz;
|
|
update site_account set login_name = user_info ->> 'username' where user_info ? 'username';
|
|
|
|
alter table site
|
|
add column last_health jsonb,
|
|
add column last_health_at timestamptz,
|
|
add column proxy boolean not null default false,
|
|
add column deleted_at timestamptz;
|
|
|
|
${entityTable(
|
|
"site_user_data",
|
|
`
|
|
site_account_id uuid not null references site_account (id) on delete cascade,
|
|
day date not null,
|
|
upload bigint not null default 0,
|
|
download bigint not null default 0,
|
|
ratio double precision,
|
|
bonus double precision,
|
|
seeding integer not null default 0,
|
|
seeding_size bigint not null default 0,
|
|
leeching integer not null default 0,
|
|
user_level text,
|
|
vip boolean,
|
|
message_unread integer not null default 0,
|
|
join_at text,
|
|
raw jsonb not null default '{}'::jsonb,
|
|
captured_at timestamptz not null default now(),
|
|
constraint site_user_data_day_key unique (site_account_id, day)`,
|
|
)}
|
|
`,
|
|
);
|
|
}
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: 同上
|
|
export async function down(db: Kysely<any>): Promise<void> {
|
|
await execDdl(
|
|
db,
|
|
`
|
|
drop table if exists site_user_data;
|
|
alter table site
|
|
drop column last_health,
|
|
drop column last_health_at,
|
|
drop column proxy,
|
|
drop column deleted_at;
|
|
alter table site_account
|
|
drop column login_name,
|
|
drop column totp_secret_ref,
|
|
drop column session_secret_ref,
|
|
drop column passkey_secret_ref,
|
|
drop column user_agent,
|
|
drop column last_login_at,
|
|
drop column last_error,
|
|
drop column user_data,
|
|
drop column user_data_at;
|
|
update site_account set status = 'expired' where status = 'challenge';
|
|
alter table site_account drop constraint site_account_status_check;
|
|
alter table site_account add constraint site_account_status_check ${oneOf("status", OLD_STATUS)};
|
|
`,
|
|
);
|
|
}
|