Skip to content

Commit 524c100

Browse files
authored
Merge pull request #7 from YuWei-CH/GMAP-Support
Use GMAP as map and routing
2 parents 25c1313 + 11bf64b commit 524c100

File tree

21 files changed

+615
-176
lines changed

21 files changed

+615
-176
lines changed

.env.example

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# EasyRelocate (repo root) — unified env file
2+
#
3+
# Copy this file to `.env` and fill in your own keys.
4+
# Never commit `.env` (it contains secrets).
5+
6+
###############################################################################
7+
# Frontend (Vite / browser)
8+
###############################################################################
9+
# Required: Browser API key (HTTP referrer-restricted)
10+
VITE_GOOGLE_MAPS_API_KEY="YOUR_BROWSER_KEY"
11+
12+
# Optional: Backend API base URL (defaults to http://localhost:8000)
13+
VITE_API_BASE_URL="http://localhost:8000"
14+
15+
# Optional: Disable Google Maps loading (useful for CI)
16+
# VITE_DISABLE_GOOGLE_MAPS="1"
17+
18+
###############################################################################
19+
# Backend (FastAPI / server)
20+
###############################################################################
21+
# Optional: Server API key (for Geocoding API server-to-server calls)
22+
# If you don't set this, the backend will fall back to Nominatim (OSM) for geocoding.
23+
GOOGLE_MAPS_API_KEY="YOUR_SERVER_KEY"
24+
25+
# Optional: Force geocoding provider (google or nominatim)
26+
GEOCODING_PROVIDER="google"
27+
28+
# Optional: Enable/disable all geocoding calls
29+
ENABLE_GEOCODING="1"
30+
31+
# Optional: Database URL (default is an auto-created SQLite DB under backend/)
32+
# DATABASE_URL="sqlite+pysqlite:////absolute/path/to/easyrelocate.db"

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,7 @@ jobs:
4848
- name: Install dependencies
4949
run: npm ci
5050
- name: Build
51+
env:
52+
# CI doesn't have real Google API keys. Build should still validate typecheck + bundle.
53+
VITE_DISABLE_GOOGLE_MAPS: "1"
5154
run: npm run build

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ node_modules/
1919
dist/
2020
.vite/
2121

22+
# Env files (do not commit secrets)
23+
.env
24+
.env.local
25+
.env.*.local
26+
frontend/.env
27+
frontend/.env.local
28+
frontend/.env.*.local
29+
backend/.env
30+
backend/.env.local
31+
backend/.env.*.local
32+
!.env.example
33+
2234
# Extension build artifacts
2335
extension/dist/
2436

README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,48 @@ EasyRelocate does not scrape platforms server-side, host listings, process payme
99

1010
## Repo structure
1111
- `backend/`: FastAPI + SQLite API
12-
- `frontend/`: React (Vite) web app (MapLibre + OpenStreetMap map, US-only for now)
12+
- `frontend/`: React (Vite) web app (Google Maps JS map + routing, US-only for now)
1313
- `extension/`: Chrome extension (Manifest V3) for user-side extraction
1414

15+
## Configuration (API keys & env vars)
16+
EasyRelocate uses a single repo-root `.env` file for both frontend + backend.
17+
18+
1. Copy the example:
19+
```bash
20+
cp .env.example .env
21+
```
22+
23+
2. Edit `.env` and set your keys.
24+
25+
### Frontend (Vite / browser)
26+
Frontend variables must start with `VITE_`:
27+
```bash
28+
# Required (browser key)
29+
VITE_GOOGLE_MAPS_API_KEY="YOUR_BROWSER_KEY"
30+
31+
# Optional (defaults to http://localhost:8000)
32+
VITE_API_BASE_URL="http://localhost:8000"
33+
34+
# Optional (useful for CI / keyless dev)
35+
# VITE_DISABLE_GOOGLE_MAPS="1"
36+
```
37+
38+
### Backend (FastAPI / server)
39+
Backend reads standard env vars (auto-loads repo-root `.env` on startup):
40+
```bash
41+
# Optional (server key; used for /api/geocode and /api/reverse_geocode)
42+
GOOGLE_MAPS_API_KEY="YOUR_SERVER_KEY"
43+
GEOCODING_PROVIDER="google"
44+
45+
# Optional
46+
ENABLE_GEOCODING="1"
47+
DATABASE_URL="sqlite:///easyrelocate.db"
48+
```
49+
50+
### Extension (Chrome)
51+
The extension does not read `.env` files. Configure its API base URL in Chrome:
52+
Extension → **Details****Extension options** → “API base URL” (default: `http://localhost:8000`).
53+
1554
## Local dev (MVP)
1655

