This repository has been archived on 2026-08-11. You can view files and clone it, but cannot push or open issues or pull requests.
Gishen-Admin/docs/GISHEN-MASTER-SPEC.md
Kirubel-Kibru-Yaltopia 8616c03645 Align org activation and Money with B2B platform contracts
Use pending_activation, commercial Money terms, and activate flows so Admin master/spec and mocks match the shared organisation lifecycle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-08 00:29:44 +03:00

18 KiB
Raw Blame History

Gishen — Cross-App Master Spec

Living collective contract across Gishen client apps. Deeper API sketches live in each repo’s own backend sheet; this file is the shared map of roles, domain objects, auth providers, and known divergences.

Field Value
Home repo (this file) Gishen-Admin
Sibling root /Users/kirukib/Desktop/Yaltopia Project/
Shared API base (TBD) Prefer https://api.gishenpharmacy.org/v1 (B2B draft / Admin alignment). Legacy sheets still show api.gishen.example — unify TBD
Last reconciled 2026-08-08

Changelog

Date Change
2026-08-08 Org/Money alignment: Canonical org status pending_activation; Admin activate path + CommercialTerms/Money; B2B register POST /v1/org/register + org.activated/org.suspended. Resolved Money default (decimal major ETB). Refreshed divergence table + Sources stamp after sibling B2B/Ecom skim.
2026-08-07 Seed batch: Created master spec from Admin living contract + sibling Mob/Ecom/B2B/Dispatch sheets. Documented product surface map, shared domain objects (auth, orgs, doctors, orders/guest, Rx dosing, catalogue multi-UOM + PDP, stock, loyalty), auth provider matrix, divergence & sync notes, deeper-doc links, Sources stamp, and pre-push update rule. Wired .cursor/rules + optional .githooks/pre-push reminder. Linked from Admin README.md and admin-backend-spec.md.

Update rule (before every push)

This file is the cross-app master. Before git push from Gishen-Admin (humans and agents):

  1. Diff Admin src/ / docs/admin-backend-spec.md against the last Sources stamp below.
  2. Skim sibling Mob / Ecom / B2B / Dispatch specs if those folders exist on disk.
  3. Refresh relevant sections here; append a Changelog row (date + why).
  4. If Admin endpoints/fields changed, also update admin-backend-spec.md in the same change set.
  5. Update the Sources stamp (Last reconciled + checklist dates).

Agents: the Cursor rule .cursor/rules/update-master-spec-before-push.mdc applies on push requests. Optional git hook: see Pre-push tooling.


Sources stamp

Update these dates whenever you reconcile against a sibling.

Source Path (sibling area) Found Spec / README Last skimmed
Admin Gishen-Admin/ ✅ docs/admin-backend-spec.md 2026-08-08
Mob Gishen-Mob/ ✅ docs/BACKEND_SPEC.md (relative from sibling root) 2026-08-07
Ecom Gishen-Ecom/ ✅ docs/backend.md 2026-08-08
B2B Gishen-B2B/ ✅ docs/backend/OVERVIEW.md + coordination 2026-08-08
Dispatch Bot Gishen-Dispatch-Bot/ ✅ (related) docs/BACKEND_SPEC.md 2026-08-07
Telegram Mini App Gishen-Telegram-MiniApp/ ⚠️ empty scaffold — 2026-08-07

Sources not found

None for the four primary surfaces (Admin / Mob / Ecom / B2B). Related folders present but thin: Gishen-Telegram-MiniApp (empty), Dispatch Bot documented as rider surface.

Pre-push checklist (human / agent)

  • Changelog row added if domain contract changed
  • Auth / orders / Rx / catalogue / org notes still match siblings (or divergences listed)
  • Last reconciled date bumped
  • admin-backend-spec.md updated if Admin modules changed
  • Reminder script run (optional): bash scripts/sync-master-spec-reminder.sh

1. Product surface map

One shared pharmacy platform; four primary clients + rider bot.

