Personal Ledger System (Postgres-first architecture)
- Frontend: React (Vite, TypeScript, TailwindCSS v4, shadcn/ui)
- API: PostgREST
- Database: PostgreSQL
Everything is configured in compose.yaml with safe local defaults (no .env required). Optional overrides: copy compose.env.example to .env in the repo root.
docker compose up --build- UI:
http://localhost:8080(default login token:local-dev-login) - API:
http://localhost:3000
See the banner at the top of compose.yaml for the full variable list. The Docker UI build uses COMPOSE_VITE_APP_API_URL (default http://localhost:3000), not VITE_APP_API_URL from .env, so a dev API URL does not leak into the container image. If you change that URL or ports, rebuild the app (docker compose build --no-cache app).
Extra login tokens:
docker compose run --rm --entrypoint python3 app \
/opt/finances/scripts/generate_token.py "Description"- Clone the repository.
- Install frontend dependencies:
cd app && npm install. - Configure environment: Copy
.env.exampleto.envand fill inDATABASE_URL,JWT_SECRET, andVITE_APP_API_URL. - Run database migrations:
python scripts/migrate.py. - Set database JWT secret:
python scripts/set_jwt_secret.py. - Generate an initial access token:
python scripts/generate_token.py 'My Initial Token'. - Start frontend:
cd app && npm run dev.
The system is protected by token-based authentication.
Use the Python script to generate new access tokens:
python scripts/generate_token.py "Description of the token"The script will provide the token once. Save it safely.
- Tokens are hashed in the database using SHA-256.
- JWTs expire after 7 days.
- Login is handled via a secure Postgres RPC.
- Permissions are enforced using database roles (
anonandauthenticated).
Ensure your PostgREST server is configured with:
db-anon-role = "anon"
jwt-secret = "your-secret-from-env"scripts/migrate.py: Run database migrations.scripts/seed.py: Seed the database with sample data.scripts/import_excel.py: Import data from Excel.scripts/reset_db.py: Wipe all data and reset the database.