مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت. تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
@agy/billing-worker
Rolls the usage ledger into draft invoices — one invoice per organization per billing period.
pnpm --filter @agy/billing-worker run # one pass, then exit (cron shape)
pnpm --filter @agy/billing-worker dev # long-running loop
What it does
For every organization, for the requested period:
- Skip the organization if the period already has an invoice (idempotent — a cron job that fires twice must not bill twice).
- Otherwise sum the usage ledger for the period.
- Skip if the total is zero — no
$0drafts littering the table. - Otherwise create a
draftinvoice carrying the ledger's total.
What it deliberately does not do
- It never invents an amount. The ledger is the source of truth; the worker
only snapshots it. See
docs/architecture/overview.md§8. - It never moves money. Charging a card is
BillingService.settle_payment, behind an authenticated API call — not a background job.
Implementation
apps/api/app/workers/billing.py. The service wiring comes from
apps/api/app/application/container.py, so this worker and the API compose
services identically. Tests: apps/api/tests/test_workers.py.
Extracting this into its own process
The worker already opens its own database sessions and holds no request state,
so extraction is a deployment change, not a code change: run
python -m app.workers billing --loop as its own process with the same
DATABASE_URL, and point the cron/loop interval at your billing cycle.