Credit activity ledger: every earn and spend logged with a reason, listed under Campaigns

Hugh earned a 10-credit sign-in bonus, then bought a 280-credit extension; earned credits spend
first, so Earned read 0 and the bonus looked lost. There was no record a member could check.
Now every real credit movement writes a credit_log row (JSON store in file mode): welcome, sign-in
bonus with streak, daily claim, inbox reads, video watches, verified visits, milestone/leaderboard
bonuses, partner codes, admin/team grants, AI Copy Engine charges + refunds, flat buys (featured
run, extension, visit pack, more visits), login-ad days, and metered delivery rolled up per
campaign per day; on-chain purchased-credit spends are marked. GET /api/my/credits/activity;
dashboard shows the last 40 under Campaigns (also when there are no campaigns) with a link from
Earn credits. Chatbot canned answer + AI prompt updated; my.js tag bumped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-16 08:41:43 -05:00
parent ffacf741da
commit 69d672665c
8 changed files with 50 additions and 14 deletions
+12
View File
@@ -262,6 +262,18 @@ async function bootstrap() {
burned_at BIGINT NULL,
INDEX (burned_tx)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`);
// credit activity ledger: one row per real credit movement (metered delivery rolls up per campaign per day)
await q(`CREATE TABLE IF NOT EXISTS credit_log (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(190) NOT NULL,
ts BIGINT NOT NULL,
day CHAR(10) NOT NULL,
delta INT NOT NULL,
kind VARCHAR(20) NOT NULL,
note VARCHAR(160) NOT NULL,
ref VARCHAR(40) NULL,
INDEX (email, ts), INDEX (email, kind, ref, day)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`);
// follow-up email sequence queue (one row per free account)
await q(`CREATE TABLE IF NOT EXISTS drips (
email VARCHAR(190) PRIMARY KEY,