Commit Graph

9 Commits

Author SHA1 Message Date
Suriya
fd7cf3e35e fix: console tenant scoping, miler identity spoofing, delivery proof, timezone
Security
- Express console had no tenant scoping at all: LoginAdmin hardcoded tenantid 0
  into every JWT and none of the 85 admin handlers filtered by tenant, so any
  client given a console login would read every other client's bookings,
  customers, pricing and reports. Adds DoormileAuth.Tenantid (nil = Doormile
  staff, unrestricted; set = client, scoped), emits it in the token, and scopes
  reads, guards writes and pins tenantid on create.
- Miler telemetry (/miler/logs, /miler/status, /miler/consignments/logs) took
  userid from the request body, letting any authenticated rider write another
  rider's status and GPS trail — data the dispatch layer reasons over. Identity
  now comes from the token.
- POST /miler/reset-pin was unauthenticated and overwrote a PIN given only a
  phone number, so reset-pin + verify-pin took over any rider account. Now
  requires admin/manager/executive auth.

Correctness
- Date ranges compared the container's UTC clock against timestamps the DB
  writes as IST wall-clock (DSN sets TimeZone=Asia/Kolkata), so "today so far"
  ended 5h30m in the past and silently dropped everything created after noon
  IST from every report. Sets TZ in the image and adds utils.DBNow/DBToday,
  which stay correct regardless of container timezone.
- CreateMiler never set Configid, so console-created riders got the column
  default of 1 while LoginMiler looks up configid 1001 — every such rider was
  unable to log in, reported as "no miler account found".
- Delivery wrote no consignment history row, so a tracking timeline never
  showed the parcel arriving.

Features
- Delivery OTP is now real (crypto/rand, issued to the receiver, verified and
  cleared on delivery) but opt-in per client via Tenant.Requiredeliveryotp,
  defaulting off — friction worth it for a courier parcel, not a food order.
- Express bookings accept pickuplocationid, so the console can name a client
  site (a DailyGrubs kitchen) instead of retyping its address; validated
  against the tenant and carried through to the consignment.
- TenantLocation.Locationname, miler tenantid/hubid, Nagercoil (629) opened.
- PUT /miler/availability accepts both "status" and "availabilitystatus", and
  /miler/location no longer drops speed/heading — both were contract
  mismatches against the doc the Flutter dev was given.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 18:16:56 +05:30
c272a33fa6 feat: 14 new endpoints closing jupiter->Doormile API gaps, plus two tenant-scoping bug fixes
New endpoints:
- Admin: partner CRUD (GET/POST /admin/partners, GET/PUT/DELETE
  /admin/partners/:id), bulk express booking create
  (POST /admin/expressbooking/bulk), bulk cancel
  (POST /admin/bookings/bulk-cancel), reports (GET /admin/reports),
  password change (PUT /admin/profile/password), miler notify
  (POST /admin/milers/:id/notify)
- Miler: PIN reset (POST /miler/reset-pin), cancel assignment
  (POST /miler/bookings/:bookingid/cancel), skip delivery
  (POST /miler/consignments/:id/skip)
- Hub: batch assign (POST /hub/bookings/batch-assign) - greedy
  nearest-rider queue clearing, capped per rider

Bug fixes:
- BookingPickupComplete now sets Consignment.Tenantid from the
  booking's tenant instead of the completing miler's own tenant
  (fixes cross-tenant shipment mis-attribution)
