expense-tracking

byJwalant Mehta

**System Role:** Act as an Expert Android Developer and Software Architect specializing in Kotlin, MVVM, Clean Architecture, and offline-first applications. **Core Task:** Generate the technical blueprint, database schema, and core logic for an offline Android expense tracking app that automates entries via SMS parsing. **Context & Variables:** - Platform: Android (Kotlin). - Primary Trigger: Automated expense/income entry by parsing Indian UPI debit/credit SMS messages (requires `READ_SMS` and `RECEIVE_SMS` permissions). - Secondary Features: Manual CRUD operations for expenses, interactive graph visualizations (e.g., MPAndroidChart or Jetpack Compose Canvas). - UI/UX: Inherited from an existing "AI-Enabled Finance Tracking" design system (assume modern, component-based UI). - Infrastructure: Local Room Database. **Constraints:** - STRICTLY OFFLINE: Zero internet permissions. No login, no cloud sync, no Firebase. - ZERO generic setup code (e.g., do not show me how to start a new Android Studio project). - Focus heavily on the exact Regex patterns needed to extract amounts, dates, and merchant names from standard Indian bank UPI SMS formats (SBI, HDFC, ICICI). - Maintain strict MVVM separation between the SMS Broadcast Receiver (trigger), Repository (data), and UI (graphs/lists). **Output Topology (Format strictly as follows):** 1. **Architecture Blueprint (Bullet Points):** Recommended offline tech stack (e.g., Room, Coroutines, Jetpack Compose vs XML, Charting library). 2. **Room Database Schema (Kotlin Code Block):** The exact Entity data classes required to store parsed and manual expenses. 3. **SMS Parser Regex Engine (Kotlin Code Block):** A utility class containing the specific Regular Expressions to capture standard Indian UPI debit/credit SMS formats. 4. **Implementation Roadmap (Markdown Table):** Columns for [Phase, Component (e.g., BroadcastReceiver, ViewModel), Key Logic to Implement].

No preview

Comments (0)

No comments yet. Be the first!

System Requirements

System Requirements Document for expense-tracking

1. Introduction

expense-tracking is a strictly offline Android expense tracker written in Kotlin. Its purpose is to remove the manual bookkeeping burden from everyday Indian UPI spending: instead of typing every payment into a spreadsheet, the user lets the app read the UPI debit and credit SMS messages their bank already sends, parse the amount, date and merchant out of them, and file each one as a ledger row in a local Room database. Manual create, read, update and delete operations exist alongside the automatic capture so the record can be corrected and completed, and interactive graph visualizations turn the accumulated ledger into spending insight.

The audience is a pragmatic Indian Android user who pays by UPI, wants an accurate record of where money went, and is deliberately unwilling to hand that record to a cloud service. There is no login, no cloud sync, no Firebase and no internet permission of any kind — the ledger lives on the device and nowhere else. The interface inherits the modern, component-based "AI-Enabled Finance Tracking" design system and is rendered as a calm, instrument-panel-like ledger rather than a marketing surface.

This document is the System Requirements Document for the product; it specifies the app's features, data model, SMS parsing engine, architecture separation and delivery boundaries in full.

Page 1 of 27

2. System Overview

expense-tracking is a single-user, on-device Android application. Its two entry paths converge on one local ledger:

  • Automatic capture. An SMS Broadcast Receiver listens for incoming messages, requires READ_SMS and RECEIVE_SMS permissions, and hands UPI debit/credit message bodies to a parser that extracts amount, date and merchant name for standard Indian bank formats (SBI, HDFC, ICICI). Parsed results are written through the Repository into the Room database as expense (debit) or income (credit) entries tagged as SMS-sourced.
  • Manual entry. The user creates, reads, updates and deletes expense entries directly through the UI; these are tagged as manual-sourced.
  • Insight. The user views interactive graph visualizations of the recorded expenses.

Architecture is strict MVVM with Clean Architecture layering: the Broadcast Receiver is the trigger only, the Repository owns all data access, and the UI (lists and graphs) observes state through ViewModels. Nothing in the app performs network I/O.

The only active human actor is the Expense Tracker (App User) — the person who owns the device and its financial record. There are no other human roles, no administrators, no shared accounts and no counterparties inside the product.

Page 2 of 27

Removed from scope

  • Login and user accounts (also: sign-in, authentication, account creation)
  • Cloud sync (also: cloud backup, remote backup, server-side storage)
  • Firebase (also: Firestore, Firebase Analytics, Firebase Auth)
  • Internet access and internet permissions (also: network calls, online services, web APIs)
  • Generic Android Studio project setup scaffolding

2a. Product Interpretation and Delivery Boundary