App Repo Who Primary jobs
Admin Gishen-Admin Pharmacy staff: pharmacist, stock_manager, procurement, finance, marketing_manager, operations, super_admin Branch Rx queue, orders/POS, stock, procurement, org commercial activation, CRM/loyalty config, dispatch board, team/audit, catalogue master, doctor roster
Mob Gishen-Mob Retail customer (Expo) Catalog/PDP, cart/checkout, guest pharmacist codes, Rx Care (scan/reminders), loyalty, family, subscriptions, B2B join/contexts, tracking
Ecom Gishen-Ecom Retail customer (Next.js PWA) Storefront catalog, Rx upload/check, cart → order request, profile/favorites/loyalty, branches; v1 confirmation often phone/WhatsApp
B2B Gishen-B2B Institutional: SUPER_USER, HR_ADMIN, FINANCE, MEMBER Org self-register; HR members/packages/migration; Finance statements/approvals; Member allowance + own Rx (clinical withhold for HR/Finance)
Dispatch Bot Gishen-Dispatch-Bot Riders/drivers Telegram-enrolled trip status + POD; no separate rider login app for v1
Telegram Mini App Gishen-Telegram-MiniApp Customers (planned) Placeholder — Ecom backend mentions Telegram auth/bootstrap; TBD

Who creates what

Artefact Created by Verified / fulfilled by
Retail order (registered) Customer (Mob/Ecom) Pharmacist / Ops (Admin)
Guest order / pharmacist code (GSH-XXXX) Guest/customer Mob/Ecom; staff/doctor Admin Pharmacist Admin (by-code / POS)
Prescription intake (customer scan) Mob/Ecom/B2B member Pharmacist Admin
Doctor-authored Rx / clinical order Doctor (hospital org) Pharmacist Admin
Catalogue Item master Stock/super_admin Admin Consumed by Mob/Ecom as /catalog/products
Org commercial terms Admin Finance B2B unlocks on org.activated
Trip assign Ops Admin Dispatch Bot rider

External actors (not Admin staff roles)

Actor Auth surface Notes
Doctor Separate doctor JWT (Admin sheet); hospital/clinic org affiliation Create Rx & guest/registered patient orders; not a StaffRole
End customer (guest) None / Mob POST /auth/guest / Ecom guest order Phone required for assisted/guest checkout; loyalty gated
B2B roles B2B portal session Distinct from pharmacy staff; shared customer_id linkage TBD

2. Shared domain objects

Fields below are the platform-level vocabulary. Path prefixes and exact DTOs still differ per sheet — see §4 Divergence.

2.1 Users & auth providers

Concept Shared idea App notes
Platform person UUID user / customer Staff vs customer vs doctor vs B2B user are actors, not one role enum everywhere
Staff Admin StaffUser + StaffRole + optional branchId Bearer JWT
Customer Retail identity; loyalty points/tier Mob GET /users/me; Ecom same idea
Doctor Hospital/clinic-affiliated clinician Admin roster + POST /auth/doctor/login
B2B session user roles[], org_id, active_role Clinical withhold for HR/Finance
authProvider email | google | phone | telegram (+ Mob guest) Report on /me / login response
Locale en | am Admin preferredLocale; Mob/Ecom/B2B locale / Accept-Language

See §3 Auth matrix.

2.2 Organisations

Type (Admin) Used for
corporate | ngo | other B2B benefits clients — credit, packages, members
hospital | clinic Doctor affiliation; clinical Rx/orders

Lifecycle (canonical): pending_activation → active → suspended | closed (+ rejected for denied self-reg). Admin writes commercial (Money credit_limit/used, payment_terms_days, price_list_id, contract dates) via create-active or POST /admin/organisations/:id/activate and emits org.activated. B2B self-register: POST /v1/org/register → org.registration_submitted → Admin queue.

2.3 Doctors

  • Roster under hospital/clinic orgs in Admin (/doctors, org detail).
  • Fields (Admin): name, specialty, licenseNumber, phone, email, status, orgId, …
  • Can create prescriptions and orders for guest or registered patients, org-scoped.
  • Cannot manage catalogue, RBAC, finance, other hospitals.
  • Identity provider strategy vs B2B hospital users: open (Admin Q8 / Q17).

2.4 Orders (registered + guest)

Field / idea Meaning
customerType Admin: registered | guest on staff/doctor-created orders
Guest identity customerName + required customerPhone; no customerId
Channels Admin includes branch / POS / doctor / (ops); Mob/Ecom retail + guest codes
Pharmacist code Mob/Ecom: GSH-XXXX via POST /orders/guest-codes; Admin fulfill GET/POST .../by-code/:code
Fulfillment pickup | delivery (+ branch / any-branch for guest codes)
Payments Mob: Chapa / Telebirr / M-Pesa for delivery; pay_at_branch pickup-only. Ecom v1 often offline confirm

Guest limits (proposed): valid phone; controlled SKUs still need approved Rx; no loyalty earn until claim/merge — TBD claim-by-OTP (Admin Q9–10).

2.5 Prescriptions + dosing schedule

