Documentation Index
Fetch the complete documentation index at: https://mintlify.com/soker90/finper/llms.txt
Use this file to discover all available pages before exploring further.
The Finper monorepo is managed with pnpm workspaces and contains four application packages under packages/. Each package has a single well-defined responsibility. api and client are runtime applications; db and types are library packages that must be compiled to dist/ before the API can import them.
packages/api — @soker90/finper-api
An Express 5 REST API that listens on port 3008. It is the sole owner of all business logic and is the only process that reads and writes to SQLite.
| |
|---|
| npm name | @soker90/finper-api |
| Port | 3008 |
| Runtime | Node 24 with ts-node (no pre-build needed for the API itself) |
| Test stack | Jest + ts-jest + supertest + in-memory SQLite |
Key directories:
src/modules/ — one subfolder per domain resource (accounts, transactions, categories, budgets, loans, …). Each module follows the module pattern described below.
src/auth/ — Passport.js strategy registrations (local and jwt).
src/middlewares/ — auth.middleware.ts (JWT guard + token refresh), handle-error.ts, registration-enabled.middleware.ts.
src/config/ — runtime configuration loaded from environment variables.
Key files:
src/server.ts — constructs the Express app, registers middleware, mounts all routers, and runs Drizzle migrations on startup.
src/db.ts — creates and exports the Drizzle database connection using DATABASE_FILE from config.
packages/client — @soker90/finper-client
A React 19 single-page application built with Vite, served on port 5173 in development.
| |
|---|
| npm name | @soker90/finper-client |
| Port | 5173 (Vite dev server) |
| UI library | MUI v6 with a custom light theme, esES locale, dayjs es adapter |
| Routing | React Router v7 ('react-router', not '-dom') using useRoutes + lazy loading |
| Test stack | Vitest + happy-dom + MSW + @testing-library/react |
Key patterns:
- axios interceptor —
authService.setSession sets axios.defaults.headers.common.Authorization to Bearer <token>, so every outgoing call carries the standard Authorization: Bearer header. The response interceptor reads the refreshed Token response header and updates both localStorage[FINPER_TOKEN] and the axios default, implementing continuous silent token refresh.
- SWR for all data reads: a global axios-based fetcher, API path constants from
api-paths.ts as SWR cache keys.
- PWA — Vite PWA plugin configured with
autoUpdate strategy.
- Auth guards —
AuthGuard and GuestGuard redirect unauthenticated or already-authenticated users based on AuthContext.
packages/db — @soker90/finper-db
The Drizzle ORM schema and SQLite connection package. This package must be built before the API can start.
| |
|---|
| npm name | @soker90/finper-db |
| ORM | Drizzle ORM + better-sqlite3 (synchronous driver) |
| Test stack | Vitest |
Key contents:
src/schema/ — one file per entity (accounts.ts, transactions.ts, loans.ts, …). All schema files are re-exported from src/schema/index.ts.
src/client.ts — exports the createDb factory used by the API’s db.ts.
src/constants.ts — shared enum constants (TRANSACTION, LOAN_PAYMENT, SUPPLY_TYPE) used by both API modules and tests.
drizzle/ — auto-generated SQL migration files produced by drizzle-kit generate. The API applies these migrations on startup.
Build before starting the API. Run make build-db (and make build-types) before make start-api. The API imports @soker90/finper-db from dist/ — if the build is missing or stale, the API will throw a module-not-found error at startup.
packages/types — @soker90/finper-types
Shared TypeScript interfaces consumed by both the API and the React client. Keeping interfaces here means a single source of truth for request/response shapes without coupling the frontend to Drizzle or better-sqlite3.
| |
|---|
| npm name | @soker90/finper-types |
The package contains only TypeScript type declarations and no runtime code. It must be built first so both api and client can resolve the types during compilation.
Module pattern
Every domain resource in packages/api/src/modules/ follows a consistent six-file structure:
| File | Role |
|---|
*.routes.ts | Mounts HTTP verbs and paths, applies authMiddleware, and chains validators before handing off to the controller. |
*.controller.ts | Runs the Bluebird Promise chain: extracts request data, calls validators, delegates to the service, and sends the HTTP response. |
*.service.ts | Owns business logic. Calls the repository for data access and throws Boom.<x>(...).output for domain errors. |
*.repository.ts | Executes Drizzle ORM queries against SQLite. Returns plain objects; has no knowledge of HTTP. |
*.serializer.ts | Maps raw database rows to the API response shape (e.g. converts numeric IDs to strings, formats dates). |
*.validators.ts | Joi schemas that validate and transform incoming request payloads; existence validators that query the DB and throw if a referenced resource is missing. |
Frontend data pattern
The client makes a clear distinction between reads and writes:
- Reads → SWR hooks — Each resource has one or more
use<Resource> hooks that call useSWR(API_PATH_CONSTANT, fetcher). SWR handles caching, background revalidation on focus, and deduplication of in-flight requests.
- Writes → plain axios calls — Mutations call
axios.post/put/delete directly and then call mutate(API_PATH_CONSTANT) to invalidate the relevant SWR cache entries, triggering a fresh fetch.
Required build order: types → db → api. The client build is independent at the JavaScript level but relies on types at compile time. The API will not start without the compiled artifacts from both @soker90/finper-db and @soker90/finper-types.