Files
sankofa-hw-infra/docs/vendor-portal.md

50 lines
2.3 KiB
Markdown
Raw Normal View History

# Vendor portal and vendor users
Selected vendors can log in to assist in fulfilling needs: view and update their offers, and see purchase orders relevant to them.
## Model
- **Vendor user:** A user record with `vendor_id` set is a *vendor user*. That user can be assigned the role `vendor_user` and receive a JWT that includes `vendorId` in the payload.
- **Scoping:** When the API sees `req.user.vendorId`, it restricts:
- **Vendors:** List returns only that vendor; GET/PATCH/DELETE only for that vendor; POST (create vendor) is forbidden.
- **Offers:** List/GET/PATCH/DELETE only offers for that vendor; on create, `vendorId` is forced to the logged-in vendor.
- **Purchase orders:** List/GET only POs for that vendor.
## Onboarding a vendor user
1. Create or select a **Vendor** in the org (e.g. "The Server Store", "Sergio's Hardware").
2. Create a **User** with:
- `org_id` = same as org
- `vendor_id` = that vendor's ID
- `email` / `name` as needed
3. Assign the role **vendor_user** to that user (via your IdP or `user_roles` if you manage roles in-app).
4. At **login**, ensure the issued JWT includes:
- `roles`: e.g. `["vendor_user"]`
- `vendorId`: the vendor's UUID
Then the vendor can call the same API under `/api/v1` with that JWT (and `x-org-id`). They will only see and modify data for their vendor.
## Permissions for vendor_user
The role `vendor_user` has:
- `vendor:read_own` read own vendor
- `vendor:write_offers_own` create/update own offers
- `vendor:view_pos_own` view POs for their vendor
- `offers:read`, `offers:write` used in combination with `vendorId` scoping above
- `purchase_orders:read` used with vendor filter
Vendor users cannot create/update/delete vendor records, nor see other vendors' offers or POs.
## API surface (vendor portal)
Vendor users use the same endpoints as procurement, with automatic scoping:
- **GET /api/v1/vendors** Returns only their vendor.
- **GET /api/v1/vendors/:id** Allowed only when `:id` is their vendor.
- **GET/POST/PATCH/DELETE /api/v1/offers** Only their vendor's offers; POST forces their vendorId.
- **GET /api/v1/purchase-orders** Only POs where vendorId is their vendor.
- **GET /api/v1/purchase-orders/:id** Allowed only for POs of their vendor.
No changes to URLs or request bodies are required; scoping is derived from the JWT `vendorId`.