# Backend overview Living spec for the **shared platform API** consumed by Gishen-B2B. This repo implements mocks typed to this contract; the backend service is consolidated later from B2B, Ecom, Mobile, and Admin spec sheets. **Workspace:** `/Users/kirukib/Desktop/Yaltopia Project/Gishen-B2B` ## Base URL (future) ``` https://api.gishenpharmacy.org/v1 ``` Mock adapters in this repo live under `src/lib/api/` and `src/mocks/`. ## Tenancy - Every authenticated request (except public registration) is scoped to an **organisation** via `orgId` on the session or explicit path prefix. - Org lifecycle: `pending_activation` → `active` → `suspended` | `closed`. - Pending orgs: SUPER_USER may read status and submitted registration; **cannot** create members, packages, or migration commits until Admin activates. ``` X-Org-Id: org_01H... ``` For single-org sessions, `orgId` is implicit from JWT/session. Multi-org users (rare in B2B) pass `X-Org-Id`. ## Authentication | Mode (this phase) | Description | |-------------------|-------------| | Mock demo | `/login` role selector sets session cookie with role + org + user | | Production (future) | OAuth2 / magic link / SSO — TBD with platform auth | ### Session shape See [`entities/session-user.md`](entities/session-user.md). ### JWT claims (future) ```json { "sub": "usr_01H...", "org_id": "org_01H...", "roles": ["HR_ADMIN", "FINANCE"], "locale": "am", "iat": 1710000000, "exp": 1710003600 } ``` ## RBAC matrix | Resource / action | SUPER_USER | HR_ADMIN | FINANCE | MEMBER | |-------------------|:----------:|:--------:|:-------:|:------:| | Org profile (commercial read) | ✓ | ✓ (active only) | ✓ (active only) | — | | Org registration submit | ✓ (public path) | — | — | — | | Departments CRUD | ✓ | ✓ | read | — | | Members CRUD / import / invite | ✓ | ✓ | read metadata | own row | | Packages CRUD | ✓ | ✓ | read | own assignment | | Migration jobs | ✓ | ✓ | read history | — | | Finance spend / statements | ✓ | read aggregates | ✓ | — | | Finance approvals | ✓ | — | ✓ | — | | Member allowance / orders | ✓ | — | — | ✓ | | Prescriptions (clinical) | ✓ full | **withheld** | **withheld** | own only | | Settings / verification | ✓ | ✓ | — | — | **Clinical withhold:** HR_ADMIN and FINANCE never receive prescription images, medicine line items, dosages, prescriber notes, or diagnosis-related fields. Aggregates (e.g. “Rx order — ETB 450, category: chronic”) may appear in finance spend. SUPER_USER bypasses withhold for support/disputes. ## Error model All errors return: ```json { "error": { "code": "VALIDATION_FAILED", "message": "Human-readable summary", "details": [ { "field": "email", "code": "INVALID_FORMAT", "message": "..." } ], "request_id": "req_01H..." } } ``` ### Standard HTTP status codes | Status | Usage | |--------|-------| | 400 | Validation failed, malformed JSON | | 401 | Missing or expired session | | 403 | Authenticated but role/org forbids action; clinical withhold | | 404 | Resource not found or not visible in tenant | | 409 | Conflict (duplicate member, job already committed) | | 422 | Business rule violation (org pending, credit exceeded) | | 429 | Rate limit | | 500 | Internal error | ### Error codes (catalog) | Code | HTTP | Description | |------|------|-------------| | `UNAUTHENTICATED` | 401 | No valid session | | `FORBIDDEN` | 403 | Role cannot perform action | | `CLINICAL_WITHHELD` | 403 | Clinical field requested by HR/Finance | | `ORG_PENDING` | 422 | Org not yet activated by Admin | | `ORG_SUSPENDED` | 422 | Org suspended | | `VALIDATION_FAILED` | 400 | Field-level validation | | `DUPLICATE_MEMBER` | 409 | Phone/email/employee_id conflict | | `CREDIT_LIMIT_EXCEEDED` | 422 | Would exceed org credit | | `MIGRATION_JOB_LOCKED` | 409 | Job already committed or rolled back | | `INVITE_EXPIRED` | 422 | Invite token expired | | `NOT_FOUND` | 404 | Generic not found | ## Pagination List endpoints accept: ``` ?page=1&page_size=25&sort=-created_at&q=search ``` Response envelope: ```json { "data": [ ... ], "pagination": { "page": 1, "page_size": 25, "total_items": 142, "total_pages": 6 } } ``` Default `page_size`: 25. Max: 100. ## Filtering & date ranges Finance and spend endpoints accept: ``` ?from=2026-01-01&to=2026-01-31&department_id=dept_01H... ``` ISO 8601 dates in org timezone (default `Africa/Addis_Ababa`). ## File uploads Multipart for Rx images and migration files: ``` POST /v1/... Content-Type: multipart/form-data ``` Max file size (Rx page): 10 MB. Accepted: `image/jpeg`, `image/png`, `application/pdf`. Migration uploads: 50 MB `.xlsx`, `.xls`, `.csv`. ## Idempotency Mutating endpoints that create billing or migration commits accept: ``` Idempotency-Key: ``` Duplicate keys within 24h return the original response. ## Webhooks / events Domain events published to platform bus; see [`events/README.md`](events/README.md). B2B emits and consumes events for org registration, migration, and prescriptions. ## Environment (Vercel frontend) | Variable | Purpose | |----------|---------| | `NEXT_PUBLIC_API_BASE_URL` | Platform API base (mock or real) | | `NEXT_PUBLIC_MOCK_AUTH` | `true` for demo role selector | | `NEXT_PUBLIC_DEFAULT_LOCALE` | `en` | Document production URL in this file when first Vercel deploy is finalized. ## Related docs - [Entities index](entities/README.md) - [Endpoints index](endpoints/README.md) - [Events](events/README.md) - [Features INDEX](../features/INDEX.md)