Skip to main content

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
Port3008
RuntimeNode 24 with ts-node (no pre-build needed for the API itself)
Test stackJest + 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
Port5173 (Vite dev server)
UI libraryMUI v6 with a custom light theme, esES locale, dayjs es adapter
RoutingReact Router v7 ('react-router', not '-dom') using useRoutes + lazy loading
Test stackVitest + happy-dom + MSW + @testing-library/react
Key patterns:
  • axios interceptorauthService.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 guardsAuthGuard 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
ORMDrizzle ORM + better-sqlite3 (synchronous driver)
Test stackVitest
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:
FileRole
*.routes.tsMounts HTTP verbs and paths, applies authMiddleware, and chains validators before handing off to the controller.
*.controller.tsRuns the Bluebird Promise chain: extracts request data, calls validators, delegates to the service, and sends the HTTP response.
*.service.tsOwns business logic. Calls the repository for data access and throws Boom.<x>(...).output for domain errors.
*.repository.tsExecutes Drizzle ORM queries against SQLite. Returns plain objects; has no knowledge of HTTP.
*.serializer.tsMaps raw database rows to the API response shape (e.g. converts numeric IDs to strings, formats dates).
*.validators.tsJoi 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: typesdbapi. 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.

Build docs developers (and LLMs) love