Skip to main content

Expense splitting

An expense belongs to expense.expenses and expense.expense_splits. It is often anchored to a feed post, but the money rows stay in the expense schema. Feed stores the evidence presentation and calls internal expense APIs; expense calls feed when a guest payment needs a comment or when bulk evidence is attached.

Guest invites​

GetPublicBillInviteUseCase and ClaimBillInviteUseCase use an unguessable token. The pepper is SPLICK_BILL_INVITE_PEPPER. Guest email at rest uses SPLICK_GUEST_EMAIL_ENCRYPTION_KEY. Public routes are /api/v1/public/bills/{token} and the claim route under /api/v1/bills. Kong rate-limits them. The website can render an invite link; it does not calculate splits.

Settlement​

SettleExpenseSplitUseCase marks a split. SubmitBulkSettlementUseCase groups many splits, with approve and reject events. Payment evidence can be approved or rejected. Each of those facts is an outbox type on splick.streams.expense.* so notification-service can render the inbox item. Daily and automatic reminders are cron jobs (DailyDebtReminderJob, AutoExpenseReminderJob), not client polling.

Deletion​

splick.streams.auth.user-deleted lands in deleted_users handling so a removed account does not keep receiving debt reminders. Splits that involve a deleted user follow the use case rules already in the module; do not null them out from a SQL console.

PostgresIntegrationTestSupport runs these persistence rules on Testcontainers Postgres 16. Use it when a migration changes split or settlement shape.