TailSpend Docs

Group balances

BALANCE#v1 in GroupData stores participant net amounts in group-currency minor units. Expense and settlement create, edit and delete operations commit the source row, its balance delta and notification event in one DynamoDB transaction. Existing version/uniqueness conditions reject a repeated or stale mutation before any delta commits. Guest takeover keeps its participant ID; bulk transfers use the same expense and settlement mutation paths. The existing allocator determines FX, rounding and item splits.

Initialized dashboard reads use the membership GSI query, group-head BatchGet and balance BatchGet. Group and People balance reads use the snapshot and current roster, without loading expense or settlement history. The roster keeps current zero-balance members visible; removed zero-balance members are omitted.

Rollout and migration

Deploy the new transaction writers to every stage before applying the backfill. Wait for invocations of the old Lambda code to finish (including recurring and transfer writers). New groups initialize their aggregate atomically with creation. Legacy groups keep history-based reads until explicitly migrated: a user request never publishes a legacy snapshot during a rolling deployment.

With normal AWS credentials and the repository dependencies installed:

npx tsx apps/services/scripts/backfill-group-balances.ts --table tailspend-dev-groups
npx tsx apps/services/scripts/backfill-group-balances.ts --table tailspend-dev-groups --apply

Use the actual deployed GroupData table name for beta and production. The first command is a dry run. --apply scans active group heads and initializes missing snapshots. It is safe to resume: initialized groups are skipped. Each migration uses strongly consistent base-table reads and conditionally publishes against BalanceRevision; a concurrent new writer changes that revision in the same transaction as its source write, forcing the migration to recompute. Three busy retries fail explicitly and can be retried later. No schema deployment or new IAM permission is required. Do not roll back to writers that omit aggregate deltas after initialization without disabling aggregate reads and rebuilding snapshots.

The migration and AWS read-capacity measurements must be run against the target stage; local mock tests do not claim deployment or production cost measurements.

View Markdown source