The product is delivered as an Android application installed on the user's own device. All durable state — every expense and income entry, whether captured from SMS or entered manually — is held in a local Room database on that device. The app requests READ_SMS and RECEIVE_SMS so the SMS trigger can function; if those permissions are not granted, automatic capture is unavailable and the user continues with manual entry only. There is no identity layer: the app opens directly into its own content, because there is no login and no account to establish. Access to every destination is therefore unauthenticated and local.

The delivery boundary is deliberately narrow. Nothing leaves the device, nothing is fetched from a server, and no remote party participates in any workflow. The provisioned shared backend, database and frontend services in the project inventory are infrastructure scaffolding and are not part of this product's runtime behavior; the product's runtime is the Android app and its on-device Room store. The current horizon contains only the SMS-driven ledger, manual CRUD and graph insights described here; no future capabilities are committed.

2c. Page Content and Component Coverage

Page 3 of 27

Landing

  • Information and state. The app's root entry surface, reachable without any identity step. Presents the product's premise — an offline ledger fed by UPI SMS — and the current state of the on-device record: whether SMS permissions are granted, and a short excerpt of the most recent ledger rows (date, merchant, source tag, amount) so the user sees real data immediately. If the ledger is empty, the excerpt area states that no entries exist yet and points to manual entry and permission granting.
  • Primary action. Proceed into the ledger (Transactions). Supporting actions. Grant READ_SMS/RECEIVE_SMS permissions when not yet granted; jump to Add Entry to record an expense manually.
  • Domain entities. Ledger entry excerpt (date, merchant, source, amount, debit/credit direction); permission state.
  • Component responsibilities. Instrument band with the product headline and the primary call to action; a ruled ledger excerpt component rendering real rows with tabular right-aligned amounts and a "FROM SMS" small-caps tag on captured rows; a schematic diagram component showing an SMS bubble becoming a ledger row; a permission-status component that reflects granted/not-granted and offers the grant action.
  • States. Loading: ledger excerpt shows a ruled skeleton of rows. Empty: explicit "no entries yet" message with the two entry paths offered. Success: five most recent rows rendered. Error/recovery: if the local read fails, the excerpt area shows a retry control and the rest of the page remains usable; if permissions are denied, the status component explains that automatic capture is off and manual entry still works.
Page 4 of 27

Transactions

  • Information and state. The full, independently revisitable ledger: a ruled table of every recorded expense and income entry with date, merchant, source (SMS or manual), category and amount, amounts right-aligned into a tabular column and debit/credit distinguished by colour. Reflects newly captured SMS entries as they land.
  • Primary action. Open an entry's details. Supporting actions. Navigate to Add Entry; navigate to Insights; refresh/observe the list.
  • Domain entities. Ledger entry (id, amount, direction, date, merchant, category, source, raw SMS reference where applicable).
  • Component responsibilities. Ledger table component with hairline row separators and a 2px section divider; source tag component ("FROM SMS" / "MANUAL"); amount column component enforcing tabular alignment and debit/credit colour coding; capture indicator that shows a square orange pip and a digit-tick on the amount when a new SMS-parsed row arrives.
  • States. Loading: ruled skeleton rows. Empty: message that no entries exist, with a direct route to Add Entry and a note that SMS capture will populate the list once permissions are granted. Success: populated ledger, newest first. Error/recovery: read failure shows an inline retry; a row that failed to parse is not silently dropped — it is surfaced as an unparsed SMS notice the user can act on by entering the transaction manually.
Page 5 of 27

Add Entry

  • Information and state. A focused form for manually creating an expense entry, presented alongside the automatic SMS path. Shows the fields to be captured and the resulting entry's source as manual.
  • Primary action. Save the new entry. Supporting actions. Cancel and return without saving; choose debit or credit direction; assign a category.
  • Domain entities. New ledger entry draft (amount, direction, date, merchant, category, note).
  • Component responsibilities. Ruled label-above-value field components in small caps ("AMOUNT", "MERCHANT", "DATE", "CATEGORY"); tabular numeric input for amount; direction selector distinguishing expense from income; validation component; save/cancel control pair.
  • States. Loading: not applicable beyond form readiness. Empty: blank form with sensible defaults for date. Success: entry persisted and the user is returned to the ledger with the new row visible. Error/recovery: invalid or missing amount blocks save with an inline message; a persistence failure keeps the entered values on screen and offers retry so nothing typed is lost.
Page 6 of 27