Layer Contract
Admin line item frequency?: QD|BID|TID|QID|QXH|custom; intervalHours? (QXH); times?: HH:mm[]
Mob reminders POST /health/reminders with times[], grace, escalate; calendar UI; confirm/snooze
Sync intent Persist pharmacist final times (+ interval) on approve/dispense so Mob can seed reminders without re-derive — when to push still open (Admin Q13)
Customer Rx Care Mob/Ecom upload + prescriptions/check stock match statuses
B2B Member submits Rx; HR/Finance never see clinical lines

Admin helper: src/lib/dosingSchedule.ts.

2.6 Catalog / Items + multi-UOM + storefront PDP

Concept Admin (source of truth for ops) Mob / Ecom (retail read model)
Master product /admin/catalog/items — Item with SKU, classification, media, EFDA, … /catalog/products (+ slug)
Stock link Inventory rows reference itemId /stock/product/:productId, branches nearby
Multi-UOM uoms[] + conversionFactor into stock baseUnit; toStockQty / fromStockQty Not yet on Mob product type — sell unit is display unit string only
PDP fields storefrontUnit, useCase, compareAtPriceEtb, side-effect lists, directions[], storageNotes[], pharmacistTip Mob PDP: product + getDrugFacts() clinical overlay (useCase, form, dosages, mild/severe, storage, directions, advice)
Pricing lists B2B price_list_id on org commercial Ecom/Mob show retail (and credit quote at checkout)

2.7 Stock

  • Branch qty, batch/lot, expiry on Stock, not Item.
  • ERP sync / field ownership / merge proposals: Admin Stock module.
  • Mob/Ecom: availability APIs only (no warehouse write).

2.8 Loyalty

Surface Role
Admin Marketing Config, ledger, activities, CRM points adjust, liability KPI; POS earn
Mob / Ecom GET /loyalty/me, ledger, redeem; referrals (Ecom)
Guests No earn by default until registered claim
Rx/Controlled Catalogue auto-excludes loyalty eligibility (Admin)
B2B Pointer/summary only; retail owns full wallet UI

3. Auth provider matrix

Provider Admin (staff) Mob (customer) Ecom (customer) B2B (portal) Dispatch (rider) Doctor
Google POST /auth/staff/oauth/google (ID token); mock UI POST /auth/oauth/google OTP-first sheet; Google TBD in older Ecom auth § UI mock → demo session; .../oauth/google/start planned — TBD (Admin Q17)
Email Password POST /auth/staff/login POST /auth/email/login (+ optional register) Magic-link sketched Magic/OTP planned; demo persona login today — Email/invite primary (/auth/doctor/login)
Phone OTP phone/start + phone/verify otp/request + otp/verify (primary demo) otp/request + otp/verify SMS OTP planned — TBD
Telegram Login Widget → POST /auth/staff/telegram POST /auth/oauth/telegram Telegram Mini App POST /telegram/auth sketched Widget/Mini App callback planned Telegram user id enrollment (identity) Not primary
Guest N/A (staff always auth); guest customers on orders POST /auth/guest + guest-codes Guest checkout by phone N/A (org membership) N/A Creates guest patients
Biometric — Bind device key (Mob) — — — —

