Customer Solution
Developer Reference
Stack
| Layer | Technology |
|---|---|
| Backend API | Cloudflare Workers (TypeScript) — single file worker/index.ts |
| Database | Cloudflare D1 (SQLite-compatible) |
| Frontend | React 18 + Vite + TypeScript |
| Hosting | Cloudflare Pages |
Authentication
Password hashing: PBKDF2-SHA256, 100,000 iterations, salt = SONAN_SP_2026
import hashlib, binascii
dk = hashlib.pbkdf2_hmac('sha256', password.encode(), b'SONAN_SP_2026', 100000)
hash_hex = binascii.hexlify(dk).decode()
Session tokens: HMAC-SHA256 JWT, 24-hour TTL, stored in localStorage key cc_admin_token.
Database Schema (Key Tables)
admins (id, email, password_hash, created_at)
clients (id, name, email, phone, address, notes, created_at, updated_at)
service_requests(id, client_id, full_name, phone, email, address,
preferred_contact, service_types JSON, travel_details JSON,
home_care_details JSON, notes, internal_notes JSON,
status, created_at, updated_at)
appointments (id, client_id, request_id, title, start_time, end_time,
notes, status, created_at)
invoices (id, client_id, request_id, line_items JSON,
subtotal_cents, tax_cents, total_cents, status,
due_date, created_at, updated_at)
settings (key, value, updated_at)
API Endpoints
All endpoints require Authorization: Bearer <jwt> except POST /api/auth/login.
| Method | Path | Description |
|---|---|---|
| POST | /api/auth/login | Login, returns JWT |
| GET | /api/requests | List all service requests |
| POST | /api/requests | Create request (public form) |
| GET | /api/requests/:id | Get single request |
| PATCH | /api/requests/:id | Update request fields |
| DELETE | /api/requests/:id | Delete request |
| GET/POST | /api/clients | List / create clients |
| GET/PATCH/DELETE | /api/clients/:id | Get / update / delete client |
| GET/POST | /api/appointments | List / create appointments |
| PATCH/DELETE | /api/appointments/:id | Update / delete appointment |
| GET/POST | /api/invoices | List / create invoices |
| PATCH | /api/invoices/:id | Update invoice |
| GET/PATCH | /api/settings | Get / update settings |
| PATCH | /api/settings/password | Change admin password |
CSS Variable System
Critical: --accent: #f0e8d8 is beige — decorative only. Never use for interactive elements (invisible on white background).
| Variable | Value | Use |
|---|---|---|
--primary | #2d6a4f | All interactive elements, buttons, links |
--primary-light | #52b788 | Hover states |
--accent | #f0e8d8 | Decorative backgrounds ONLY |
--white | #ffffff | Cards, surfaces |
--bg | #f8f6f3 | Page background |
--text | #1a1a1a | Body text |
FUSE-Safe Git Pattern
The workspace is FUSE-mounted. Standard git add causes corruption. Always:
- Write content to
/tmp(never directly to the FUSE path) - Hash from
/tmpvia Python stdin:git hash-object -w --stdin - Build tree with Python
ls_tree/mktreehelpers - Create commit via
git commit-tree - Update
.git/refs/heads/mainvia Python file write
Push from user's Windows terminal (sandbox gets 403):
cd E:\Claude_Projects\sonan-trackers\caretaker-portal-Claude\caretaker-portal
git push origin <sha>:refs/heads/main
Deployment Commands
# Deploy Worker API
npx wrangler deploy --env castlecheckers
# Apply D1 migrations
npx wrangler d1 migrations apply caretaker_db --remote --env castlecheckers
Frontend (React/Vite) auto-deploys on push to main via Cloudflare Pages.