Entry Details

  • Information and state. The full record of one existing entry: amount, direction, date, merchant, category, source (SMS or manual), and the originating SMS text when the entry was captured automatically. This is the owner of reviewing, editing and deleting an existing entry.
  • Primary action. Save edits to the entry. Supporting actions. Delete the entry; return to the ledger without changes.
  • Domain entities. Existing ledger entry, including its source and raw SMS reference.
  • Component responsibilities. Read/edit field components matching Add Entry's ruled label/value pattern; source badge; raw-SMS disclosure component for captured entries; delete control with a confirmation step; save/cancel control pair.
  • States. Loading: field skeleton while the entry is read. Empty: not applicable — the page is only reached for an existing entry; if the entry no longer exists (deleted elsewhere), a clear "entry not found" state returns the user to the ledger. Success: edits or deletion persisted and reflected in the ledger. Error/recovery: validation errors block save inline; a persistence failure preserves the edited values and offers retry; a failed delete leaves the entry intact and reports the failure.
Page 7 of 27

Insights

  • Information and state. Interactive graph visualizations of the recorded expense data — spend by category rendered as segmented circular gauge rings on the ruled grid, with a flush-left small-caps legend labelling every segment, plus the underlying totals. Reflects the current ledger.
  • Primary action. Interact with the charts to read a category's value. Supporting actions. Switch the visualized period or grouping offered by the charts; return to the ledger.
  • Domain entities. Aggregated spend by category; totals; entry counts.
  • Component responsibilities. Gauge-ring chart component (charcoal, orange and deep-green segments); legend component; total/tabular figure component; period selector; empty-state component.
  • States. Loading: ring placeholders on the grid. Empty: message that there is not yet enough data to chart, with a route to Add Entry. Success: rendered rings and legend with exact figures. Error/recovery: aggregation failure shows an inline retry and keeps the legend readable.
Page 8 of 27

3. Functional Requirements

FR-1 — Offline Android app in Kotlin. As an Expense Tracker (App User), I should have an Android expense tracking app built in Kotlin that runs entirely on my device, so that my financial record never depends on a network. (explicit)

  • Trigger: app launch. Result: the app opens to its own content with no network dependency. Access: unauthenticated, local. Failure/recovery: none beyond normal app start. Continuation: the user proceeds to the ledger.

FR-2 — Automatic entry from UPI SMS. As an Expense Tracker (App User), I should have expense and income entries created automatically from the Indian UPI debit/credit SMS messages my bank sends, so that I do not have to type every payment. (explicit)

  • Trigger: an incoming SMS is received by the device. Input: the message body. Result: a parsed debit becomes an expense entry and a parsed credit becomes an income entry, tagged as SMS-sourced, persisted in the local database and visible in the ledger. Access: requires SMS permissions. Failure/recovery: a message that does not match a supported UPI format produces no entry and is surfaced as an unparsed notice rather than a silent drop. Continuation: the entry appears in Transactions and is included in Insights.

FR-3 — SMS permissions. As an Expense Tracker (App User), I should be asked for READ_SMS and RECEIVE_SMS permissions so that incoming UPI SMS can be captured and parsed. (explicit)

  • Trigger: first use of the SMS-driven capability. Result: with both permissions granted, the receiver captures incoming messages; without them, automatic capture is inactive and the app states this plainly. Failure/recovery: a denial leaves manual entry fully usable and the permission state visible so the user can grant later. Continuation: manual entry or later grant.
Page 9 of 27

FR-4 — Manual create. As an Expense Tracker (App User), I should be able to manually create an expense entry so that spending not captured by SMS is still recorded. (explicit)

  • Trigger: the user opens Add Entry and submits the form. Input: amount, direction, date, merchant, category. Result: a manual-sourced entry is persisted and appears in the ledger. Failure/recovery: invalid input blocks save with an inline message; persistence failure preserves the typed values with retry. Continuation: return to the ledger.

FR-5 — Manual read. As an Expense Tracker (App User), I should be able to read my recorded entries, both SMS-captured and manual, so that I can review what I have spent and received. (explicit)

  • Trigger: opening Transactions or an entry's details. Result: the ledger list and the individual entry record are displayed with amount, date, merchant, category, source and direction. Failure/recovery: read failure shows an inline retry. Continuation: open details, edit, or move to Insights.

FR-6 — Manual update. As an Expense Tracker (App User), I should be able to update an existing expense entry so that incorrect or incomplete captured data can be corrected. (explicit)

  • Trigger: the user edits fields on Entry Details and saves. Result: the entry is updated in the local database and the change is reflected in the ledger and Insights. Failure/recovery: validation errors block save; persistence failure preserves edits with retry. Continuation: return to the ledger.

FR-7 — Manual delete. As an Expense Tracker (App User), I should be able to delete an expense entry so that erroneous or unwanted records can be removed. (explicit)

  • Trigger: the user chooses delete on Entry Details and confirms. Result: the entry is removed from the local database and disappears from the ledger and Insights. Failure/recovery: a failed delete leaves the entry intact and reports the failure. Continuation: return to the ledger.
Page 10 of 27

