d582f15681
- Implemented tests for import polling functionality, ensuring correct behavior for active and terminal import statuses. - Created tests for the login page, validating user interactions and error handling. - Added unit tests for money utility functions, covering parsing, formatting, and summation of monetary values. - Developed tests for query keys, ensuring proper scoping and invalidation roots. chore: setup testing environment and configuration - Added setup file for testing with Vitest and Testing Library. - Configured TypeScript and Vite for the frontend project. - Created Docker and Nginx configurations for local development and production environments. - Established a PostgreSQL initialization script for setting up application roles. docs: add README and environment configuration for infra - Included README for the infra directory, detailing local development setup and service descriptions. - Created an example environment configuration file for local development with placeholders for sensitive information.
71 lines
2.9 KiB
Markdown
71 lines
2.9 KiB
Markdown
# Finance frontend
|
|
|
|
React + TypeScript SPA for the finance tracker: RU/EN, WCAG-aware, data-dense
|
|
desktop tables that reflow into cards on mobile.
|
|
|
|
## Stack
|
|
|
|
- Vite + React 19 + TypeScript (strict)
|
|
- React Router (library mode)
|
|
- TanStack Query v5 (space-scoped query keys, v5 `refetchInterval` callback polling)
|
|
- React Hook Form + Zod
|
|
- i18next (RU default, EN fallback)
|
|
- Vitest + Testing Library (jsdom)
|
|
- ESLint 9 (typescript-eslint, react-hooks, jsx-a11y)
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
npm install # install
|
|
npm run dev # dev server on :5173, proxies /api -> http://localhost:8000
|
|
npm run build # tsc --noEmit && vite build
|
|
npm run typecheck # tsc --noEmit
|
|
npm run lint # eslint .
|
|
npm test # vitest run
|
|
npm test:watch # vitest
|
|
npm run api:generate
|
|
```
|
|
|
|
`npm run api:generate` looks for an OpenAPI schema at `../backend/openapi.json`
|
|
(or fetches `/api/v1/openapi.json` from a running backend) and emits
|
|
`src/api/generated/schema.d.ts` via `openapi-typescript`. Until the backend
|
|
schema exists the script exits with an explanation and the hand-written client
|
|
remains the source of truth.
|
|
|
|
## API client
|
|
|
|
`src/api/client.ts` is a small typed wrapper over `fetch` bound to same-origin
|
|
`/api/v1` with `credentials: 'same-origin'`, a CSRF header read from the
|
|
`csrf_token` cookie on mutating requests, and a single `ApiError` type carrying
|
|
`status` + machine-readable `code` (translated via the `errors.*` i18n keys).
|
|
`src/api/endpoints.ts` declares one function per endpoint with payload/return
|
|
types from `src/api/types.ts`, so each group can be swapped one-for-one by
|
|
OpenAPI-generated functions without touching UI code.
|
|
|
|
Assumed endpoints (matching the approved plan): `/auth/login`, `/auth/logout`,
|
|
`/auth/me`, `/auth/invitations/accept`, `/accounts`, `/operations`,
|
|
`/budget/summary`, `/budget/categories` (+ close/reopen/copy-previous and
|
|
per-category plan/fund actions), `/imports`, `/imports/{id}` (+ confirm /
|
|
reparse / revert / row decisions), `/analytics/{category-spend|plan-fact|cash-flow|balances}`,
|
|
`/exports`, `/spaces/current/deletion`. Amounts are integer kopecks everywhere.
|
|
|
|
## Query keys
|
|
|
|
All space-data keys are rooted at `['space', ...]` (`src/api/queryKeys.ts`);
|
|
mutations invalidate by prefix (e.g. an applied import invalidates the whole
|
|
space root). Import list/detail queries poll with the v5 `refetchInterval`
|
|
callback and stop automatically in terminal states (`ready`,
|
|
`review_required`, `confirmed`, `failed`).
|
|
|
|
## Accessibility & responsiveness
|
|
|
|
- Every chart figure ships a real data table (`<details>` toggle) with
|
|
captions and scoped headers; decorative graphics are `aria-hidden`.
|
|
- Dense `<table>` markup reflows into cards under 880px via the
|
|
`data-label` pattern — no horizontal scrolling for data.
|
|
- Skip link, focus-visible rings, `aria-live` toasts, `role="alert"` errors,
|
|
`prefers-reduced-motion` support, AA-contrast palette.
|
|
|
|
No secrets are read from `VITE_*` — the app only ever talks to same-origin
|
|
`/api/v1`.
|