initial code commit
This commit is contained in:
commit
27bb45f7df
56 changed files with 15106 additions and 0 deletions
107
README.md
Normal file
107
README.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# ten99timecard
|
||||
|
||||
Income logging, projections, and quarterly estimated tax calculations for US
|
||||
1099 contractors. Entirely client-side by default — your data is encrypted with
|
||||
your password and stored in a browser cookie. Optionally sync to a self-hosted
|
||||
MongoDB backend (still encrypted end-to-end; the server never sees plaintext).
|
||||
|
||||
**Not tax advice.** Calculations are federal-only approximations. Talk to a CPA.
|
||||
|
||||
---
|
||||
|
||||
## What's inside
|
||||
|
||||
| Page | What it does |
|
||||
| --- | --- |
|
||||
| **Dashboard** | Configurable stat widgets + charts. YTD income, projected annual tax, next quarterly due date. |
|
||||
| **Ledger** | Three tabs: **Work Log** (non-taxable billable record — flat amount *or* hours×rate), **Payments** (taxable 1099 income), **Expenses** (with deductible flag). Each is a year→month→day→item collapsible spreadsheet with global expand-to-level controls. Period summaries show totals, per-child averages, and linear projections. |
|
||||
| **Tax** | Full estimated-tax breakdown: SE tax (with SS wage-base cap + additional Medicare), QBI deduction, progressive federal brackets, safe harbor (100%/110% rule), quarterly schedule with past-due flags. Fields you haven't filled in (prior-year AGI, W-2 withholding, etc.) appear as **highlighted prompts** explaining why they'd sharpen the estimate. |
|
||||
| **Timer** | Billable-work stopwatch. Start / Pause / Split / Reset. Each split captures the rate *at split time* (changing the rate never rewrites history). Editable split table with two-step confirm. One-click push to Work Log. Logged rows get a badge. **Crash-proof:** state is heartbeated to a cookie every second; if the page reloads while running, a red banner shows exactly when you crashed, when you came back, and the gap — with a button to subtract the gap or keep it (because you were working during the outage). |
|
||||
| **Settings** | Theme picker (10 themes × dark/light), default hourly rate, storage mode (cookie / file / cloud), encrypted file import/export. |
|
||||
|
||||
### Themes
|
||||
Standard · Sakura · Pumpkin · Fall · Aqua · Lavender · Comic · Manga · High Contrast · Cyberpunk — each in dark & light.
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # client on http://localhost:5173
|
||||
```
|
||||
|
||||
The app works out of the box with **cookie storage**. No server, no database,
|
||||
no account. Open the page, create a local vault (username + password), start
|
||||
logging. Your password derives an AES-256-GCM key via PBKDF2 (100k rounds);
|
||||
the cookie holds only ciphertext.
|
||||
|
||||
### Run the cloud sync server (optional)
|
||||
|
||||
```bash
|
||||
cp server/.env.example server/.env # edit MONGO_URI + JWT_SECRET
|
||||
npm run dev:server # Express on http://localhost:4000
|
||||
```
|
||||
|
||||
Then switch storage mode to **Cloud** in Settings. The server stores one opaque
|
||||
blob per user. Plaintext never leaves the browser.
|
||||
|
||||
### Google OAuth (optional)
|
||||
|
||||
Fill `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` in `server/.env`. Without these
|
||||
the server still serves email+password auth.
|
||||
|
||||
---
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
npm test # 155 tests: 135 client (Vitest+RTL) + 20 server (supertest+mongodb-memory-server)
|
||||
npm run build # tsc --noEmit && vite build, both workspaces
|
||||
```
|
||||
|
||||
Coverage spans the tax engine, crypto round-trip, cookie chunking, statistics
|
||||
rollup/projection, timer crash recovery, store CRUD, and component interaction.
|
||||
|
||||
---
|
||||
|
||||
## Stack
|
||||
|
||||
**Client:** Vite · React 18 · TypeScript 5 · Zustand · React Router · Recharts · date-fns · Web Crypto API
|
||||
**Server:** Express · MongoDB · bcrypt · jsonwebtoken · Passport (Google OAuth) · zod
|
||||
**Testing:** Vitest · React Testing Library · jsdom · supertest · mongodb-memory-server
|
||||
|
||||
Everything is MIT/Apache/BSD licensed.
|
||||
|
||||
---
|
||||
|
||||
## Tax math (summary)
|
||||
|
||||
- **SE tax** = 15.3% of `netProfit × 0.9235`
|
||||
(12.4% Social Security up to wage base, 2.9% Medicare uncapped, +0.9% additional Medicare above threshold)
|
||||
- **Half of SE tax** is an above-the-line deduction
|
||||
- **QBI §199A** = 20% of qualified business income, limited to 20% of taxable income, phased out above threshold
|
||||
- **Taxable income** = gross − deductible expenses − ½SE − QBI − standard deduction − other adjustments
|
||||
- **Safe harbor** = pay the lesser of 90% of current-year tax or 100% (110% if prior AGI > $150k) of prior-year tax, split across four quarters
|
||||
- Tax year data shipped for **2024** and **2025**; unknown years fall back to closest
|
||||
|
||||
State tax is intentionally out of scope.
|
||||
|
||||
---
|
||||
|
||||
## Storage model
|
||||
|
||||
| Mode | Where | Encrypted? |
|
||||
| --- | --- | --- |
|
||||
| Cookie (default) | `document.cookie`, chunked at ~3.8KB, mirrored to localStorage | ✅ AES-256-GCM |
|
||||
| File | Download/upload `.t99` blob | ✅ Same key derivation |
|
||||
| Cloud | `PUT /api/data` on your server | ✅ Encrypted *before* upload |
|
||||
|
||||
Ciphertext format: `base64( salt[16] || iv[12] || aes-gcm-ciphertext )`.
|
||||
Lose your password → lose your data. That's the point.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Loading…
Add table
Add a link
Reference in a new issue