FR-8 — Interactive graph visualizations. As an Expense Tracker (App User), I should be able to view interactive graph visualizations of my expenses so that I can understand where my money goes. (explicit)

  • Trigger: opening Insights. Result: charts of the recorded expense data are rendered and respond to interaction, with exact figures readable. Failure/recovery: aggregation failure shows an inline retry. Continuation: return to the ledger or adjust the visualized grouping.

FR-9 — Local Room storage. As an Expense Tracker (App User), I should have all entries stored in a local Room database on my device so that my record is durable and private. (explicit)

  • Trigger: any create, update or delete. Result: the change is committed to the on-device Room database and survives app restarts. Failure/recovery: a failed write is reported and the prior state remains intact. Continuation: the ledger reflects the committed state.

FR-10 — Design-system-conformant UI. As an Expense Tracker (App User), I should see a modern, component-based interface consistent with the "AI-Enabled Finance Tracking" design system so that the app feels coherent and legible. (explicit)

  • Result: every destination uses the shared component vocabulary, ruled label/value pairs, tabular amounts and small-caps labels. Continuation: consistent navigation across the five destinations.

FR-11 — Strictly offline operation. As an Expense Tracker (App User), I should be able to use the app with zero internet permissions, no login, no cloud sync and no Firebase so that nothing about my spending leaves my device. (explicit)

  • Result: the app performs no network I/O, presents no sign-in, and stores nothing remotely. Failure/recovery: not applicable — there is no remote dependency to fail. Continuation: all capabilities remain available offline.
Page 11 of 27

FR-12 — MVVM separation. As an Expense Tracker (App User), I should have the SMS Broadcast Receiver, the Repository and the UI kept in strict MVVM separation so that capture, data and presentation stay reliable and independently correct. (explicit)

  • Result: the receiver only triggers parsing and hands results to the Repository; the Repository is the sole data access path; the UI observes state through ViewModels and never touches the database or the receiver directly. Continuation: each layer can be reasoned about and corrected without disturbing the others.

FR-13 — UPI field extraction. As an Expense Tracker (App User), I should have amounts, dates and merchant names extracted from standard Indian bank UPI SMS formats — SBI, HDFC and ICICI — so that captured entries are accurate without my intervention. (explicit)

  • Input: an SMS body from one of the supported bank formats. Result: amount, date and merchant name are extracted and stored on the entry, along with the debit/credit direction. Failure/recovery: a message that does not match any supported pattern yields no entry and is surfaced as an unparsed notice. Continuation: the user can record it manually.

FR-14 — Permission grant and permission-state visibility. As an Expense Tracker (App User), I should be able to grant READ_SMS and RECEIVE_SMS from within the app and see whether they are currently granted, so that I know whether automatic capture is active. (required_inference)

  • Trigger: the user acts on the permission-status component on Landing. Result: the permission state is reflected truthfully and automatic capture becomes active once granted. Failure/recovery: denial is shown as such and manual entry remains available. Continuation: the user returns to the ledger.
Page 12 of 27

FR-15 — Unparsed-SMS notice and manual fallback. As an Expense Tracker (App User), I should be told when an incoming SMS could not be parsed, so that I can record that transaction manually instead of losing it. (required_inference)

  • Trigger: an incoming SMS fails every supported pattern. Result: an unparsed notice is surfaced in the ledger context with the message available for reference, and the user can open Add Entry to record it. Failure/recovery: the notice persists until acknowledged. Continuation: the manual entry joins the ledger alongside captured rows.

FR-16 — Capture feedback in the ledger. As an Expense Tracker (App User), I should see a newly captured SMS entry arrive in the ledger with a clear source marker, so that I can tell automatic capture apart from what I typed. (required_inference)

  • Trigger: a parsed entry is committed. Result: the row appears with a "FROM SMS" tag and a square orange pip, and its amount ticks into place. Failure/recovery: if the ledger is not on screen, the row is present on next view. Continuation: the user opens the entry's details if correction is needed.

4. User Personas

Page 13 of 27

Expense Tracker (App User)

Product context. This person pays for everyday things by UPI and receives the bank's debit and credit SMS for each payment. They want a record of that spending without maintaining it by hand, and they have chosen this app specifically because it is offline: no account, no sync, no service holding their transaction history. They are pragmatic and slightly anxious about money — the register must feel like a trustworthy instrument, with honest controls and precise numbers.

Primary goal. An accurate, fully offline transaction history assembled automatically from UPI SMS, correctable by hand where needed, and readable as spending insight — with no login and no cloud sync at any point.

Distinct accepted responsibilities.

  • Grant READ_SMS and RECEIVE_SMS so automatic capture can run, and understand when it is not running.
  • Review the ledger of SMS-captured and manually entered expenses and income.
  • Manually create an expense entry for spending the SMS path did not capture.
  • Open an existing entry to review it, correct its fields, or delete it.
  • Study interactive graph visualizations to understand where money goes.
  • Act on an unparsed-SMS notice by recording that transaction manually.

