2026-07-06 21:34:45 +02:00
|
|
|
# Ledger — Outstanding Work
|
|
|
|
|
|
2026-07-06 22:01:09 +02:00
|
|
|
## Status as of end of session (2026-07-06, evening)
|
|
|
|
|
|
|
|
|
|
**Done and committed:** §1–§4 (Categories page, Add-transaction form,
|
|
|
|
|
Add/edit-budget form + Overview budget panel, Transactions filters + Export,
|
|
|
|
|
Overview date-range dropdown) are all implemented and committed as 5
|
|
|
|
|
separate commits (`319c023` through `c7af925`, one per chunk). Local branch
|
|
|
|
|
is 2 commits ahead of `origin/main` — not pushed yet, no push has been
|
|
|
|
|
requested.
|
|
|
|
|
|
|
|
|
|
**Uncommitted:** only this file (`TODO.md`) — the §7 edit/delete tracking
|
|
|
|
|
section added below was written after the last commit and hasn't been
|
|
|
|
|
committed.
|
|
|
|
|
|
|
|
|
|
**Not started:** §7 (edit/delete for Transactions/Budgets/Accounts/
|
|
|
|
|
Categories + a User profile page) — tracked below, nothing built yet.
|
|
|
|
|
Suggested order there: Account + Category edit/delete first, then Budget
|
|
|
|
|
delete, then User profile, then Transaction edit/delete last (trickiest,
|
|
|
|
|
touches running-balance recomputation).
|
|
|
|
|
|
|
|
|
|
**Environment reminders for next session** (see [[project-dev-environment]]
|
|
|
|
|
in memory for more):
|
|
|
|
|
- Local dev runs via `docker compose` — containers `ledger-backend` (8080),
|
|
|
|
|
`ledger-frontend` (5173), `ledger-db` (5432) — check `docker ps` before
|
|
|
|
|
assuming anything needs starting.
|
|
|
|
|
- The real logged-in user is `ricardompcampos@hotmail.com`, not the seeded
|
|
|
|
|
`demo@ledger.app` account.
|
|
|
|
|
- **Demo login is still broken** (`seed-data.sql`'s bcrypt hash uses an
|
|
|
|
|
incompatible `$2b$` prefix) — not fixed, see §5.
|
|
|
|
|
- **Editing any file under `backend/src/main/java` while `quarkus:dev` is
|
|
|
|
|
running wipes the local database** (Hibernate `drop-and-create` on live
|
|
|
|
|
reload) — expect this, not a bug. User has said to just proceed without
|
|
|
|
|
pausing for confirmation each time, since local data is disposable.
|
|
|
|
|
|
2026-07-06 21:34:45 +02:00
|
|
|
Snapshot from a full frontend + backend audit (2026-07-06). The backend is
|
|
|
|
|
further along than it looks from the UI — Transactions, Budgets, and
|
|
|
|
|
Categories all have working create endpoints that are simply never called.
|
|
|
|
|
The gap is almost entirely in the frontend; a couple of backend gaps are
|
|
|
|
|
called out separately at the end.
|
|
|
|
|
|
|
|
|
|
Reference pattern for "how a working button looks in this codebase":
|
|
|
|
|
`frontend/src/pages/Accounts.jsx` — `useState` toggle for a panel +
|
|
|
|
|
controlled form inputs + `useMutation` (react-query) + `queryClient
|
|
|
|
|
.invalidateQueries` on success. There is no shared `<Modal>` or `<Dropdown>`
|
|
|
|
|
component yet, so the first one built should probably be extracted for reuse
|
|
|
|
|
rather than copy-pasted three more times.
|
|
|
|
|
|
|
|
|
|
## 1. Categories — no UI at all (highest priority, blocks the rest)
|
|
|
|
|
|
|
|
|
|
Backend is fully ready: `Category` entity, `GET /categories`, `POST
|
|
|
|
|
/categories` (`backend/src/main/java/com/ledger/category/CategoryResource.java`).
|
|
|
|
|
Frontend `CategoriesApi.list()` / `.create()` already exist in
|
|
|
|
|
`frontend/src/api/ledger.js:14-17` but are never imported anywhere.
|
|
|
|
|
|
2026-07-06 21:42:24 +02:00
|
|
|
- [x] Add a Categories page (`frontend/src/pages/Categories.jsx`) with list +
|
2026-07-06 21:34:45 +02:00
|
|
|
create form (name, color), using the Accounts.jsx pattern.
|
2026-07-06 21:42:24 +02:00
|
|
|
- [x] Add `/categories` route in `App.jsx`.
|
|
|
|
|
- [x] Add "Categories" link to `Sidebar.jsx` (`links` array, currently only
|
2026-07-06 21:34:45 +02:00
|
|
|
Overview/Transactions/Budgets/Accounts).
|
|
|
|
|
- [ ] Backend: add `PUT /categories/{id}` and `DELETE /categories/{id}` —
|
|
|
|
|
currently create/list only, no edit or delete.
|
|
|
|
|
- [ ] Once this exists, wire the Transactions category filter/picker to
|
|
|
|
|
`CategoriesApi.list()` instead of the hardcoded `categoryColors` object
|
|
|
|
|
(`Transactions.jsx:112-117`).
|
|
|
|
|
|
|
|
|
|
## 2. Transactions page — "Add transaction" is a dead button
|
|
|
|
|
|
|
|
|
|
`Transactions.jsx:86-89` — no `onClick`, no form/modal exists anywhere.
|
|
|
|
|
Backend `POST /transactions` already works
|
|
|
|
|
(`backend/src/main/java/com/ledger/transaction/TransactionResource.java:36`),
|
|
|
|
|
required fields: `accountId`, `description`, `amount`; optional:
|
|
|
|
|
`categoryId`, `occurredOn` (defaults to today). Note it also updates the
|
|
|
|
|
account's running balance server-side as a side effect.
|
|
|
|
|
Frontend `TransactionsApi.create` already exists in `ledger.js:22`.
|
|
|
|
|
|
2026-07-06 21:42:24 +02:00
|
|
|
- [x] Build the add-transaction form/panel (account select, category select
|
2026-07-06 21:34:45 +02:00
|
|
|
populated from `CategoriesApi.list()`, description, amount, date).
|
2026-07-06 21:42:24 +02:00
|
|
|
- [x] Wire it to `TransactionsApi.create` + invalidate the relevant queries
|
2026-07-06 21:34:45 +02:00
|
|
|
(account list for balance, transactions list).
|
2026-07-06 21:49:31 +02:00
|
|
|
- [x] Wire the account filter select (`Transactions.jsx:104-109`) — currently
|
2026-07-06 21:34:45 +02:00
|
|
|
renders options but has no `onChange`/state.
|
2026-07-06 21:49:31 +02:00
|
|
|
- [x] Wire the category filter select (`Transactions.jsx:112-117`) — same
|
|
|
|
|
issue, also depends on item 1. Now populated from `CategoriesApi.list()`.
|
|
|
|
|
- [x] Wire the date-range select ("Last 30 days" / "Last 90 days" / "This
|
|
|
|
|
year", `Transactions.jsx:120-124`) — filtering is still done client-side
|
|
|
|
|
over all fetched transactions (no backend date-range params yet, see
|
|
|
|
|
§6), but the control now actually filters the visible list.
|
|
|
|
|
- [x] Wire or remove the "Export" button (`Transactions.jsx:127-130`) —
|
|
|
|
|
exports the currently filtered transactions as a CSV download.
|
2026-07-06 21:34:45 +02:00
|
|
|
|
|
|
|
|
## 3. Budgets page — no way to create or edit a budget
|
|
|
|
|
|
|
|
|
|
`Budgets.jsx:51-54` — "Edit budgets" button has no `onClick`, and there's no
|
|
|
|
|
"Add budget" affordance either. Backend `POST /budgets` is a working
|
|
|
|
|
upsert-by-category-and-month
|
|
|
|
|
(`backend/src/main/java/com/ledger/budget/BudgetResource.java:67`), needs
|
|
|
|
|
`categoryId`, `month`, `limitAmount`. Frontend `BudgetsApi.upsert` already
|
|
|
|
|
exists in `ledger.js:30`.
|
|
|
|
|
|
2026-07-06 21:46:17 +02:00
|
|
|
- [x] Build a set/edit-limit form (category select, month, limit amount),
|
2026-07-06 21:34:45 +02:00
|
|
|
reusing the Accounts.jsx pattern, calling `BudgetsApi.upsert`.
|
2026-07-06 21:46:17 +02:00
|
|
|
- [x] `Budgets.jsx:24` hardcodes `yearMonth` to the current month
|
2026-07-06 21:34:45 +02:00
|
|
|
(`new Date().toISOString().slice(0, 7)`) — no way to view or set a
|
|
|
|
|
budget for any other month. Add month navigation.
|
2026-07-06 21:46:17 +02:00
|
|
|
- [x] `Overview.jsx:118-124` has a placeholder panel ("Category breakdowns
|
2026-07-06 21:34:45 +02:00
|
|
|
will live here once budgets have real spend data behind them") even
|
|
|
|
|
though `GET /budgets/month/{yearMonth}/spend` already returns exactly
|
|
|
|
|
that data — just needs to be fetched and rendered (as cards/progress
|
|
|
|
|
bars per CLAUDE.md, not charts).
|
|
|
|
|
|
|
|
|
|
## 4. Overview page — "This month" button does nothing
|
|
|
|
|
|
|
|
|
|
`Overview.jsx:51-54` — static button, no `onClick`, no dropdown markup, no
|
|
|
|
|
date-range state anywhere on the page.
|
|
|
|
|
|
2026-07-06 21:58:00 +02:00
|
|
|
- [x] Build the dropdown (This week / Last week / This month / Last 30 days /
|
|
|
|
|
This year) — added as a reusable `frontend/src/components/Dropdown.jsx`
|
|
|
|
|
(generic trigger + menu, click-outside-to-close), styled to match
|
|
|
|
|
`.btn-ghost` and the hairline-border/no-shadow language.
|
|
|
|
|
- [x] Wire selection to the "Recent activity" list — filtered client-side
|
|
|
|
|
over the already-fetched per-account transactions (same approach as
|
|
|
|
|
the Transactions date-range filter in §2/§4; no backend date-range
|
|
|
|
|
endpoint needed at current data volumes, see §6).
|
2026-07-06 21:34:45 +02:00
|
|
|
|
|
|
|
|
## 5. Security / data fixes found and applied during implementation
|
|
|
|
|
|
|
|
|
|
- [x] `User.passwordHash` had no `@JsonIgnore` — every endpoint that embeds a
|
|
|
|
|
`User` relation (Category, Account, Transaction, Budget) was leaking
|
|
|
|
|
the bcrypt hash in plain JSON. Fixed in
|
|
|
|
|
`backend/src/main/java/com/ledger/user/User.java`.
|
|
|
|
|
- [x] `seed-data.sql`'s transaction INSERTs referenced the `t` (VALUES)
|
|
|
|
|
alias inside the `categories` JOIN condition before `t` was introduced
|
|
|
|
|
in the FROM clause — fails on Postgres ("missing FROM-clause entry for
|
|
|
|
|
table t"). Fixed by reordering the JOINs so `t` is introduced before
|
|
|
|
|
it's referenced.
|
|
|
|
|
- [ ] `seed-data.sql`'s demo password hash uses a `$2b$` bcrypt prefix that
|
|
|
|
|
Quarkus's Elytron `BcryptUtil` doesn't recognize (`ELY08003: Unknown
|
|
|
|
|
crypt string algorithm`) — demo login (`demo@ledger.app`/`demo12345`)
|
|
|
|
|
is currently broken. Needs a hash regenerated via `BcryptUtil.bcryptHash`
|
|
|
|
|
(Elytron-compatible, likely `$2a$` prefix) rather than a hash lifted
|
|
|
|
|
from another bcrypt implementation.
|
|
|
|
|
|
|
|
|
|
**Note:** editing any file under `backend/src/main/java` while `quarkus:dev`
|
|
|
|
|
is running triggers a live-reload schema regeneration (`drop-and-create`,
|
|
|
|
|
per the Known Gaps section above) — it silently wipes all local data. Not a
|
|
|
|
|
bug to fix, just something to expect until real migrations exist.
|
|
|
|
|
|
|
|
|
|
## 6. Backend gaps
|
|
|
|
|
|
|
|
|
|
- [ ] No date-range query params on `GET /transactions/account/{accountId}`
|
|
|
|
|
— returns everything, unbounded, no pagination. Needed for both the
|
|
|
|
|
Overview dropdown and the Transactions date-range select to be
|
|
|
|
|
meaningful server-side rather than client-side filtering over the full
|
|
|
|
|
history.
|
|
|
|
|
- [ ] No dashboard/stats aggregation endpoint — Overview currently computes
|
|
|
|
|
totals client-side from full per-account transaction lists fetched one
|
|
|
|
|
account at a time. Fine for now at small data volumes, but worth an
|
|
|
|
|
endpoint if this needs to scale.
|
|
|
|
|
- [ ] No `DELETE`/`PUT` for Transaction or Budget (Budget's create doubles as
|
|
|
|
|
update via upsert, so this is lower priority than Category's missing
|
|
|
|
|
edit/delete).
|
|
|
|
|
|
2026-07-06 21:58:00 +02:00
|
|
|
## Suggested order (all done as of 2026-07-06)
|
2026-07-06 21:34:45 +02:00
|
|
|
|
2026-07-06 21:58:00 +02:00
|
|
|
1. [x] Categories page (unblocks category pickers everywhere else).
|
|
|
|
|
2. [x] Add-transaction form.
|
|
|
|
|
3. [x] Add/edit-budget form + wire the Overview budget-spend panel (data
|
|
|
|
|
already exists server-side, purely a frontend job).
|
|
|
|
|
4. [x] Transactions filters (account/category/date) + Export.
|
|
|
|
|
5. [x] Overview "This month" dropdown (client-side range filter).
|
|
|
|
|
|
|
|
|
|
All five UI-wiring chunks from this audit are implemented. What's left is
|
|
|
|
|
§6's backend gaps (date-range/pagination endpoint, Category edit/delete,
|
|
|
|
|
Transaction/Budget delete) and the outstanding bcrypt-prefix bug in
|
|
|
|
|
§5 (demo login) — none of these block normal use of the app with a real
|
|
|
|
|
account, they're follow-ups for later.
|
2026-07-06 22:01:09 +02:00
|
|
|
|
|
|
|
|
## 7. Edit/delete + profile management (requested 2026-07-06, not yet built)
|
|
|
|
|
|
|
|
|
|
Every entity currently only supports create + list. There is no edit or
|
|
|
|
|
delete UI anywhere, and the only delete endpoint that exists server-side
|
|
|
|
|
(`DELETE /accounts/{id}`) isn't even called from the frontend. None of this
|
|
|
|
|
is built yet — tracked here for a future round of chunks.
|
|
|
|
|
|
|
|
|
|
1. **Transactions** — no edit, no delete, anywhere.
|
|
|
|
|
- Backend: no `PUT`/`DELETE /transactions/{id}` at all
|
|
|
|
|
(`backend/src/main/java/com/ledger/transaction/TransactionResource.java`
|
|
|
|
|
only has `GET`/`POST`). A delete needs to reverse the transaction's
|
|
|
|
|
effect on `account.balance` and re-derive `runningBalance` for later
|
|
|
|
|
transactions on that account — not a trivial delete, needs thought.
|
|
|
|
|
- Frontend: no edit/delete affordance on any `txn-row` in
|
|
|
|
|
`Transactions.jsx`.
|
|
|
|
|
|
|
|
|
|
2. **Budgets** — edit already works implicitly (re-submitting the same
|
|
|
|
|
category+month via `POST /budgets` upserts the limit), but there's no
|
|
|
|
|
delete and no explicit per-card edit affordance.
|
|
|
|
|
- Backend: no `DELETE /budgets/{id}`.
|
|
|
|
|
- Frontend: no delete button on `budget-card`; editing means reopening
|
|
|
|
|
the top form and re-picking the same category rather than clicking
|
|
|
|
|
"edit" on the card itself.
|
|
|
|
|
|
|
|
|
|
3. **Accounts** — backend already has `DELETE /accounts/{id}` and
|
|
|
|
|
`AccountsApi.remove()` exists in `ledger.js`, but nothing in
|
|
|
|
|
`Accounts.jsx` calls it — no delete button on `account-card-lg` at all.
|
|
|
|
|
No edit (`PUT`) exists on either side — can't change name/institution/
|
|
|
|
|
kind after creation.
|
|
|
|
|
- Backend: needs `PUT /accounts/{id}`.
|
|
|
|
|
- Frontend: needs a delete affordance (with a confirm step — deleting an
|
|
|
|
|
account presumably should be blocked or cascade-handled if it still
|
|
|
|
|
has transactions, similar to the FK constraint hit during testing of
|
|
|
|
|
chunk 2) and an edit form.
|
|
|
|
|
|
|
|
|
|
4. **Categories** — no edit, no delete, on either side (same gap noted in
|
|
|
|
|
§1). Deleting a category needs a decision on what happens to existing
|
|
|
|
|
transactions/budgets referencing it (null out `category_id`? block?).
|
|
|
|
|
- Backend: needs `PUT`/`DELETE /categories/{id}`.
|
|
|
|
|
- Frontend: needs edit/delete affordance on `Categories.jsx`'s list rows.
|
|
|
|
|
|
|
|
|
|
5. **User profile** (email, password, display name) — nothing exists at
|
|
|
|
|
all: no backend endpoint, no frontend page/route/sidebar link.
|
|
|
|
|
- Backend: no `UserResource`/profile endpoint anywhere — only
|
|
|
|
|
`POST /auth/signup` and `POST /auth/login`. Changing a password
|
|
|
|
|
should go through `BcryptUtil` (same as signup) and probably require
|
|
|
|
|
the current password as confirmation. Changing email likely needs a
|
|
|
|
|
uniqueness check (same constraint signup already enforces).
|
|
|
|
|
- Frontend: needs a Settings/Profile page, route, and sidebar entry —
|
|
|
|
|
none exist today.
|
|
|
|
|
|
|
|
|
|
**Suggested build order:** Account edit/delete and Category edit/delete
|
|
|
|
|
first (simplest, most requested day-to-day), then Budget delete, then User
|
|
|
|
|
profile (self-contained, new page), then Transaction edit/delete last since
|
|
|
|
|
it's the trickiest (running-balance recomputation on delete/edit affects
|
|
|
|
|
every later transaction on that account).
|
2026-07-06 21:34:45 +02:00
|
|
|
</content>
|