1756
### 1) Backend API
@@ -49,6 +88,14 @@ Set your workplace target by:
4988

5089
Then open an Airbnb listing detail page (`/rooms/...`) and click “Add to Compare”.
5190

91+
## Google Maps setup (required)
92+
EasyRelocate uses Google Maps Platform for:
93+
- **Maps JavaScript API** (frontend map)
94+
- **Directions API** (routing: Drive/Bus/Walk/Bike)
95+
- **Geocoding API** (backend address lookup; optional but recommended)
96+
97+
See: `docs/GOOGLE_MAPS_APPROX_LOCATION.md`
98+
5299
## Docs
53100
- Platform organization: `docs/PLATFORM_ORGANIZATION.md`
54101
- Google maps “approx street”: `docs/GOOGLE_MAPS_APPROX_LOCATION.md`

backend/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ pip install -r requirements.txt
1515
uvicorn app.main:app --reload --port 8000
1616
```
1717

18+
### Env vars (where to put them)
19+
The backend reads configuration from process environment variables.
20+
21+
EasyRelocate auto-loads a repo-root `.env` file (recommended). Copy `.env.example``.env`
22+
in the repo root and put backend env vars there.
23+
24+
You can still override via shell exports if needed.
25+
1826
API docs:
1927
- Swagger UI: `http://localhost:8000/docs`
2028
- OpenAPI: `http://localhost:8000/openapi.json`
@@ -37,6 +45,7 @@ Env vars:
3745
- `GEOCODING_USER_AGENT` (default `EasyRelocate/0.1 (local dev)`)
3846
- `NOMINATIM_BASE_URL` (default `https://nominatim.openstreetmap.org`)
3947
- `GEOCODING_TIMEOUT_S` (default `6`)
48+
- `DATABASE_URL` (optional; defaults to `backend/easyrelocate.db`)
4049

4150
### Google setup requirements
4251
If you use Google geocoding (`GEOCODING_PROVIDER=google` or `GOOGLE_MAPS_API_KEY` is set):

backend/app/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
5+
from dotenv import load_dotenv
6+
7+
8+
def _load_repo_root_dotenv() -> None:
9+
# backend/app/__init__.py -> backend/app -> backend -> repo root
10+
repo_root = Path(__file__).resolve().parents[2]
11+
env_path = repo_root / ".env"
12+
if env_path.exists():
13+
load_dotenv(env_path, override=False)
14+
15+
16+
_load_repo_root_dotenv()
117

backend/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ fastapi>=0.115
22
uvicorn>=0.30
33
sqlalchemy>=2.0
44
httpx>=0.27
5+
python-dotenv>=1.0

docs/GOOGLE_MAPS_APPROX_LOCATION.md

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,31 @@ So any street-level result we show is:
1515
3. **Frontend** (when a listing is selected) calls reverse geocoding to display:
1616
- `Approx street: <road>` (clearly labeled approximate).
1717

18+
## Where to put API keys / env vars
19+
### Frontend (browser) key
20+
Put your browser key in the repo-root `.env` file:
21+
```bash
22+
VITE_GOOGLE_MAPS_API_KEY="YOUR_BROWSER_KEY"
23+
```
24+
25+
This key is used in the browser for:
26+
- **Maps JavaScript API** (render the map)
27+
- **Directions API** (routing: Drive / Bus(Transit) / Walk / Bike)
28+
29+
### Backend (server) key
30+
Put your server key in the repo-root `.env` file:
31+
```bash
32+
GOOGLE_MAPS_API_KEY="YOUR_SERVER_KEY"
33+
GEOCODING_PROVIDER="google"
34+
```
35+
36+
This key is used server-to-server for:
37+
- **Geocoding API** (address → lat/lng)
38+
- reverse geocoding lat/lng → rough location / street name
39+
40+
### Extension
41+
The extension does not read `.env` files. Set its API base URL in Chrome Extension options.
42+
1843
## How we extract the map pin coordinates
1944
File: `extension/platforms/airbnb/content.js`
2045