Relevant inputs and decisions. The amount, date, merchant and category of a transaction; whether a row is a debit (expense) or credit (income); whether a captured entry needs correction; whether an entry should be deleted; which grouping of spending to inspect in the charts.

Page 14 of 27

Interactions with other participants. None inside the product. The persona is the sole human actor; the bank's SMS is an inbound message, not a participant, and no counterparty, administrator or support role exists. The persona's own actions on one destination (capture, correction, deletion) are what the other destinations reflect.

Observable success. The ledger contains every UPI payment the user made, tagged by source, with correct amounts, dates and merchants; manual corrections stick; deleted entries are gone; the charts show the same totals the ledger implies; and the app has never asked for a login or a network connection.

5. Core User Flows

Flow A — First launch and permission grant

  1. The user opens expense-tracking for the first time. The app starts on Landing with no identity step of any kind.
  2. Landing shows the product premise, the current ledger excerpt (empty on first launch, with an explicit "no entries yet" message), and a permission-status component reading "not granted".
  3. The user acts on the permission-status component. The Android system permission prompt for READ_SMS and RECEIVE_SMS appears.
  4. The user grants both permissions. Landing's status component updates to "granted" and states that automatic capture is now active.
  5. Failure/recovery: if the user denies, the status component states that automatic capture is off and that manual entry still works; the user can grant later from the same component. Nothing else in the app is blocked.
  6. Continuation: the user proceeds into Transactions, or jumps to Add Entry to record something immediately.
Page 15 of 27

Flow B — Automatic capture from a UPI SMS

  1. The user pays a merchant by UPI. The bank sends a debit SMS to the device.
  2. The SMS Broadcast Receiver fires (trigger only) and passes the message body to the parser.
  3. The parser matches the message against the supported SBI, HDFC and ICICI UPI patterns and extracts the amount, date and merchant name, and determines the direction as debit.
  4. The result is handed to the Repository, which writes an expense entry tagged as SMS-sourced into the local Room database.
  5. The user opens Transactions. The new row is present with its date, merchant, "FROM SMS" tag and right-aligned tabular amount; a square orange pip marks it and the amount ticks into place. Debit amounts are rendered in the debit colour, credit amounts in the income colour.
  6. Failure/recovery: if the message matches no supported pattern, no entry is created; an unparsed-SMS notice appears in the ledger context with the message available for reference (see Flow C).
  7. Continuation: the user opens the row's Entry Details to review it, or moves to Insights where the new expense is already included in the totals.
Page 16 of 27

Flow C — Handling an unparsed SMS

  1. An incoming SMS does not match any supported UPI pattern. The parser produces no entry.
  2. The user sees an unparsed-SMS notice in the ledger context, with the message text available.
  3. The user reads the message, notes the amount, date and merchant, and opens Add Entry.
  4. The user fills the form and saves. The entry is persisted as manual-sourced.
  5. The user acknowledges the notice. Continuation: the transaction is now in the ledger alongside captured rows, and the notice no longer appears.

Flow D — Manually creating an expense entry

  1. From Transactions (or Landing), the user opens Add Entry.
  2. The user enters the amount into the tabular numeric field, selects the direction (expense or income), confirms or changes the date, enters the merchant, and assigns a category.
  3. The user saves. The Repository persists a manual-sourced entry in the Room database.
  4. The app returns the user to Transactions, where the new row is visible with a "MANUAL" tag.
  5. Failure/recovery: if the amount is missing or invalid, save is blocked with an inline message and the other values stay on screen. If persistence fails, the entered values are preserved and a retry is offered.
  6. Continuation: the user opens the new entry's details, or continues browsing.
Page 17 of 27

Flow E — Reviewing, editing and deleting an existing entry

  1. From Transactions, the user opens a row. Entry Details loads that entry's amount, direction, date, merchant, category and source; for an SMS-captured entry the originating SMS text is available through the raw-SMS disclosure.
  2. The user corrects a field — for example, the merchant name parsed from an SMS — and saves. The Repository updates the entry in the Room database.
  3. The app returns the user to Transactions, where the corrected row is shown, and Insights totals reflect the change.
  4. Deletion path: instead of editing, the user chooses delete, confirms at the confirmation step, and the entry is removed from the database and disappears from the ledger and Insights.
  5. Failure/recovery: validation errors block save inline with the edited values retained; a persistence failure offers retry without losing edits; a failed delete leaves the entry intact and reports the failure. If the entry no longer exists when opened, an "entry not found" state returns the user to the ledger.
  6. Continuation: the user returns to browsing or moves to Insights.
Page 18 of 27

Flow F — Studying spending through interactive graphs

  1. From Transactions (or Landing), the user opens Insights.
  2. The app aggregates the recorded expenses by category and renders segmented circular gauge rings on the ruled grid, with a flush-left small-caps legend labelling every segment and exact totals in tabular figures.
  3. The user interacts with the charts — selecting a segment or changing the visualized grouping — and reads the corresponding value from the legend and totals rather than a floating tooltip.
  4. Failure/recovery: if there is not yet enough data, an empty state explains this and offers a route to Add Entry. If aggregation fails, an inline retry is shown and the legend remains readable.
  5. Continuation: the user returns to Transactions to inspect the rows behind a category, or opens an entry's details.
Page 19 of 27

6. Visuals Colors and Theme

The visual direction is Dieter Rams' "Less, but better" — an instrument panel for your money. Nothing decorative that is not also functional; one signal colour that means "money moved"; a strict grid where every amount aligns to a ruled column.

Colour tokens (light mode).

RoleHexUse
Background#F2F0EBWarm off-white ground, ~65% of every screen
Surface#FBFAF7Panels, sitting on the ground with a 1px hairline instead of a shadow
Hairline#D8D4CA1px panel and row borders
Text / Primary#1C1B18All type, rules, the instrument band, primary controls
Accent (signal)#E2571EBraun-signal orange: primary CTA and the "auto-captured" state dot; at most twice per screen, never a large fill except the single hero ticker strip
Muted#8A867CLabels, timestamps, secondary metadata
Income / credit#2F6B4FDeep green, used only for income/credit values so debit and credit are colour-coded like Braun controls

Typography. Headings and body both use Archivo — a grotesque with a slightly condensed, mechanical cut. Headings at weight 600–700 with tight tracking (−0.02em), flush-left ragged-right, numerals tabular and set large. Every label is 12px small caps with +0.12em letterspacing ("AMOUNT", "MERCHANT", "SOURCE"), so the UI reads like a well-printed instrument panel. Body is 16px with 1.55 line-height.

Type scale (1.25 modular). 12 / 14 / 16 / 20 / 25 / 32 / 40 / 56 / 72. Display headline clamp(40px, 7vw, 96px); section heads 32–40px; amounts 25–56px tabular; labels 12px small caps; body 16px.

Page 20 of 27

Shape language. Modular rounded-rectangle controls with a consistent 10px radius and 1px hairline borders, no drop shadows. Ruled data rows with aligned label/value pairs, chunky 2px dividers separating sections, and circular gauge rings for the insight charts. Hard edges everywhere else — square panels, square status pips, square colour swatches — so the only curves are functional (buttons, gauges).

Layout. A strict 12-column grid with 24px gutters and 64px outer margins on desktop, collapsing to a single column at 375px. The ledger is the spine: a full-width ruled table of transactions with columns for date, merchant, source (SMS/manual), category and amount, each row separated by a hairline and every amount right-aligned into a tabular column. Labels sit above values in small caps, Braun-style. A persistent left rail carries the five destinations as numbered 01–05 items in small caps with a 2px charcoal rule — the rail is the only chrome.

Imagery. Diagrammatic line art only: a thin-stroke schematic of an SMS bubble flowing through a parser into a ledger row, drawn in charcoal on off-white with an orange arrow; pictograms for categories (fuel, groceries, transport, utilities) drawn on a 24px grid with 2px strokes. No photography, no stock people, no illustration for its own sake.

Accessibility. Readable text and controls stay whole at 375px, 768px and 1280px, wrapping or scaling to fit and never covered by another element. Debit and credit are distinguished by colour and by sign/label so the meaning survives without colour perception.

Page 21 of 27

7. Signature Design Concept

The public entry is not a centred SaaS hero — it is an instrument panel. The first screen is composed in three horizontal registers:

  1. The charcoal instrument band. A full-bleed band of #1C1B18 across the top third carries an oversized flush-left headline in off-white — "YOUR MONEY, ON YOUR DEVICE" — at clamp(40px, 7vw, 96px), spanning nine of twelve columns. Beneath it sits a single line of body copy, and a solid orange rectangular CTA, "Record an expense", is pinned to the baseline. No centred text, no gradient.
  2. The orange ticker rule. A thin #E2571E rule runs between band and ledger, reading "SBI · HDFC · ICICI · UPI DEBIT · UPI CREDIT" in 12px small caps — the only large use of the signal colour on the page.
  3. The live ruled ledger excerpt. Below the band, the off-white ground holds five real transaction rows with tabular amounts, a "FROM SMS" small-caps tag on captured rows, and on the right a schematic arrow diagram showing an SMS bubble becoming a row.

