Open Net Worth
Open Net Worth는 직접 운영하는 오픈소스 개인 AI 자산 비서로, 전체 재무를 하나의 원장에 기록하고 사용자가 제어하는 AI가 관리
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A complete, self-hosted personal expense tracker: Python/Flask API + Telegram bot webhook + responsive vanilla HTML/CSS/JavaScript. No frontend build step. Start with RENDER_SETUP_KH.md for the simplest Render + Neon deployment and owner bootstrap.
static/entryui.css + static/entryui.js): big amount with live ៛/$ conversion, Riel/Dollar toggle, quick-add amount chips, category chips, Needs/Wants and Cash/Bank toggles, Today/Yesterday/Pick-date shortcuts, recent-note chips, and a sticky save bar that shows the amount. It drives the same form and API as before, so validation, itemised expenses and favorites are unchanged.static/clean.css).REMINDER_SCHEDULER=1, or an external call to /ops/reminders/<secret> every minute or so)./api/notifications/feed). New Telegram reminders for bills and an optional Sunday weekly summary, both in Settings → Notifications.static/spacious.css): larger gutters, card padding, tap targets and a wider desktop layout./id works before approval; /request submits access; /requests recovers pending requests for the owner.ADMIN_USER_ID grants the owner access; nobody can claim admin through the UI.Scope: This version implements the core tracker. OCR, voice recognition, bank integration and account transfers are not included. The exchange rate is manually editable and used for display totals only; it is not a live market quote. The dashboard net figure is selected-month income minus expenses, not a verified bank balance. Cash/bank are labels only. CSV downloads may depend on Telegram client support; try Telegram Desktop if mobile download is blocked.
@BotFather in Telegram and send /newbot.mymoney-miniapp.py -3.12 -m venv .venv
.venv\Scripts\python -m pip install -r requirements.txt
Copy-Item .env.example .env
.venv\Scripts\python -c "import secrets; print(secrets.token_hex(32))"
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
cp .env.example .env
.venv/bin/python -c 'import secrets; print(secrets.token_hex(32))'
Put the generated random string in WEBHOOK_SECRET. Edit .env with your own values:
BOT_TOKEN=your_botfather_token
APP_URL=https://your-service.onrender.com
WEBHOOK_SECRET=your_generated_random_secret
ADMIN_USER_ID=your_numeric_personal_telegram_id
# Choose ONE: set a direct password, or use the optional hash below.
ADMIN_PASSWORD=choose_your_own_long_password
# ADMIN_PASSWORD_HASH=your_werkzeug_password_hash
FLASK_SECRET_KEY=your_random_64_character_secret
ALLOWED_USER_IDS=
DATABASE_URL=postgresql://user:password@host/database
Optional extra pre-approved IDs in ALLOWED_USER_IDS are comma-separated. If both ADMIN_USER_ID and ALLOWED_USER_IDS are empty, Mini App access is disabled until owner bootstrap. Approved users are stored in access_requests, not environment variables. Never commit .env or password hashes/secrets.
To choose a password directly, set ADMIN_PASSWORD in Render → Environment to the password you want, then save and redeploy. Keep the Render service private to your trusted users and use a long, unique password. The app compares direct passwords safely and never displays them. For stronger secret handling, you can instead leave ADMIN_PASSWORD empty and set ADMIN_PASSWORD_HASH to a Werkzeug password hash:
.venv\Scripts\python -c "from getpass import getpass; from werkzeug.security import generate_password_hash; print(generate_password_hash(getpass('New Admin password: ')))"
Set FLASK_SECRET_KEY to a separate random secret and keep it unchanged; it signs secure Admin sessions and keyed deletion markers. The password is required again after 15 minutes or when you press Lock. Five failed attempts lock Admin login for 15 minutes. Admin APIs require both valid Telegram Mini App authentication and the password unlock.
app.py should be the service root).?sslmode=require when required.pip install -r requirements.txtpython setup_bot.py && gunicorn wsgi:app --bind 0.0.0.0:$PORT --workers 1 --threads 4 --timeout 60APP_URL to the actual public HTTPS service URL, without a trailing slash. Set PYTHON_VERSION to 3.12.14 if using the included blueprint./health. Deploy. Tables are created automatically for a new database.render.yaml is also provided for Blueprint deployment; fill its prompted values. The blueprint does not provision a database or choose a service plan. Check the provider's current plan pricing, idle/sleep behavior, storage retention and backup policy before choosing it.
Do not use SQLite on an ephemeral host filesystem. Use external PostgreSQL for deployed data. SQLite is only the local default. CSV is an export, not a full database backup (budgets are excluded). Enable database backups and test restoration. The needs/wants feature adds its column to existing transaction tables automatically; other future schema changes may still need migrations because create_all does not migrate existing tables.
The updated Render Start Command runs setup_bot.py automatically. You can skip local setup below when using that command. For first setup, leave ADMIN_USER_ID and ALLOWED_USER_IDS empty, deploy, send /id to the bot, then place your own numeric ID in ADMIN_USER_ID and redeploy. Send /start once as admin so the bot can notify you.
On your computer, set .env to the same BOT_TOKEN, APP_URL and WEBHOOK_SECRET as the deployed service, then run:
.venv\Scripts\python setup_bot.py
Linux/macOS: .venv/bin/python setup_bot.py.
The script registers the webhook, chat menu button and bot commands including /start, /menu, /id, /summary and /allowance. It replaces any existing webhook for this bot; use a dedicated bot, and do not run a polling bot with the same token.
If you don't know your Telegram ID: deploy initially with an empty ALLOWED_USER_IDS, run setup_bot.py, then send /id in your bot's private chat. Copy that numeric ID into Render's ALLOWED_USER_IDS environment variable and redeploy. The /id command works before access is allowed. For approval management, put your personal ID in ADMIN_USER_ID, not only in ALLOWED_USER_IDS.
Now send /start and tap 💰 Open MyMoney or the chat menu button. Use a private bot chat. The app must be opened through Telegram for authenticated API access. Ordinary browser access shows the layout and an instruction to open Telegram; it does not bypass login.
The Mini App checks Render's Deploy API when an external uptime monitor calls /ops/render-deploy-watch/<RENDER_WATCH_SECRET>. It sends one Telegram notice after each deploy reaches a final status (live, failed, or canceled), and stores notice IDs in PostgreSQL to avoid repeats. This uses Render API credentials kept in Render Environment; no GitHub Actions workflow or GitHub Secrets are used.
Add RENDER_API_KEY and a long random RENDER_WATCH_SECRET in Render → Environment. Render automatically provides RENDER_SERVICE_ID. Keep BOT_TOKEN and numeric ADMIN_USER_ID set there, and send /start to the bot as Admin. Configure a separate HTTP monitor (for example, UptimeRobot) to request https://YOUR-APP.onrender.com/ops/render-deploy-watch/YOUR_SECRET every five minutes. Treat the monitor URL as a secret. The endpoint returns a pending status while a deploy is in progress and checks again at the next monitor request.
This is polling, so notices can be delayed up to the monitor interval. It requires the existing service to be reachable when the monitor calls it; if the service is fully unavailable, it cannot notify through itself. Render's direct workspace webhooks can deliver official deploy events, but require a Pro workspace.
Users choose their reminders in Settings → Notifications:
| Reminder | Default | What it does |
|---|---|---|
| Daily spending reminder | Off | At the chosen hour (Phnom Penh time, sent within a 3-hour window) tells the user they haven't logged anything today. Skipped if they already saved a transaction that day. |
| Debt due-date reminders | On | From 09:00, one grouped message listing debts that are due in N days (0–7, user's choice), due today, or overdue by up to 14 days. Each stage is announced once per debt; changing a due date re-arms it. Only open debts with a due date, and only the remaining (unpaid) balance. |
Reminders are sent by the bot, so each user must have started the bot (/start) once. The Send a test message button confirms delivery.
Something has to trigger the check, because the app only runs code when it is awake. Pick one or both (duplicate sends are impossible because every message is recorded in notification_log before it is sent):
REMINDER_SECRET to a long random value (if empty, RENDER_WATCH_SECRET is used) and make an uptime monitor request https://YOUR-APP.onrender.com/ops/reminders/YOUR_SECRET every 5–15 minutes. Treat the URL as a secret. The response is JSON such as {"ok":true,"daily":1,"debt":2,"skipped":0,"failed":0}.REMINDER_SCHEDULER=1; the web process checks every 5 minutes while it is running.If Telegram rejects a message (for example the user never started the bot), the reminder is released and retried on the next check. Reminder history is kept for 90 days.
Dates use Asia/Phnom_Penh. Future transaction dates are rejected. The API accepts month filters from 2000 through 2100. Transactions may have up to 300 note characters. An app session expires after one hour; close and reopen it to refresh Telegram authentication. Authentication data is never stored in localStorage; only the language preference is.
.venv\Scripts\python -m flask --app wsgi run --port 5000
Linux/macOS: .venv/bin/python -m flask --app wsgi run --port 5000.
Use DATABASE_URL=sqlite:///money.db locally. For a real Telegram test, expose the local server through an HTTPS development tunnel, update APP_URL, and run setup_bot.py again. The repository does not include an authentication bypass. No live Telegram token is needed for automated tests.
.venv\Scripts\python -m pip install -r requirements-dev.txt
.venv\Scripts\python -m pytest -q
Tests cover signed authentication, expired/forged sessions, user ownership, create retry deduplication, edit/delete, money precision, currency/month budget isolation, CSV escaping and webhook secret checks. PostgreSQL and live Telegram deployment require verification with your own service configuration.
/id, set the correct numeric allowlist and redeploy.setup_bot.py, reopen the private bot chat, send /start.app.py: API, database schema, Telegram authentication and webhook.wsgi.py: web service entry point.setup_bot.py: one-time Telegram registration.static/: Mini App HTML, CSS and JavaScript.tests/test_app.py: backend regression tests..env.example, render.yaml: configuration templates.@BotFather ហើយរក្សា Token ជាសម្ងាត់។DATABASE_URL។ កុំប្រើ SQLite លើ hosting ដែលលុបទិន្នន័យពេល redeploy។BOT_TOKEN, APP_URL, WEBHOOK_SECRET និង ALLOWED_USER_IDS។.env ហើយ run setup_bot.py។/id ទៅ Bot បន្ទាប់ពី setup រួច។ បន្ថែមលេខនោះក្នុង ALLOWED_USER_IDS ហើយ redeploy។/start ហើយចុចបើក MyMoney។ មិនចាំបាច់វាយ Command ដើម្បីកត់ចំណាយទេ។មិនទាន់ deploy ដោយស្វ័យប្រវត្តិទេ៖ អ្នកត្រូវបំពេញ Token, HTTPS URL និង Database របស់អ្នកជាមុន។
Render Deploy API watcher ផ្ញើស្ថានភាព deploy ផ្លូវការទៅ Telegram Admin ដោយប្រើ RENDER_API_KEY, RENDER_WATCH_SECRET, BOT_TOKEN និង ADMIN_USER_ID នៅក្នុង Render Environment។ បង្កើត HTTP monitor ឱ្យហៅ https://YOUR-APP.onrender.com/ops/render-deploy-watch/YOUR_SECRET រៀងរាល់ 5 នាទី។ កុំដាក់ secret ទាំងនេះក្នុង GitHub។
កំណត់ RENDER_API_KEY និង RENDER_WATCH_SECRET នៅ Render → Environment រួមជាមួយ BOT_TOKEN និង ADMIN_USER_ID ដែលអ្នកប្រើរួច។ Render ផ្ដល់ RENDER_SERVICE_ID ដោយស្វ័យប្រវត្តិ។ Admin ត្រូវផ្ញើ /start ទៅ Bot ម្ដង។ កុំបញ្ចូល secret ណាមួយក្នុង GitHub។
New users send /start and tap Request access, or send /request. The bot displays their own ID. An admin receives their name/ID and Approve/Reject buttons. Decisions are saved in the new access_requests table; existing transaction/budget tables are not altered. A deployment creates this new table automatically.
Only ADMIN_USER_ID may approve or reject. Callback decisions apply only to pending requests; repeated/stale clicks cannot reverse them. Notifications for the same pending user are throttled to one per minute. If Telegram delivery fails, requests remain saved and the admin can use /requests to retrieve batches of five. Decisions remain saved even if a user blocks the notification; the user can reopen the app to check.
Rejected users cannot automatically reapply. The owner can grant or revoke access through /admin with confirmation. Saved decisions override ALLOWED_USER_IDS. Revoking access preserves records. The owner can review users' transactions, budgets and savings goals through the Telegram admin panel and Mini App. Only the configured owner can edit or add a user's transactions or send direct messages; deleted transactions are archived in the user's Trash for restoration. Admin users cannot use these owner-only actions. Users are informed that the owner/admin can review their financial records.
When upgrading an existing deployment, re-register the webhook with allowed_updates including BOTH message and callback_query. The new setup script/Start Command handles this. A setWebhook success does not by itself prove delivery; inspect getWebhookInfo and service logs if /id does not respond.
Upload ALL project files, including admin_panel.py and static/index.html, style.css and app.js. Do not replace only app.js. Keep your existing Neon DATABASE_URL. New tables are created automatically; existing financial records are retained.
Telegram budget warnings run when saving an expense or monthly budget, for the current month in Asia/Phnom_Penh. One alert per threshold (80%, 100%), currency and month; changing the budget does not reset sent alerts. There is no background reminder scheduler. Failed notification delivery does not roll back the saved transaction.
Savings totals are manual records, not bank transfers and do not change income/expenses. The owner must set their own numeric ADMIN_USER_ID in Render; no admin identity is hardcoded.
/allowance shows the same calculation for each currency with a budget. Set a monthly budget first.Home now focuses on monthly totals, the current summary and recent activity. Insights contains the daily bar chart and category donut, including percentages, exact amounts, largest category and empty-state support. Donut values follow the selected month/currency and update after edits/deletions. Desktop uses two columns at 900px and above; mobile remains one column. Budget editing is available through the Home budget card’s Manage button.
History supports Add expense/income, tap-to-view, Edit and individual Delete. Select enables checkboxes; Select visible selects only currently rendered rows. Load more reveals additional rows. Filtering discards selections outside the current filter. Delete selected previews the count before confirmation.
Manage my data → Delete all my entries covers all of your transaction history, across months and both currencies. It preserves budgets, goals and access settings. The dialog requires typing DELETE. Deletion moves records to Trash. Restore from Settings → Trash; only Delete forever inside Trash is permanent. The server uses an owner-bound, five-minute, single-use snapshot, so later entries are not included. Creating a new preview invalidates the old one. No live user records are deleted during deployment.
Upload the full static folder, including design.js, design.css and history.js. The backend creates the delete_batches table automatically. Keep your existing Neon DATABASE_URL.
The eye button in the header hides monetary values in the current browser until toggled back on; the choice is stored locally in that browser. It is a quick privacy aid for shoulder viewing, not a password lock. Up to 12 personal favorites can be saved from an entry form and launched from Home. A favorite fills a draft; review it and press Save to make a transaction. Removing a favorite does not delete transactions.