Commit Graph

94 Commits

Author SHA1 Message Date
null 488f329e14 chore: sync package.json version to 0.27.0 2026-05-14 02:24:50 -05:00
null 7d2d0bf45e 0.28.0 snowball release 2026-05-14 02:11:54 -05:00
null 48fe87ea25 corrections 2026-05-14 01:17:05 -05:00
null d2acf44846 chore: untrack private docs (STRUCTURE, FUTURE, HISTORY, DEVELOPMENT_LOG) 2026-05-13 04:04:29 -05:00
null 34b0f75918 v0.26.1: fix dual-column XLSX parser bugs
- Rewrite detectAllHeaderSets() with repeat-field detection instead of gap-based splitting
- Require ≥2 header fields per group (filters out false matches like 'Left Over | Paid')
- Fix column leakage: right-side bills no longer pick up left-side amounts
- Add header_set_index to analyzeRow return object for frontend use
- Add isLikelySummaryRow() filter (Paycheck, Left Over, Enter how much, etc.)
- Expand isLikelyTotalRow() to catch 'Auto Total ------>' patterns
- Filter leftover calc rows (null name + negative amount, dash separators)
- Remove 'paid' from HEADER_PATTERNS.amount (was false-matching 'Paid' cells)
- Skip empty string cells in detectAllHeaderSets
2026-05-11 23:17:19 -05:00
null d32a30495d docs: update HISTORY v0.26.0, remove completed XLSX dual-column from FUTURE 2026-05-11 22:19:02 -05:00
null 831f617893 v0.26.0: dual-column XLSX import parser
- detectAllHeaderSets() finds multiple header groups per row (left 1st / right 15th)
- isBlankRowForHeaderSet() checks blanks per column range for dual layouts
- parseSheetRows() scans rows 0-4 for header row, processes each set independently
- analyzeRow() computes due_day from date/label/pattern with fallback to defaultDueDay
- Cell type validation allows 's' (shared formula) type
- Non-numeric amounts (auto, double pay, past due) become detected labels
- Day patterns (1st, 15th, 24th) parsed as due_day values
- Security: bounds validation in isBlankRowForHeaderSet, anchored regex, label sanitization
2026-05-11 22:13:37 -05:00
null 579eed37b8 docs: update HISTORY v0.25.0, remove completed CSRF fix from FUTURE 2026-05-11 21:46:33 -05:00
null 2ce5328fd2 v0.25.0: roadmap redesign, import CSRF fix, AdminDashboard removed
- RoadmapPage: kanban-style priority lanes, shadcn Collapsible/Tabs,
  lazy-loaded activity log, admin-only /api/about/roadmap + /dev-log endpoints
- Import CSRF fix: added x-csrf-token header to importAdminBackup,
  previewSpreadsheetImport, previewUserDbImport raw fetch() calls
- Removed AdminDashboard.jsx, replaced by RoadmapPage
- Added @radix-ui/react-collapsible + collapsible shadcn component
- Security audit by Private_Hudson: PASS (CSRF fix verified,
  admin endpoints gated, path traversal mitigated, XSS safe)