The concept is implementable with the accepted content alone: the headline, the CTA into Add Entry, the permission status, and the real ledger excerpt are all existing states and controls, recomposed into an instrument panel. The ledger spine — ruled label/value pairs with amounts right-aligned into a column that lines up across the whole page — is the signature that carries from Landing through Transactions, Entry Details and Insights.

Page 22 of 27

8. Interaction Model & Motion Direction

Interaction Model: Animated Motion Tempo: restrained Hero Dimensionality: flat

Landing Hero Motion Brief.

  • Focal subject. The charcoal instrument band and its oversized flush-left headline, with the orange ticker rule directly beneath it and the ruled ledger excerpt below that.
  • Input → transformation → outcome thesis. The ticker rule sweeps slowly across the band, carrying the bank and transaction-type names; beneath it, the ledger excerpt's captured rows present their amounts in tabular figures with a square orange pip and a "FROM SMS" tag. The motion makes the product's premise legible — messages arriving and becoming ruled rows — using only the accepted capture behavior and the real excerpt.
  • Motion vocabulary. Instant, mechanical feedback: 120–160ms linear state changes; a number that ticks up digit-by-digit when a transaction is captured; a single slow 8s sweep of the signal-orange ticker strip. No bounce, no parallax, no hover-lift.
  • Composed first frame. Charcoal band occupying the top third with the headline flush-left across nine columns, the body line and orange CTA pinned to the baseline, the orange ticker rule at the band's lower edge mid-sweep, and the first three ledger rows already ruled and legible below.
  • Reduced-motion state. Under prefers-reduced-motion the ticker becomes a static rule with the same copy set flush-left, the digit-tick resolves instantly to its final value, and all state changes are instantaneous. Every item remains fully readable.
Page 23 of 27

9. Non-Functional Requirements

  • Strict offline operation. The app declares zero internet permissions and performs no network I/O. No login, no cloud sync, no Firebase. (explicit) Rationale: the user's record must never leave the device.
  • SMS permission scope. READ_SMS and RECEIVE_SMS are the only sensitive permissions required, and they are required solely for SMS-based entry. (explicit) Rationale: capture is the primary trigger; nothing else needs message access.
  • Local durability. All entries persist in a local Room database and survive app restarts; a failed write leaves prior state intact. (explicit)
  • Architectural separation. Strict MVVM with Clean Architecture layering: the Broadcast Receiver is a trigger only, the Repository is the sole data access path, and the UI observes through ViewModels. (explicit) Rationale: capture, data and presentation must remain independently correct.
  • Parser coverage. The parser must handle standard Indian UPI debit/credit SMS formats for SBI, HDFC and ICICI, extracting amount, date and merchant name. (explicit)
  • UI consistency. All destinations use the inherited "AI-Enabled Finance Tracking" component-based design system. (explicit)
  • Legibility and layout integrity. Readable text and controls remain whole and uncovered at 375px, 768px and 1280px; amounts use tabular figures so columns align. (explicit, from the design direction)
  • Motion accessibility. Under reduced-motion preferences the interface provides a usable static arrangement with all content readable. (explicit, from the design direction)
  • No setup scaffolding. The deliverable contains no generic Android Studio project setup code. (explicit)
Page 24 of 27

10. Tech Stack

  • Platform: Android, written in Kotlin. (explicit)
  • Architecture: MVVM with Clean Architecture layering — SMS Broadcast Receiver (trigger), Repository (data), ViewModels and UI (graphs/lists). (explicit)
  • UI: Jetpack Compose, component-based, following the inherited "AI-Enabled Finance Tracking" design system. (explicit for the design system; Compose is the stated option in the source alongside XML)
  • Charting: interactive graph visualizations via MPAndroidChart or Jetpack Compose Canvas. (explicit)
  • Persistence: local Room database. (explicit)
  • Concurrency: Kotlin Coroutines for repository and parsing work off the main thread. (explicit)
  • SMS integration: Android SMS Broadcast Receiver with READ_SMS and RECEIVE_SMS permissions. (explicit)
  • Provisioned project infrastructure: the project inventory lists a shared FastAPI backend, a MariaDB database and a React frontend. These are scaffolding for the project workspace and are not part of this product's runtime, which is the offline Android app and its on-device Room store; no product requirement depends on them. (basic_default)
Page 25 of 27

