Guests can generate a shareable GSH code for admin fulfillment; sign-in now supports Google, email, phone, and Telegram demos, with the backend spec updated. Co-authored-by: Cursor <cursoragent@cursor.com>
192 lines
9.6 KiB
Markdown
192 lines
9.6 KiB
Markdown
# Gishen-Mob Backend Spec
|
||
|
||
**Base URL (TBD):** `https://api.gishen.example/v1`
|
||
**Auth:** Bearer JWT after verified sign-in (phone OTP, email, Google, or Telegram)
|
||
**Headers:** `Authorization`, `Accept-Language` (`en` | `am`), `Content-Type: application/json`
|
||
|
||
Shared with Gishen-Ecom / Gishen-B2B where noted.
|
||
Patch this file whenever a feature is added or finalized.
|
||
|
||
## Auth
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/auth/otp/request` | Required | `{ phone }` — SMS OTP |
|
||
| POST | `/auth/otp/verify` | Required | `{ phone, code }` → session + user |
|
||
| POST | `/auth/email/login` | Required | `{ email, password }` → session + user |
|
||
| POST | `/auth/email/register` | Optional | `{ name, email, password, phone? }` |
|
||
| POST | `/auth/oauth/google` | Required | `{ idToken }` (or auth code) → session + user |
|
||
| POST | `/auth/oauth/telegram` | Required | Telegram Login Widget payload → session + user |
|
||
| POST | `/auth/guest` | Required | Optional device id → limited guest session (`isGuest: true`) |
|
||
| POST | `/auth/biometric/bind` | Required | Device biometric public key |
|
||
| GET | `/users/me` | Required | Profile, locale, points, tier, `authProvider` |
|
||
| PATCH | `/users/me` | Required | name, email, phone, `locale`, biometric flag |
|
||
|
||
**Providers (mobile UI):** `google` \| `email` \| `phone` \| `telegram` \| `guest`
|
||
Guest sessions may browse catalog and generate **pharmacist order codes**; loyalty, corporate, and some care features require a non-guest account.
|
||
|
||
## Locale
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| PATCH | `/users/me` | Required | `{ locale: "en" \| "am" }` |
|
||
| — | Accept-Language | Required | All requests |
|
||
|
||
## Catalog
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/catalog/products` | Required | q, category, badge, max — parity with Ecom |
|
||
| GET | `/catalog/products/:idOrSlug` | Required | |
|
||
| GET | `/catalog/categories` | Required | |
|
||
|
||
## Favorites
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/favorites/me` | Required | Product ids |
|
||
| PUT | `/favorites/:productId` | Required | Add |
|
||
| DELETE | `/favorites/:productId` | Required | Remove |
|
||
|
||
## Addresses
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/users/me/addresses` | Required | Saved delivery addresses |
|
||
| POST | `/users/me/addresses` | Required | label, street, area, landmark?, isDefault? |
|
||
| PATCH | `/users/me/addresses/:id` | Required | |
|
||
| DELETE | `/users/me/addresses/:id` | Required | |
|
||
|
||
## Branches / Stock
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/branches` | Required | |
|
||
| GET | `/branches/nearby` | Required | `lat`, `lng` |
|
||
| GET | `/stock/product/:productId` | Required | Nearby availability |
|
||
|
||
## Orders
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/orders` | Required | items, fulfillment, branchId?, location, paymentMethod, prescriptionFileKeys?, notes, credit?, `anyBranch?` |
|
||
| GET | `/orders/me` | Required | Authenticated user’s orders |
|
||
| GET | `/orders/:id` | Required | |
|
||
| GET | `/orders/by-code/:code` | Required | Lookup by `GSH-XXXX` (guest + pickup). Mobile uses this for “find my code”. |
|
||
| GET | `/orders/:id/tracking` | Required | Rider trail when assigned |
|
||
| POST | `/orders/:id/cancel` | Required | |
|
||
|
||
### Guest / pharmacist order codes (parity with Gishen Ecom Web)
|
||
Guests (and optionally signed-in pickup) receive a short **pharmacist reference code** (`GSH-XXXX`).
|
||
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/orders/guest-codes` | Required | Basket snapshot + customer name/phone → `{ code, orderId, status: "requested" }`. Mobile shows copy / share / screenshot card. |
|
||
| GET | `/admin/orders/by-code/:code` | Required | **Admin** — pharmacist enters code to create / hydrate the POS order (shared with Ecom admin). |
|
||
| POST | `/admin/orders/by-code/:code/fulfill` | Required | Mark created / confirmed after admin processing |
|
||
|
||
**Mobile contract**
|
||
- Guest checkout forces pickup + `pay_at_branch` + any-branch code.
|
||
- Response includes `pickupCode`, `status: requested` until pharmacist creates the order in admin.
|
||
- Share payload should include code, customer, line items, total (plain text for WhatsApp / clipboard).
|
||
|
||
## Payments
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/payments/initiate` | Required | `chapa` \| `telebirr` \| `mpesa` only for delivery |
|
||
| POST | `/payments/webhook/*` | Required | Gateway callbacks |
|
||
| — | `pay_at_branch` | Required | Allowed **only** when `fulfillment=pickup` (required for guest pharmacist codes) |
|
||
|
||
## Prescriptions (Rx Care)
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/uploads/signed-url` | Required | Rx images |
|
||
| POST | `/prescriptions` | Required | Multi-page keys, medicines[], patient, memberId? |
|
||
| POST | `/prescriptions/check` | Required | Match catalog → ready/review/unavailable |
|
||
| GET | `/prescriptions/me` | Required | |
|
||
| GET | `/prescriptions/:id` | Required | Detail + attached reminders |
|
||
| POST | `/prescriptions/:id/reorder` | Required | |
|
||
|
||
## Reminders
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/health/reminders` | Required | Dose/refill schedules (times[], graceMinutes, escalate?) |
|
||
| POST | `/health/reminders/:id/confirm` | Required | `dose.confirmed` |
|
||
| POST | `/health/reminders/:id/snooze` | Required | |
|
||
| GET | `/health/reminders/me` | Required | |
|
||
| — | Local + remote push | Required | Daily dose window; calendar UI on `/prescriptions/:id/calendar` |
|
||
|
||
## Emergency contacts
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/users/me/emergency-contacts` | Required | |
|
||
| POST | `/users/me/emergency-contacts` | Required | name, phone, relationship |
|
||
| DELETE | `/users/me/emergency-contacts/:id` | Required | |
|
||
| — | Job `dose.missed_escalation` | Required | After grace (default 30m) SMS/push to contact if no confirm |
|
||
|
||
## Family
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/family/members` | Required | |
|
||
| POST | `/family/invites` | Required | phone or link code |
|
||
| POST | `/family/invites/accept` | Required | |
|
||
| DELETE | `/family/members/:id` | Required | |
|
||
|
||
## Subscriptions
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/subscriptions/me` | Required | |
|
||
| POST | `/subscriptions` | Required | |
|
||
| POST | `/subscriptions/:id/pause` | Required | |
|
||
| POST | `/subscriptions/:id/resume` | Required | |
|
||
| POST | `/subscriptions/:id/cancel` | Required | |
|
||
|
||
## B2B / Corporate (shared with Gishen-B2B)
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/users/me/contexts` | Required | personal + org memberships |
|
||
| POST | `/orgs/join` | Required | `{ code }` |
|
||
| GET | `/company/me` | Required | Member view: plan, allowance |
|
||
| POST | `/checkout/credit/quote` | Required | Basket split covered vs selfPay |
|
||
|
||
## Loyalty
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/loyalty/me` | Required | |
|
||
| GET | `/loyalty/me/ledger` | Required | |
|
||
| POST | `/loyalty/redeem` | Required | |
|
||
| GET | `/referrals/me` | Required | |
|
||
|
||
## Notifications (in-app inbox)
|
||
Distinct from order list. Home bell → inbox.
|
||
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| GET | `/notifications/me` | Required | kinds: `order` \| `rx` \| `dose` \| `loyalty` \| `promo` \| `system` |
|
||
| POST | `/notifications/:id/read` | Required | |
|
||
| POST | `/notifications/read-all` | Required | |
|
||
| DELETE | `/notifications/:id` | Required | |
|
||
| POST | `/devices` | Required | push token registration |
|
||
|
||
## Push / Tracking
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/devices` | Required | push token |
|
||
| — | Events | Required | order.*, dispatch.*, dose.*, refill.*, escalation.*, guest_code.* |
|
||
| GET | `/orders/:id/tracking` | Required | |
|
||
|
||
## Contact / Support
|
||
| Method | Path | Status | Notes |
|
||
|--------|------|--------|-------|
|
||
| POST | `/contact` | Required | |
|
||
| — | Chatwoot | Deeplink | https://chat.yaltopia.com |
|
||
| — | WhatsApp / Call | Deeplink | Branch support numbers |
|
||
|
||
### Changelog
|
||
- 2026-08-06: Scaffold — skeleton created with all domains.
|
||
- 2026-08-06: Auth/Locale — OTP mock, biometric bind flag, language picker en/am, Accept-Language noted.
|
||
- 2026-08-06: Catalog — products/categories from Ecom data port; shop/search/favorites.
|
||
- 2026-08-06: Branches/Stock — GPS nearest sort; pickup selection (stock map stub).
|
||
- 2026-08-06: Orders/Payments/B2B — checkout with Chapa/Telebirr/M-Pesa; pay_at_branch pickup-only; WhatsApp handoff; credit quote split stub.
|
||
- 2026-08-06: Prescriptions/Reminders/Emergency — camera multi-page scan, check statuses, calendar dose push, escalation job contract.
|
||
- 2026-08-06: Family/Subscriptions — invite/manage; refill subscription CRUD.
|
||
- 2026-08-06: B2B/Account — contexts, join codes, profile switcher.
|
||
- 2026-08-06: Loyalty/Push/Tracking — wallet redeem/referral; order tracking map mock; device push channels.
|
||
- 2026-08-06: Contact/Support — contact form + Chatwoot/WhatsApp/call deeplinks.
|
||
- 2026-08-07: Auth providers — Google, Email, Phone OTP, Telegram, and Guest session contracts; `authProvider` on `/users/me`.
|
||
- 2026-08-07: Guest pharmacist codes — `POST /orders/guest-codes`, `GET /orders/by-code/:code`, admin fulfill-by-code (Ecom parity); mobile copy/share/screenshot card.
|
||
- 2026-08-07: Notifications inbox — dedicated `/notifications/me` (separate from Orders); Favorites + Addresses endpoints documented; Rx Care dose reminder confirm/snooze.
|