# nkrameshkrishnan/expense-tracker architecture

> Architecture diagram of the GitHub repository nkrameshkrishnan/expense-tracker, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-12). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/nkrameshkrishnan/expense-tracker
- Repository: https://github.com/nkrameshkrishnan/expense-tracker

## Overview

#### Purpose and Entry Points
Ledger is a zero-build, static expense-tracking SPA hosted on GitHub Pages. It uses a Google Sheet as the authoritative database through a Google Apps Script web app; browser seed data supports an unconnected demo mode.

Primary entry points:
- `index.html` loads the application shell and CDN dependencies.
- `assets/app.js` owns UI routing, views, forms, and user actions.
- `google-apps-script/Code.gs` is separately deployed as the Sheet-facing API.
- `.github/workflows/deploy.yml` produces the Pages deployment.

#### Client Application Shell
The frontend is ES-module JavaScript with no server runtime or package build. `assets/app.js` coordinates navigation between dashboard, transactions, budget, charts, and data-management flows, then renders against state supplied by the store.

- `index.html`
- `assets/app.js`
- `assets/styles.css`

Charts are browser-rendered through Chart.js, while spreadsheet import/export uses SheetJS loaded from CDNs.

#### State, Persistence, and Data Source Boundary
`assets/store.js` defines the data abstraction: a Sheets-backed store when configured, plus IndexedDB and memory/seed-backed behavior for local use. The configured endpoint/token may be injected at deployment or entered at runtime and retained in browser localStorage.

The key boundary is that the UI talks to a store API rather than directly assuming Google Sheets. On load or explicit reload, transaction and budget state is refreshed from the remote Sheet; failed writes are surfaced rather than queued offline.

- `assets/store.js`
- `assets/config.js`
- `data/seed.json`

#### Transaction and Budget Flow
Transactions use a normalized model with positive `amount` values; `type` determines whether a row represents expense or income. Client actions add, update, or delete transactions through the Sheets store, then refresh/render dependent dashboard and chart data.

Budget data is category-by-month and is maintained separately from transactions. Aggregation, CSV/XLSX-oriented transformations, and flat-table imports are handled in the browser.

- `assets/app.js`
- `assets/store.js`
- `assets/xlsxio.js`

#### Google Sheets API and Workbook Safety
`google-apps-script/Code.gs` is the authoritative mutation adapter. It exposes GET/POST handlers because Apps Script web apps do not support other verbs. Client mutations are POSTed as `text/plain;charset=utf-8` to avoid an unanswerable CORS preflight.

The script validates the Transactions header layout before writing. It preserves the workbook’s established formulas and reports: dates are real Sheet Date objects; formula-backed Month/Year columns are not overwritten; deletes clear rows rather than removing them; inserts reuse cleared slots. Budget writes target only allowed month columns.

- `google-apps-script/Code.gs`
- `assets/store.js`

#### External Services and Security Boundary
GitHub Pages hosts public static assets. GitHub Actions can inject `SHEETS_ENDPOINT` and `SHEETS_TOKEN` into generated `assets/config.js`; this avoids committing them but does not hide them from deployed-page visitors. Runtime entry is the only option that keeps those values out of published assets.

Google Apps Script executes as the Sheet owner and accesses the Google Spreadsheet. A shared token protects API calls only when it is not shipped with the static client.

- `.github/workflows/deploy.yml`
- `assets/config.js`
- `google-apps-script/Code.gs`

#### Deployment Pipeline
The Pages workflow validates and publishes the static repository, overwriting endpoint configuration from optional GitHub secrets. No application compilation occurs. The Apps Script deployment is manual and independent: code changes require creating a new web-app deployment version.

- `.github/workflows/deploy.yml`
- `assets/config.js`
- `index.html`

Main entry points: [`assets/store.js`](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/store.js) (Store API), [`assets/app.js`](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/app.js) (UI router and views), [`index.html`](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/index.html) (Application shell), [`.github/workflows/deploy.yml`](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/.github/workflows/deploy.yml) (Pages workflow)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["Static browser client"]
  node_shell["Application shell<br/>HTML entry<br/>[index.html]"]
  node_app["UI router and views<br/>ES module<br/>[app.js]"]
  node_styles["Client styles<br/>CSS<br/>[styles.css]"]
  node_charts["Chart.js<br/>browser CDN"]
  node_xlsx["Spreadsheet I/O<br/>browser module<br/>[xlsxio.js]"]
end

subgraph group_data["Data and API"]
  node_store["Store API<br/>data abstraction<br/>[store.js]"]
  node_config["Endpoint configuration<br/>client config<br/>[config.js]"]
  node_local[("Browser persistence<br/>localStorage / IndexedDB")]
  node_seed["Demo seed data<br/>JSON data<br/>[seed.json]"]
  node_apps_script{{"Sheets API adapter<br/>Google Apps Script<br/>[Code.gs]"}}
  node_spreadsheet[("Google Spreadsheet<br/>authoritative database")]
