BillTracker/DEVELOPMENT_LOG.md

176 lines
8.0 KiB
Markdown

# Bill Tracker - Development Log
**Purpose:** Track active development work across all agents. Bishop uses this to update Engineering_Reference_Manual.md.
**⚠️ Note for Agents:** When you complete your task, update this file with results, completion status, and any files modified. Ripley will then notify Bishop to review and decide on manual updates. You have `write` and `edit` access to this file.
---
### v0.26.1 — Dual-Column XLSX Parser Bug Fixes
**Status:** ✅ COMPLETED
**Date:** 2026-05-11
**Priority:** HIGH
| Agent | Status | Time | Notes |
|-------|--------|------|-------|
| Bishop | ✅ COMPLETED | 15m | Build verified, version bumped, test runtime validated |
| Ripley | ✅ COMPLETED | 10m | Bugfixes implemented and verified with real spreadsheet |
**Files modified:** `services/spreadsheetImportService.js`, `package.json`, `client/lib/version.js`
**Work Completed:**
- [x] **`detectAllHeaderSets()` rewritten** — Uses repeat-field detection instead of gap-based splitting. Second "Bill" or "Amount" column starts a new group. Requires ≥2 header fields per group (filters out "Left Over | Paid" rows).
- [x] **Column leakage fixed**`allColumnsIndices` Set includes full range [startCol..endCol] for every header set, passed to `analyzeRow` and `collectNotesCells`. Prevents right-side bills from picking up left-side amounts.
- [x] **`header_set_index` added to output** — `analyzeRow` return object now includes `header_set_index` so frontend can distinguish left vs right bills.
- [x] **`isLikelySummaryRow()` added** — Catches Paycheck, Left Over, Enter how much, Starting/Ending Balance rows.
- [x] **`isLikelyTotalRow()` expanded** — Catches "Auto Total ------>" patterns.
- [x] **Leftover calc rows filtered** — null/blank bill name + negative amount, or dash-separator names like "--------->".
- [x] **`HEADER_PATTERNS.amount`** — Removed `paid` from alternation (was matching "Paid" text as a header).
- [x] **Empty cell filter** in `detectAllHeaderSets` — Skips cells with empty string values.
**Functional Test Results (verified by Ripley):**
January 2026 sheet from real spreadsheet:
- ✅ 15 left-side bills (due ~1st), 12 right-side bills (due ~15th)
- ✅ No null-name rows, no dash names, no negative amounts
- ✅ Amazon chase card correctly shows null amount (no column leakage)
- ✅ All amounts parse correctly
**Build & Runtime Verification:**
1. ✅ Build completed successfully:
```
Successfully built 97480952ed3e
Successfully tagged bill-tracker:local
```
2. ✅ Container started on http://localhost:3036
**Changes Applied:**
**Version bump:**
- `package.json`: `0.26.0``0.26.1`
- `client/lib/version.js`: `APP_VERSION = '0.26.1'`
- `client/lib/version.js`: RELEASE_NOTES version updated with v0.26.1 highlights
**Files Modified:**
- `services/spreadsheetImportService.js` - Dual-column parser bugfixes (already verified by Ripley)
- `package.json` - Version bumped to 0.26.1
- `client/lib/version.js` - APP_VERSION and RELEASE_NOTES updated
**Deliverables:**
- XLSX dual-column parser correctly detects multiple header sets using repeat-field detection
- XLSX dual-column parser prevents column leakage between left and right column groups
- API response includes `header_set_index` for frontend column distinction
- Summary rows (Paycheck, Left Over, Auto Total) correctly filtered
- Amount header pattern no longer false-matches "Paid" text
---
### v0.24.6 — XLSX Dual-Column Parser Bug Fixes
**Status:** ✅ COMPLETED
**Date:** 2026-05-11
**Priority:** MEDIUM
| Agent | Status | Time | Notes |
|-------|--------|------|-------|
| Neo | ✅ COMPLETED | 2m | Added filter for null-name + negative amount rows and dash separators |
| Bishop | ✅ COMPLETED | 2m | Build verified, parsed data cleaned |
**Files modified:** `services/spreadsheetImportService.js`
**Work Completed:**
- [x] **Bug 1 Fixed:** Added filter in `parseSheetRows` to skip rows where bill name is null/blank AND amount is negative (leftover calculation rows)
- [x] **Bug 1 Fixed:** Added filter to skip rows where bill name matches `/^-+>/` or `/^--+$/` (dash separators like "--------->")
- [x] **Bug 2 Verified:** `header_set_index` was already present in API output (no changes needed)
- [x] **Bug 3 Verified:** "kids lunches" has null amount because the spreadsheet cell is genuinely empty (correct behavior, not a bug)
- [x] Docker build passes, container starts, import preview shows 27 rows instead of 29 (removed 2 leftover calculation rows)
**Changes Applied:**
**Before (buggy behavior):**
- Row 23 (Excel row 24): Left side `[null, null, "-$3,429.47", ...]` parsed as bill with null name and negative amount
- Row 23 (Excel row 24): Right side `["--------->", null, "-$1,915.78", ...]` parsed as bill named "--------->" with negative amount
**After (fixed behavior):**
- Both rows skipped during parsing
- Total rows reduced from 29 to 27
- No null-name or negative-amount rows in parsed output
**Code Added (in `parseSheetRows` loop):**
```javascript
// Skip leftover calculation rows: null/blank bill name with negative amount, or dash separators
const getBillName = (field) => {
const idx = headerMap[field];
return idx !== undefined ? cells[idx] : undefined;
};
const get = (field) => {
const idx = headerMap[field];
return idx !== undefined ? cells[idx] : undefined;
};
const rawBillName = getBillName('bill_name') ?? cells[0];
const billName = rawBillName ? String(rawBillName).trim() || null : null;
const rawAmount = get('amount') ?? findFirstAmountCell(cells, new Set(Object.values(headerMap)));
const amount = rawAmount !== null ? parseAmount(rawAmount) : null;
// Check if bill name is a dash separator (--- or ---->)
const isDashSeparator = billName && (billName.match(/^-+>/) || billName.match(/^--+$/));
// Check if this is a leftover calculation row (null/blank bill name + negative amount)
// Skip if bill name is null AND amount is negative
const isLeftoverCalcRow = !billName && amount !== null && amount < 0;
if (isDashSeparator || isLeftoverCalcRow) continue;
```
**Test Results:**
**Header Detection:** ✅ PASSED
- Left set: startCol=0, endCol=4, defaultDueDay=1
- Right set: startCol=6, endCol=9, defaultDueDay=15
**Parsing:** ✅ PASSED
- 27 rows parsed (down from 29)
- No null-name + negative-amount rows
- No dash-separator rows
**API Output:** ✅ PASSED
- `header_set_index` present in all rows
- Correctly assigns 0 to left column bills, 1 to right column bills
**Files Modified:**
- `services/spreadsheetImportService.js` - Added row skip filter in `parseSheetRows`
**Deliverables:**
- XLSX dual-column parser correctly filters calculation leftover rows
- XLSX dual-column parser correctly filters dash separator rows
- `header_set_index` available in preview API response for frontend column distinction
- Kids lunches null amount correctly reflects genuine empty cell (not a parsing bug)
---
### v0.24.4 - Analytics Mobile Layout + Previous Month Payment Toggle
**Status:** ✅ COMPLETED
**Date:** 2026-05-11
**Priority:** MEDIUM
| Agent | Status | Time | Notes |
|-------|--------|------|-------|
| Scarlett | ✅ COMPLETED | 12m | Mobile responsiveness fixes for AnalyticsPage |
| Neo | ✅ COMPLETED | 3m | Toggle-paid scoped to year/month on backend + frontend |
| Bishop | ✅ COMPLETED | 7m | Build verified, runtime tested, version bumped |
**Files modified:** `client/pages/AnalyticsPage.jsx`, `routes/bills.js`, `client/pages/TrackerPage.jsx`, `package.json`, `client/lib/version.js`
**Work Completed:**
- [x] AnalyticsPage: Heatmap table responsive (removed min-w-760px, narrower columns)
- [x] AnalyticsPage: Controls grid breakpoints (sm:grid-cols-2 → lg:grid-cols-6)
- [x] AnalyticsPage: Chart card grid (sm:grid-cols-1 → lg:grid-cols-2)
- [x] AnalyticsPage: Donut chart responsive SVG sizing
- [x] AnalyticsPage: Checkbox grid mobile layout
- [x] AnalyticsPage: Loading skeleton mobile height
- [x] Backend: toggle-paid accepts year/month params, scopes payment lookup to specific month
- [x] Backend: paid_date calculated from due_day when year/month provided but no explicit date
[... remaining content unchanged from original file ...]