2026-05-11 21:42:36 -05:00
null 98ede20cd3 fix: prevent duplicate payment prompts 2026-05-11 16:04:21 -05:00
null 22f9a570aa v0.24.5: starting amounts fix, pay badge alignment, demo data persistence 2026-05-11 15:25:04 -05:00
null b29d3a0b02 fix: starting amounts paid_from_other calculation + pay badge alignment on tracker 2026-05-11 15:00:35 -05:00
null 890427c75a v0.24.3: Session fixes, activity log corrections, UI polish 2026-05-11 13:39:48 -05:00
null 24b4e8d24e refactor: extract bills.js business logic into services/billsService.js (Phase 1) 2026-05-11 12:12:31 -05:00
null c1ac14efe3 v0.24.4: analytics mobile layout + previous month payment toggle 2026-05-11 11:56:49 -05:00
null 86148a101f feat: remove confirmation popup from status badge toggle (v0.24.3)
Clicking status badges (Late, Due Soon, Upcoming, Missed) now instantly
toggles paid/unpaid. Removed AlertDialog from TrackerPage.jsx — no more
confirmation dialog blocking the action.
2026-05-10 17:56:23 -05:00
null 6d42453e07 fix: status badge toggle-paid using wrong property name (v0.24.2)
handleTogglePaid() was using row.bill_id instead of row.id, causing
the API call to fail with an undefined bill ID. Clicking status badges
(Late, Due Soon, Upcoming, Missed) now correctly toggles paid/unpaid.
2026-05-10 17:28:26 -05:00
null ba888c1c6f feat: export privacy warning + updated included fields list (v0.24.1)
- Added amber warning banner on Download My Data section about sensitive metadata
- Updated 'What's included' list to show monthly starting amounts and history ranges
- Marked LOW export sensitive fields item as FIXED in FUTURE.md
2026-05-10 15:29:35 -05:00
null 80b3bcc17b fix: HIGH+MEDIUM batch — 10 fixes (v0.24.0)
HIGH:
- Admin toggle-paid: removed cross-user admin branch, now requires ownership
- Analytics crash: imported missing standardizeError
- Export data loss: added cycle_type, cycle_day, bill_history_ranges to exports
- Single-user lockout: removed unnecessary sessions join from getSingleModeUser

MEDIUM:
- Password rate limiter: scoped to change-password only, not all profile routes
- Profile session invalidation: fixed req.sessionId → req.cookies[COOKIE_NAME]
- CSRF default: httpOnly now defaults to false (matches SPA double-submit pattern)
- CSRF password routes: removed csrfSkip for password change endpoints
- Notification due-day: calendar day comparison instead of timestamp floor
- Upcoming bills: clamped days to 1-365, default 30 for invalid input

FUTURE.md: marked all 10 items as FIXED, bumped version refs
HISTORY.md: added v0.24.0 entry
2026-05-10 15:25:47 -05:00
null 5537ab2bd5 fix: clear demo data button, seed user ID bug, duplicate endpoint (v0.23.4)
- DataPage: removed 'coming soon' placeholder, made Clear Demo Data button accessible from seeded state
- seedDemoData.js: fixed userId -> targetUserId bug
- settings.js: removed duplicate /api/settings/seed-demo-data endpoint
- Version bumped to 0.23.4
2026-05-10 15:11:02 -05:00
null 6d488aa8bd docs: update HISTORY.md and FUTURE.md for v0.23.3 2026-05-10 14:37:42 -05:00
null 5eed5932b4 feat: replace native confirm() with shadcn/ui AlertDialog (v0.23.3)
- TrackerPage: confirm('Mark as paid?') → AlertDialog with dynamic bill name
- DataPage: window.confirm('Import SQLite?') → AlertDialog for import confirmation
- Both dialogs use proper shadcn/ui components (AlertDialogAction/Cancel)
- Theme-aware, accessible, consistent with app design system
- STRUCTURE.md: corrected tech stack (Vite+React, not Next.js)
- Version bumped to 0.23.3
2026-05-10 14:36:59 -05:00
null 7c3cfd1715 docs: update README.md, ERM, FUTURE.md, HISTORY.md
README.md updates:
- Added billing cycles (weekly/biweekly/quarterly/annual), history ranges,
  monthly income/starting amounts, migration rollback, audit logging,
  auth-mode/OIDC config, CSRF protection details
- Added INIT_REGULAR_USER/PASS and SESSION_CLEANUP_INTERVAL_MS env vars
- Added CSRF env vars (CSRF_HTTP_ONLY, CSRF_SAME_SITE, CSRF_SECURE,
  CSRF_COOKIE_NAME)
