Software Requirement Specifications (SRS) - Bill Splitter
1. Introduction
The Bill Splitter is a high-performance native mobile application built with Flutter, designed to help groups of people seamlessly divide shared bills, accurately track expenses, and easily settle transactions at the point of service (restaurants, bars, events). The system is built for extreme on-the-go utility, providing a fluid native experience with reliable synchronization via a Java-based backend.2. Business Aspects and Requirements
2.1. Target Audience
- Groups of friends, families, or colleagues who frequently share meals, events, or trips.
- Event organizers (Hosts) who pay upfront and need to accurately collect money from attendees.
2.2. Business Value
- Accuracy & Fairness: Calculates mathematically sound splits based on actual consumption, avoiding estimations and feelings of unfairness.
- Time Savings: Automates complex calculations including proportional distribution of unassigned items, percentage-based taxes, service charges, and individual sponsorships.
- Frictionless Settlements: Translates complicated debt sheets into a simple “Hub and Spoke” settlement plan, reducing the number of total transactions and directing all payments to or from a single Host.
2.3. High-Level Business Requirements
- Bill Management: Users must be able to create, name, and localize shared bills, retaining a history of previous bills.
- Participant & Host Management: Users can add participants. One participant must be designated as the “Host” (the central point for payments).
- Itemized Billing: The system must allow adding bill items with specific quantities and prices, and assign them to one or multiple participants based on their consumption quantity.
- Global Charges: The system must support bill-wide adjustments such as fixed discounts, percentage-based taxes (VAT), or service charges.
- Sponsorships & Upfront Payments: The system must handle scenarios where a participant volunteers to sponsor a specific amount of the bill, or has already paid a certain amount upfront.
- Settlement Generation: The system must calculate the final net payable for each participant and generate clear payment instructions (who pays whom).
- Read-only Sharing: The app should allow sharing the generated bill and settlement instructions via a QR code or link.
3. Detailed Business Use Cases
3.1. Bill Initialization and Global Configuration
Identifier: UC-01Actor: Any User / Bill Creator
Description: The user initiates a new calculation session for a bill.
Pre-conditions: The user accesses the application. Main Flow:
- The system generates a unique identifier (UUID) for a new bill session.
- The user inputs a Bill Name (e.g., “Friday Night BBQ @ Gyu-Kaku”) to easily identify the bill in the history.
- The user optionally inputs a Location (e.g., “District 1, HCMC”).
- The system automatically maintains timestamps (
created_at,updated_at). - A QR Code URL or shareable link is optionally generated or attached later to allow participants to view a read-only state of the bill.
3.2. Participant and Host Management
Identifier: UC-02Actor: Any User
Description: Adding the people who attended the event and managing their specialized roles.
Pre-conditions: A bill session exists (UC-01). Main Flow:
- The user adds participants by providing their names. Each participant receives a unique ID.
- This could enhanced to be a social feature where users can connect with each other and form groups.
- The user selects exactly ONE participant to be the Host.
- Host Role Definition: The Host acts as the central clearinghouse (“Hub”) for all monetary settlements. The Host is assumed to be the person who settled the final receipt with the venue.
- When a Host is selected, their upfront
paidAmountis internally set to $0, as the system will automatically assume they covered whatever portion of the bill was not covered by other participants’ upfront payments.
- Upfront Payments (
paidAmount):- Non-host participants may have contributed to the bill upfront (e.g., Bob threw down $50 cash on the table). The user can input these specific
paidAmountvalues for each non-host participant.- This does not change the total amount to be paid for a person.
- Non-host participants may have contributed to the bill upfront (e.g., Bob threw down $50 cash on the table). The user can input these specific
- Sponsorships (
sponsorAmount):- A participant may volunteer to sponsor a portion of the bill (e.g., Charlie chips in $20 to treat the group). The user assigns a
sponsorAmountto that participant. - Applied to Final Total: Sponsorships are deducted from the Total Bill After Global Charges (Subtotal + Taxes/Fees).
- Capping Rule: The total sponsorship amount provided by participants is capped at the total bill amount. The system prevents “over-sponsoring” where the surplus would exceed the amount owed to the venue.
- The remaining amount after sponsorships is split among all non-sponsoring participants as usual.
- A participant may volunteer to sponsor a portion of the bill (e.g., Charlie chips in $20 to treat the group). The user assigns a
3.3. Itemized Receipt Entry and Assignment
Identifier: UC-03Actor: Any User
Description: Recording individual line items from the receipt and assigning consumption to participants.
Pre-conditions: Participants exist (UC-02).
Main Flow:
- The user adds a line item, specifying the Item Name, Price (total price or unit price × quantity depending on entry style, though usually total line price), and Quantity (default is 1).
- The user selects which participants consumed the item.
- Consumption Assignment:
- The user assigns specific “quantities” of the item to participants.
- Example 1: If 1 “Wagyu Plate” (Quantity 1) is shared by 5 people, each is assigned 1 “share”, making the total claimed shares 5. The cost is divided equally (1/5 each).
- Example 2: If 3 “Grilled Corns” (Quantity 3) are bought, Eve might claim 2 and David might claim 1.
- Unassigned / Under-Claim Handling:
- If an item (or a portion of an item) is NOT explicitly fully assigned, the system detects an incomplete allocation state.
- The system must trigger a clear validation error identifying the exact item name and the exact quantity or monetary amount that remains unassigned.
- Settlement and final calculations are blocked until the user resolves the discrepancy by either assigning the remainder or adjusting the item total.
3.4. Global Charges Application (Taxes, Fees, Discounts)
Identifier: UC-04Actor: Any User
Description: Applying bill-wide modifiers like VAT, Service Charges, or flat discounts.
Pre-conditions: Items exist (UC-03).
Main Flow:
- The user adds a Global Charge by specifying a Name (e.g., “VAT”), an Amount, and a Type (
fixedorpercent). - Percentage Type: The system calculates the fee as a percentage of the Total Item Subtotal (e.g., 10% VAT on a 10).
- Fixed Type: The system applies the exact flat amount (e.g., -$20 for a voucher discount).
- These extra costs are distributed proportionally across participants based on the value of the items they individually consumed, rather than split evenly (e.g., someone who ordered a 10 salad).
- There must be a way to either make the extra cost (per item) be split evenly among all participants or proportionally based on the value of the items they individually consumed.
3.5. Automated Settlement and Debt Resolution
Identifier: UC-05Actor: System
Description: Calculating final owings and generating peer-to-peer transfer instructions.
Pre-conditions: Items and participants are completely entered.
Main Flow:
- The system calculates the Base Item Cost for each participant (including their share of unassigned communal items).
- The system calculates the Global Extras (taxes/fees/discounts) for each participant.
- The system calculates the Total Cost for the person (Base + Extras).
- The system applies any Sponsorships (
sponsorAmount). If a person’s total cost is 100, their owed amount drops to 50 surplus applies a discount ratio to all other participants in deficit. - The system establishes what everyone fundamentally “Owes” (
finalPayables). - The system determines the Effective Paid Amounts. Non-hosts use their explicitly entered
paidAmount. The Host’s paid amount is dynamically determined asTotal Bill - SUM(Non-Host Paid Amounts). - Hub & Spoke Routing: The system compares
PaidvsOwesfor each person.- If
Paid<Owes(Top Up Required): The person must transferOwes - Paidto the Host to settle their remaining debt. - If
Paid>Owes(Reimbursement Due): The Host must transferPaid - Owesto the person, returning the amount they overpaid upfront. - All transactions are strictly routed to or from the Host (no participant-to-participant transfers).
- If
3.6. Multi-Device Cloud Persistence & Account-Bound Sync
Identifier: UC-06Actor: User / System
Description: Bills are stored in the cloud and bound to the user’s authenticated account. Any signed-in device can access the full bill history and edit state. Sync is pull-based and manual (user-triggered refresh only) — no real-time streaming, background polling, or WebSocket updates. The last successful write wins; simultaneous co-editing is not supported. Bill ownership is tied to the creator account; shared viewers cannot permanently store the bill locally.
Pre-conditions: User is authenticated and has an active account session. Main Flow:
- Snapshot on Change: After any meaningful state mutation (item added, participant updated, settlement generated, payment status marked), the client pushes a full bill snapshot to the Java Backend Service. The server returns a
server_version(monotonic counter) and alast_synced_attimestamp, both stored locally alongside the bill. - Bill Ownership & Visibility:
- Only the bill creator (Host) owns the bill and sees it in their Bill History.
- Bills are linked to the user account’s UUID; bills created by User A are not visible to User B even if they share the same device (after logout/login).
- On App Launch / Login (Multi-Device Support):
- The system fetches a lightweight bill index (Bill ID, Name, Date, Host Name,
server_version) for the authenticated account. - Bills missing locally are queued for on-demand download; cached bills with a stale
server_versionare flagged as outdated. - Bills synced on Device 1 are not automatically cached on Device 2. Device 2 downloads individual bill snapshots on first open.
- The system fetches a lightweight bill index (Bill ID, Name, Date, Host Name,
- Explicit Manual Pull-to-Refresh:
- On the Bill History screen: User drags-to-refresh or taps a refresh icon. The system fetches the latest bill index and detects any new, deleted, or updated bills.
- On the Bill Detail screen: User taps a refresh icon. The system downloads the latest snapshot and hydrates local state, including any new payment confirmations, reports, or participant status updates.
- No automatic background sync; all sync is user-initiated.
- Cross-Device Consistency:
- If User A edits Bill X on Device 1 (iPhone), the changes are immediately synced to the backend.
- If User A then opens the same bill on Device 2 (iPad), the initial open will show a cached (possibly stale) version. The user must manually refresh to see the latest changes.
- Conflict Resolution: If Device 2 detects a newer
server_versionthan its local cache, an inline banner appears: “Bill updated on another device. Refresh to see the latest changes.” The user can tap “Refresh” to pull the latest snapshot.
- Cloud-to-Local Seed (Fresh Login):
- After a logout/login cycle or app reinstall, local storage is empty.
- The bill index is fetched immediately on successful login.
- Individual bill snapshots are downloaded on demand as the user opens them, not in bulk.
- This ensures fast login without waiting for large snapshot downloads.
- Network Unavailable on Save: The mutation is persisted locally, marked
sync_status: pending. A subtle cloud-off icon and tooltip appear in the bill header (e.g., “Offline mode — changes will sync when online.”) The user can continue editing. On next network availability, the pending changes are pushed. If a conflict is detected (server version is newer), the user is prompted: “Another device has modified this bill. Resolve before syncing.” The user must refresh to fetch the latest state before retrying the save. - Stale-Write Rejection: If the server rejects a push because another device wrote a newer snapshot, an inline banner appears: “This bill was updated on another device. Refresh before saving.” The local edit is preserved but marked as
sync_status: conflict. No data is lost.
- Bill Deleted on Another Device: The next bill index refresh detects the deletion. If the user had the bill open, they are redirected to History with a toast: “This bill has been deleted from another device.”
- Viewer-Side Sync (Shared Bills): A participant viewing via share link (UC-09) reads the snapshot on-demand. The bill is not permanently stored in their local history; they see a temporary “Shared Bill” view that persists only for the session or until they explicitly clear it. The bill’s owner account retains full ownership and control.
- Large Snapshots: Bills sync as atomic JSON snapshots — no field-level delta sync. The full snapshot is always pushed/pulled each cycle.
- Offline Edit Persistence: If the app is closed while offline with pending changes, the next app launch (even without network) will restore the bill to its last local state. Changes are queued and synced on next network availability.
- Multi-Account Access: If a user logs out of Account A and logs into Account B on the same device, Bills from Account A are archived locally but not visible to Account B. Logging back into Account A shows the previous account’s bill history.
Pre-conditions: A bill session is active and changes have occurred.
Main Flow:
- Upon any state change (adding items, changing host, etc.), the system persists the changes to the local secure storage (e.g., Hive, SQLite, or SharedPreferences).
- The Flutter client automatically initiates a background synchronization request to the Java Backend Service.
- The Java service upserts the bill metadata, participant lists, and consumption assignments into the centralized repository, ensuring all shared viewers (UC-09) can see the latest state.
3.7. Resolving Discrepancies and Incomplete Data (Edge Case Handlings)
Identifier: UC-07Actor: System
Description: The system must seamlessly handle scenarios where data input contradicts itself (e.g., users claim 4 beers, but only 3 were purchased).
Pre-conditions: Items are under-claimed or over-claimed by participants.
Main Flow:
- The Over-Claim Scenario: If participants accidentally claim more portions than the item has (e.g., 5 claims on 1 item), the system dynamically dilutes their claims to fit the item’s max quantity. No one pays more than the item’s actual price.
- The Under-Claim Scenario: If parts of an item remain unclaimed (under-assigned), the system does NOT silently distribute the cost. Instead, it surfaces a direct and relevant error message (e.g., “Item ‘Grilled Corn’ has 1.5 portions remaining. Please assign them.”). This ensures the user knows the exact discrepancy and can correct the input immediately.
- The Sponsorship Error Trap: If a participant sponsors $50, the total amount the group “owes” dynamically shrinks. The system natively recalculates the Host’s expected return to ensure the Host doesn’t mathematically demand repayment for the sponsored money.
3.8. Retrieving Historical Bills
Identifier: UC-08Actor: Any User
Description: Viewing and restoring past calculation sessions.
Pre-conditions: Bills have been previously saved to the database (UC-06).
Main Flow:
- The user navigates to the Bill History section.
- The system retrieves a chronological listing of past bills, generating a summarized view containing the Bill Name (or the first item’s name), Date, Location, and total Bill Amount.
- The user selects a bill, and the system hydrates the application state, allowing the user to continue modifying the bill or viewing the final settlement screen.
3.9. Shareable Bill Access — Link Generation & Read-Only Viewer Portal
Identifier: UC-09Actor: Host (Link Generation) / Viewer (Portal Access)
Description: Covers the full bill-sharing lifecycle: the Host generates a unique link or QR code, participants use it to open a personalized read-only in-app portal. The portal is the sole entry point for payment confirmations (UC-10) and discrepancy reports (UC-11).
Pre-conditions (Link Generation): An active bill session exists. Host is authenticated and owns the bill.
Pre-conditions (Portal Access): Participant has a valid shareable link and is signed into their Zeus account. 3.9.1 — Host: Generating and Distributing the Share Link
- The Host taps “Share Bill” on the Bill Detail page.
- The system generates (or retrieves a previously created) unique, opaque URL:
- Deep link (in-app):
zeus://bill/<bill_uuid>/view - HTTPS fallback:
https://app.zeusapp.io/bill/<bill_uuid>/view(for devices without the app installed — future scope).
- Deep link (in-app):
- A QR code is rendered inline. The Host can also Copy Link to clipboard or use the system Share Sheet (messaging apps, email, etc.).
- The Host may Revoke the Link from Share settings at any time, immediately invalidating it server-side.
- The viewer taps the link or scans the QR code.
- If the Zeus app is installed, the OS deep-link handler opens the Read-Only Viewer Portal directly.
- If the viewer is not signed in, they are redirected to the Login screen; on success they are routed back to the portal automatically.
- The system fetches the bill snapshot from the cloud via
bill_uuidand renders the portal.
- Persistent Read-Only Banner: A full-width, amber or info-blue banner is always visible: ”📄 View Only — You cannot edit this bill.” It cannot be dismissed.
- Disabled Controls: All form fields, quantity steppers, “Add” buttons, delete actions, and assignment controls are visibly greyed out. Tapping a disabled element may trigger a haptic pulse and a tooltip: “Only the bill owner can edit this.”
- Personalized Debt Summary Card: A pinned card at the top shows the viewer’s name, total amount owed, payment instruction (e.g., “Your share: ₫250,000 → Pay Alex”), and their current settlement status badge.
- Full Bill Transparency: The viewer can scroll to see the itemized receipt, global charges, and all participants’ calculated shares. Other participants’ proof images and submission details are not visible to viewers — only the Host sees those.
- Manual Refresh: Pull-to-refresh or a refresh icon fetches the latest snapshot. If a newer
server_versionis detected, a banner prompts: “Bill updated — pull to refresh.”
- Invalid / Revoked Link: Full-screen error: “This bill link is no longer valid. Contact the bill host.”
- Bill Not Found: Full-screen error: “Bill not found.”
- Viewer Is the Bill Owner: The system bypasses the portal and opens the standard editable Bill Detail view instead.
- Multiple Simultaneous Viewers: Many participants can use the same link concurrently; submissions are tracked independently by
user_id. - Link Forwarded to Non-Participants: Any signed-in Zeus user can open the link and view the bill; their
user_idis recorded against any submission they make. - Bill Archived / Closed by Host: Portal opens with a “This bill has been closed.” watermark; “Mark as Paid” and “Report an Issue” buttons are hidden.
- Viewer Already Submitted: The portal loads in its post-submission state (green paid badge or amber report banner); the primary action button is disabled.
3.9.1. Predefined Discrepancy Reasons
Identifier: UC-09.1Actor: System / UX Design
Description: A predefined list of common dispute reasons that viewers can select when reporting discrepancies. This standardizes feedback and speeds up the reporting process.
Predefined Reasons:
- Wrong Amount Calculated — The participant believes their share calculation is incorrect (e.g., math error, tax applied incorrectly).
- Item Wasn’t Consumed by Me — The participant claims they did not actually eat/use the item (e.g., assigned by mistake).
- Already Paid in Cash / Other Method — The participant claims they already settled directly with the Host or another participant outside the app.
- Pricing Mismatch on Item — The item price in the bill does not match the actual receipt (e.g., discount was applied at the register).
- Other — A custom reason not covered above. Selecting this allows the reader to type a custom description and optionally attach an image.
- The Host receives a notification when a report is submitted, including the selected reason and any custom notes or images.
- The system tracks dispute frequency by reason to identify systemic issues (e.g., recurring calculation errors).
- Future analytics may suggest which scenarios cause the most disputes.
3.10. Viewer Payment Confirmation
Identifier: UC-10Actor: Viewer (authenticated participant)
Description: A participant in the Read-Only Portal confirms they have transferred their owed amount to the Host. This permanently updates their settlement status on the server, updates the portal UI, and triggers an FCM push notification to the Host.
Pre-conditions: Viewer has the portal open (UC-09). Their current status is
Pending or Disputed.
Main Flow:
- A prominent “Mark as Paid” CTA button (success-green styling) is pinned below the viewer’s Debt Summary Card.
- The viewer taps “Mark as Paid”. A confirmation Bottom Sheet slides up:
- Summary: “Confirm payment of ₫250,000 to Alex.”
- Optional Proof Image: Image picker to attach a bank transfer screenshot or payment receipt. Attaching is strongly encouraged but not mandatory.
- “Submit Confirmation” and “Cancel” actions.
- The viewer taps “Submit Confirmation”. The system:
a. Uploads the proof image (if provided) to a private, access-controlled cloud storage bucket.
b. Creates a
payment_confirmationrecord server-side:confirmed_paidstatus, server timestamp, proof image URL, andviewer_user_id. c. Permanently updates the participant’s settlement status to “Confirmed Paid” on the server. - The portal UI immediately reflects the new state:
- The CTA button is replaced with a green checkmark badge: ”✓ Payment Confirmed.”
- The button is disabled; re-submission from the same account is not possible.
- An FCM Push Notification is dispatched to the Host: ”💸 [Viewer Name] confirmed payment of ₫250,000.” Tapping it deep-links to the Settlement Tab.
- Image Upload Failure: The status update proceeds even if image upload fails; the upload retries independently. A non-blocking warning is shown.
- Network Error on Submit: A retry prompt is shown. Status is not updated until a successful server response (HTTP 2xx) is received.
- Overriding a Prior Dispute: If the viewer’s status is
Disputed, “Mark as Paid” remains visible. Confirming payment overrides status toConfirmed Paid; the prior dispute record is retained for audit. - Proof Image Privacy: Proof image URLs are presigned and short-lived. Accessible only to the Host and the submitting
user_id— never in push notification payloads. - Idempotent Server Writes: Duplicate requests (e.g., network retry) are discarded server-side; only the first accepted submission creates a record.
3.11. Viewer Discrepancy Reporting
Identifier: UC-11Actor: Viewer (authenticated participant)
Description: A participant flags a calculation error, incorrect assignment, or another dispute with their computed share. The report permanently updates their settlement status and notifies the Host via FCM.
Pre-conditions: Viewer has the portal open (UC-09). Their current status is
Pending or Confirmed Paid.
Main Flow:
- A “Report an Issue” button (secondary / outlined style, below the “Mark as Paid” CTA) is always visible in the portal.
-
The viewer taps “Report an Issue”. A Bottom Sheet slides up containing:
a. Reason Selector (required — single select):
b. Additional Information (text field): Always visible. Optional for all reasons except
Reason Code Display Label wrong_totalIncorrect total amount calculated item_not_mineItem assigned to me that I didn’t order already_paid_externalI already paid via cash or another method price_mismatchItem price doesn’t match what I saw on the receipt otherOther — please describe below other, where it becomes required. c. Attach Image (optional): Image picker to attach a receipt photo or supporting visual evidence. -
The viewer taps “Submit Report”. The system:
a. Validates reason is selected; validates text field is non-empty if
otheris selected. b. Uploads the proof image (if provided) to a private cloud storage bucket. c. Creates adispute_reportrecord server-side:reason_code,additional_info,proof_image_url, server timestamp,viewer_user_id. d. Permanently updates the participant’s status to “Reported / Disputed”. -
The portal UI updates:
- “Report an Issue” button label changes to “Issue Reported” and is disabled.
- An amber banner appears below the Debt Summary Card: ”⚠ Report submitted — awaiting Host review.”
- An FCM Push Notification is dispatched to the Host: ”⚠ [Viewer Name] reported a discrepancy: [Reason Label].” Tapping it deep-links to the Settlement Tab.
- Validation Failure: Submit button stays disabled; inline hints appear below unfilled required fields.
- Image Upload Failure: Status update proceeds; upload retried independently.
- Report After Confirming Payment: If status is
Confirmed Paid, submitting a report overrides it toDisputed. Both records are retained for audit. - Re-Submit / Amend: In MVP, existing reports are non-editable from the viewer side (pre-populated read-only reference). An “Amend Report” flow is deferred to a future version.
- Multiple Viewers Reporting the Same Item: Each participant’s report is independent. The Host adjudicates; the system does not auto-deduplicate reports.
3.12. Host Settlement Dashboard Tab
Identifier: UC-12Actor: Host
Description: The Host monitors payment confirmations and dispute reports from a dedicated “Settlements” tab embedded within the existing Bill Detail page. All data is fetched on-demand via manual pull-to-refresh. The tab enriches the participant list with status badges and tap-to-detail interactions, reusing existing list and bottom-sheet components.
Pre-conditions: The Host has an active bill with at least one participant. The bill has been shared (UC-09). Main Flow:
- The Host opens the Bill Detail page. A “Settlements” tab is visible in the tab bar alongside existing tabs (e.g., Items, Charges). This tab is exclusively visible to the bill owner; viewers accessing via the portal do not see it.
-
The Settlements tab displays a Participant Status List grouped into three sections:
Section Badge Condition Confirmed Paid 🟢 Green Participant submitted a payment confirmation (UC-10) Reported / Disputed 🟡 Amber Participant submitted a discrepancy report (UC-11) Pending ⚪ Grey Participant has not yet taken any action - Each row displays: avatar / initials, name, amount owed, status badge. For Paid rows: proof image thumbnail (if provided). For Disputed rows: the short reason label (e.g., “Price mismatch”).
-
Tap for Detail: Tapping a row opens a Detail Bottom Sheet showing:
- Participant name, amount owed, status, and submission timestamp.
- Confirmed Paid: Full-resolution proof image viewer.
- Disputed: Full reason label, additional info text, proof image (if any). A “Mark as Resolved” action button is available.
- Pending: A prompt noting no submission yet.
-
Host Action — “Mark as Resolved”: Tap from a Disputed detail sheet to resolve the dispute.
- Updates server record:
resolved_by_host: true, resolution timestamp. - Changes status badge to “Resolved” (grey-green).
- Does not automatically modify bill calculations; the Host must separately edit items/charges if needed.
- Updates server record:
- Pull-to-Refresh: Drag-to-refresh on the Settlements tab fetches the latest server submissions. A loading spinner is shown during the fetch.
- Tab Badge Count: The tab label shows an unread badge count (e.g., “Settlements (3)”) for new, unacknowledged confirmations or reports since the last refresh.
- No Submissions Yet: Empty-state illustration: “No responses yet. Share the bill link to get participants started.” with a shortcut to the Share flow.
- Pull-to-Refresh Fails: Stale data is retained; a toast appears: “Could not refresh. Check your connection.”
- Host Edits Bill After Submissions: Existing submission records are not automatically invalidated. Each record stores the
server_versionit was based on; the detail sheet surfaces a warning: “Submitted against an earlier version of the bill.” - Participant Upgrades Dispute to Paid: Their row moves from “Disputed” to “Confirmed Paid”. Both records are shown in the detail view in reverse-chronological order.
- Large Groups: The list is virtualized / paginated for participant counts above a threshold (e.g., 20) to maintain scroll performance.
- In-App FCM Notification: If the app is in the foreground when a notification arrives, an in-app banner slides in. Tapping it navigates to the Settlement Tab and auto-fetches the latest state.
Actor: Any User
Description: Copying the final settlement instructions to a clipboard for sharing in messaging apps.
Pre-conditions: Calculations are valid and settlement flows exist.
Main Flow:
- The user triggers the “Copy Text” action.
- The system generates a formatted text string (e.g., “Dinner Settlement: Bob pays Alex 15.”) and copies it to the system clipboard.
3.13. Exporting Settlement as Text
Identifier: UC-13Actor: Any User
Description: Copying final settlement instructions to the clipboard.
Pre-conditions: Calculations are valid and settlement flows exist.
Main Flow:
- The user triggers the “Copy Text” action.
- The system generates a formatted text string (e.g., “Dinner Settlement: Bob pays Alex 15.”) and copies it to the system clipboard.
3.14. Collaborative Viewer Synchronization (Soft Refresh)
Identifier: UC-14Actor: Any User
Description: Users are alerted when the cloud state has a newer version than their local version, prompting a manual refresh.
Pre-conditions: A viewer has scanned the QR code (UC-09) and the Host is active.
Main Flow:
- The Host modifies the bill and the system persists (UC-06).
- The viewer’s client periodically polls the server to check for a newer state version.
- If a change is detected, the system surfaces an “Updates Available” indicator or prompt.
- The user triggers the refresh action to hydrate the latest state and update the read-only debts view.
3.15. Configuring Global Charge Distribution
Identifier: UC-15Actor: Any User
Description: Defining how global extras (Tax, Tip, Fees) are distributed among participants.
Pre-conditions: At least one Global Charge exists (UC-04).
Main Flow:
- The user selects a Global Charge.
- The user toggles between Proportional Split (default) or Even Split.
- Proportional: Cost is based on the ratio of the participant’s individual subtotal to the bill’s total subtotal.
- Even: Cost is divided equally by the number of participants.
3.16. Modifying Entities and Safe Deletions
Identifier: UC-16Actor: Any User
Description: Removing items or participants or changing the Host without corrupting the session state.
Pre-conditions: Participants or items exist.
Main Flow:
- Removing a Participant: The system deletes the person and automatically scrubs all their assignments from every item. Any items they were part of are flagged as Under-Claimed (UC-07).
- Changing the Host: The system assigns the Host role to a new person. The previous Host’s upfront payments are audited, and the new Host becomes the central point for all resettlement flows.
- Removing an Item: The item and all its associated assignments are deleted. Total bill amounts are recalculated instantly.
3.17. Real-time Calculation Feedback
Identifier: UC-17Actor: System
Description: Providing instant visual feedback on how a change (adding an item, changing a claim) affects the final settlement.
Pre-conditions: Active items and participants exist.
Main Flow:
- The user modifies a value (e.g., increases the price of “Wagyu”).
- The system instantly triggers a re-calculation on the client-side.
- All total costs, net payables, and settlement flows are updated in the UI without page refresh.
- Since they are all math calculations, they are all done on the Client-side.
3.14. Collaborative Viewer Synchronization
Identifier: UC-14Actor: Any User (Viewer)
Description: Viewers are alerted to updates in near-real-time when the Host makes changes.
Pre-conditions: A viewer has scanned the QR code (UC-09) and the Host is active.
Main Flow:
- The Host modifies the bill and the system persists (UC-06).
- The viewer’s client periodically polls the server to check for a newer state version.
- If a change is detected, the system surfaces an “Updates Available” indicator or prompt.
- The user triggers the refresh action to hydrate the latest state and update the read-only debts view.
4. Functional Requirements, Formulas, and Algorithms
4.1. Base Item Cost Calculation (Raw Costs)
The algorithm determines the base monetary value consumed by each participant before applying global modifiers. It handles edge cases like over-claiming, under-claiming, and unassigned “communal” items dynamically. Algorithm & Formulas: For eachItem (with properties ItemPrice and ItemQuantity):
- Identify Claims: Let
AssignedQty(Person)be the quantity of the item claimed by aPerson. - Calculate Total Claims:
TotalClaimedQty = SUM(AssignedQty(Person))for all participants. - Determine Participant Shares:
- Case A: Fully or Over-Claimed (
TotalClaimedQty >= ItemQuantity) If participants claim more portions than the item’s available quantity (e.g., 5 people claim 1 portion each of a single $100 plate), the system limits individual cost liability. Capped Quantity:CappedQty(Person) = MIN(AssignedQty(Person), ItemQuantity)Share Calculation:Share(Person) = (CappedQty(Person) / SUM(CappedQty of all claimers)) * ItemPrice - Case B: Under-Claimed (
TotalClaimedQty < ItemQuantity) If portions remain unclaimed, the system identifies a validation error. Action: The algorithm halts and returns a specific error state. Error Message Calculation:Delta = ItemQuantity - TotalClaimedQty. Result: “Item [Name] has [Delta] unassigned portions.”
- Case A: Fully or Over-Claimed (
- Final Raw Cost:
RawCost(Person) = Sum_of_Item_Shares(Person)
- Floating Point Consistency: The system natively uses full-precision floating point math for all ratio divisions to prevent dropped cents.
- Zero Claim Edge Case: Ensures
UnassignedValuesplits across all users if the “Effective Splitters” list is empty.
4.2. Global Extras Additions (Taxes, Fees, Discounts)
Global charges act as modifiers that scale based on an individual’s base consumption. The system forbids equal distribution of taxes to prevent unfair scaling. Algorithm & Formulas:- Calculate Total Modifiers:
- For
Percenttypes:FeeValue = (ChargeAmount / 100) * TotalItemCost - For
Fixedtypes:FeeValue = ChargeAmount(can be negative for discounts). TotalExtras = SUM(FeeValue of all Global Charges)
- For
- Distribution Selection:
- Scenario 1: Proportional Split (Weighted by Consumption)
If
SumOfAllRawCosts > 0:Ratio(Person) = RawCost(Person) / SumOfAllRawCostsExtraComponent(Person) = TotalExtras * Ratio(Person) - Scenario 2: Even Split (Flat Per-Capita)
ExtraComponent(Person) = TotalExtras / COUNT(Participants)
- Scenario 1: Proportional Split (Weighted by Consumption)
If
- Final Calculation:
TotalCosts(Person) = RawCost(Person) + ExtraComponent(Person) - Zero Base Edge Case: If
SumOfAllRawCosts == 0and the mode is Proportional, the system defaults to an Even Split among participants.
- Discounts: Fixed negative values (e.g., a 80 of a $100 bill receives 80% of the voucher discount.
4.3. Sponsorship Application and Remainder Splitting
Sponsorships are applied to the final calculated total (after all global taxes and fees are added) to reduce the financial burden on the rest of the group. Algorithm & Formulas:- Identify Sponsors: A participant is a Sponsor if their
SponsorAmount> their calculated consumptionTotalCosts(Person). - Liabilty Capping:
- Let
TotalBillAfterCharges = SUM(TotalCosts(Person))for all participants. EffectiveSponsorship(Person) = SponsorAmount(Person)- Sum Cap: The system ensures
SUM(EffectiveSponsorship) <= TotalBillAfterCharges. If a user inputs an amount that would make the total sponsorship surpass the bill, the system caps the liability at the total bill amount.
- Let
- Assign Sponsor Liability: For every Sponsor, their
FinalNetPayableis theirEffectiveSponsorship(Person). - Calculate Remaining Group Debt:
TotalRemainingBill = TotalBillAfterCharges - SUM(EffectiveSponsorship)
- Distribute Remainder to Non-Sponsors:
- For all non-sponsoring participants (Debtors), the remaining bill is split based on their relative consumption.
GroupRawCost = SUM(RawCost of all Non-Sponsors)- If
GroupRawCost > 0:FinalNetPayable(Non-Sponsor) = (RawCost(Non-Sponsor) / GroupRawCost) * TotalRemainingBill - Else:
FinalNetPayable(Non-Sponsor) = 0(The bill is fully covered).
- The “Alex & Bob” Case: If the bill is 80, Charlie’s payable is 20 is split between Alex and Bob (e.g., $10 each if they ate equally).
- Full Coverage: If
SumOfSponsorships == TotalBill, all non-sponsors have theirFinalNetPayableset to $0.
4.4. The Settlement Model (Hub and Spoke)
The system ensures that the Host (who paid the venue) is fully reimbursed for everything except their own share, while forcing Sponsors to pay their promised amounts. Algorithm & Formulas:- Determine Effective Paid Amounts:
EffectivePaid(Non-Host) = User_Input_PaidAmount(Upfront cash/card at the venue).EffectivePaid(Host) = TotalBillReceiptCost - SUM(EffectivePaid(Non-Hosts))
- Balance Calculation:
Balance(Person) = EffectivePaid(Person) - FinalNetPayable(Person)
- Flow Generation:
- If
Balance < -0.01(Debtor): The person owes money. [Person] pays [Host] the amount of ABS(Balance) (Top Up). - If
Balance > 0.01(Creditor): The person is owed. [Host] pays [Person] the amount of Balance (Reimbursement). - Because
FinalNetPayablenow includes the fullSponsorshipAmount, the ledger naturally balances to zero. The Host no longer “absorbs” any discrepancy; they simply act as the collector for the sponsors’ and debtors’ payments.
- If
5. Non-Functional Requirements (NFR)
- Uninterrupted Native Performance: Maintain 60fps-120fps during all calculations and UI transitions.
- Account-Bound Security: No anonymous access; all bill data is tied to a user account for cloud synchronization and multi-device support. Bill ownership is enforced at the backend.
- Optimized Notification System: Push notifications (FCM/APNs) for payment/dispute events must be delivered within 5 seconds of the viewer action. Host is notified when participant submissions occur.
- Visual Hierarchy (Viewer Mode): The “Read-Only” (Shared Bill) state must be impossible to mistake for “Editable” state. Use combination of header badges, background tints, disabled controls, and tooltips.
- Offline-Resilient Sync: Changes made while offline must be queued and marked
sync_status: pending. Manual refresh should prioritize cloud state but never overwrite local-only unsynced edits without user confirmation. - Privacy of Proofs: Payment screenshots and dispute images must be accessible only to the Host and the participant who submitted them. End-to-end encryption recommended for image transport.
- Manual Sync Only: No real-time WebSocket, polling, or background sync. All data synchronization is user-initiated via explicit refresh actions.
- Multi-Device Consistency: Bill state must eventually be consistent across devices. Conflict resolution defaults to last-write-wins for automated recovery; user is prompted for manual resolution if they attempt to edit conflicting versions.
- Image Handling: Attached images must be optimized for size (compressed on client-side) and securely stored with metadata (timestamp, submitter).
- Accessibility: Settlement Tab, Shared Bill view, and Payment/Report modals must follow WCAG guidelines for font sizes, color contrast, and keyboard navigation.
- Data Retention: Images and reports are retained for at least 30 days after bill finalization (to allow dispute resolution). Delete policies align with regional privacy laws (GDPR, CCPA, etc.).
6. Glossary of Terms
| Term | Definition |
|---|---|
| Bill Ownership | The user account that created the bill. Only the owner can edit the bill and access the Settlement Tab. |
| Shared Bill | A read-only snapshot of a bill shared with non-owning participants via link or QR code. |
| Settlement Tab | A dedicated view for the Host to track payment confirmations, dispute reports, and participant statuses within the bill detail page. |
| Participant Status | The current state of a participant: Pending (no action), Paid (payment confirmed with proof), Reported (dispute raised). |
| Discrepancy Report | A participant-submitted flag indicating disagreement with their calculated share, including predefined or custom reasons and optional proof images. |
| Read-Only View | The application state when a participant opens a shared bill they do not own. Editing is disabled; only viewing, payment confirmation, and dispute reporting are allowed. |
| Hub and Spoke | A settlement model where all payments go to or come from a central Host, simplifying settlement complexity. |
| Effective Paid | The actual monetary contribution of a person to the vendor, dynamically adjusted for the Host. |
| Raw Cost | The base price of items consumed by a participant before any taxes, tips, or sponsorships. |
| Sponsorship | A voluntary amount a participant pays into the bill to cover others, distinct from their own consumption. |
| Global Charge | A bill-wide adjustment (like VAT, Service Charge, or Discount) that can be applied proportionally or evenly across participants. |
| Net Payable | The final amount a person is responsible for after all consumption, fees, and sponsorship logic are applied. |
| Proof Image | A screenshot, receipt, or transaction confirmation attached by a participant when confirming payment or reporting a discrepancy. |
| Share Token | A secure, shareable token embedded in bill share links that grants temporary read-only access to the bill. Tokens may expire after a set duration. |
| Soft Refresh | A manual pull-to-refresh action that fetches the latest bill state from the cloud without closing the app or losing scroll position. |
| Push Notification | An in-app or system notification sent to the Host when participants confirm payment or report issues, notifying within 5 seconds. |
7. Revision History
| Version | Date | Description |
|---|---|---|
| 1.0.0 | 2026-03-03 | Initial Draft - Business Aspects and Requirements. |
| 1.1.0 | 2026-03-03 | Added Algorithm Formulas and Settlement Model. |
| 1.2.0 | 2026-03-03 | Expanded Use Cases (UC-07 to UC-09) and finalized NFRs. |
| 1.3.0 | 2026-03-03 | Integrated User Feedback: Under-claim errors, Sponsorship rules, and Persistence logic. |
| 1.4.0 | 2026-03-03 | Finalized SRS with Glossary and Safe Modification flows. |
| 1.5.0 | 2026-03-03 | Removed destructive Reset (UC-12) and changed UC-14 to manual refresh with indicator. |
| 1.6.0 | 2026-03-03 | Clarified Sponsorship applies to total bill after charges and added Sum Cap logic. |
| 1.7.0 | 2026-03-03 | Introduced ‘Top Up’ and ‘Reimbursement’ terminology to settlement flows. |
| 1.8.0 | 2026-03-03 | Shifted emphasis to Mobile-First/PWA requirements (Offline-resilience, thumb-driven UX). |
| 1.9.0 | 2026-03-03 | Tech Stack Pivot: Transitioned from PWA to Flutter Native + Java Backend Sync. |
| 2.0.0 | 2026-03-04 | Added Multi-device Cloud Sync, Interactive Viewer roles (Payments/Reports), and Host Settlement Dashboard. Mandatory Auth NFR. |
| 2.1.0 | 2026-03-04 | Expanded UC-06 with detailed multi-device sync and account binding; redesigned UC-09 as comprehensive shared bill workflow with 3 sub-flows; added UC-09.1 predefined dispute reasons; enhanced UC-10/UC-11 with image proof workflows and permanent status changes; detailed UC-12 Settlement Dashboard with refresh and push notifications; renumbered UC-13-17; manual-sync only (no real-time WebSocket); comprehensive NFR updates including offline queuing, conflict resolution, image handling, accessibility, and data retention. |

