Stack
| Layer | Technology |
| Frontend | React 18 + TypeScript (Vite 5) — Cloudflare Pages |
| Backend API | Cloudflare Worker (TypeScript) — env: bernies |
| Database | Cloudflare D1 — lawncare_db (ID: f029e545-6c71-4762-8776-fd4f930264df) |
| Auth | PBKDF2-SHA256 password hash in D1, HMAC-signed JWT (24hr expiry) |
| Mobile | Position:fixed sidebar drawer + hamburger button (mobile-first) |
Database Tables
| Table | Key Columns |
| admin_users | id (UUID), email, password_hash |
| clients | id, name, email, phone, service_address, city, zip, status, notes |
| jobs | id, client_id, service_type, scheduled_date, scheduled_time, duration_minutes, address, price_cents, status, recurrence, notes |
| estimates | id, estimate_number, client_id, services, total_cents, status, valid_until, notes |
| invoices | id, invoice_number, client_id, job_id, amount_cents, description, status, issue_date, paid_date |
| invoice_items | id, invoice_id, description, quantity, unit_price_cents, total_cents |
| payments | id, invoice_id, amount_cents, method, paid_date, notes |
| notes | id, entity_type, entity_id, content, created_at |
| settings | key, value — business_name, service_types, invoice_footer, invoice/estimate counters |
File Structure
lawncare-portal/
src/
App.tsx ← Root — token check → PublicSite or AdminApp
api.ts ← All fetch() calls — VITE_API_URL base
index.css ← Mobile-first CSS (sidebar drawer, hamburger, stat grid)
main.tsx ← Vite entry
context/AppContext.tsx ← Global state — auth, all data, config; sets document.title
components/
PublicSite.tsx ← Config-driven public landing page + estimate form
AdminApp.tsx ← Sidebar drawer + hamburger shell
admin/
Dashboard.tsx ← Stats + recent jobs panel
JobsView.tsx ← Job CRUD + modal form
ClientsView.tsx ← Client CRUD + job history
EstimatesView.tsx ← Estimate CRUD + convert to invoice
InvoicesView.tsx ← Invoice CRUD + print view
CalendarView.tsx ← Month/week calendar
ReportsView.tsx ← Revenue charts + KPIs
SettingsView.tsx ← Business settings + password change
worker/index.ts ← Worker API (all routes)
migrations/
0001_init.sql ← Full schema
0002_settings_seed.sql ← Bernie's Backyard defaults + admin hash
wrangler.toml ← bernies env + D1 binding + custom domain
Key API Routes
| Method | Route | Auth |
| GET | /api/config | None — public settings for public site |
| POST | /api/requests | None — estimate request from public form |
| POST | /api/auth/login | None — returns JWT |
| GET/POST/PUT/DELETE | /api/jobs/* | JWT — job CRUD |
| GET/POST/PUT/DELETE | /api/clients/* | JWT — client CRUD |
| GET/POST/PUT/DELETE | /api/estimates/* | JWT — estimate CRUD |
| GET/POST/PUT/DELETE | /api/invoices/* | JWT — invoice CRUD + line items |
| GET/PUT | /api/settings | JWT — business settings |