end

subgraph group_delivery["Delivery"]
  node_workflow["Pages workflow<br/>GitHub Actions<br/>[deploy.yml]"]
  node_pages["GitHub Pages<br/>static hosting"]
  node_secrets["GitHub secrets<br/>deployment secrets"]
  node_apps_deploy["Apps Script deployment<br/>manual release"]
end

node_pages -->|"serves"| node_shell
node_shell -->|"loads"| node_app
node_shell -->|"loads"| node_styles
node_app -->|"reads and mutates data"| node_store
node_app -->|"renders charts with"| node_charts
node_app -->|"imports and exports via"| node_xlsx
node_store -->|"uses connection settings"| node_config
node_config -.->|"runtime values retained in"| node_local
node_store -->|"uses local mode"| node_local
node_store -.->|"loads demo data"| node_seed
node_store -->|"GET/POST text/plain API"| node_apps_script
node_apps_script -->|"validates and safely updates"| node_spreadsheet
node_workflow -->|"optionally injects secrets into"| node_config
node_secrets -.->|"provides endpoint/token"| node_workflow
node_workflow -->|"publishes static repository"| node_pages
node_apps_deploy -->|"deploys web-app version"| node_apps_script

click node_shell "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/index.html"
click node_app "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/app.js"
click node_styles "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/styles.css"
click node_xlsx "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/xlsxio.js"
click node_store "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/store.js"
click node_config "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/config.js"
click node_seed "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/data/seed.json"
click node_apps_script "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/google-apps-script/Code.gs"
click node_workflow "https://github.com/nkrameshkrishnan/expense-tracker/blob/main/.github/workflows/deploy.yml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_shell,node_app,node_styles,node_charts,node_xlsx toneBlue
class node_store,node_config,node_local,node_seed,node_apps_script,node_spreadsheet toneAmber
class node_workflow,node_pages,node_secrets,node_apps_deploy toneMint
```

## Components

### Static browser client

Zero-build SPA served as static files.

- [Application shell](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/index.html): HTML entry · `index.html`
- [UI router and views](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/app.js): ES module · Owns user actions, forms, and rendered screens. · `assets/app.js`
- [Client styles](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/styles.css): CSS · `assets/styles.css`
- **Chart.js**: browser CDN · Renders dashboard and analysis charts.
- [Spreadsheet I/O](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/xlsxio.js): browser module · Handles flat-table imports and CSV/XLSX transformations. · `assets/xlsxio.js`

### Data and API

Store abstraction and Google Sheets mutation boundary.

- [Store API](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/store.js): data abstraction · Selects Sheets-backed, IndexedDB, or memory/seed behavior. · `assets/store.js`
- [Endpoint configuration](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/assets/config.js): client config · Accepts deployed or runtime-entered endpoint and token values. · `assets/config.js`
- **Browser persistence**: localStorage / IndexedDB · Retains runtime connection settings and local data mode.
- [Demo seed data](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/data/seed.json): JSON data · Supports unconnected browser demo mode. · `data/seed.json`
- [Sheets API adapter](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/google-apps-script/Code.gs): Google Apps Script · GET/POST adapter that validates and safely mutates workbook rows. · `google-apps-script/Code.gs`
- **Google Spreadsheet**: authoritative database · Stores transactions, budgets, formulas, and reports.

### Delivery

Independent static-site and Apps Script deployment paths.

- [Pages workflow](https://github.com/nkrameshkrishnan/expense-tracker/blob/main/.github/workflows/deploy.yml): GitHub Actions · Validates and publishes static assets without a build step. · `.github/workflows/deploy.yml`
- **GitHub Pages**: static hosting · Serves the public SPA.
- **GitHub secrets**: deployment secrets · Optional source for generated endpoint and token configuration.
- **Apps Script deployment**: manual release · New web-app versions are deployed independently.

## Connections

- GitHub Pages → Application shell: serves
- Application shell → UI router and views: loads
- Application shell → Client styles: loads
- UI router and views → Store API: reads and mutates data
- UI router and views → Chart.js: renders charts with
- UI router and views → Spreadsheet I/O: imports and exports via
- Store API → Endpoint configuration: uses connection settings
- Endpoint configuration → Browser persistence: runtime values retained in
- Store API → Browser persistence: uses local mode
- Store API → Demo seed data: loads demo data
- Store API → Sheets API adapter: GET/POST text/plain API · Writes refresh state; failed writes are surfaced.
- Sheets API adapter → Google Spreadsheet: validates and safely updates · Preserves formulas and reuses cleared transaction rows.
- Pages workflow → Endpoint configuration: optionally injects secrets into
- GitHub secrets → Pages workflow: provides endpoint/token
- Pages workflow → GitHub Pages: publishes static repository
- Apps Script deployment → Sheets API adapter: deploys web-app version
