# Vault Ledger — Product Requirements (v2.6)

Vault Ledger is a retail-banking view for internal transfers. A customer sees a Portfolio of a Checking and a Savings account with net liquidity, moves money between them through Move Funds, Review Transfer and an explicit Authorize step, and gets a reference for every completed transfer.

**Problem.** Customers must be certain that an authorized transfer debits and credits exactly the amount shown at review, so that balances and net liquidity always reconcile to the cent.

## Users
- **Retail customer** — Shift money between own accounts and see exact balances afterwards.

## Goals
- Every transfer debits the origin and credits the destination by exactly the reviewed amount; net liquidity never changes.
- Nothing moves until the customer authorizes it.
- Invalid amounts and account choices are refused at review with a specific message.

## Portfolio (PRT)

Balances and net liquidity.

- **FR-PRT-01** (Must) A fresh session shows the seeded balances and net liquidity equal to their sum.
  - Heading "Portfolio"; Checking •••• 4417 $4,823.50; Savings •••• 9032 $12,150.00; Net liquidity $16,973.50
- **FR-PRT-02** (Should) Each browser tab has its own ledger and balances are stored on the server, so they survive a reload but never leak into another tab.
  - After a $100.00 transfer in one tab Checking is $4,723.50; a second new tab shows $4,823.50
  - Balances are identical after a reload

## Transfer flow (TRF)

Move Funds, Review Transfer and Authorize.

- **FR-TRF-01** (Must) Review shows the origin, destination and amount; Authorize Transfer then moves money and shows a confirmation with a reference starting "TRF-". Returning to the Portfolio shows the new balances.
  - Checking → Savings $50.00: "Review transfer" From Checking, To Savings, Amount $50.00; "Transfer authorized" — "Moved $50.00 from Checking to Savings."
  - Checking $4,773.50; Savings $12,200.00; Net liquidity $16,973.50
- **FR-TRF-02** (Must) Transfers work in both directions and keep net liquidity unchanged.
  - Savings → Checking $1,250.75: "Moved $1,250.75 from Savings to Checking."; Checking $6,074.25; Savings $10,899.25; Net liquidity $16,973.50
- **FR-TRF-03** (Should) Balances carry over between transfers in the same session.
  - $20.00 then $30.00 from Checking: Checking $4,773.50, Savings $12,200.00, same after a reload
- **FR-TRF-04** (Could) The From list labels each account with its current balance; the To list shows names only, with Savings preselected.
  - From: "Checking ($4,823.50)", "Savings ($12,150.00)"; To: "Checking", "Savings"
- **FR-TRF-05** (Should) Edit on the review screen returns to Move Funds with the previous values; Cancel at any step leaves balances unchanged.
  - Edit shows Amount "75.00", From Checking, To Savings
  - Cancel returns to the Portfolio with Checking $4,823.50
- **FR-TRF-06** (Could) Reloading in the middle of a transfer returns to the Portfolio and nothing is transferred.
  - After review of $60.00 and a reload: Portfolio, Checking $4,823.50

## Amount validation (AMT)

Limits, rounding and account choice.

- **FR-AMT-01** (Must) A transfer may use the entire available balance but not one cent more.
  - 4823.50 from Checking: Checking $0.00, Savings $16,973.50
  - 4823.51: alert "Amount exceeds the available balance."; stays on Move Funds
- **FR-AMT-02** (Must) Only positive amounts are accepted; zero, negative, blank and non-numeric values are refused.
  - "0", "-5", empty and "fifty": "Enter an amount greater than $0.00."
- **FR-AMT-03** (Should) Amounts are rounded to whole cents; the smallest valid transfer is $0.01.
  - "0.004" rounds to $0.00 and is refused with "Enter an amount greater than $0.00."
  - "0.01": Checking $4,823.49; Savings $12,150.01
- **FR-AMT-04** (Must) Origin and destination must differ.
  - "Choose two different accounts."
- **FR-AMT-05** (Should) An amount typed with a thousands separator is accepted and shown correctly on the review screen.
  - "1,000" reviews as Amount $1,000.00

## Ledger API (API)

REST access to the portfolio, review and transfers.

- **FR-API-01** (Should) The portfolio is returned in cents per session; review validates without moving money.
  - checking 482350, savings 1215000, netLiquidity 1697350
  - Review checking → savings "50": 200, amount 5000, fromName "Checking", toName "Savings"; balances unchanged
  - Same account both sides: 422 "Choose two different accounts."
- **FR-API-02** (Should) Authorize returns the new balances and the session’s transfers are listed; over-limit amounts are refused.
  - Authorize $50: 201, id "TRF-…", status "authorized", checking 477350, savings 1220000, netLiquidity 1697350
  - List shows exactly one transfer of amount 5000
  - Amount "999999": 422 "Amount exceeds the available balance."

## Non-functional requirements

- **NFR-01** (Must) Ledger integrity: for every authorized transfer the origin falls and the destination rises by exactly the reviewed amount, so net liquidity is unchanged.
- **NFR-02** (Should) Data format: money is shown with a $ sign, thousands separators and two decimals; the API uses integer cents.

## Glossary and rules

- **Net liquidity** — Checking balance plus Savings balance.
- **Review Transfer** — The validation step that precedes authorization and moves no money.

## Out of scope

- External transfers and payees
- Authentication
