尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證WorthIt — free Singapore HDB & condo resale price explorer. 370K+ transactions, deal scoring, price trends, and BTO launch comparisons. Built on data.gov.sg and URA open data.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
🏠 WorthIt — Singapore Property Value Detective
Instantly check if a Singapore HDB resale flat or private property is fairly priced based on real transaction data from data.gov.sg and URA.
A free tool for Singapore homeowners and buyers — check HDB resale prices, condo transaction history, price trends, and fair-value estimates for any town, district, or project.檢視完整 README ↗Instantly check if a Singapore HDB resale flat or private property is fairly priced based on real transaction data from data.gov.sg and URA.
A free tool for Singapore homeowners and buyers — check HDB resale prices, condo transaction history, price trends, and fair-value estimates for any town, district, or project.
Check My Price: search any HDB postal code, enter an asking price, and get a 0–100 Deal Score with a fair-value range from storey-adjusted comparable sales nearby — flat type, size, floor, and remaining lease are inferred automatically from the block's transaction history.
WorthIt uses a split architecture:
public/) served via Cloudflare Pages (or node server/index.js locally)/api/* (public/config.js sets API_BASE = ''): locally Express serves it; in production the Cloudflare Pages Function (functions/[[path]].js) proxies it to Fly.ionpm install
pip install requests pyproj # for data download scripts
npm run download-hdb # HDB transactions (~230K records)
# npm run download-ura # Optional: URA private property data (requires URA_API_ACCESS_KEY)
This downloads HDB resale transaction records from data.gov.sg into server/db/resale.db.
npm start
Open http://localhost:3000 in your browser. Express serves both the frontend and API.
npm install -g flyctl
fly auth login
fly launch # Follow prompts (choose region, set app name)
fly secrets set ONEMAP_TOKEN=your_token_here # optional, for geocoding
fly deploy
The Fly.io free tier (256MB RAM) is too small to run the Python download scripts. Instead, build the database locally and upload it:
# 1. Build database locally
python scripts/download_data.py
python scripts/download_ura_data.py # optional
# 2. Upload to Fly.io volume
fly ssh sftp put server/db/resale.db /data/resale.db
# 3. Restart the machine to pick up the new DB
fly machine restart <machine-id>
curl https://<your-app>.fly.dev/api/status
# Expected: {"status":"ok","total_transactions":370252,"latest_month":"2026-05",...}
fly logs # live log stream
fly logs --no-tail # recent logs only
fly machines list # list all machines and their states
fly machine status <id> # detailed status of a machine
fly ssh issue # one-time: create SSH certificate
fly ssh console # open a shell on the machine
Inside the SSH shell:
ls -la /data/ # check database file exists
ls -la /app/ # check deployed files
curl localhost:8080/api/status # test API from inside the machine
cat /app/server/index.js | head # verify deployed code
fly ssh sftp put local_file.txt /data/remote_file.txt # upload
fly ssh sftp get /data/resale.db ./downloaded.db # download
fly machine restart <machine-id> # restart a specific machine
fly machines restart # restart all machines
| Problem | Cause | Fix |
|---|---|---|
503 Database not ready | No DB file on volume | Run download scripts locally, then fly ssh sftp put |
| OOM kill on SSH | Not enough RAM for Python | Build DB locally and upload via SFTP |
| SSH auth failed | No SSH certificate | Run fly ssh issue then fly ssh establish |
no_database status | DB missing at /data/resale.db | Upload via SFTP |
# Re-download latest data locally
python scripts/download_data.py
# Re-upload to Fly.io
fly ssh sftp put server/db/resale.db /data/resale.db
fly machine restart <machine-id>
npx wrangler pages deploy public --project-name=worthit
First run will prompt browser authentication. This uploads public/ and gives you a live URL (e.g., https://worthit.pages.dev).
public# Re-deploy after changes
npx wrangler pages deploy public --project-name=worthit
The frontend auto-connects to the Fly.io API via config.js.
The frontend is live at worthit.canlah.app. Here's how it was configured:
canlah.app) → Continueworthit.canlah.appcurl -I https://worthit.canlah.app
# Should return HTTP 200 with Cloudflare headers
| Endpoint | Description |
|---|---|
GET /api/status | Database status and record count |
GET /api/towns | List all HDB towns + district labels |
GET /api/flat-types | List all flat types |
GET /api/resolve?q= | Resolve town name or postal code |
GET /api/area-overview?town= | Main HDB market overview endpoint (accepts lat/lng for 500m radius) |
GET /api/valuation?postal=&price= | Deal Score + fair value from storey-adjusted nearby comps |
POST /api/geocode | Batch geocode addresses |
POST /api/feedback | In-app feedback (rate-limited, separate feedback.db) |
GET /api/private/projects?q= | Search private property projects |
GET /api/private/project-overview?project= | Private project details |
GET /api/private/property-types | List private property types |
GET /api/private/district-summary?districts= | District aggregate stats |
GET /api/private/district-overview?district= | Full district overview |
GET /api/nearby-hdb?lat=&lng= | Nearby HDB transactions + private projects (800m) |
GET /api/bto/launches | All BTO launches grouped by exercise |
GET /api/bto/projects?q= | BTO project autocomplete |
GET /api/bto/project-overview?project= | BTO project flats, nearby-resale comparison, and own resales once past MOP |
GET /api/seo/metadata?route= | Bot metadata for edge-function injection |
GET /api/seo/sitemap | Sitemap URLs (consumed by Cloudflare edge function) |
WorthIt/
├── scripts/
│ ├── download_data.py # HDB data download (data.gov.sg)
│ ├── download_ura_data.py # URA private property data
│ ├── bto_launches.json # Hand-curated BTO launch data
│ ├── fetch_bto_blocks.py # BTO project → HDB blocks (OneMap)
│ └── bto_project_blocks.json # Output of fetch_bto_blocks.py
├── server/
│ ├── index.js # Express API server
│ └── db/
│ ├── resale.db # SQLite database (generated)
│ └── feedback.db # In-app feedback (writable, generated)
├── functions/
│ └── [[path]].js # Cloudflare edge: /api proxy, bot SEO injection, sitemap
├── public/
│ ├── index.html # Main SPA
│ ├── config.js # API base URL config (same-origin)
│ ├── css/
│ │ └── styles.css
│ └── js/
│ ├── api.js # API client
│ ├── app.js # Main app logic
│ ├── charts.js # Chart.js configs
│ └── map.js # Leaflet map
├── Dockerfile # Fly.io Docker config
├── fly.toml # Fly.io app config
├── package.json
├── requirements.txt
└── README.md
Prices shown are indicative and based on historical transaction data. They should not be considered as professional valuations. Always consult a licensed valuer or property agent for formal advice.