| src | ||
| .gitignore | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
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
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)
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
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