# Feature: Members & onboarding Employee and dependant enrolment — CRUD, quick import, invites, join codes, offboarding. **Workspace:** `/Users/kirukib/Desktop/Yaltopia Project/Gishen-B2B` ## Pages | Route | Purpose | |-------|---------| | `/members` | Searchable/filterable member list | | `/members/new` | Invite / create employee (department + package) | | `/members/import` | Quick Excel/CSV import | | `/members/[id]` | Member detail — profile, package, dependants, pharmacy ID card, offboard | | `/join` | Self-join via join code or email domain | | `/invite/[token]` | Accept invite and set password | ## Entities - [`Member`](../backend/entities/member.md) ## Endpoints - [`members.md`](../backend/endpoints/members.md) ## Capabilities | Action | Roles | |--------|-------| | List / search | SUPER_USER, HR_ADMIN, FINANCE (metadata) | | Create / edit | SUPER_USER, HR_ADMIN | | Quick import | SUPER_USER, HR_ADMIN | | Send/resend invite | SUPER_USER, HR_ADMIN | | Add dependant | SUPER_USER, HR_ADMIN | | Offboard | SUPER_USER, HR_ADMIN | | Self-join | Public (join code / domain) | | Accept invite | Public | ## Member lifecycle ``` invited → active → inactive | offboarded ``` Offboarding sets `end_date`; prescriptions remain on `customer_id` (portable). ## Dependants - Linked via `primary_member_id` - Subject to org `dependant_limit` - Share primary's package by default; overrides optional ## Join rules (org-level) Configured on `/organisation`: - Join code (e.g. `ACME-2026`) - Allowed email domains - Optional expiry ## Quick import vs migration | Path | Use case | |------|----------| | `/members/import` | Small ad-hoc batch | | `/migration` | Full onboarding with mapping profiles | Both use shared validation engine — see [migration.md](migration.md). ## Validation / errors | Scenario | Code | |----------|------| | Duplicate phone in org | `DUPLICATE_MEMBER` | | Duplicate employee_id | `DUPLICATE_MEMBER` | | Dependant limit exceeded | `DEPENDANT_LIMIT_EXCEEDED` | | Org pending | `ORG_PENDING` | | Invite expired | `INVITE_EXPIRED` | ## Clinical withhold Member list/detail for HR/Finance shows: - Name, contact, employee ID, department, package, status - Allowance summary (amounts) - `prescription_count` (integer only) - Pharmacy verification ID / printable ID card (employee verification — not clinical) No prescription list, images, or medicine detail. SUPER_USER sees full member record including Rx summary link. ## Pharmacy ID card Printable employee badge on `/members/[id]` → **ID card** tab (SUPER_USER, HR_ADMIN; MEMBER for own record). | Field | Source | |-------|--------| | Photo | `avatar_url` (demo: deterministic DiceBear) | | Full name | Member name | | Employee ID | `employee_id` | | Card ID | `card_id` (e.g. `GSH-1001`) | | Verification ID | `verification_id` | | Package / status | Assigned plan + member status | | Org | Trade name + join code hint | **QR scan payload** (pharmacist): ``` gishen://member/{memberId}?v={verificationId} ``` Print uses `window.print()` with `@media print` CSS that isolates `#member-id-card-print` at credit-card size (85.6 × 54 mm). ## Profile pictures Optional `avatar_url` on Member and SessionUser. List, detail rail, `/profile`, topbar chip, and login demo personas show avatars with initials fallback. ## UI components - DataTable with toolbar (search, status filter, department filter) - Detail layout: profile card, package assignment, dependants tab, ID card tab, offboard dialog - Import dropzone with template download - Invite link copy + resend ## Related - [packages.md](packages.md) — package assignment - [member-experience.md](member-experience.md) — member portal after enrolment