{"ns":"splitter","title":"Fair Share","version":"1.0","summary":"Fair Share splits restaurant and shopping bills. A user uploads a receipt photo (or picks a sample) and the parser extracts items, tax, tip and discounts. The user edits items, adds people, assigns items whole, shared or by unit, and gets per-person totals with proportional tax and tip and exact-cent rounding, then copies or shares a read-only link. Optional accounts add bill history, groups with running balances, debt simplification, recurring drafts, multi-currency expenses and sandbox settlement payments with fees, refunds and requests.","problem":"Splitting a bill by hand is error-prone: tax and tip must follow what each person ordered, cents must not vanish, and groups that share expenses over time need to know who owes whom and settle it with the fewest payments.","personas":[{"name":"Casual splitter","need":"Photograph a receipt, say who had what, and get fair totals without signing up."},{"name":"Group member","need":"Track shared expenses in a group, see a balance and settle it with the fewest payments."},{"name":"Group admin","need":"Manage members and invites for a household or trip group."}],"goals":["Per-person totals always add up to the bill to the cent.","Tax and tip follow each person's share of the items.","Group balances net to zero and can be settled with the fewest transfers; payments and refunds keep the ledger correct."],"features":[{"id":"RCP","title":"Receipt reading","summary":"Photo upload, sample receipts and failure handling.","reqs":[{"id":"FR-RCP-01","weight":"Must","text":"A receipt is read into items, tax, tip and a total check.","accept":["Choosing the \"Harbor Grill — dinner for three\" sample and \"Use sample\" shows \"Reading your receipt…\", then the Items step","Margherita pizza 1 × 16.50, Caesar salad 1 × 11.25, Craft beer 3 × 7.00, Truffle fries 1 × 8.75, Sparkling water 2 × 3.50","Tax 5.72, tip 0, \"✓ Matches the receipt total $70.22\""]},{"id":"FR-RCP-02","weight":"Should","text":"A receipt in another currency keeps its currency, and a service charge is read as the tip.","accept":["\"Café Lumière — euro receipt with service\": symbol €","Croque-monsieur 12.50, Café crème 2 × 3.80, Tarte Tatin 7.90 (subtotal €28.00); tax 2.80, tip 2.80; matches the receipt total €33.60"]},{"id":"FR-RCP-03","weight":"Should","text":"The receipt check flags a total that does not match the printed one and clears when the line is corrected.","accept":["\"Corner Market — groceries with a member discount\": badge \"⚠ … off by $0.45\"","Price of Sourdough 6.49 + Enter: \"✓ Matches the receipt total\""]},{"id":"FR-RCP-04","weight":"Should","text":"An unreadable photo is rejected with a clear message and recovery options.","accept":["\"A blurry photo (not readable)\": \"We couldn't find a receipt in this photo. Try a sharper photo, or enter the items yourself.\"","Buttons \"Try another photo\" and \"Enter items manually\", no Retry; manual entry opens an empty Items step with \"New item name\""]},{"id":"FR-RCP-05","weight":"Could","text":"A non-image file is refused with \"Unsupported file type. Use a JPG, PNG, HEIC or WebP photo.\""},{"id":"FR-RCP-06","weight":"Could","text":"A temporary reading failure keeps the photo and can be retried.","accept":["The first attempt fails with an error and a \"Retry\" button; Retry reads the receipt and opens Items"]}]},{"id":"ITM","title":"Items, tax and tip","summary":"Editing the bill lines, tax and tip.","reqs":[{"id":"FR-ITM-01","weight":"Should","text":"Quantity is a whole number from 1 to 99 and a negative price is allowed only on a Discount line.","accept":["Quantity 0, 100 or 2.5: \"Quantity must be a whole number from 1 to 99\"","Quantity 99 on Craft beer gives a line total of 693.00","Price -2: \"Price can't be negative — tick “Discount” for a discount line\""]},{"id":"FR-ITM-02","weight":"Should","text":"A bill can be entered by hand, including discount lines that lower the total.","accept":["Soup 2 × 6.00 and Bread 1 × 3.00: bill total $15.00","Coupon 5.00 with Discount ticked: bill total $10.00"]},{"id":"FR-ITM-03","weight":"Should","text":"Tip percent must be between 0 and 100 and the toggle switches to a fixed tip amount.","accept":["101: \"Tip must be between 0 and 100%\"","Switching to $ and typing 10 gives bill total $80.22 on Harbor Grill"]},{"id":"FR-ITM-04","weight":"Must","text":"A percentage tip is calculated on the pre-tax subtotal, not on subtotal plus tax.","accept":["Harbor Grill with the \"18\" chip: tip $11.61 and bill total $81.83"]},{"id":"FR-ITM-05","weight":"Could","text":"Tax more than twice the subtotal shows a warning but does not block.","accept":["Tax 200.00 shows a warning about unusually high tax; the total still updates"]}]},{"id":"PPL","title":"People and assignment","summary":"Adding people and assigning items whole, shared or by unit.","reqs":[{"id":"FR-PPL-01","weight":"Should","text":"Names are unique case-insensitively and at most 30 characters.","accept":["Ana then ana: \"Ana is already on this bill\"; only one Ana","A 31-character name is refused"]},{"id":"FR-PPL-02","weight":"Could","text":"Removing a person who has items asks for confirmation in an in-page dialog.","accept":["Removing Cleo opens a dialog (not a browser popup); Cancel keeps her and her items"]},{"id":"FR-PPL-03","weight":"Should","text":"The unassigned counter drops to zero as items are assigned, and per-unit assignment shows how many units are assigned.","accept":["Assign starts with \"5 unassigned\"","Craft beer \"By unit\" with Ana 2 and Ben 1 shows \"3 of 3 assigned\"","All items assigned shows \"All items assigned\""]},{"id":"FR-PPL-04","weight":"Could","text":"Results are blocked while nothing is assigned.","accept":["\"Nothing is assigned yet…\" followed by the five item names"]}]},{"id":"RES","title":"Results and rounding","summary":"Per-person totals with proportional tax and tip.","reqs":[{"id":"FR-RES-01","weight":"Must","text":"Tax and tip are spread in proportion to each person's item total, and the per-person totals add up to the bill.","accept":["Harbor Grill, 18% tip; Margherita pizza to Ana + Ben, Caesar salad to Cleo, Craft beer by unit Ana 2 and Ben 1, Truffle fries to everyone, Sparkling water to Cleo","Ana $31.93, Ben $23.05, Cleo $26.85; grand total $81.83 and sum of people $81.83","Ana's card: items 25.17, tax 2.23, tip 4.53"]},{"id":"FR-RES-02","weight":"Must","text":"Rounding never loses or invents cents: the leftover cent goes to one person and the people always sum to the bill.","accept":["A $10.00 item shared by three: one person $3.34, two $3.33, sum $10.00 equals the grand total"]}]},{"id":"SHR","title":"Sharing","summary":"Read-only share links.","reqs":[{"id":"FR-SHR-01","weight":"Should","text":"A share link opens the split read-only for anyone, without signing in.","accept":["\"Create share link\" shows a /splitter/s/<id> link","In a fresh browser: Harbor Grill with Ana $31.93, Ben $23.05, Cleo $26.85 and no edit controls"]},{"id":"FR-SHR-02","weight":"Should","text":"The link of a deleted bill stops working and says so.","accept":["After deleting the shared bill from History the link shows \"This bill no longer exists — its owner deleted it.\""]}]},{"id":"HST","title":"Bill history","summary":"Saved bills of a signed-in user.","reqs":[{"id":"FR-HST-01","weight":"Must","text":"A signed-in user lands on history, which lists saved bills newest first, 20 per page.","accept":["Lands on /splitter/history with 23 bills for Maya","First rows: Harbor Grill 2026-10-16 $81.83, Corner Market $34.46, Noodle Bar 88 $44.02","\"Older ›\" shows three rows: Green Bowl, Night Market, Bill 20 Jun 2026, with \"‹ Newer\" enabled"]},{"id":"FR-HST-02","weight":"Could","text":"History search matches participant names as well as titles.","accept":["\"rafael\" finds exactly Noodle Bar 88 (2026-10-11) and Golden Wok (2026-09-02)"]},{"id":"FR-HST-03","weight":"Could","text":"A saved bill can be renamed (1 to 80 characters) and duplicated.","accept":["81 characters: \"Title must be 1–80 characters\"","Rename to \"Team lunch\"; Duplicate adds a second \"Team lunch\" at $44.02, 24 bills in total"]}]},{"id":"ATH","title":"Accounts","summary":"Sign-up, verification, reset, lockout and deletion.","reqs":[{"id":"FR-ATH-01","weight":"Must","text":"After five wrong passwords the sixth attempt locks sign-in for 15 minutes, even with the correct password.","accept":["Wrong attempts one to five: \"Incorrect email or password\"","Sixth attempt: \"Too many failed attempts. Try again in 15 minutes.\"","The correct password is still refused with the same message"]},{"id":"FR-ATH-02","weight":"Should","text":"Sign-up refuses taken emails and weak passwords, and a new account stays unverified until its mailbox link is used once.","accept":["Existing email: \"That email is already in use.\"","Password under 8 characters or lacking a letter or number: \"Password must be at least 8 characters and include a letter and a number\"","Valid sign-up signs in with an \"unverified\" banner; the Mailbox link removes it; opening it again: \"This link was already used.\""]},{"id":"FR-ATH-03","weight":"Should","text":"A password reset link changes the password once.","accept":["The new password works and the old one fails","The same link again: \"This reset link was already used. Request a new one.\""]},{"id":"FR-ATH-04","weight":"Could","text":"Account deletion needs the exact word DELETE and a password change needs the correct current password.","accept":["\"delete\": \"Type DELETE to confirm\"","Wrong current password: \"Current password is incorrect\""]}]},{"id":"GRP","title":"Groups","summary":"Group list, membership and invites.","reqs":[{"id":"FR-GRP-01","weight":"Must","text":"The group list shows each group's member count, currency and the user's balance direction.","accept":["Flat 4B 🏠 (4 members) \"gets back $40.00\"; Lisbon trip ✈️ (3 members) \"owes €85.08\""]},{"id":"FR-GRP-02","weight":"Must","text":"A member cannot leave a group while their balance is not zero.","accept":["Leaving Flat 4B with −$80.00: \"You can't leave while your balance is −$80.00. Settle up first.\"; the member stays"]},{"id":"FR-GRP-03","weight":"Could","text":"A valid invite code joins the group; a revoked code does not.","accept":["LISBON-JOIN opens Lisbon trip with 4 members","FLAT4B-NOPE: \"This invite link is no longer valid.\""]},{"id":"FR-GRP-04","weight":"Should","text":"Only the group admin can remove members, make admins or share invites; others can still leave.","accept":["A non-admin sees no \"Remove\", \"Make admin\" or invite link controls in Flat 4B; \"Leave group\" is present"]}]},{"id":"EXP","title":"Group expenses","summary":"Expenses with several split modes and currencies.","reqs":[{"id":"FR-EXP-01","weight":"Could","text":"The expense list shows amounts and dates for every split mode, recurring expenses and drafts.","accept":["Flat 4B: Concert tickets $150 (10 Oct), Pizza night $80, Cleaning supplies $45, Groceries $120, Internet $60 (repeats monthly)","Banner: a draft \"Internet\" due 2026-10-15 awaiting confirmation"]},{"id":"FR-EXP-02","weight":"Should","text":"Exact and percent splits show a live remainder and cannot be saved until it is zero.","accept":["Taxi $40.00 exact 10 / 10 / 10: remainder $10.00 left, Save disabled; Sam 10: remainder 0, Save enabled","Percent 25 / 25 / 25 / 20: 5% left, Save disabled"]},{"id":"FR-EXP-03","weight":"Should","text":"An expense paid in another currency keeps its original amount, rate and rate date, and balances are in the group currency.","accept":["Lisbon trip: Museum tickets €49.68, Dinner in Alfama €84.60, Hostel (3 nights) €270.00","Museum tickets: originally $54.00 at 0.92, rate of 2026-09-12","Balances: Theo +€135.24, Maya −€85.08, Jonas −€50.16"]}]},{"id":"BAL","title":"Balances and settle-up","summary":"Who owes whom and the suggested payments.","reqs":[{"id":"FR-BAL-01","weight":"Must","text":"Group balances are computed from the expenses and payments and net to zero.","accept":["Flat 4B: Maya +$40.00, Theo +$70.00, Priya −$80.00, Sam (guest) −$30.00"]},{"id":"FR-BAL-02","weight":"Must","text":"Suggested payments are simplified across the whole group, using the fewest transfers that settle every balance.","accept":["Flat 4B suggests exactly three: Priya → Theo $70.00, Sam → Maya $30.00, Priya → Maya $10.00"]}]},{"id":"PAY","title":"Payments","summary":"Sandbox in-app payments, fees, refunds and requests.","reqs":[{"id":"FR-PAY-01","weight":"Must","text":"A card payment shows the fee quote, cannot exceed the amount owed, and on success reduces the debt.","accept":["Priya paying Maya $10.01 when she owes $10.00: \"You owe Maya Lin $10.00 — you can't pay more than that\"","$10.00 by card: fee \"2.9% + 0.30\" = $0.59, total $10.59","Status turns to succeeded within about 5 s; Flat 4B balances Maya +$30.00, Priya −$70.00"]},{"id":"FR-PAY-02","weight":"Must","text":"The bank transfer fee is 0.8% capped at $5.00.","accept":["A $700 payment by bank shows fee \"0.8%, max 5.00\" = $5.00 and total $705.00"]},{"id":"FR-PAY-03","weight":"Must","text":"A refund reverses the payment in the ledger so balances return to what they were before it.","accept":["The recipient refunds the $10.00 payment: status refund_pending then refunded within about 2 s","Balances return to Maya +$40.00, Priya −$80.00"]},{"id":"FR-PAY-04","weight":"Should","text":"A recipient whose payout account is not verified cannot be paid.","accept":["\"Theo Park can't receive payments yet — their payout account isn't verified\""]},{"id":"FR-PAY-05","weight":"Could","text":"In a country where payments are unsupported, payments are unavailable but everything else, including manual payments, keeps working.","accept":["\"Payments are not available in your country yet. Everything else keeps working.\"","\"Record a payment\" saves and updates balances"]},{"id":"FR-PAY-06","weight":"Could","text":"Payment requests are listed for the payer and can be declined with a reason.","accept":["Theo asks $70.00 \"Concert tickets 🎟️\" (Flat 4B), open; declining with \"Paid in cash\" shows declined with the reason"]}]}],"nfr":[{"id":"NFR-01","weight":"Should","text":"An unsaved bill survives a page reload in the same browser, and \"Start new bill\" asks for confirmation before discarding it.","accept":["After reload: still on People with Ana, Ben, Cleo and five items","Start new bill, confirm: back to Upload with no items"]},{"id":"NFR-02","weight":"Should","text":"Each browser tab works on its own seeded copy of the data, which can be reset."}],"glossary":[{"term":"Settle-up","meaning":"The set of payments that brings every group balance to zero."},{"term":"Sandbox processor","meaning":"A simulated payment network; no real money moves."}],"outOfScope":["Reading arbitrary real photos accurately (samples are deterministic)","Real card or bank networks","The native share sheet on mobile"]}