- Noted export limitation: cycle_type, cycle_day, history_ranges omitted
- Fixed: CSP is now implemented with per-request nonces (was 'deferred')
- Added: default admin restricted from tracker routes, session rotation
  on password change, audit logging
- Cleaned up demo server formatting, project structure listing, scripts
- Removed authLogin.js from project structure (file was deleted in v0.23.2)

Engineering_Reference_Manual.md:
- Removed stale authLogin.js duplicate route note (file no longer exists)
- Removed 401/403 error detail from login endpoint (simplified)
- Updated version to 0.23.2

FUTURE.md:
- Marked notification privacy leak (CRITICAL) as FIXED v0.23.2
- Marked duplicate login route (LOW) as FIXED v0.23.2
- Updated current version to v0.23.2

HISTORY.md:
- Added v0.23.2 entry with security fix and route consolidation details
2026-05-10 12:42:45 -05:00
null 6b1ef7dcfa fix: notification privacy leak — per-user bills no longer sent to all recipients (v0.23.2)
CRITICAL security fix: In per-user notification mode, the notification runner
was fetching ALL active bills globally and sending each bill's details to
every opted-in recipient regardless of ownership. This meant User A's bill
names, amounts, and due dates could be emailed to User B.

Fix: Added ownership filter in the recipient loop:
  if (allowUserConfig && bill.user_id !== recipient.id) continue;

Also added a defensive guard for bills with no user_id (orphaned bills),
which are now skipped with a console.warn instead of being broadcast.

Global notification mode (single admin recipient) is unaffected.

Security audit: Private_Hudson confirmed the fix is airtight. All other
routes (bills, payments, tracker, analytics, export, calendar, summary,
categories) properly scope data by user_id.

