-
- {/* Size the board to its populated lanes so sparse roadmaps stay readable. */}
+
+
{visibleLanes.map(lane => (
-
+
))}
- >
+
)}
diff --git a/package.json b/package.json
index ba5e9b3..7a24f87 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bill-tracker",
- "version": "0.35.0",
+ "version": "0.35.1",
"description": "Monthly bill tracking system",
"main": "server.js",
"scripts": {
diff --git a/roadmap.md b/roadmap.md
new file mode 100644
index 0000000..f9b2ee5
--- /dev/null
+++ b/roadmap.md
@@ -0,0 +1,154 @@
+# Bill Tracker Roadmap
+
+This document tracks the planned features and enhancements for Bill Tracker, organized by priority and implementation status.
+
+## π‘ MEDIUM Priority Items
+
+### π‘ Projected Cash Flow β MEDIUM
+**Status:** Not implemented
+
+**Description:**
+Show users what's coming: "You'll have $X left before the 15th", "Upcoming bills before next paycheck", and a "Safe-to-spend" estimate based on starting amount, unpaid bills, and scheduled income. Fits naturally with the existing 1st/15th bucket model.
+
+**Scope:**
+- "Remaining after bills" projection per bucket (1st half / 15th half)
+- "Upcoming bills before next paycheck" list
+- "Safe-to-spend" estimate based on starting balance minus unpaid bills
+- Scheduled income support (payday amounts)
+
+**Rationale:**
+- The 1st/15th bucket model is already built β cash flow projection is the natural next step
+- Most valuable feature for day-to-day money management
+- Turns a bill tracker into a financial planning tool
+
+**Implementation Notes:**
+- Requires user to enter starting balance and payday amounts (new settings fields)
+- Calculate: starting amount - unpaid bills due before next payday = safe-to-spend
+- Files to modify: `TrackerPage.jsx`, `routes/tracker.js`, `user_settings` table (new fields)
+- Estimated effort: 8-10 hours
+
+---
+
+### π‘ Recurring Payment Rules β MEDIUM
+**Status:** Partially implemented
+
+**Description:**
+Auto-mark certain bills as paid on due date if `autodraft_status = assumed_paid`. Or create suggested payments awaiting confirmation. Good for autopay-heavy users.
+
+**Scope:**
+- Bills with autopay/autodraft get a "suggested payment" on their due date
+- User confirms or dismisses the suggestion
+- Auto-mark option: bills can be set to automatically mark as paid on due date
+
+**Implementation Status:**
+- β `auto_mark_paid` column + bill edit checkbox
+- β `applyAutopaySuggestions()` in trackerService handles auto-mark + suggestion generation
+- β Confirm (`POST /api/payments/autopay-suggestions/:billId/confirm`) and dismiss (`POST /.../dismiss`) endpoints
+- β Suggestion UI in TrackerPage with badge + confirm/dismiss buttons
+- β No proactive suggestion engine β only runs when tracker loads
+- β No scheduled task/cron to evaluate bills and create suggestions on due date
+
+**Remaining Work:**
+- Implement scheduled task/cron to evaluate bills and create suggestions on due date
+- Estimated effort remaining: 2-3 hours
+
+---
+
+### π‘ Calendar Agenda Mode β MEDIUM
+**Status:** Not implemented
+
+**Description:**
+Replace the month-grid calendar with an agenda view: Today / This Week / Next 14 Days. Group bills by "needs action," "autopay," "already paid." More useful when actually paying bills.
+
+**Rationale:**
+- Month grids are pretty but not actionable
+- Agenda mode answers "what do I need to do right now?"
+- Groups by status makes it immediately clear what needs attention
+
+**Implementation Notes:**
+- New view toggle on CalendarPage: Grid vs Agenda
+- Agenda shows: Overdue β Today β This Week β Next 14 Days
+- Each group sorted by due date, with action status badges
+- Files to modify: `CalendarPage.jsx`, `routes/calendar.js`
+- Estimated effort: 6-8 hours
+
+---
+
+### π‘ Filtered Exports β MEDIUM
+**Status:** Not implemented
+
+**Description:**
+Export only utilities, debts, overdue, date range, tax-relevant categories. Currently exports everything with no filtering.
+
+**Rationale:**
+- Users need "all Q1 utility bills" or "overdue payments this year" for reconciliation and tax prep
+- `/api/export/user-excel` exports everything β no query params for date range, category, or status
+
+**Implementation Notes:**
+- Add query params to export endpoints: `category_id`, `start`, `end`, `status` (paid/unpaid/overdue)
+- Files to modify: `routes/export.js`, `client/pages/DataPage.jsx`
+- Estimated effort: 6 hours
+
+---
+
+## π΅ LOW Priority Items
+
+### π΅ Payment Method Tracking and Summary β LOW
+**Status:** Not implemented
+
+**Description:**
+The `payments` table has a `method` column (free-text) but no way to see "how much did I pay via autopay vs manual vs credit card this month."
+
+**Implementation Notes:**
+- Standardize payment methods: enum or controlled list (autopay, bank_transfer, credit_card, check, cash, other)
+- Add payment method breakdown to analytics or summary page
+- Files to modify: `routes/payments.js`, `AnalyticsPage.jsx`, schema migration
+- Estimated effort: 4-6 hours
+
+---
+
+### π΅ No Keyboard Navigation or Shortcuts β LOW
+**Status:** Partially implemented
+
+**Description:**
+Only a skip link exists for keyboard accessibility. No `Cmd+K` to find a bill, no `Esc` to close modals, no arrow keys to navigate the tracker grid.
+
+**Implementation Status:**
+- β `Esc` closes any open modal/dialog (via Radix Dialog default)
+- β `Cmd+K` / `Ctrl+K` opens command palette (`CommandPalette.jsx`)
+- β Arrow keys navigate tracker rows when grid is focused
+
+**Remaining Work:**
+- Implement arrow key navigation for tracker rows
+- Estimated effort: 1-2 hours
+
+---
+
+### π΅ Add comprehensive unit and integration tests
+**Status:** Not implemented
+
+**Description:**
+Currently no unit tests exist for components or hooks. The only testing is functional tests in `test-functional.js`.
+
+**Implementation Notes:**
+- Set up Jest + React Testing Library (or vitest)
+- Test key components: BillModal, TrackerPage row, BillsTableInner
+- Test hooks: useAuth, custom form hooks
+- Test utility functions in `client/lib/utils.js`
+- Estimated effort: 8-12 hours for baseline coverage
+
+---
+
+## π NICE TO HAVE Items
+
+### π Add consistent form state management pattern
+**Status:** Not implemented
+
+**Description:**
+Form state management is inconsistent across components. Some use `useState` for each field, others use form libraries.
+
+**Implementation Notes:**
+- Consider react-hook-form for complex forms
+- Create reusable form field components (InputField, SelectField, etc.)
+- Standardize validation approach
+- Estimated effort: 4-6 hours
\ No newline at end of file
diff --git a/routes/aboutAdmin.js b/routes/aboutAdmin.js
index d6711d6..73390d4 100644
--- a/routes/aboutAdmin.js
+++ b/routes/aboutAdmin.js
@@ -397,6 +397,23 @@ function redactSensitiveContent(content) {
.replace(/\bpassword\s*=\s*['"][^'"\s]+['"]/gi, 'password=[REDACTED]')
}
+// ββ Forgejo issues cache ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+const FORGEJO_BASE = 'https://dream.scheller.ltd/api/v1/repos/null/BillTracker';
+let _forgejoCache = null;
+let _forgejoCacheTs = 0;
+const FORGEJO_TTL_MS = 5 * 60 * 1000;
+
+async function fetchForgejoIssues() {
+ const res = await fetch(
+ `${FORGEJO_BASE}/issues?type=issues&state=open&limit=50&page=1`,
+ { headers: { Accept: 'application/json' }, signal: AbortSignal.timeout(10000) },
+ );
+ if (!res.ok) throw new Error(`Forgejo API returned ${res.status}`);
+ const issues = await res.json();
+ if (!Array.isArray(issues)) throw new Error('Unexpected Forgejo response shape');
+ return issues;
+}
+
// Admin-only endpoint to serve FUTURE.md and DEVELOPMENT_LOG.md content (raw markdown, backward compat)
router.get('/', requireAuth, requireAdmin, (req, res) => {
try {
@@ -423,19 +440,22 @@ router.get('/', requireAuth, requireAdmin, (req, res) => {
}
});
-// Admin-only endpoint: parsed roadmap items from FUTURE.md
-router.get('/roadmap', requireAuth, requireAdmin, (req, res) => {
+// Admin-only endpoint: open issues from Forgejo (5-min cache, ?refresh=1 to bypass)
+router.get('/roadmap', requireAuth, requireAdmin, async (req, res) => {
+ const now = Date.now();
+ const refresh = req.query.refresh === '1';
try {
- const futureContent = fs.readFileSync(ALLOWED_FILES['FUTURE.md'], 'utf-8');
- const sanitized = redactSensitiveContent(futureContent);
- const result = parseFutureMd(sanitized);
- res.json(result);
+ if (!refresh && _forgejoCache && now - _forgejoCacheTs < FORGEJO_TTL_MS) {
+ return res.json(_forgejoCache);
+ }
+ const issues = await fetchForgejoIssues();
+ _forgejoCache = { issues, fetchedAt: new Date().toISOString() };
+ _forgejoCacheTs = now;
+ res.json(_forgejoCache);
} catch (err) {
- console.error('[aboutAdmin] Error reading FUTURE.md for roadmap');
- res.status(500).json({
- error: 'Failed to read roadmap data',
- code: 'FILE_READ_ERROR'
- });
+ console.error('[aboutAdmin] Forgejo issues error:', err.message);
+ if (_forgejoCache) return res.json({ ..._forgejoCache, stale: true });
+ res.status(502).json({ error: 'Failed to fetch issues from repository', code: 'FORGEJO_ERROR' });
}
});