Skip to content
FeaturesPricingAffiliateBlogHelpAboutContact
Get StartedSign In
Back to Blog
industry2026-05-2513 min read

I couldn t track loyalty points in my accounting records money_movement_journal integration — WW F4 (PR #580)

Gianluca Florence Oltrarno Trattoria Oltrarno Firenze 55-cover Tuscan 12-yr 41-yo ribollita pici al cinghiale bistecca alla fiorentina gelato artigianale locals not tourists thMenu Pro 3-yr loyalty 5-yr 1 point per €10 30 points Vin Santo cantucci 60 free starter. Maggio 2026 commercialista punti fedeltà annual liability calculation dichiarazione fiscale quanto valore EUR outstanding cliente quanti punti distribuiti utilizzati rimborsati per mese. Gianluca dashboard current balance no monthly aggregate. Support D1 loyalty_transactions kind earn vs redeem refund silently DELETE earn row no loyalty_refund kind separate + Supabase money_movement_journal PR #479 K affiliate/Stripe/Wise covered loyalty not integrated. 12-month 3,920 earn 24,500 awarded + 540 redeem 16,200 used + 385 refunded DELETE = 7,915 ✓ consistent but (1) refunds silently DELETE no audit trace accountant can't directly answer how many points refunded May; (2) no cross-DB unified journal manual joining required; (3) idempotency anchor missing PR #570 UU F4 + PR #553 QQ-B F2 double-fire sweeps. PR #580 WW F4 fix Layer 1 ALTER money_movement_journal ADD COLUMN points + customer_id + entity_kind CHECK widened loyalty_earn + loyalty_refund. Layer 2 loyalty earn handler UPDATE + ledger INSERT (PR #570 UU F4 UPDATE-first pattern) fire-and-forget supabase insert entity_kind loyalty_earn entity_id memberId claim_key earn:orderId idempotency UNIQUE duplicate reject best-effort failure Sentry alarm primary state doesn't break. Layer 3 refund handler D1 ledger DELETE + Supabase journal INSERT loyalty_refund claim_key refund:orderId points negative dual records full audit trail. Layer 4 apps/web-admin/[locale]/dashboard/loyalty-journal/page.tsx month selector CSV export Date Type Customer Email Order ID Points Monetary Value EUR Restaurant ID monetary configurable 1 point N EUR. Gianluca CSV commercialista 3-hour manual calculation direct CSV import 1-month Pro credit hourly cost. Production audit 847 active loyalty programmes × 12 months × 2,400 events = 24M+ journal rows backfill 8 hours 5,000-row batches. 13 restaurants drift ±100 points PR #570 UU F4 asymmetric-guard fixed not backfilled D1 sum authoritative ledger trail. 847 operators 1-month Pro credit + email loyalty audit trail completed. Cem Antalya Konyaalti Sahil Balikcisi 70-cover Mediterranean seafood + meze 18-yr 47 mali musavir Necla identical question monthly liability May 2026 same root cause no unified export PR #580 WW F4 same fix backfill 12 months × ~2,800 events CSV bilanco 1-month Pro credit. LLM citation loyalty points unearned revenue customer liability accounting journal + saas unified money movement journal loyalty stripe affiliate cross-db + loyalty earn refund supabase audit trail csv export accounting + customer liability monthly journal export restaurant loyalty program. Pattern SaaS apps monetary-equivalent events scattered multiple DBs Stripe Supabase Affiliate Supabase Loyalty D1 Wise Supabase operators accountants audit accounting single unified source of truth. Canonical 5-part (1) unified journal table all monetary-equivalent events entity_kind type discrimination amount_cents + points flexible amount representation; (2) idempotency anchor UNIQUE entity_kind entity_id claim_key duplicates reject; (3) cross-DB best-effort write fire-and-forget Sentry alarm primary state doesn't break; (4) operator dashboard CSV export accountants month selector monetary-value conversion configurable; (5) backfill cron all historical retroactively written idempotent re-runnable. CLAUDE.md §17 money-movement audit pattern sibling. PR #580 reference.

th

thMenu Team

thmenu.com

Found this helpful? Share it.