refined financial system for a hackerspace. simple by design.
anything that can send or receive money: human, donate-box, rent, utility.
move X from A to B. supports all currencies.
- non-confirmed
- confirmed
sum of all transactions. both confirmed and not. separated.
mark entities and transactions for quick search.
- you can request a login link with your entity name, telegram id, signal id or whatever.
- login link will be sent to all available destinations (telegram, signal, email, etc)
- new login link does not revoke old ones, so no one can deauthenticate you.
Flow overview:
- UI calls
POST /tokens/request
with one of:entity_id
,entity_name
,entity_telegram_id
. - API finds the
Entity
by the first matching criterion and generates a signed token. - API builds a link
${REFINANCE_UI_URL}/auth/token/<token>
and tries to send it through providers inEntity.auth
. - If
auth.telegram_id
is present, API uses the Telegram bot to send a button with the login link. - When you click the link, UI saves the token in session and you are logged in.
Environment variables used:
REFINANCE_SECRET_KEY
: JWT signing key for tokens.REFINANCE_UI_URL
: Used to construct login links.REFINANCE_API_URL
: Used by deposit callbacks.REFINANCE_TELEGRAM_BOT_API_TOKEN
: Telegram bot token to deliver login links.REFINANCE_DATABASE_URL
: PostgreSQL connection string (defaults topostgresql://postgres:postgres@db:5432/refinance
when running via docker compose).
Testing locally:
- Create
secrets.dev.env
:
cp secrets.env.example secrets.dev.env
# set:
REFINANCE_SECRET_KEY=dev-secret-xxxx
REFINANCE_UI_URL=http://localhost:9000
REFINANCE_API_URL=http://localhost:8000
# Optional: set a real Telegram bot token if you want to receive login links in Telegram
REFINANCE_TELEGRAM_BOT_API_TOKEN=123456:ABC...
# Optional: override REFINANCE_DATABASE_URL if Postgres is running elsewhere
REFINANCE_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/refinance
- Start stack:
make dev
- Open UI
http://localhost:9000/auth/login
, enter an entity name that exists.- The seed includes
F0
and several system entities. To test personal login via Telegram, create your own entity and setauth.telegram_id
to your Telegram numeric ID.
- The seed includes
- Check API logs for debug info:
docker compose -f docker-compose.yml -f docker-compose.dev.yml logs -f api
- You will see whether
entity_found
,token_generated
, and whether a Telegram message was sent.
- If Telegram is configured, the bot will DM you a login button. If Telegram blocks button URLs, a fallback message with a bare link is sent.
Add user (entity) quickly:
- Start dev stack:
make dev
- Add a new user using the Makefile helper (runs inside the API container):
make add-entity NAME=<name> [TELEGRAM_ID=<numeric_id>] [ID=<explicit_id>]
# examples:
make add-entity NAME=alice
make add-entity NAME=alice TELEGRAM_ID=123456789
- On the login page, enter
<name>
. IfTELEGRAM_ID
was set and the bot token is valid, you will receive a Telegram login link.
Entity & user management:
- UI: after login, go to
Entities
to add or edit entities. You can setAuth → Telegram ID
(from@myidbot
) and tags. - CLI: use
make add-entity
to upsert by name or id. Under the hood it callspython -m app.scripts.add_entity
inside the API container. - Deleting entities: not supported yet in the API/UI.
Troubleshooting:
- If the login page shows failure, call the API directly to see details:
curl -s -X POST -H 'Content-Type: application/json' -d '{"entity_name":"skywinder"}' http://localhost:8000/tokens/request
message_sent=false
usually means either:auth
is empty or has notelegram_id
for the entity, orREFINANCE_TELEGRAM_BOT_API_TOKEN
is invalid, or- the bot cannot message your account (you have not started the bot in Telegram, or privacy settings block it).
- Check UI -> API call logs:
docker compose -f docker-compose.yml -f docker-compose.dev.yml logs -f ui
- Verify the bot token:
TOKEN=<paste bot token>
curl -s https://api.telegram.org/bot${TOKEN}/getMe
should return ok=true for a valid token.
use secrets.prod.env
for production secrets. start from the example file:
cp secrets.env.example secrets.prod.env
# then edit secrets.prod.env (set real domain URLs and database URL)
make prod
API: http://0.0.0.0:8000/docs UI: http://0.0.0.0:9000
create secrets.dev.env
for development variables. see secrets.env.example
as a reference. docker compose loads this file automatically in dev.
cp secrets.env.example secrets.dev.env
uv python install 3.12
uv sync --dev
open project in vscode, F1 python.setInterpreter
, select .venv
(workspace)
if you need to change project deps:
uv add packagename
uv remove packagename
uv sync
install pre-commit hook
source ./.venv/bin/activate
pre-commit install
make test
make dev
open http://localhost:8000/docs and http://localhost:9000
- Postgres is available at
localhost:5432
(userpostgres
, passwordpostgres
, databaserefinance
).
secrets.dev.env
: used bymake dev
(docker-compose.dev.yml)secrets.prod.env
: used bymake prod
/make prod-daemon
(docker-compose.prod.yml)secrets.env.example
: used by CI and as a template; do not put secrets here
- base classes
- errors
- unit tests
- complex search
- pagination
- tags
- transactions
- balances
- balance cache
- date range search
- payment splits
- multiple auth providers
- docker
- authentication?
- pytest ci
- generic deposit service
- usdt top-up
- currency exchange
- unit of work?
- fixed amount participation in split
- add split participants by a tag
-
grafana, statistics - treasuries
- logging
- postgres
- card processing
- migrations
- pass tags as a list, not as add/delete operations
- fix ui tag management
- misc validation of amounts (>0.00)
- improve split ux
- make a uniform deposit api CRUD, provider should be enum
- update all boolean attrs to status enums
- mobile ui
- rename base to common where applicable
-
remove _in and _out postfixes for entitiesnot needed - remove base service class
- permissions?
- deposit ui
- donation categories (entities?)
- easy payment urls
tests are mostly autogenerated by llm, given the route and schema. human review would be beneficial.
MIT