White-label household-services matchmaking platform. Negotiation-first, thin-market-viable, disintermediation-tolerant, white-label from day one. See the driver document for the full spec; this repo is Phase 0 — the seed directory (ships value at ~10 workers).
Cloudflare Pages/Workers + D1 (SQLite) + Hono, server-rendered HTML, no SPA.
The same src/app.mjs runs two ways:
- Production:
src/worker.mjsbinds the app to D1 (wrangler.toml). - Local/dev + tests:
node:sqlite(Node's built-in — zero native deps), bridged to the app inscripts/dev-server.mjs.
Only runtime dependency is Hono; jsdom + wrangler are dev-only.
npm install
npm run seed # create .data/homematch.sqlite with 12 demo workers
npm run serve # http://localhost:4310 (dev tenant answers on 'localhost')
npm test # 77 tests (schema, tenant isolation, contrast, i18n, auth,
# directory filters, verification, a11y, contact-withholding,
# self-listing, base path)npm run dev uses wrangler pages dev against D1 (needs the Cloudflare
toolchain + a local D1 binding).
migrations/ numbered schema (applies from zero; tested per-state)
tenants/*.json per-operator config (brand, theme, taxonomy, zones, fee, legal)
src/
db.mjs async adapter — node:sqlite (dev) OR D1 (prod)
migrate.mjs migration runner
app.mjs Hono app (tenant middleware, routes) — portable
worker.mjs Cloudflare entry (D1)
repo.mjs tenant-scoped data access (every query carries operator_id)
i18n/ en (key schema) + th packs, override-able per operator
lib/ contrast, tenant, taxonomy (title guard), auth, verify, html
pages/ layout + directory + profile + components (server render)
scripts/ dev-server, seed
test/ behavioural suites (§11)
tenants/motdang.json runs at motdang.net/home-help — a Worker route more
specific than the site Worker's motdang.net/*. BASE_PATH=/home-help is
stripped in src/worker.mjs; pages print every link under it. That tenant has
self-listing on: /join, the private /edit/<token> link, and /admin.
BASE_PATH=/home-help ADMIN_KEY=dev npm run serve # tenant answers on 127.0.0.1
node scripts/operator-sql.mjs motdang > /tmp/op.sql # install/refresh the operator row
npx wrangler d1 execute homematch --remote --file=/tmp/op.sql
npx wrangler deploy # needs workers_routes on the zoneA new operator = one tenants/<id>.json + an operator row. Everything
city-specific (brand, theme colours, enabled categories, zones, fee model,
legal footer, locales) lives there. Theme colours are contrast-checked
numerically at load — an unreadable theme cannot ship (test/tenant.test.mjs).
Phase 0 complete and browser-verified. See DISCLOSURE.md for exactly what is
stubbed (SMS, R2, Phase 1+ features), the fee-default assumption, and the legal
flags — notably that the domestic-worker floor is Ministerial Regulation
No. 15 (2024), not the spec's MR14 (research in ../baanstaff/docs/LEGAL_RESEARCH.md).
Phases 1–4 (negotiation + offers, contracts + reviews, fee model + LINE + second-tenant proof, escrow/background-checks) are not built here.
Records, prose and pages: CC BY 4.0. Code: MIT. Attribution is the only condition — name the work and link back. Anything carried in from elsewhere keeps its own terms — see LICENSE and NOTICE.txt.
Using it. Attribution is the whole of the condition — copy it, adapt it, sell it, index it, train on it, and say where it came from. Open an issue if something is missing.
Contact: Nan · nan@motdang.net · Sponsor: Ko-fi · Patreon