Stack

LayerTechnology
FrontendReact 18 + TypeScript (Vite 5) — Cloudflare Pages
Backend APICloudflare Worker (TypeScript) — env: premierrealty
DatabaseCloudflare D1 — realtor_db (ID: 788cf2ea-86f8-4b88-bf0a-06277168455e)
AuthPBKDF2-SHA256 password hash in D1, HMAC-signed JWT (24hr expiry)
MobilePosition:fixed sidebar drawer + hamburger (mobile-first)

Database Tables

TableKey Columns
admin_usersid, name, email, password_hash
clientsid, name, email, phone, client_type (Buyer/Seller/Both), status, address, notes
listingsid, client_id, address, city, state, zip, property_type, list_price_cents, bedrooms, bathrooms, sqft, mls_number, description, status, listing_date
showingsid, client_id, listing_id, date, start_time, end_time, status (Scheduled/Completed/Cancelled/No Show), notes
invoicesid, invoice_number, client_id, amount_cents, description, status, issue_date, paid_date
invoice_itemsid, invoice_id, description, quantity, unit_price_cents, total_cents
notesid, entity_type, entity_id, content
settingskey, value — business_name, property_types, invoice_footer, invoice_next_number

Public API Endpoints (No Auth)

RoutePurpose
GET /api/configBusiness name, property types for public site
GET /api/listings-publicAll Active listings for public property search
POST /api/showings-publicVisitor-submitted showing request (no client_id required)

File Structure

realtor-portal/
  src/
    App.tsx / api.ts / index.css / main.tsx
    context/AppContext.tsx
    components/
      PublicSite.tsx        ← Property listings + showing request form
      AdminApp.tsx          ← Mobile-first sidebar shell
      admin/
        Dashboard.tsx / ClientsView.tsx / ListingsView.tsx / ShowingsView.tsx
        InvoicesView.tsx / CalendarView.tsx / ReportsView.tsx / SettingsView.tsx
  worker/index.ts
  migrations/0001_init.sql / 0002_settings_seed.sql (Premier Realty defaults)
  wrangler.toml             ← premierrealty env