11. Assumptions and Constraints

  • Assumption: the user's bank sends UPI debit/credit SMS in the standard SBI, HDFC or ICICI formats the parser targets; messages outside those formats are surfaced as unparsed notices rather than guessed at. (required_inference)
  • Assumption: the app is used by a single person on a single device; there is no multi-user or shared-device requirement. (required_inference)
  • Constraint: strictly offline — zero internet permissions, no login, no cloud sync, no Firebase. (explicit)
  • Constraint: READ_SMS and RECEIVE_SMS are required for SMS-based entry; without them, manual entry remains fully available. (explicit)
  • Constraint: strict MVVM separation between the SMS Broadcast Receiver, the Repository and the UI. (explicit)
  • Constraint: no generic Android Studio project setup code is produced. (explicit)
  • Constraint: the interface inherits the "AI-Enabled Finance Tracking" design system and must not adopt a generic indigo/blue-on-white template look. (explicit)
  • Constraint: the provisioned backend, database and frontend services do not add product requirements, identity, or domain entities to this offline app. (basic_default)
Page 26 of 27

12. Glossary

  • UPI — Unified Payments Interface, the Indian instant payment system whose debit and credit notifications arrive as bank SMS.
  • UPI debit SMS — a bank message reporting money paid out; parsed into an expense entry.
  • UPI credit SMS — a bank message reporting money received; parsed into an income entry.
  • SMS Broadcast Receiver — the Android component that is triggered by incoming messages and hands their bodies to the parser; it holds no data logic.
  • Parser / Regex engine — the utility that matches an SMS body against bank-specific patterns and extracts amount, date and merchant name.
  • Repository — the single data-access layer between the parser or UI and the Room database.
  • Room database — the on-device SQLite-backed persistence layer holding all entries.
  • Ledger entry — one recorded transaction with amount, direction (debit/credit), date, merchant, category and source.
  • Source — whether an entry was captured automatically from SMS or entered manually.
  • Unparsed SMS notice — the surfaced indication that an incoming message matched no supported pattern and therefore produced no entry.
  • Insights — the interactive graph visualizations of recorded expenses.
  • MVVM — Model–View–ViewModel, the separation pattern enforced across receiver, repository and UI.
Page 27 of 27

No completed page designs yet.

Completed design pages will appear here when they are ready to preview.

Landing: Open app to instrument panel
Landing: Grant SMS permissions
Landing: Note capture active
Landing: Note capture off, manual works
Landing: Retry ledger excerpt read
Landing: 1. Proceed to ledger
Landing: Jump to Add Entry
Transactions: 2. Review captured SMS row
Transactions: 3. Read unparsed SMS notice
Transactions: 4. Retry ledger read
Transactions: 5. Open entry details
Transactions: 6. Open Add Entry
Transactions: 7. Open Insights
Add Entry: 8. Enter amount and direction
Add Entry: 9. Assign merchant and category
Add Entry: 10. Save manual entry
Add Entry: 11. Fix invalid amount
Add Entry: 12. Retry failed save
Add Entry: 13. Cancel without saving
Transactions: 14. Confirm manual row visible
Transactions: 15. Acknowledge unparsed notice
Entry Details: 16. Review entry and raw SMS
Entry Details: 17. Correct merchant field
Entry Details: 18. Save edits
Entry Details: 19. Retry failed save
Entry Details: 20. Delete entry and confirm
Entry Details: Return to ledger on not found
Entry Details: 21. Return without changes
Transactions: 22. Confirm corrected row
Transactions: 23. Confirm deleted row gone
Insights: 24. Read category gauge rings
Insights: 25. Switch visualized grouping
Insights: 26. Retry failed aggregation
Insights: Open Add Entry from empty state
Insights: 27. Return to ledger

No completed page designs yet.

Completed design pages will appear here when they are ready to preview.

Landing: Open app to instrument panel
Landing: Grant SMS permissions
Landing: Note capture active
Landing: Note capture off, manual works
Landing: Retry ledger excerpt read
Landing: 1. Proceed to ledger
Landing: Jump to Add Entry
Transactions: 2. Review captured SMS row
Transactions: 3. Read unparsed SMS notice
Transactions: 4. Retry ledger read
Transactions: 5. Open entry details
Transactions: 6. Open Add Entry
Transactions: 7. Open Insights
Add Entry: 8. Enter amount and direction
Add Entry: 9. Assign merchant and category
Add Entry: 10. Save manual entry
Add Entry: 11. Fix invalid amount
Add Entry: 12. Retry failed save
Add Entry: 13. Cancel without saving
Transactions: 14. Confirm manual row visible
Transactions: 15. Acknowledge unparsed notice
Entry Details: 16. Review entry and raw SMS
Entry Details: 17. Correct merchant field
Entry Details: 18. Save edits
Entry Details: 19. Retry failed save
Entry Details: 20. Delete entry and confirm
Entry Details: Return to ledger on not found
Entry Details: 21. Return without changes
Transactions: 22. Confirm corrected row
Transactions: 23. Confirm deleted row gone
Insights: 24. Read category gauge rings
Insights: 25. Switch visualized grouping
Insights: 26. Retry failed aggregation
Insights: Open Add Entry from empty state
Insights: 27. Return to ledger