Version bump: 0.23.1 → 0.23.2 (security patch)
2026-05-10 12:34:53 -05:00
null 78f95f784e fix: remove duplicate login route (authLogin.js), consolidate into auth.js
- Deleted routes/authLogin.js (orphaned duplicate login handler)
- Removed authLoginRouter import and mount from server.js
- Rate limiter now runs as standalone middleware on /api/auth/login
- Added try/catch to auth.js login handler (was only in deleted file)
- Consistent audit log variable naming (username vs req.body.username)
- No functionality change — login flow works identically
2026-05-10 12:20:50 -05:00
null 24bac8e506 docs: refresh engineering reference manual 2026-05-10 11:49:05 -05:00
null 52db06001f v0.23.1: migration rollback capability
- Add rollbackMigration() function in db/database.js with transaction safety
- Add POST /api/admin/migrations/rollback endpoint (admin-only)
- Rollback SQL for v0.44 (indexes), v0.45 (audit_log table), v0.46 (cycle columns)
- Error codes: NOT_APPLIED (404), ROLLBACK_NOT_SUPPORTED (422)
- Audit logging for rollback events
- Fix duplicate migrationStartTime declaration from v0.23.0 commit
- Fix broken migration completion audit log from v0.23.0 commit
- Fix DB path exposure (uses path.basename() now)
2026-05-10 10:44:39 -05:00
null 53783aaec5 v0.23.0: Detailed migration logging with timing, error context, and audit logging
- Added [migration] logging for each migration step (applying, completed, timing)
- Added [migration-error] logging with elapsed time on failures
- Added [migration] All migrations completed in Xms total timing
- Added lazy getLogAudit() for audit logging of migration failures (avoids circular dep)
- Changed DB path log to basename only (Hudson rec: reduce info disclosure)
- Version bumped to 0.23.0
2026-05-10 09:45:39 -05:00
null ee960c5c5a fix: remove circular dependency in database.js audit logging
- Remove logAudit import and call from db/database.js (circular dep with auditService)
- database.js init code uses console.log instead
- logAudit remains in setup/firstRun.js and server.js (safe, no circular dep)
2026-05-10 04:28:34 -05:00
null eb86da1e69 v0.22.3: fix ENV-seeded users skip first-login flow, add audit logging
- setup/firstRun.js: reset first_login=0, must_change_password=0 on update
- server.js: reset flags for existing regular users + add logAudit
- db/database.js: fix must_change_password=0 in init code (was 1)
- Add logAudit calls for seed.flag_reset events
- database.js uses console.log for init-time resets (avoids circular dep)
- Hudson audit: 6/6 PASS after audit logging fix
2026-05-10 04:24:51 -05:00
null 9647275854 docs: add HISTORY.md for v0.22.2 2026-05-10 03:57:31 -05:00
null c4a3593241 v0.22.2: Session Token Rotation on Auth Events
- invalidateOtherSessions() in authService.js: deletes all sessions except current
- Password change (auth.js + profile.js) now invalidates all other sessions
- Password change rotates current session ID (sets new cookie)
- New POST /api/auth/logout-all endpoint (deletes all sessions + clears cookie)
- Audit logging for logout.all and password.change
- Added last_password_change_at to auth.js change-password for consistency
- Hudson security audit: 6/6 PASS
2026-05-10 03:55:14 -05:00
null 65849fc554 v0.22.1: N+1 Query Optimization
- Batch queries replace per-bill loops in tracker and analytics
- monthly_bill_state, payments, prev month payments batched with WHERE IN
- Empty billIds guards prevent SQL errors
- Hudson security audit: 5/5 PASS (SQL injection, empty IN, user scoping, data leakage, type safety)
2026-05-10 03:29:09 -05:00
null 5c35b20c00 docs: update HISTORY, FUTURE, DEVELOPMENT_LOG for v0.22.0 2026-05-10 03:14:40 -05:00
null d67fe6e61d v0.22.0: React Query Migration
- Added @tanstack/react-query and @tanstack/react-query-devtools
- Created useTracker, useBills, useCategories custom hooks (useQueries.js)
- Migrated TrackerPage from manual useState/useEffect to useQuery
- Added QueryClientProvider with 2min staleTime, 1 retry, refetchOnWindowFocus: false
- Added ReactQueryDevtools for development
- Fixed error handling: useRef pattern prevents duplicate toast notifications
- Replaced load() callback with refetch() from useQuery
- Hudson security audit: 4/5 PASS (1 FAIL fixed: error handling toast duplication)
2026-05-10 03:10:43 -05:00
null 314159d241 v0.21.1: Loading Skeletons & Async State
- Reusable Skeleton component (line, circle, card, button, input variants)
- TrackerPage: skeleton cards, rows, buckets with aria-busy attributes
- BillsPage: skeleton rows during loading
- Bug fix: double closing brace />}} on Bucket component
- Hudson security audit: 5/5 PASS
2026-05-10 01:35:41 -05:00
null ac4b4653a5 docs: update DEVELOPMENT_LOG for v0.21.0 pipeline completion 2026-05-10 01:24:47 -05:00
null cfb074c7cd v0.21.0: 3-Month Trend Indicator on Tracker
- Backend: 3-month payment aggregation with year-wrapping, trend object in API (direction, percent_change, 3_month_avg)
- Frontend: TrendIndicator component (arrow + percentage + label), TrendCard with purple gradient
- Bug fix: Bishop fixed 3-month query to JOIN through bills for user scoping (payments table has no user_id)
- Bug fix: Ripley removed duplicate TrendIndicator function definition
- Hudson security audit: 5/5 PASS (SQL injection, user scoping, date wrapping, division by zero, XSS)
2026-05-10 01:22:51 -05:00
null 38394a8bcd docs: update DEVELOPMENT_LOG for v0.20.9 pipeline completion 2026-05-10 00:54:19 -05:00
null 4990bf47f6 v0.20.9: Previous Month Paid column on Tracker
- Backend: previous month calculation with year wrapping (Jan→Dec)
- Backend: previous_month_paid per bill row, previous_month_total in summary
- Frontend: 'Last Month' column in desktop table with muted text
- Frontend: 'Last Month' in mobile view, summary card for prev month total
- Hudson security audit: 5/5 PASS (SQL injection, date wrapping, user scoping, auth, XSS)
2026-05-10 00:52:23 -05:00
null 08975582f2 docs: update DEVELOPMENT_LOG for v0.20.8 completion 2026-05-10 00:41:08 -05:00
null bd796d61c0 v0.20.8: Billing cycle sub-categories + server-side cycle_day validation
- Migration v0.46: cycle_type (monthly/weekly/biweekly/quarterly/annual) and cycle_day columns
- Server-side validation: cycle_type whitelist, cycle_day validated per type
  - monthly: 1-31 integer
  - weekly/biweekly: day name enum
  - quarterly/annual: free text (max 50 chars)
