Redesign v2#4
Open
prybalko wants to merge 38 commits into
Open
Conversation
Pulls the canonical 11-category list and the pure stats math out of internal/handlers/ so the upcoming JSON API can reuse them without dragging HTML rendering along. - internal/categories: Label/Slug pairs, All() accessor returning a copy. - internal/insights: Month()/Year() compute totals, category rollups, daily/ monthly chart series, percent-change, MTD comparison, and average-per-day, taking a *storage.DB and a now clock; no HTML, no http.ResponseWriter.
Introduces internal/api/ — a JSON HTTP layer the React PWA will consume: - json.go: writeJSON / decodeJSON / error envelope - auth.go: POST /api/auth/login, /logout, GET /me (JSON over cookies) - categories.go: GET /api/categories - expenses.go: cursor-paginated list, create, patch, delete - insights.go: GET /api/insights?view=month|year - router.go + middleware.go: wires routes, applies session auth Adds storage.ListExpensesBefore (composite (date,id) cursor) and InsertExpense (returns the persisted row with its id). Adds internal/auth/sessions.go with the SessionCookieName, SessionDuration, context key, and cookie helpers. Each endpoint has table-driven tests covering happy paths and error cases. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Remove internal/handlers/, web/templates/, and the legacy vanilla-JS/CSS assets (datepicker.js, pull-to-refresh.js, style.css, sw.js, manifest.json) now that the JSON API + SPA fallback are wired up. cmd/server/main.go was already free of references to these. Dockerfile copies and the e2e Playwright DOM selectors are intentionally deferred to Tasks 11 and 13. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Adds web/app/ Vite project that builds into web/dist/ for the Go embed, with dev proxy to the Go API and vite-plugin-pwa configured for the expected Workbox runtime caching shape. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Task 6 of the React PWA redesign: scaffold the frontend foundation that
the upcoming components and screens will build on.
- theme.ts: ports the Linen & Ink palette from mockups/v2-clay.jsx as the
only theme.
- types.ts: Expense, Category, Insights, User, plus list/page wrappers.
- api/client.ts: fetch wrapper with cookie credentials, JSON envelopes,
and automatic 401 -> /login redirect.
- api/{auth,categories,expenses,insights}.ts: typed request functions.
- hooks/{useCategories,useExpenses,useInsights}.ts: TanStack Query
wrappers; useExpenses is useInfiniteQuery with cursor pagination.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add CategoryGlyph, Hero, DayGroup, ExpenseRow, CategoryPicker, Keypad, CalendarGrid, DatePickerPill, and TabBar under web/app/src/components/. Introduce a small fmtEUR/splitInt helper module. Components consume the existing theme + useCategories() hook and use category slugs to drive glyphs and tones while exposing label-based props to align with the API.
Wires up the React PWA with React Router and React Query: - Login posts to /api/auth/login and redirects to / - Feed renders the Hero card and day-grouped expenses with IntersectionObserver-driven infinite scroll - Insights renders the spent/per-day cards, the 31-day bar chart, and the by-category list, with month navigation via prev/next arrows - EntryForm handles both /add and /edit/:id, reusing CategoryPicker, Keypad, and DatePickerPill; create/update/delete mutations invalidate expenses + insights queries (offline queue arrives in Task 9) - App.tsx provides QueryClientProvider + BrowserRouter; index.css resets to the linen background and DM Sans
Introduces an offline-first mutation layer for expense writes. New `web/app/src/offline/` module wraps `idb` with two stores: `queued_writes` (operation log persisted across reloads) and `cached_expenses` (last-N mirror for offline reads). `useCreateExpense`, `useUpdateExpense`, and `useDeleteExpense` apply optimistic React Query updates, persist the intent to IndexedDB, then attempt the network call — network failures leave the queue entry for replay; API errors roll back the optimistic update and drop the entry. `setupOnlineSync` in `App.tsx` drains the queue on the `online` event and once on mount. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…binary Splits the image build into a node:20-alpine web-builder stage that runs `npm ci && npm run build`, a golang:1.25-alpine go-builder stage that copies the freshly built bundle into web/dist for `//go:embed all:dist`, and a slim alpine:latest runtime that only carries the static binary. Also adds web/app/node_modules and web/dist to .dockerignore so host artifacts don't override what each stage produces.
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add Set up Node + npm ci + tsc --noEmit + npm run build steps so go test ./... runs against a real web/dist/ bundle. - Trim the Go test step to ./cmd/... ./internal/... so we don't try to drive the Playwright e2e suite (which still targets the old HTMX DOM) and so go list doesn't pick up stray .go files inside node_modules. - Add a gated Run E2E Tests step alongside Install Playwright (both if: false) so the suite is easy to re-enable once selectors are updated for the React PWA. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Drop the HTMX badges/tagline and document the new architecture: React + Vite + TypeScript PWA frontend embedded in a slim Go JSON API. Adds Offline-first / Installable PWA / Linen & Ink design feature lines, a Local development two-terminal flow, a Production build subsection, and refreshes the project structure + tech stack to point at web/app/, web/dist/, internal/api/, internal/insights/, internal/categories/. Flags that the Playwright e2e suite needs selector updates for the new React DOM. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Run the full Task 15 validation matrix and adjust the golangci-lint config so it stays clean under the CI-pinned v2.7.2: - exclude web/app/node_modules from lint paths (an npm package ships its own Go file at flatted/golang/pkg/flatted/ that has nothing to do with this repo) - exclude revive's "var-naming: avoid meaningless package names" since internal/api is the conventional name for an API package Tests, typecheck, frontend build, and Go build all pass. The two remaining manual checkboxes (docker-compose data persistence and end-to-end smoke flows) are flagged as deferred to manual QA in the plan.
- Backend now accepts both RFC3339 and YYYY-MM-DD dates so the PWA's date-picker payload no longer 400s on every create/update. - Entertainment gets its own slug + glyph + tone so it no longer renders identically to Other. - SPA fallback returns 404 for missing static assets (e.g. stale hashed /assets/*.js after a deploy) instead of serving index.html as JS. - Offline drainQueue distinguishes permanent (4xx) vs transient errors so a single bad entry can no longer jam the queue forever. - Optimistic mutations now roll back the React Query cache when enqueueWrite throws (e.g. IndexedDB unavailable / quota / private mode). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add GET /api/expenses/{id} so EntryForm can resolve any expense by deep
link, not just rows in the first 50-item page (previously hung on
Loading... for older edits).
- Make IndexedDB optional: if enqueueWrite throws (private browsing,
storage quota), fall back to a network-only mutation instead of
blocking the write entirely.
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.