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.