@@ -44,15 +69,15 @@ If you see an error like:
4469
`Google Geocoding failed with status REQUEST_DENIED: This API is not activated on your API project`
4570
it means the **Geocoding API is not enabled** (or billing/key restrictions are blocking it).
4671

47-
Set these env vars before starting the backend:
72+
Set these env vars in the repo-root `.env` (recommended) or your shell before starting the backend:
4873
```bash
49-
export GOOGLE_MAPS_API_KEY="YOUR_KEY"
50-
export GEOCODING_PROVIDER="google"
74+
GOOGLE_MAPS_API_KEY="YOUR_KEY"
75+
GEOCODING_PROVIDER="google"
5176
```
5277

5378
Optional:
5479
```bash
55-
export GEOCODING_COUNTRY_CODES="us"
80+
GEOCODING_COUNTRY_CODES="us"
5681
```
5782

5883
Then run:
@@ -67,6 +92,23 @@ uvicorn app.main:app --reload --port 8000
6792
- Restrict by **API**: allow only **Geocoding API**
6893
- Optionally restrict by **IP address** (for local dev, this can be inconvenient)
6994

95+
## Google Maps UI + routing (frontend)
96+
EasyRelocate’s compare page uses Google Maps Platform in the browser for:
97+
- **Maps JavaScript API** (render the map)
98+
- **Directions API** (routing: Drive / Bus(Transit) / Walk / Bike)
99+
100+
### Frontend env var
101+
Add this to the repo-root `.env`:
102+
```bash
103+
VITE_GOOGLE_MAPS_API_KEY="YOUR_KEY"
104+
```
105+
106+
### API requirements
107+
If routing fails with errors like `Route failed: REQUEST_DENIED`, ensure in Google Cloud Console:
108+
- Billing is enabled
109+
- “Maps JavaScript API” is enabled
110+
- “Directions API” is enabled
111+
70112
## Local dev env vars
71113
Backend env vars:
72114
- `GOOGLE_MAPS_API_KEY` (enables Google geocoding)

extension/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
2. Click **Extension options**
1212
3. Set the API base URL (default: `http://localhost:8000`)
1313

14+
Note: the extension does **not** read `.env` files. Its API base URL is stored in Chrome sync storage
15+
and can differ from the frontend’s `VITE_API_BASE_URL` if needed.
16+
1417
## Notes on Airbnb location
1518
Airbnb typically does **not** show precise street addresses. The extension tries to capture:
1619
- Lat/lng (when available in structured data / meta tags)

extension/api.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
const DEFAULT_API_BASE_URL = 'http://localhost:8000'
2+
3+
function storageGet(keysWithDefaults) {
4+
return new Promise((resolve) => {
5+
chrome.storage.sync.get(keysWithDefaults, (items) => resolve(items))
6+
})
7+
}
8+
9+
function storageSet(items) {
10+
return new Promise((resolve) => {
11+
chrome.storage.sync.set(items, () => resolve())
12+
})
13+
}
14+
15+
function normalizeBaseUrl(v) {
16+
const raw = String(v || '').trim()
17+
if (!raw) return DEFAULT_API_BASE_URL
18+
return raw.replace(/\/$/, '')
19+
}
20+
21+
async function getApiBaseUrl() {
22+
const items = await storageGet({ apiBaseUrl: DEFAULT_API_BASE_URL })
23+
return normalizeBaseUrl(items.apiBaseUrl)
24+
}
25+
26+
async function setApiBaseUrl(v) {
27+
const next = normalizeBaseUrl(v)
28+
await storageSet({ apiBaseUrl: next })
29+
return next
30+
}
31+
32+
async function postJson(url, payload) {
33+
const res = await fetch(url, {
34+
method: 'POST',
35+
headers: { 'Content-Type': 'application/json' },
36+
body: JSON.stringify(payload),
37+
})
38+
const text = await res.text()
39+
if (!res.ok) {
40+
throw new Error(`${res.status} ${res.statusText}${text ? ` — ${text}` : ''}`)
41+
}
42+
return text ? JSON.parse(text) : null
43+
}
44+
45+
async function postToApi(path, payload) {
46+
const base = await getApiBaseUrl()
47+
const full = `${base}${path.startsWith('/') ? '' : '/'}${path}`
48+
return postJson(full, payload)
49+
}
50+

0 commit comments

Comments
 (0)