Finper is a self-hosted application designed for personal use. There is no admin panel or user directory UI — user accounts are managed via a CLI seed script or the REST API. By default, open registration is disabled; only the seed script can create users unless you explicitly enable the registration endpoint.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.
Creating the first user
- make command
- pnpm command
- REST API
The simplest way to bootstrap a user from the project root:The Makefile translates
USERNAME and PASSWORD into the INIT_USERNAME and INIT_PASSWORD environment variables expected by the seed script (packages/api/src/scripts/seed-user.ts). The script:- Validates the credentials against the length rules.
- Applies any pending Drizzle migrations to the SQLite database.
- Creates the user if the username does not already exist.
- Exits silently without error if the user already exists (idempotent).
Validation rules
Both the seed script and the registration endpoint enforce the same constraints:| Field | Rule |
|---|---|
username | 3–15 characters. Automatically lowercased and trimmed. |
password | Minimum 5 characters. |
1. The REST API returns a 422 Unprocessable Entity (Boom badData) with the Joi error message.
Registration control
TheALLOW_REGISTRATION environment variable controls whether POST /api/auth/register is reachable:
| Value | Behaviour |
|---|---|
false (default) | The endpoint returns 403 Forbidden. No new users can be created via the API. |
true | The endpoint is open. Any caller with network access can register a new account. |
.env:
Enable
ALLOW_REGISTRATION only temporarily when you need to add an account, then set it back to false. Leaving it enabled exposes the registration endpoint to anyone who can reach your API.Multi-tenancy
Every data record in Finper carries auser field containing the username string of its owner. All service-layer queries automatically filter by the authenticated user, so:
- A user can only read and modify their own accounts, transactions, debts, goals, and every other record.
- There is no cross-user data access and no admin role.
- There is no shared data between users.
user field in the database is the username (a plain string), not a foreign-key ID — this is the req.user value set by auth.middleware.ts after JWT verification.
Changing passwords
There is no dedicated password-change API endpoint. To update a user’s password, re-run the seed script with the same username and a new password:UNIQUE constraint on username, running it with an existing username does not create a duplicate — it will report that the user already exists. To actually change the password you need to use a direct database approach or implement a custom migration.
The seed script is idempotent for the creation path — it detects the
UNIQUE constraint failed SQLite error and exits cleanly with an info message rather than crashing or creating a duplicate record.Logging in
Once a user exists, obtain a JWT token by calling the login endpoint:token header for all subsequent authenticated requests: