Architecture
Architecture
Section titled “Architecture”Macadam is a zero-backend Progressive Web App. There is no server, no build step, and no transpilation. The browser is the runtime.
Runtime Model
Section titled “Runtime Model”Browser | +-- index.html / weekly.html / expenses.html / settings.html | Static HTML shells. Each page loads the shared navbar, | its own inline content, and the script bundle at the bottom. | +-- static/db.js (Dexie schema + seed data) +-- static/script.js (Dashboard logic, charts, theme, presets) +-- static/weekly_vault.js (Weekly CRUD + table rendering) +-- static/expenses_vault.js (Expense CRUD + category management + charts) +-- static/vault_aggregation.js (Read-only aggregation for the dashboard) +-- static/vault_backup.js (Export / import JSON) +-- static/style.css (Design tokens, dark mode, component styles) | +-- sw.js (Service Worker -- offline cache) +-- manifest.json (PWA metadata)Every script attaches to window.
There are no ES modules, no bundler, and no framework.
Scripts are loaded in dependency order via <script> tags at the bottom of each HTML file:
- Bootstrap Bundle (CDN)
- Chart.js (vendored at
static/chart.min.js) - Dexie.js (CDN)
static/db.js— opens the IndexedDB database, attacheswindow.dbstatic/script.js— shared logic (theme toggle, dashboard rendering)- Page-specific script (e.g.
static/weekly_vault.js)
Data Flow
Section titled “Data Flow”All reads and writes go through Dexie.js, which wraps IndexedDB. There are no network calls for data — everything is local.
User action (form submit, button click) --> JS event handler (e.preventDefault()) --> Dexie put/add/delete on window.db --> IndexedDB transaction --> Re-render the affected DOMThe dashboard page (index.html) calls window.generateVaultSummary() from
vault_aggregation.js, which reads all stores and returns a computed summary
object. That object drives every KPI, chart, and table on the page.
Offline Strategy
Section titled “Offline Strategy”The service worker (sw.js) uses a network-first strategy:
- Try fetching from the network.
- If the network responds with 200, clone the response into the cache and serve it.
- If the network fails (offline), serve from the cache.
On install, the service worker pre-caches every HTML page, every JS/CSS file, and the CDN dependencies (Bootstrap, Dexie, Bootstrap Icons). Old caches are purged on activation.
Theming
Section titled “Theming”Two themes: light and dark.
The toggle button swaps data-bs-theme on <html> and persists the choice
to localStorage under the key theme.
CSS custom properties in style.css define two sets of design tokens:
:rootfor light mode[data-bs-theme="dark"]for dark mode
Chart colors are also driven by CSS variables (--chart-line-color-1, etc.),
read at runtime via getComputedStyle. When the theme toggles, charts are
destroyed and re-initialized to pick up the new palette.