- BillModal UI: conditional cycle_day selector (ordinal/weekday/text)
- Hudson audit: 4/5 PASS, fixed medium-risk cycle_day validation gap
2026-05-10 00:39:11 -05:00
null 5f8c366c70 docs: update DEVELOPMENT_LOG for v0.20.7 pipeline completion 2026-05-10 00:19:13 -05:00
null e184fed88a v0.20.7: Keyboard navigation and ARIA accessibility
- Skip-to-content link for keyboard users (sr-only/focus:not-sr-only pattern)
- aria-expanded and aria-haspopup on Tracker menu dropdown
- aria-label on footer, role='main' and aria-labelledby on layout wrapper
- Main content wrapped in <main> with unique id from React useId()
- Fixed build error: useId imported from react, not react-router-dom
- Hudson security audit: 5/5 PASS (no XSS, no DOM clobbering, no injection)
2026-05-10 00:18:36 -05:00
null 39f3577f04 docs: update DEVELOPMENT_LOG for v0.20.6 pipeline completion 2026-05-10 00:03:50 -05:00
null 7503a54f81 v0.20.6: Audit logging for critical operations
- New audit_log table (migration v0.45) with indexes
- logAudit() service with try/catch safety (never crashes app)
- Audit events: login.success, login.failure, logout, password.change, role.change, csrf.failure, profile.update, profile.settings.update
- All events include ip_address and user_agent
- No passwords, tokens, or session IDs logged
- Hudson security audit: 7/7 PASS
2026-05-10 00:03:12 -05:00
null 4f1eec36f5 docs: update DEVELOPMENT_LOG for v0.20.5 pipeline completion 2026-05-09 23:42:19 -05:00
null 8e7f977fef v0.20.5: Bulk payment input validation
- Request body must contain `payments` array (breaking change from raw array)
- Max 50 items per bulk request
- Per-item validation: bill_id (integer regex + parseInt), paid_date (YYYY-MM-DD), amount (finite number >= 0)
- Duplicate detection using bill_id + paid_date + amount composite key — skipped, not rejected
- Response format: { created, skipped, errors }
- Security fix: bill_id type coercion attack (parseInt('1abc') bypass) blocked via regex check
- Security fix: Infinity amount bypass blocked via isFinite() check
- Hudson audit: 5/7 PASS, 2 FAIL fixed (type coercion + Infinity)
2026-05-09 23:41:28 -05:00
null 565b837196 docs: update DEVELOPMENT_LOG, FUTURE.md, HISTORY.md for v0.20.4 2026-05-09 23:25:43 -05:00
null 35e09430c9 v0.20.4: Explicit migration dependency management
- Added dependsOn field to all 17 versioned migrations
- Added validateMigrationDependencies() function for dependency validation
- Migrations with unmet dependencies are skipped with error log (no crash)
- Dependency satisfaction logged: [migration] vX depends on [vY] — satisfied
- appliedVersions Set tracks newly applied migrations for subsequent checks
- Hudson security audit: 7/7 PASS
2026-05-09 23:24:51 -05:00