尚未收集仓库信息。
尚未检测到更新。GitHub 发布版本后会显示在这里。
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A marketplace connecting US truck drivers and fleets with truck repair shops: a searchable geographic directory imported from the SHOPS MAP v2 dataset, plus negotiated partner offers, quote/booking workflows, verified reviews, and configurable commissions.
| Layer | Technology |
|---|---|
| Frontend | Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS 4, Leaflet + OpenStreetMap |
| Backend | FastAPI, Pydantic v2, SQLAlchemy 2, Alembic |
| Database | PostgreSQL 16 with cube + earthdistance (GiST-indexed radius search; PostGIS-ready swap path in backend/app/services/geo.py) |
| Auth | JWT bearer tokens (PyJWT), bcrypt password hashing, server-side RBAC |
Both files are Google My Maps exports of the same dataset (the KMZ's
doc.kml matches the standalone KML record-for-record):
| Metric | Value |
|---|---|
| Placemarks per file | 2,833 |
| Folders | TRUCK & TRAILER shops (2,582), PICK UP & AUTO shops (251) |
| Exact in-file duplicates | 1 (identical name+coords+description) |
| Canonical businesses imported | 2,832 |
| Valid US coordinates | 100% |
| Phone parsed (E.164) | 2,533 (89%) |
| City/State/ZIP parsed | 2,757 (97%) |
| Website parsed | 1,672 (59%) |
| Probable-duplicate pairs flagged for admin review | 224 |
Notes: ExtendedData fields (Shop Name, Info, Longtitude, Latitude)
exist but are empty in every record — all usable data lives in the name,
coordinates, and the HTML description (address / website / phone). Some
addresses contained mojibake (���, an encoding artifact of a non-ASCII
country suffix) which the importer strips; originals are preserved in
source_records.raw. The dataset also contains a few stray placemarks (e.g.
"Dallas City Hall") that admins can unpublish.
Prereqs: Python 3.11+, Node 22+, PostgreSQL 16 with the cube and
earthdistance extensions available (bundled with standard Postgres contrib).
# 1. Database
createdb yourfleet_dev # or: CREATE DATABASE yourfleet_dev;
# 2. Backend
cd backend
python -m venv .venv && .venv/Scripts/activate # Windows; use bin/activate elsewhere
pip install -r requirements.txt
copy .env.example .env # then edit DATABASE_URL and set a strong JWT_SECRET
alembic upgrade head # creates schema + geo index (+ extensions if permitted)
python -m app.cli seed-services
python -m app.cli import-kml "../SHOPS MAP v2.kml" --dry-run # preview
python -m app.cli import-kml "../SHOPS MAP v2.kml" # import (idempotent)
python -m app.cli create-admin [email protected] # prompts for password
uvicorn app.main:app --port 8000
# 3. Frontend (second terminal)
cd frontend
npm install
echo NEXT_PUBLIC_API_URL=http://localhost:8000 > .env.local
npm run dev # or: npm run build && npm start
Open http://localhost:3000. API docs at http://localhost:8000/docs.
createdb yourfleet_test
cd backend
set DATABASE_URL=postgresql+psycopg://...:...@localhost:5432/yourfleet_test
.venv/Scripts/python -m pytest tests -q # 43 tests
Covers: KML/KMZ parsing, normalization, idempotent imports, duplicate flagging, invalid coordinates, dry-run isolation, auth, RBAC, geo search ordering/radius, offer validation & visibility rules, every booking state transition, optimistic-concurrency conflicts, commission math, review eligibility, and the claim flow.
python -m app.cli enrich-google [--limit N] [--stale-days 30] [--qps 5] [--dry-run]
fills google_rating, google_rating_count, google_place_url and
google_place_id from the Places API (New) Text Search, once
GOOGLE_PLACES_API_KEY is set in backend/.env. Behavior:
google_synced_at;
re-runs only process unchecked or stale rows. Run with --stale-days 30
on a schedule to respect Google's data-caching policy (place IDs may be
kept indefinitely; ratings must be refreshed).--qps) with exponential backoff on 429/5xx; aborts after
25 consecutive API errors.| Variable | Where | Purpose |
|---|---|---|
DATABASE_URL | backend .env | PostgreSQL connection string |
JWT_SECRET | backend .env | Token signing key — long random string, never commit |
JWT_EXPIRES_MINUTES | backend .env | Access-token lifetime (default 1440) |
CORS_ORIGINS | backend .env | Comma-separated allowed origins |
ENVIRONMENT | backend .env | development / production |
NEXT_PUBLIC_API_URL | frontend .env.local | Backend base URL |
GOOGLE_PLACES_API_KEY | backend .env | Optional; enables enrich-google |
A listing's trust level is never a single mutable "status" — each level is a separate fact:
source_records provenance; shown as "Directory listing".BusinessClaim set owner_user_id.identity_verified_at after checking evidence.partner_status = active (admin-managed commercial agreement).Honesty rules enforced in code:
savings_cents is computed, never stored or invented).requested ─→ quoted ─→ confirmed ─→ in_progress ─→ completed ─→ disputed (admin resolves)
│ ↘ accepted ─→ ↑ ↘ disputed
└────────── cancelled (allowed from any pre-completion state, by role)
All transitions validated server-side per role; concurrent updates rejected via a version token (HTTP 409).
backend/app/services/notifications.py.fleet_manager role can book like a driver;
multi-vehicle/multi-driver company management is not built.backend/
app/api/ routers (auth, businesses, claims, offers, bookings, reviews, me, admin)
app/services/ geo search, booking state machine, notifications
app/importer/ KML/KMZ parsing, normalization, idempotent pipeline
app/cli.py import-kml | seed-services | create-admin
alembic/ migrations
tests/ pytest suite
frontend/
src/app/ pages (home, search, business, bookings, dashboard, provider, admin)
src/components/ Header, MapView, BookingForm, badges, HomeSearch
src/lib/ API client, auth context, types