-- users 加两列 ALTER TABLE users ADD COLUMN invite_code TEXT; ALTER TABLE users ADD COLUMN first_paid_at DATETIME; CREATE UNIQUE INDEX ux_users_invite_code ON users(invite_code); -- 邀请关系(一对一绑定) CREATE TABLE referrals ( id INTEGER PRIMARY KEY AUTOINCREMENT, inviter_id INTEGER NOT NULL, invitee_id INTEGER NOT NULL UNIQUE, device_uuid TEXT, status TEXT NOT NULL DEFAULT 'bound' CHECK (status IN ('bound','reg_rewarded','paid_rewarded','rejected')), reg_rewarded_at DATETIME, paid_rewarded_at DATETIME, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (inviter_id) REFERENCES users(id), FOREIGN KEY (invitee_id) REFERENCES users(id) ); CREATE INDEX ix_referrals_inviter ON referrals(inviter_id, created_at); -- 通用一次性任务领取 CREATE TABLE reward_claims ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, task_key TEXT NOT NULL, external_ref TEXT NOT NULL DEFAULT '', granted_days INTEGER NOT NULL, granted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); CREATE UNIQUE INDEX ux_claim_user_task ON reward_claims(user_id, task_key); CREATE UNIQUE INDEX ux_claim_task_ref ON reward_claims(task_key, external_ref); -- subscriptions.source 扩容(SQLite 需重建表) CREATE TABLE subscriptions_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, plan_id INTEGER NOT NULL, expires_at DATETIME NOT NULL, source TEXT NOT NULL CHECK (source IN ('trial','code','pay','invite','task')), created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (plan_id) REFERENCES plans(id) ); INSERT INTO subscriptions_new (id,user_id,plan_id,expires_at,source,created_at) SELECT id,user_id,plan_id,expires_at,source,created_at FROM subscriptions; DROP TABLE subscriptions; ALTER TABLE subscriptions_new RENAME TO subscriptions; CREATE INDEX idx_subs_user_exp ON subscriptions (user_id, expires_at);