51ee4ecb5a
Finished the planner end to end. Corrected rollover and yearly accounting, recurring targets, savings rules, and targeted dormant restorations. Added editing/deletion for income, expenses, targets, and categories. Rebuilt dashboard, analytics, calendar, settings, exports, authentication, and responsive mobile UI. Added original artwork at [financial-flow.png](/Users/tyemeclifford/Documents/GH/budget/public/assets/images/financial-flow.png), generated with built-in Imagegen using an abstract financial-momentum landscape prompt. Added [self-test.php](/Users/tyemeclifford/Documents/GH/budget/scripts/self-test.php). Verification passed: automated accounting/export tests, full browser workflow, responsive 390px layout, light/dark themes, and no console errors. Tested with FrankenPHP v1.12.4. Live Mailgun delivery was not attempted without credentials.
67 lines
2.9 KiB
Markdown
67 lines
2.9 KiB
Markdown
# Neon Ledger
|
|
|
|
A self-contained monthly financial planner built with PHP, SQLite, JavaScript, and HTML5. It tracks rolling budget remainders, income withholding, bill progress, categorized expenses, dormant savings, calendar due dates, comparisons, and Mailgun reminders from an administrator dashboard.
|
|
|
|
## Requirements
|
|
|
|
- PHP 8.1 or newer
|
|
- PDO SQLite extension
|
|
- Optional: PDO MySQL for MySQL/MariaDB migration
|
|
- HTTPS is recommended outside local development
|
|
|
|
No Composer or Node dependencies are required.
|
|
|
|
## Start locally
|
|
|
|
```bash
|
|
php -S 127.0.0.1:8080 router.php
|
|
```
|
|
|
|
Open `http://127.0.0.1:8080` and create the first administrator account. The SQLite database is created automatically at `storage/database/budget.sqlite`.
|
|
|
|
Run the accounting and export smoke test with:
|
|
|
|
```bash
|
|
php scripts/self-test.php
|
|
```
|
|
|
|
For Apache, use `public/` as the document root and enable `mod_rewrite`.
|
|
|
|
## Core behavior
|
|
|
|
- Each month has a manual starting income and an explicit previous-month remainder.
|
|
- Positive remaining funds can roll into the next month. Use **Recalculate** to refresh an existing month's rollover after changing the prior month.
|
|
- Income and expense rules can move a percentage or fixed amount into the dormant account automatically.
|
|
- Dormant deposits reduce usable funds; restorations can return to monthly income or be tagged to a specific budget target.
|
|
- Payments linked to a budget item progress its paid and owing totals.
|
|
- Monthly and yearly recurring items materialize from the latest matching series, even when a month was skipped.
|
|
- Annual fresh-income totals exclude rollover so carried money is not counted twice.
|
|
- JSON exports use the `neon-ledger/budget-planner` version 1 format and exclude credentials, 2FA secrets, and the Mailgun API key.
|
|
|
|
## Bill reminders
|
|
|
|
Configure Mailgun, recipient, alert windows, and reminder times in **Settings**. Run the reminder worker every minute:
|
|
|
|
```cron
|
|
* * * * * cd /path/to/neon-ledger && php scripts/send-reminders.php
|
|
```
|
|
|
|
Use `php scripts/send-reminders.php --force` to scan immediately. Duplicate reminders for the same bill, recipient, window, and day are suppressed.
|
|
|
|
## Optional MySQL/MariaDB mode
|
|
|
|
SQLite is the default and is always sufficient. The **Import & export** screen can create the MySQL schema, copy all SQLite records, and update `config/database.json` in one step. The original SQLite file remains untouched as a fallback snapshot.
|
|
|
|
Create the target database and user before running the transfer. The PHP runtime must include `pdo_mysql`.
|
|
|
|
## Backup
|
|
|
|
Use **Export JSON** for a portable planner package. For a direct SQLite backup, copy `storage/database/budget.sqlite` while the app is stopped.
|
|
|
|
## Security
|
|
|
|
- Passwords use PHP's current `PASSWORD_DEFAULT` algorithm.
|
|
- All state-changing forms use CSRF tokens.
|
|
- Optional TOTP two-factor authentication works with standard authenticator apps.
|
|
- The application should be served with `public/` as its web root.
|