Living document. Update before coding.
Purpose: Amazon Expense Allocation for Tax Prep — help accountants (including business owners acting as their own accountant) allocate Amazon/bank expenses between Business Supplies and Board Member Benefits for tax reporting.
Target Market: For-profit C Corporations, S Corporations, LLCs (nonprofit on roadmap)
Core UX: Import → Allocate (slider) → Export totals
┌─────────────────────────────────────────────────┐
│ Cloudflare Pages (tsv-ledger.pages.dev) │
│ Static: index.html, css/*, js/* │
└─────────────────────┬───────────────────────────┘
│ fetch + Bearer token
┌─────────────────────▼───────────────────────────┐
│ Cloudflare Worker (tsv-ledger-api) │
│ /auth/* OAuth, sessions │
└─────────────────────┬───────────────────────────┘
│ D1 SQL
┌─────────────────────▼───────────────────────────┐
│ Cloudflare D1 (SQLite) │
│ users, accounts, sessions, expenses │
└─────────────────────────────────────────────────┘
| Principle | Constraint |
|---|---|
| Small files | ≤100 lines (lint enforced) |
| Pure functions | Side effects at edges |
| Test first | No code without failing test |
| Minimal deps | Justify in ADR |
| Tool | Purpose | Size |
|---|---|---|
| Alpine.js | Reactivity | 15kb |
| Pico CSS | Styling | 10kb |
| noUiSlider | Allocation | 12kb |
| Playwright | E2E tests | — |
| CF Pages | Hosting | Free |
| CF Workers | API | Free |
| CF D1 | Database | Free |
Expense {
id: string, // "amazon-{orderID}-{idx}"
date: string, // ISO 8601
description: string,
amount: number, // dollars
businessPercent: number, // 0-100, default 100
benefitSubcategory: string, // Taxable Compensation | De Minimis Benefits | Working Condition Fringe | IRC §119 Meals/Lodging | Requires Review
paymentMethod: string,
reviewed: boolean
}Totals:
- Business = Σ(amount × businessPercent / 100)
- Benefits = Σ(amount × (100 - businessPercent) / 100)
Two summary cards: Business Supplies total, Board Member Benefits total.
┌─────────────────────┬─────────────────────┐
│ 🏢 Business Supplies│ 👥 Board Benefits │
│ $1,234.56 (42) │ $567.89 (18) │
├─────────────────────┼─────────────────────┤
│ ┌─────────────────┐ │ ┌─────────────────┐ │
│ │ Coffee beans │ │ │ Gift cards │ │
│ │ $50 ○──●───○ 75%│ │ │ $100 ○───●──○ 0%│ │
│ └─────────────────┘ │ └─────────────────┘ │
└─────────────────────┴─────────────────────┘
Split items (1-99%) appear in both columns with orange border.
Benefits cards now include a fringe benefit subcategory selector with default Requires Review when any benefits allocation exists.
Drag-drop CSV/ZIP. Supports Amazon Order History, Bank of America DAT.
Payment method purge (remove personal cards after import).
Retention/deletion controls:
Clear Allpermanently deletes all expenses and import history from local storage.- Local identity sign-out supports
Delete Local Datafor shared-device cleanup.
Export naming:
- CSV downloads use
tsv-ledger-export-YYYYMMDD-(local|cloud).csv. - Filenames intentionally exclude user names, account identifiers, and source filename metadata.
- CSV exports include a
BenefitSubcategorycolumn for tax-meaningful benefit classification.
User clicks "Sign In"
↓
Modal: Google | GitHub | Passkey
↓
OAuth redirect → Provider → Callback
↓
Worker creates session, returns token
↓
Frontend stores in localStorage
↓
Header shows: [avatar] User Name ▼
UI States:
- Signed out:
Sign Intext (white on blue header) - Signed in: Avatar (24px circle) + name + dropdown menu
See ADR index for full Architecture Decision Records.
| ADR | Title | Version |
|---|---|---|
| 001 | Static-first with edge API | 1.0.0 |
| 002 | Three fixed categories | 1.0.0 |
| 003 | localStorage before backend | 1.0.0 |
| 009 | Multi-provider OAuth | 2.0.0 |
| 011 | Custom auth (not Auth.js) | 2.0.0 |
| 013 | Duplicate detection | 2.1.0 |
| 014 | Percentage-based allocation | 3.0.0 |
| 015 | noUiSlider integration | 3.0.0 |
| 016 | Dual-column allocation board | 3.1.0 |
| 017 | Payment method purge | 3.1.0 |
| 019 | JWT Bearer tokens | 3.1.0 |
| 020 | CF Pages previews | 3.1.0 |
| 021 | Auth button visibility | 3.1.0 |
| 022 | Product repositioning | 3.3.0 |
| 023 | Cloud sync integration | 3.5.0 |
| 024 | Storage mode selection | 3.5.0 |
| 025 | Onboarding wizard | 3.6.0 |
| 026 | Disclaimer visibility/export attribution | 3.6.1 |
| 027 | Validation gate stabilization | 3.6.1 |
| 028 | Cloud-intent data authority hotfix | 3.6.2 |
| 029 | Explicit storage-intent/session-state/data-authority model | 3.6.3 |
| 030 | Local identity, local sign-out, and encrypted vault decision | 3.6.4 |
| 032 | Entity type configuration and tax warnings | 3.7.0 |
ADRs 001–018 archived in DESIGN-archive.md
| Rejected | Reason |
|---|---|
| React/Vue | Build step, bundle size |
| Firebase Auth | Vendor lock-in, limits |
| Auth.js | Too heavy for 2 providers |
| Cookies for auth | Cross-origin issues |
index.html Main app (Alpine.js)
css/
shell.css App shell layout
app.css Component styles
js/
app.js Alpine app state
amazon-parser.js CSV parsing
boa-parser.js Bank DAT parsing
storage.js localStorage CRUD
worker/
src/index.js API router
src/oauth.js Google/GitHub OAuth
src/helpers.js Auth utilities
tests/
auth-*.spec.js Auth button tests
allocation.spec.js Slider tests
See ROADMAP.md for future phases.
Current v1 scope intentionally excludes:
- Mobile native app (web-first)
- Multi-user collaboration (local-first)
- AI auto-categorization (planned Phase 3)
- Offline sync (PWA planned)
- Accounting software integration (planned Phase 2)
- Export to accounting software