Clean prepaid SoT, identity mailbox, public access planes, leaf policy, fleet spawn
Some checks are pending
offline / test (push) Waiting to run

Persist account-balance books; edge caches prepaid from books. Add zappier-identity, verae-nats-accounts, verae-jobs-events, verae-access-staff, zapier-decisions. Edge binds loopback; lan-134 stays off; HTTP services prefer local spawn.
This commit is contained in:
George Lambert 2026-09-11 17:15:16 -04:00
parent 345aeeead9
commit ddf772454b
153 changed files with 2236 additions and 116 deletions

View file

@ -13,7 +13,8 @@ import { UsageRepo } from './usage';
import { CreditLedger } from './credits';
import { invoicesToAccountingCsv, invoicesToQuickBooksIif } from './accounting-export';
import { composeStatement } from './statement';
import { BILLING_SUBJECTS, natsAdjust, natsPublish, natsStatement } from './billing-nats';
import { BILLING_SUBJECTS, natsPublish } from './billing-nats';
import { booksConfigured, ledgerAdjust, ledgerStatement } from './ledger';
// Issued login tokens (in-memory; a restart simply requires logging in again).
const sessions = new Map<string, number>();
@ -229,7 +230,7 @@ export function adminRouter(
/* ---------------- customer service: credits ---------------- */
router.post('/credits', (req, res) => {
router.post('/credits', async (req, res) => {
const { customerId, cents, reason, agent } = req.body ?? {};
if (typeof customerId !== 'string' || !Number.isFinite(Number(cents))) {
res.status(400).json({ error: 'customerId and cents required' });
@ -247,9 +248,7 @@ export function adminRouter(
reason: typeof reason === 'string' ? reason : 'credit adjustment',
agent: typeof agent === 'string' ? agent : 'admin',
});
customers.save({ ...customer, balanceCents: (customer.balanceCents ?? 0) + delta });
natsPublish(BILLING_SUBJECTS.CREDIT_APPLIED, { ...rec, veraeUserId: customer.veraeUserId }, 'staff');
void natsAdjust(
const row = await ledgerAdjust(
{
customerId,
veraeUserId: customer.veraeUserId,
@ -260,7 +259,12 @@ export function adminRouter(
},
'staff',
);
res.status(201).json(rec);
let prepaid = customer.balanceCents ?? 0;
if (row && typeof row.prepaidCents === 'number') prepaid = row.prepaidCents;
else if (!booksConfigured()) prepaid += delta;
customers.save({ ...customer, balanceCents: prepaid });
natsPublish(BILLING_SUBJECTS.CREDIT_APPLIED, { ...rec, veraeUserId: customer.veraeUserId }, 'staff');
res.status(201).json({ ...rec, prepaidCents: prepaid });
});
router.get('/credits', (req, res) => {
@ -274,9 +278,9 @@ export function adminRouter(
res.status(404).json({ error: 'customer not found' });
return;
}
const fromNats = await natsStatement(customer.id, 'staff', customer.veraeUserId);
if (fromNats) {
res.json({ ...fromNats, name: customer.name, tierId: customer.tierId, source: 'nats' });
const fromBooks = await ledgerStatement(customer.id, 'staff', customer.veraeUserId);
if (fromBooks) {
res.json({ ...fromBooks, name: customer.name, tierId: customer.tierId, source: fromBooks.source || 'account-balance' });
return;
}
res.json({