- GetHubUnassignedBookings/GetHubBookingsRange now scoped via
  scopeBookingsToOwnTenant (fixes partner hub staff seeing other
  tenants' bookings)

Also: CRM booking routes renamed to expressbooking to end the naming
collision with the separate CRM clients feature; PickupBooking gains
nullable Tenantid; adds CLAUDE.md project memory.

Verified: go build ./... and go vet ./... both clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 12:22:39 +05:30
Suriya
2c26cbe4ba fix: panic recovery, rate limiting, transaction error handling, pagination
Hardening pass over the API surface. No route's auth requirements change.

Resilience:
- Add recover middleware. There was none, so an unhandled panic in any
  handler propagated out of the process instead of becoming a 500.
- Add a centralized ErrorHandler so errors and recovered panics return the
  same {success,message} envelope as the utils helpers, not Fiber's default
  plain-text body. 5xx responses are logged with method and path.

Rate limiting:
- Global 300/min per IP as an abuse backstop, exempting health/readiness
  probes and websocket upgrades.
- 10/min shared across every credential endpoint (customer/miler/admin/hub
  login, verify-pin, reset-pin, email OTP). PINs are 4 digits, so the whole
  keyspace was previously walkable in seconds. One shared limiter instance
  means rotating between endpoints doesn't reset the budget.
- Add TRUSTED_PROXIES config. Limits key on c.IP(), which behind a TLS
  terminator is the proxy, collapsing every client into one bucket. When set,
  X-Forwarded-For is honoured only from those proxies so the header can't be
  spoofed to dodge the limit. Logs a warning when unset.

Transactions:
- Check the error on all 51 previously-unchecked tx.Save/Create/Delete/
  Model(...).Update/Commit calls across 6 controllers. A failed write inside
  a transaction was silently ignored and the request still reported success;
  an unchecked Commit could fail with the caller told everything worked.
  Each site now rolls back and returns a specific message.

Pagination:
- Add utils.ParsePage/Paginated, reusing the pageno/pagesize convention
  GetAdminBookings already established. Default 500, hard cap 1000.
- Apply to the previously unbounded consignments, tripsheets, exceptions,
  app-users and clients endpoints. Defaults are high so existing consoles
  that don't paginate keep working; the cap only stops a growing table from
  being loaded wholesale. total is now a real COUNT, not len(data).
- GetClients also loaded the entire auth table to join in memory; it now
  fetches only the current page's rows.

Tests (first in the repo):
- Extract the hyperlocal pincode rule out of BookingPickupComplete into
  isHyperlocal so it is testable, covering the short/empty pincode fallback.
- Cover calculateVolumetricWeight and the ParsePage clamping rules.

Repo hygiene:
- Tag scratch/*.go with //go:build ignore. Each declared its own main(), so
  `go build ./...` failed on redeclaration; it now passes repo-wide.
- Untrack scratch/node_modules (216 files) and ignore node_modules, test
  artifacts, and the `doormile` binary `go build .` emits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 12:13:39 +05:30
5a2da49c35 feat: PATCH /admin/customers/:id — customer update endpoint
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-09 12:10:49 +05:30
d7c0f35ffe fix: admin console endpoints
- Remove scratch/check_users.go
- GetAdminBookings: LIMIT/OFFSET enforced, returns pageno/pagesize/pages
- GetAdminCustomers: new B2C appcustomers list with booking count
- AdminCancelBooking: cancel + miler release + FCM + NATS event
2026-07-08 20:31:25 +05:30
707323b68c feat: hub console backend — complete API surface 2026-07-04 16:14:12 +05:30
c8adaf7815 hub apis 2026-07-04 11:10:52 +05:30
c91c887726 Add assignment engine, FCM, WebSockets, city gate, and internal APIs
- internal/assignment: GEORADIUS miler assignment with retry/escalation,
  customer-side provider scoring, FCM notifications on assign
- internal/notify: Firebase Admin SDK (FCM) client initialisation
- internal/ws: WebSocket handlers for live parcel tracking and
  customer↔miler chat
- middlewares: city gate (pincode prefix validation), internal API key
  auth, WebSocket JWT auth
- controllers: InternalNotify + InternalReassign for machine-to-machine
  calls; pricing helpers wired into CreateCustomerBooking and CreateCRMBooking
- routes: /internal/*, /ws/bookings/:id/track, /ws/bookings/:id/chat
- models/users, models/doormile_pricing: new fields for device tokens,
  assignment state, pricing bands
- seed_data.sql: initial pricing seed rows

.env and Firebase service-account JSON intentionally excluded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 12:31:53 +05:30
c577d47b75 Initial commit including .env 2026-06-22 17:43:40 +05:30