Path naming diverges (/auth/staff/* vs /auth/otp/* vs /v1/auth/*) — consolidation TBD; shared authProvider enum values should stay aligned.

Env (Admin SPA): VITE_GOOGLE_CLIENT_ID, VITE_TELEGRAM_BOT_USERNAME (empty = mock UX). Server-only: bot token, OTP gateway, Google audience.


4. Divergence & sync notes

Accurate as of 2026-08-08 skim. Prefer fixing sheets over inventing a third truth here.

Topic Divergence Sync action
API base host Some sheets still use api.gishen.example; B2B + Admin alignment prefer api.gishenpharmacy.org Pick one production host
Money Resolved default: { amount: "1250.00", currency: "ETB" } decimal major units (B2B + Admin master). Ecom open Q should close to match; Admin UI may keep numeric helpers synced from commercial Done for Admin/B2B; close Ecom
Auth path prefixes Staff /auth/staff/*, Mob /auth/otp/*, B2B /v1/auth/* Shared IdP façade TBD
Org status naming Admin mocks/UI now use pending_activation (was bare pending); activate (was /approve) Keep Admin + B2B sheets in sync
Guest orders Admin: staff/doctor customerType=guest; Mob/Ecom: guest session + GSH-XXXX codes Document both flows; Admin POS by-code must match Mob code shape
Guest Admin endpoints Mob lists GET /admin/orders/by-code/:code Ensure Admin sheet mirrors when POS wire-up lands
Rx dosing Admin structured frequency/times; Mob reminders separate resource On approve, map Admin times → /health/reminders seed
Catalogue ID Admin Item / itemId; retail productId / slug Mapping table or shared SKU key
Multi-UOM Admin full uoms[]; Mob/Ecom display unit string only Expose sales UOM on catalog DTO when POS/cart need conversion
PDP clinical Admin stores PDP fields on Item; Mob still derives much from clinical.ts overrides Prefer catalogue PDP fields once API live; keep Mob overrides as fallback
Loyalty paths Aligned idea (/loyalty/me); Admin config under /admin/loyalty/* OK
Org types Admin hospital/clinic for doctors + B2B commercial orgs Keep OrganisationType shared
Roles naming Admin snake staff roles; B2B HR_ADMIN SCREAMING; Ecom older pharmacy_staff names Map in backend claims; don't rename UI mid-flight without sheet sync
Rider auth Dispatch: Telegram enrollment; Ecom older Flutter rider JWT sketch superseded for v1 Prefer Dispatch sheet
Mini App Ecom documents endpoints; Mini App folder empty Implement or mark out of scope
Doctor in B2B Not a B2B portal role today Open: doctor realm vs hospital org user

Admin (this repo)

Doc Purpose
docs/admin-backend-spec.md Living Admin API/UI contract (primary depth)
README.md Runbook, demo accounts, deploy
src/lib/dosingSchedule.ts Frequency → default times helpers
src/config/navigation.ts Page registry

Mob

Doc Purpose
Gishen-Mob/docs/BACKEND_SPEC.md Customer mobile API sheet
Gishen-Mob/README.md Expo run + demo OTP
UI anchors app/(root)/auth/*, ...(screens)/product/[id].tsx, prescription/*, checkout.tsx

Ecom

Doc Purpose
Gishen-Ecom/docs/backend.md Storefront + platform API proposal
Gishen-Ecom/README.md Product proposal / demo
Gishen-Ecom/docs/README.md Docs index

B2B

Doc Purpose
Gishen-B2B/docs/README.md Standing rule + layout
Gishen-B2B/docs/backend/OVERVIEW.md Tenancy, RBAC, clinical withhold
Gishen-B2B/docs/backend/entities/ · endpoints/ Model + REST
Gishen-B2B/docs/coordination/gishen-admin.md Admin ↔ B2B events
Gishen-B2B/docs/coordination/gishen-ecom.md Checkout entitlement split
Gishen-B2B/docs/coordination/open-items.md Cross-repo decisions
Gishen-B2B/docs/features/INDEX.md Feature → pages map
Doc Purpose
Gishen-Dispatch-Bot/docs/BACKEND_SPEC.md Rider Telegram events / trips
Gishen-Dispatch-Bot/docs/FEATURE_BRIEF.md Acceptance inventory

6. Cross-cutting open items (rolled up)

Do not invent APIs here — track decisions:

  1. Unify API host + money units (cents vs major ETB).
  2. Shared auth façade for Google / Email / Phone / Telegram across actors.
  3. Guest order claim by phone OTP + PII retention.
  4. Checkout entitlement-split owner (B2B recommends Ecom + shared calc).
  5. Doctor IdP (dedicated realm vs hospital B2B user).
  6. Multi-UOM ownership ERP vs Platform.
  7. When Rx times fan out to Mob reminders.
  8. Telegram Mini App scope vs empty repo.
  9. Admin ↔ Mob by-code / POS scan contract end-to-end.

Admin-local list: admin-backend-spec.md § Open questions.
B2B cross-repo: Gishen-B2B/docs/coordination/open-items.md.


Pre-push tooling

Committed in Gishen-Admin only:

Piece Path Behavior
Cursor rule .cursor/rules/update-master-spec-before-push.mdc Agents must refresh this master (and Admin sheet if needed) before push
Reminder script scripts/sync-master-spec-reminder.sh Prints Sources checklist + whether master looks stale vs src/ / Admin sheet
Git hook .githooks/pre-push Warns loudly if significant paths changed since last push while master was not updated; does not call LLMs. Soft warn by default (GISHEN_MASTER_SPEC_STRICT=1 to exit 1)
Enable hooks scripts/setup-githooks.sh Sets local core.hooksPath=.githooks for this repo only
# One-time per clone (optional but recommended)
bash scripts/setup-githooks.sh

# Manual check anytime
bash scripts/sync-master-spec-reminder.sh

Do not silently rewrite global git config. Local core.hooksPath for this repository is intentional and reversible (git config --unset core.hooksPath).