Set up Vitest for both server (Node + Supertest) and client (jsdom + React Testing Library). Extract Express app into app.js for testability. Add example tests covering bills validation, bills route CRUD, ThemeContext, and App nav rendering. Update CLAUDE.md with testing docs and requirement to write tests with features. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97 lines
6.4 KiB
Markdown
97 lines
6.4 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Agent Workflow Rules
|
|
|
|
- **Commit after every task**: When a task is complete, stage all changed files and create a git commit before marking the task done.
|
|
- **Write tests with features**: New features and bug fixes must include unit tests. Run `npm test` in both `server/` and `client/` before committing.
|
|
- **Keep documentation current**: Update `CLAUDE.md` after every task that adds, changes, or removes a feature, API endpoint, or architectural pattern. This is mandatory, not optional. Update `PRD.md` only if scope/design decisions changed.
|
|
- **Mark tasks in td**: `td start <id>` when beginning, `td close <id>` when done.
|
|
- **Run td commands one at a time**: Never chain `td` commands with `&&` or `;`. Each `td` call must be its own separate shell invocation.
|
|
- **Only the orchestrator touches td**: Sub-agents must never call `td` commands directly. Concurrent `td` writes from parallel agents corrupt the SQLite database. The orchestrator handles all `td start`/`td close` calls before and after delegating to sub-agents.
|
|
- **td approve requires a separate session**: `td approve` cannot be run by the implementing agent or any sub-agent spawned from the same session — `td` tracks session involvement. Approval must come from a new conversation/session. Leave implemented tasks in review state (`td review <id>`) at the end of the session; they can be approved at the start of a fresh session.
|
|
|
|
## Task Management
|
|
|
|
This project uses `td` (a local CLI) for task tracking. At the start of each session:
|
|
|
|
```bash
|
|
td usage --new-session # required at conversation start or after /clear
|
|
td usage -q # quick check for subsequent reads
|
|
```
|
|
|
|
Optional session labeling:
|
|
```bash
|
|
td session "name" # label the current session
|
|
td session --new # force a new session in the same terminal context
|
|
```
|
|
|
|
Task state is stored in `.todos/issues.db` (SQLite).
|
|
|
|
## Development
|
|
|
|
**Run production stack (Docker):**
|
|
```bash
|
|
docker compose up
|
|
```
|
|
|
|
**Run development stack with live reload (Docker):**
|
|
```bash
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
|
|
```
|
|
|
|
**Frontend only (Vite dev server):**
|
|
```bash
|
|
cd client && npm install && npm run dev
|
|
```
|
|
|
|
**Backend only (nodemon):**
|
|
```bash
|
|
cd server && npm install && npm run dev
|
|
```
|
|
|
|
## Testing
|
|
|
|
Unit tests are required when adding or modifying features. Both server and client use [Vitest](https://vitest.dev/).
|
|
|
|
**Run all tests:**
|
|
```bash
|
|
cd server && npm test # server unit tests
|
|
cd client && npm test # client unit tests
|
|
```
|
|
|
|
**Watch mode (re-runs on file change):**
|
|
```bash
|
|
cd server && npm run test:watch
|
|
cd client && npm run test:watch
|
|
```
|
|
|
|
**Server tests** (`server/src/__tests__/`): Use Vitest + [Supertest](https://github.com/ladakh/supertest) for route testing. The CJS server code requires mocking `db.pool.query` directly (replace the method on the shared pool object) rather than using `vi.mock` for CJS modules. Validation and pure logic functions are exported and tested directly. See `bills.validation.test.js` and `bills.routes.test.js` for patterns.
|
|
|
|
**Client tests** (`client/src/__tests__/`): Use Vitest + [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/). jsdom environment is configured via `client/vitest.config.js`. The test setup file (`client/src/test/setup.js`) provides `@testing-library/jest-dom` matchers and polyfills like `window.matchMedia`. See `ThemeContext.test.jsx` and `App.test.jsx` for patterns.
|
|
|
|
**When adding features:**
|
|
- Add unit tests for new validation logic, utility functions, and API routes
|
|
- Add component tests for new React components or significant UI changes
|
|
- Export pure functions (validators, formatters, etc.) for direct testing
|
|
- Run `npm test` in both `server/` and `client/` before committing
|
|
|
|
## Application Structure
|
|
|
|
The default route `/` renders the paycheck-centric main view (`client/src/pages/PaycheckView.jsx`). It shows the current month's two paychecks side-by-side with bills, paid status, one-time expenses, and remaining balance. Month navigation (prev/next) fetches data via `GET /api/paychecks?year=&month=`.
|
|
|
|
**Theming:** `client/src/ThemeContext.jsx` provides light/dark mode via CSS custom properties on `[data-theme]`. Preference persists in `localStorage` and defaults to `prefers-color-scheme`. All design tokens live in `client/src/index.css`.
|
|
|
|
**Charts:** Monthly Summary and Annual Overview use [Recharts](https://recharts.org) (SVG-based). Monthly Summary shows a spending breakdown donut and variable-by-category bar. Annual Overview shows income vs. spending, surplus/deficit trend, and stacked variable spending by category — all driven by the single `GET /api/summary/annual?year=` endpoint.
|
|
|
|
**Bill amount locking:** When a `paycheck_bill` is marked paid, `amount_override` is set to the bill's current amount, locking in the historical value. Unmarking clears the override.
|
|
|
|
**Variable amount bills:** Bills with `variable_amount = true` require the amount to be entered each month in the paycheck view (stored as `amount_override` on `paycheck_bills`). The bill's `amount` field serves as an optional typical/estimated value.
|
|
|
|
**Lazy paycheck generation:** `GET /api/paychecks` returns virtual (unsaved) data with `id: null` when no DB record exists for the month. Paychecks are only persisted when the first interaction occurs (bill toggle, expense add, etc.). The "↺ Refresh amounts" button on the paycheck view re-runs `POST /api/paychecks/generate` to sync gross/net from current Settings. Individual paycheck gross/net can also be edited inline via the pencil icon.
|
|
|
|
**Financing:** `GET/POST /api/financing`, `PUT/DELETE /api/financing/:id`, `PATCH /api/financing-payments/:id/paid`. Plans track a total amount, payoff due date, and `start_date`. Payment per period is auto-calculated as `(remaining balance) / (remaining periods)`. Split plans (`assigned_paycheck = null`) divide each period's payment across both paychecks. Plans auto-close when fully paid. Financing payments are included in the paycheck remaining balance. `start_date` prevents a plan from appearing on paycheck months before it was created — both virtual previews and `generate` respect this guard.
|
|
|
|
**Migrations:** SQL files in `db/migrations/` are applied in filename order on server startup. Add new migrations as `00N_description.sql` — they run once and are tracked in the `migrations` table.
|