2.2 KiB
2.2 KiB
Variable Pool Rebalance / Transfer Feature
Summary
- Allow users to redistribute current variable pool (BudgetSession.availableCents) by setting per-category dollar targets, without changing future percent-based allocations.
- Enforce guards: sum = available, savings floor confirm, non-negative, no single category >80%, warnings when lowering savings.
- New backend endpoint performs atomic balance updates and audit logging; fixed expenses unaffected.
API
POST /variable-categories/manual-rebalance- Body:
{ targets: [{ id, targetCents }], forceLowerSavings?: boolean } - Uses latest BudgetSession by periodStart; availableCents is the pool to balance.
- Validations: targets cover every category; non-negative; sum(targets)=available; each ≤80% of available; lowering savings or savings <20% requires
forceLowerSavings. - Transaction: update category balanceCents to targets; insert transaction(kind=
rebalance, note snapshot); fixed plans untouched. - Response:
{ ok: true, availableCents, categories: [{ id, balanceCents }] }.
- Body:
UI/UX
- New Rebalance page (Settings → Expenses tab entry point) showing availableCents and per-category balances.
- Editable dollar inputs with live total meter and inline errors for rule violations.
- Savings floor warning/confirm; optional helper to adjust one category and auto-scale others respecting floors.
- Confirmation modal summarizing before/after deltas.
Data / Logic
- Active session = latest BudgetSession for user.
- Rebalance acts on current variable pool only; future income remains percent-based.
- Savings floor default 20% of available; lowering requires confirmation flag.
Tests
- Sum=available happy path; savings unchanged.
- Lowering savings w/out flag → 400; with flag → OK.
- Savings total <20% w/out flag → 400; with flag → OK.
-
80% single category → 400.
- Sum mismatch → 400; negative target → 400.
- Negative existing balance allowed only if target >=0 (ending non-negative).
- Adjust-one helper unit: scaling respects floors.
- Audit entry created; fixed plans and percents unchanged.
Assumptions
- availableCents equals dashboard “Available” variable pool.
- No localization requirements for new errors.