# Balinyaar — Business Requirements > **Purpose.** This document specifies the business requirements for **Balinyaar**, an MVP home-nursing marketplace in Iran where independent, individually-verified nurses list configurable services, families search and request a nurse, the nurse accepts, the family pays *through* the platform, the platform holds the money as an internal escrow ledger state, the nurse performs one or more visits with Electronic Visit Verification (EVV) check-in/out, and the platform pays the nurse weekly minus a commission. It is grounded in the verified payment/settlement research, the adversarial fact-checks, the database-model critiques, and the market/legal/verification research. It is written to be an MVP that is decisive but **not naive** about Iranian payment law, tax, and the realities of caring for vulnerable people at home. All monetary values are in **IRR (Rials)**; Toman is a display concern only and is converted to/from Rials solely at an external provider's API boundary. **Date:** 2026-06-20 --- ## How to read this document Each section covers one business area and states, in order: - **(a) Business requirements** — what the platform must do. - **(b) Iran-specific considerations** — the local legal, fiscal, cultural, and infrastructural realities that shape the requirement. - **(c) MVP vs DEFERRED** — an explicit callout of what ships at launch and what is intentionally postponed. - **(d) Supporting database entities** — the entities (using the final names from the refined data model) that implement the requirement. **Cross-cutting ground truths (true in every section):** 1. **Balinyaar cannot legally custody customer cash.** Under Iranian rules a پرداخت‌یار (payment facilitator) is forbidden from holding deposits, running wallets, or moving money between merchants. Money always flows card → licensed PSP → Shaparak settlement → **bank-registered IBANs**. "Escrow" is therefore an **internal ledger state** over funds custodied at a licensed provider/partner bank — never a Balinyaar-owned cash balance. (`ledger_entries`) 2. **VAT is 10%**, not 9% — it rose from 9% to 10% in 1403 (7% government + 3% municipal) and is treated as a configurable rate. 3. **BNPL is full-upfront.** A BNPL provider settles **one full-amount lump (net of its commission) to the merchant-of-record**, bears 100% of customer-default risk, and owns the customer's installment repayment entirely. A BNPL order behaves in Balinyaar's books exactly like a card payment landing net-of-fee. (`bnpl_transactions`) 4. **The nurse is paid by Balinyaar, weekly, on Balinyaar's own schedule** — gated on EVV completion and a closed dispute window — regardless of how the family paid. --- ## 1. Actors & Onboarding ### (a) Business requirements - Three actor types: **customer** (the family member / payer), **nurse** (the independent caregiver / seller), and **admin** (Balinyaar back-office staff: support, finance, moderation, super-admin). - **Phone number is the primary login credential.** Authentication is **phone-OTP** (one-time code by SMS). Email is optional/secondary (required only for admin accounts). - The **patient** (care recipient) is a first-class entity distinct from the customer, because the payer (an adult child, a spouse) is frequently not the patient (an elderly parent, a newborn, a post-surgical adult). A customer may register multiple patients. - **KYC timing is role- and risk-staged, not up-front-for-everyone:** - A **customer** can register and browse with only a verified phone (OTP). National-ID KYC for customers is anti-fraud only and is **deferred** at launch. - A **nurse** must complete the full verification pipeline (Section 2) before any of their service variants become bookable. `national_id` is populated only after the identity step passes. - An **admin** is provisioned internally with RBAC roles. - Each successful login creates a refresh-token session that can be revoked (logout, stolen-token detection). ### (b) Iran-specific considerations - Phone-OTP is the dominant Iranian login norm and is also the anchor for **Shahkar** SIM↔national-ID binding (Section 2). - Storing `national_id` only post-KYC matches the reality that identity is verified through gated vendor APIs, not collected casually at signup. - Cultural reality: the booking flow must let a family member act on behalf of a patient who cannot self-advocate (infant, dementia, post-anesthesia). The customer/patient split is essential, not cosmetic. ### (c) MVP vs DEFERRED - **MVP:** phone-OTP login; customer/nurse/admin roles; customer→patient (1:N); session management; admin RBAC; nurse onboarding gated on verification. - **DEFERRED:** customer national-ID KYC (`customer_profiles.national_id_verified_at` exists but is optional/unused at launch); push notifications; social login; nursing-company (organization) self-onboarding. ### (d) Supporting database entities `users`, `user_sessions`, `roles`, `user_roles`, `nurse_profiles`, `customer_profiles`, `patients`, `customer_addresses`. --- ## 2. Nurse Verification & Credentials ### (a) Business requirements Verified trust is the **entire brand**. Vetting is **platform-owned, non-optional, and performed at the authoritative source** — never delegated to families, and never marketed as a check the platform does not actually perform. A nurse is bookable only after all *required* verification steps pass. The pipeline is **data-driven**: the set of steps lives as rows in `verification_step_types` (not a code enum), so a new regulatory requirement (e.g., professional liability insurance) is one INSERT, not a migration. Each step can be **automated** (a KYC vendor API call) or **manual** (admin reviews an uploaded document). The aggregate `nurse_verifications` record rolls the step outcomes into a single status; `nurse_profiles.is_verified` flips to true **only inside the same transaction** that confirms every required step is `passed`. The verification steps: 1. **Identity (KYC) — automated.** Match person ↔ کد ملی (national ID) ↔ phone ↔ face via one Iranian KYC vendor: national-ID validity/name match + photo/video **liveness** against the national-card / civil-registry (ثبت احوال) photo. Binds the profile to a real identity and a liveness selfie to defeat the stolen-identity / alias fraud pattern. 2. **Shahkar phone↔national-id binding — automated.** Confirm the login SIM is registered to the nurse's own کد ملی. The binding result (when, which vendor, the reference) is recorded, and **re-verification is triggered on phone change**. The shared-SIM failure mode (a SIM owned by a family member) is an explicit, handled state, not an undefined edge case. 3. **MoH پروانه صلاحیت حرفه‌ای (professional-competency license) — the single most important credential.** It is the MoH-mandated license for in-home nursing and **already bundles the criminal-record (سوء پیشینه) screen** plus scientific/ethical/health vetting. Verified against the MoH source (Rn.behdasht.gov.ir). No public B2B API exists, so the realistic method at launch is **nurse-uploaded document + manual admin verification against the official record**. 4. **نظام پرستاری (Iranian Nursing Organization / INO) membership — cross-check.** The INO membership number is captured and cross-checked (ino.ir) as a second source. Manual at launch. 5. **عدم سوء پیشینه (criminal-record certificate).** Consent-gated to the individual (obtained by the nurse via adliran.ir / their own ثنا password); **no company/employer API exists**. The nurse uploads it; it is **time-limited** — on expiry the step reverts to pending and a support alert is raised. Partly covered already by credential #3. 6. **IBAN ownership verification.** The payout IBAN (Sheba) must be proven to belong to the verified nurse — the account-holder national ID must equal the verified nurse national ID. Done via automated IBAN-ownership inquiry (استعلام شبا) where available, gating the **first payout**, not merely an admin eyeballing the number. Prevents paying a nurse's earnings into a third party's account (money-mule risk). **Structured credential registry.** Beyond opaque uploaded files, the actual license **numbers**, issuing authority, holder-name-as-printed, and issue/expiry dates are stored as typed, queryable rows in `nurse_credentials`. This powers renewal/expiry alerts, the public "verified" trust badge, cross-checking against official portals, and audit defensibility — and survives the future arrival of an MoH/INO API. **Continuous monitoring**, not one-and-done: license validity and the criminal-record certificate are periodically re-verified; Shahkar is re-run on phone change. Expiring credentials raise `support_alerts`. ### (b) Iran-specific considerations - The license layer is **fragmented across regulators** (MoH vs INO) and has **no public B2B API** — manual verification against the official portal is the realistic MVP method; the structured registry makes that defensible and renewable. - The criminal-record check is **consent-gated to the person** and cannot be pulled by a company — hence nurse-uploaded + re-requested periodically, leaning on the MoH license which already embeds it. - Identity (Shahkar, liveness, national-ID match) is the **easy** layer because a competitive market of Iranian e-KYC vendors (Finnotech, U-ID, Jibbit, Farashensa, Verify, Kavoshak) already holds the regulator-gated upstream agreements. **Buy this, don't build it.** - Document forgery is the documented attack (the "imposter nurse" pattern): verify at source, bind to national ID + liveness, never trust an uploaded PDF alone. ### (c) MVP vs DEFERRED - **MVP:** all six steps; data-driven `verification_step_types`; structured `nurse_credentials` registry; manual MoH/INO verification; nurse-uploaded عدم سوء پیشینه with expiry; automated identity + Shahkar + IBAN-ownership via one KYC vendor; expiry-driven re-verification alerts; transactional `is_verified`. - **DEFERRED:** automated MoH/INO license lookup (pending a B2B API); ML-driven fraud scoring (`fraud_flags` is modeled but inactive); professional-liability-insurance step (addable as a row when required). ### (d) Supporting database entities `nurse_verifications`, `verification_step_types`, `verification_steps`, `verification_documents`, **`nurse_credentials`** (structured license registry), `nurse_bank_accounts` (IBAN ownership), `support_alerts` (expiry/renewal), `audit_logs`. --- ## 3. Service Catalog & Pricing ### (a) Business requirements - **Admin defines the catalog skeleton:** top-level **service categories** (e.g., مراقبت از سالمند / Elderly Care, مراقبت پس از جراحی / Post-Surgery Recovery, مراقبت از نوزاد / Infant Care, مدیریت بیماری مزمن / Chronic Illness Management) and **configurable option dimensions** as admin-managed **option groups** (e.g., تعداد بیمار / patient count, نوع شیفت / shift type) each with concrete **option values** (e.g., ۱ نفر, ۲ نفر, شبانه‌روزی). Admin can add new dimensions without a schema change. - **Each nurse defines their own offerings as variants.** A **variant** is the atomic bookable unit: a category + a chosen combination of option values + the nurse's **own price** and **price unit**. A nurse may have many variants per category, one per combination they choose to offer and price independently. - **Price units** must support the real shapes of home nursing: `per_hour`, `per_session`, `per_half_day`, `per_day`, and `per_24h` (شبانه‌روزی / live-in). For hourly variants an estimated duration helps the customer estimate total cost. - The variant `display_name` auto-generates from option labels but is nurse-editable. Nurses can deactivate (not delete) a variant; deactivated variants cannot be booked. - Catalog and prices are **snapshotted onto the booking** at booking time (`variant_snapshot_json`) so historical records survive later edits. ### (b) Iran-specific considerations - Iranian competitors sell exactly these shapes — hourly / daily / 24-hour (شبانه‌روزی) shifts and multi-day packages — so `per_24h` and `per_day` are first-class, not edge cases. - Competitor pricing is opaque and "توافقی" (negotiable); **transparent, upfront, nurse-set pricing is a deliberate differentiator** families value. - All catalog tables carry `name_fa` / `name_en` pairs (Persian primary). ### (c) MVP vs DEFERRED - **MVP:** admin categories + option groups/values; nurse variants with own price + price unit across all five units; activate/deactivate; snapshotting. - **DEFERRED:** holiday/surge pricing rules; a lighter "companionship / daily-living" tier (modeled as a future category); dynamic/tiered commission per category. ### (d) Supporting database entities `service_categories`, `service_option_groups`, `service_option_values`, `nurse_service_variants` (carries `price`, `price_unit`), `nurse_service_variant_options`. --- ## 4. Search & Matching ### (a) Business requirements - Families search by **service category**, **geography** (city, and optionally district), price, and availability, with results sortable by rating. - **Geography** is driven by nurse-declared **service areas**: a nurse covers one or more cities, optionally specific districts; a city-level row (no district) means the whole city. - **Search must be cheap from day one.** The naive query joins nurse profile (verified + accepting) → variants (category/price) → variant options → service areas → rating across 4+ tables. Instead a **denormalized `nurse_search_index`** holds one flat row per active, bookable variant with all search-relevant fields, maintained on write. A row exists **only** when the nurse is `is_verified` and not suspended and the variant `is_active`. This is far cheaper than introducing Elasticsearch at MVP stage. - **Same-gender caregiver matching** is a first-class filter and a near-hard requirement: in Iranian bodily-care (bathing, toileting, intimate post-surgical care) same-gender caregiving is culturally decisive, not optional. The customer specifies a required caregiver gender on the booking request (`required_caregiver_gender`), and nurse gender is an exposed search filter so families can narrow to same-gender caregivers up front. The patient's gender (`patients.gender`) and the nurse's gender support this matching. ### (b) Iran-specific considerations - District granularity varies: in Tehran, districts map to the 22 official municipal مناطق; in smaller cities they are major neighborhoods. Districts are optional. - **Same-gender matching is the single most Iran-specific matching constraint** — every real elder/post-surgical bodily-care request implies it. It must be surfaced before booking, not discovered after. - White-space opportunity: incumbents concentrate ~99% in Tehran/Karaj; the search/area model must work for under-served second-tier cities (Mashhad, Isfahan, Shiraz, Tabriz, Ahvaz, Qom). ### (c) MVP vs DEFERRED - **MVP:** category + city/district geo search; `nurse_search_index` denormalization; same-gender filter via `required_caregiver_gender`; rating sort. - **DEFERRED:** map-based discovery; availability-window filtering as a hard constraint (availability slots are soft guidance at launch); algorithmic ranking beyond rating; continuity-of-carer "preferred nurse" suggestions. ### (d) Supporting database entities `nurse_service_areas`, `cities`, `districts`, **`nurse_search_index`**, `nurse_service_variants`, `nurse_profiles` (rating, gender via `users`), `patients.gender`; `booking_requests.required_caregiver_gender` (the requested constraint). --- ## 5. Booking & Scheduling ### (a) Business requirements The lifecycle has two phases separated into two tables so each table's invariants stay clean: a **request phase** (no money) and a **booking phase** (always implies captured payment). **Request → accept → pay → confirm lifecycle:** 1. Customer submits a **booking request** (nurse, patient, variant, address, date/time, requested caregiver gender, customer notes). Status `pending_nurse_response`. 2. The nurse must respond before a **response deadline** (`nurse_response_deadline_at`, computed from config and frozen on the request). The nurse **accepts** → `accepted_awaiting_payment`, or **rejects** → `rejected_by_nurse`, or the deadline passes → `expired_no_response`. 3. On accept, a **30-minute payment window** opens (`payment_deadline_at`). The customer pays within it → a `bookings` row is created (`confirmed`). If the window lapses → `payment_deadline_expired`. **Single-visit AND multi-session / long-duration engagements must both be representable.** Home nursing is frequently multi-visit: post-surgery daily visits for ten days, month-long nightly or شبانه‌روزی (24h live-in) care. A booking therefore carries a `session_count` and owns **N `booking_sessions`** (one row per scheduled visit), each with its own schedule, its own EVV check-in/out, and its own payout eligibility. A single EVV per booking cannot represent a multi-day engagement, so the engagement-to-session split is the core scheduling model. **Booking lifecycle:** `pending_payment` → `confirmed` (payment captured) → `in_progress` (first/relevant session check-in) → `completed` (sessions checked out) → optionally `disputed` → `closed`; or `cancelled` before service. Allowed transitions are guarded explicitly so the booking and EVV state machines cannot silently contradict. **Snapshots:** `variant_snapshot_json` and `address_snapshot_json` freeze the service and address at booking time. ### (b) Iran-specific considerations - Multi-session and شبانه‌روزی live-in care is the **dominant** elder-care shape in Iran, not a niche — modeling only single visits would fail to represent demand. - Heavy platform control over multi-visit scheduling **strengthens a worker-misclassification argument** under labor law; this is flagged for counsel, and the platform deliberately keeps the nurse's accept/reject autonomy per request. - Availability slots/exceptions are **soft guidance only** (informing search), not hard blocks — the nurse still individually accepts or rejects each request, which also fits the Shamsi week and holiday rhythm. ### (c) MVP vs DEFERRED - **MVP:** request→accept→pay→confirm lifecycle with response deadline + 30-min payment window; single-visit bookings; `booking_sessions` for multi-session/long-duration engagements with per-session EVV and payout; explicit status-transition guards; snapshots; soft availability slots/exceptions. - **DEFERRED:** open-ended recurring schedules (`recurring_booking_schedules` modeled, inactive — launch is all finite engagements); milestone/progress-payment UX beyond per-session accrual; hard availability-based booking blocks. ### (d) Supporting database entities `booking_requests` (carries `nurse_response_deadline_at`, `payment_deadline_at`, `required_caregiver_gender`), `bookings` (carries `session_count`, `dispute_window_ends_at`, fee split), **`booking_sessions`**, `booking_care_instructions`, `nurse_availability_slots`, `nurse_availability_exceptions`, `nurse_service_variants`, `patients`, `customer_addresses`. --- ## 6. EVV / Service Delivery ### (a) Business requirements - **Electronic Visit Verification (EVV)** is the authoritative record that a visit actually happened, for how long, and where. The nurse **clocks in and out via the app per session**, capturing GPS coordinates and timestamps. - An **address-match tolerance** check computes whether the nurse's GPS at check-in falls within an acceptable radius of the booking address (`evv_location_tolerance_meters`). A mismatch is **advisory** — it raises a support alert / review flag but does **not** auto-cancel; it does not silently block the visit. - If the nurse has not checked in by a configurable threshold after the scheduled start, a **no-show / late support alert** is created and the family is notified. - **Payout is gated on EVV completion.** A session/booking becomes payout-eligible only after EVV check-out **and** the dispute window has closed (Section 10). EVV completion is the trigger that lets the booking enter the next weekly payout batch; for a multi-session engagement, payout accrues per completed session. ### (b) Iran-specific considerations - EVV is the core operational-trust mitigation for **unobserved in-home care** of vulnerable patients who often cannot reliably report what happened (infants, dementia, post-anesthesia) — the platform compensates for unobservability with structured proof of service. - Releasing escrow against proof of service is also a financial-correctness requirement under the Iranian "hold then pay weekly" model — the platform must not pay a nurse for a visit that has no EVV evidence. ### (c) MVP vs DEFERRED - **MVP:** per-session GPS check-in/out, timestamps, address-match tolerance flag, no-show alerting, payout gated on EVV completion + closed dispute window. - **DEFERRED:** continuous geofencing during a live-in shift; supervisory tele-check-ins; family-visible live care logs; consented in-home cameras. ### (d) Supporting database entities `visit_verifications` (per session, with check-in/out GPS, timestamps, `check_in_address_match`, status), `booking_sessions`, `support_alerts` (no-show / location-mismatch), `platform_configs` (`evv_location_tolerance_meters`). --- ## 7. Cancellation & Refunds ### (a) Business requirements - Cancellation/refund rules are **tiered and structured**, not a single blunt "default 100%". The platform defines `cancellation_policies` tiers by **lead time** and **initiating actor**: - **Free** cancellation more than 24h before start. - **Partial** refund (e.g., 50%) under 24h. - **Customer no-show:** up to 100% charge. - **Nurse no-show:** full refund to the customer **and** a penalty/forfeiture for the nurse. - The **applicable policy is snapshotted onto the booking** at booking time (mirroring the per-booking fee-rate snapshot), so later policy edits never rewrite history. The **resolved** cancellation fee / refund percentage is recorded on the refund event. - For multi-session engagements, **cancellation is per remaining session:** cancelling mid-engagement refunds only the un-started sessions, while completed-and-verified sessions remain payout-eligible. - **Refunds are admin-only** — there is no customer self-service refund. A refund is initiated by an admin and **must be linked to a support ticket** (`tickets`) that holds the conversation and dispute evidence. - A refund **decomposes across the two fee legs** — how much of the platform commission and how much of the nurse payout is being reversed — because the booking gross is `platform commission + nurse payout`. ### (b) Iran-specific considerations - A flat percentage is too blunt for شبانه‌روزی live-in engagements and Iranian holiday-period bookings; tiered, snapshotted policy reduces dispute load. - **The refund money path depends on whether the nurse has already been paid** (Section 8/10): pre-payout it is a clean reversal; post-payout it becomes a platform-funded refund plus a nurse clawback, because an Iranian bank transfer to a nurse's IBAN is effectively irreversible. - For BNPL bookings, the refund **never** goes nurse→customer or Balinyaar→customer directly — it is initiated through the BNPL provider's revert/cancel API (Section 8/9). ### (c) MVP vs DEFERRED - **MVP:** tiered `cancellation_policies`; per-booking policy snapshot; admin-only, ticket-linked refunds; per-session cancellation for engagements; nurse-no-show vs customer-no-show handling; fee-leg decomposition on refunds. - **DEFERRED:** automated nurse no-show penalty (manual admin action at launch); self-service partial-refund UI; holiday-specific cancellation overrides. ### (d) Supporting database entities **`cancellation_policies`**, `bookings` (policy snapshot, `dispute_window_ends_at`), `refunds` (admin-only, `ticket_id`, fee-leg decomposition, `refund_channel`), `tickets`, `nurse_clawbacks` (post-payout case), `ledger_entries`. --- ## 8. Payments & Escrow ### (a) Business requirements - The family pays the **gross** booking price **through the platform** by card via a licensed PSP's IPG. The platform is the **merchant-of-record**; the payment lands net of provider/Shaparak fees. - **Escrow is an internal ledger state, not platform-held cash.** The platform models money state with a minimal **double-entry `ledger_entries`** ledger: each money event posts **balanced** legs grouped by a transaction group. Account types: `escrow_held`, `platform_revenue`, `nurse_payable`, `refund_payable`, `bnpl_fee_expense`, `nurse_clawback_receivable`. The ledger is the **single source of truth** for "how much is held," "how much do we owe nurses now," and "what is our commission income" — replacing fragile inference from scattered status booleans. - On a successful card payment: debit `escrow_held` (gross), credit `platform_revenue` (Balinyaar commission), credit `nurse_payable` (nurse payout). - **Settlement-sharing (تسهیم).** The compliant marketplace primitive is splitting one incoming card payment across multiple **registered IBANs** (the nurse's share and the platform's commission) at settlement, performed by Shaparak/the provider — the platform never touches the actual split. The internal ledger mirrors this split; the per-booking fee snapshot freezes it. - **Per-booking the three amounts are stored separately and never conflated:** `gross_price_irr` (what the customer is charged), `balinyaar_commission_irr` (platform's cut — drives the nurse payout), and (for BNPL) `bnpl_commission_irr` (the provider's merchant discount — a platform expense). `nurse_payout_amount = gross_price_irr − balinyaar_commission_irr`. - **Webhook idempotency is mandatory before money moves.** Every PSP/BNPL callback is stored raw and **deduplicated by a unique external event id** in `payment_webhook_events` before any money state mutates — preventing double-confirmed bookings and double-settlements from at-least-once, retried callbacks. - **Payment uniqueness:** at most one `succeeded` payment transaction per booking, and the Shaparak reference is unique — enforced so a retried success webhook cannot double-confirm. - **Multi-provider failover.** Provider settlement cut-offs are a real continuity risk (the Toman/Jibit Nov-2024 suspensions cut businesses off mid-cycle). The payment layer abstracts the provider behind configuration so a blocked provider can be swapped, and the reconciliation ledger survives a provider being cut off. ### (b) Iran-specific considerations - **The load-bearing legal constraint:** a پرداخت‌یار may **not** hold customer deposits, run wallets, or move money between merchants; the Shaparak ban on inter-merchant/inter-facilitator transfers means the "delay the تسهیم and redistribute later from a platform pool" pattern is regulatory grey-to-prohibited. The compliant posture is: collect via the provider, model escrow as an **internal ledger over funds custodied at the licensed provider/partner bank**, and pay out by provider-side settlement to **verified, registered nurse IBANs**. A bank-grade escrow product (e.g., Vandar میندو / معاملات امن) is the only true hold/release/refund mechanism, and its EVV-triggered hold is unverified — so the platform never assumes it can lawfully custody the cash itself. - **PSP received ≠ cash in bank.** Iranian PAYA settlement is cyclic (T+0/T+1, holiday-deferred), so the ledger separates a clearing/receivable state from settled cash, making bank reconciliation possible. - Toman/PSP units differ from internal Rials; convert only at the API boundary. Amounts are BIGINT IRR internally to avoid float/rounding bugs. ### (c) MVP vs DEFERRED - **MVP:** card payment via one licensed PSP; internal double-entry `ledger_entries` escrow; per-booking three-way amount split; تسهیم-style commission/nurse-share modeling; `payment_webhook_events` idempotency; single-succeeded-transaction-per-booking guard; provider abstraction for failover. - **DEFERRED:** a nurse-facing wallet with on-demand withdrawal (facilitator wallet prohibition risk); multiple simultaneous live PSPs at launch (abstraction is built, second provider added later); bank-grade EVV-triggered escrow product integration. ### (d) Supporting database entities `payment_gateways`, `payment_transactions` (unique Shaparak ref, single-succeeded-per-booking), **`payment_webhook_events`**, **`ledger_entries`**, `bookings` (`gross_price_irr`, `balinyaar_commission_irr`, `platform_fee_rate`, `nurse_payout_amount`), `refunds`, `nurse_bank_accounts` (verified registered IBANs). --- ## 9. Installments / BNPL ### (a) Business requirements - BNPL is offered as an alternative checkout. The decisive, verified model is **full-upfront settlement**: on approval the BNPL provider pays Balinyaar the **full booking amount in one lump, net of the provider's merchant commission**, and **bears 100% of customer-default risk**. The customer's interest-free installment repayment (typically a 4-installment plan) is **owned entirely by the provider** and is **decoupled** from Balinyaar's escrow/EVV/payout cycle. - **Therefore a BNPL order is, in Balinyaar's books, identical to a card payment that lands net-of-fee in one inbound settlement.** Balinyaar **does NOT track customer installments, per-installment webhooks, or default propagation** — that fragile subsystem is intentionally not built. - A BNPL order is recorded once as a single inbound settlement in `bnpl_transactions` (1:1 with a payment transaction), capturing the provider, the merchant-of-record (Balinyaar), the external payment token / transaction id, `order_amount_irr`, `settled_amount_irr` (net of provider commission), `bnpl_commission_irr`, currency (converted at the boundary), an idempotent status state-machine (`eligible`/`token_issued`/`verified`/`settled`/`reverted`/`cancelled`/`failed`), `installment_count` (informational, default 4), `settled_at`, and the revert fields. - **BNPL refunds flow only customer ↔ provider ↔ Balinyaar** — never nurse→customer or Balinyaar→customer directly. Balinyaar initiates the reversal via the provider's revert (full) / cancel/update (partial, new amount strictly lower) API using the stored token; the provider cancels the customer's unpaid installments, restores their credit, and refunds any already-paid installment to the customer's bank in ~7–10 business days (asynchronous, owned by the provider). The refund still decomposes across the platform-fee and nurse-payout legs in Balinyaar's ledger. - **The nurse's payout is unchanged by BNPL:** computed from `gross_price_irr − balinyaar_commission_irr`, paid weekly after EVV + dispute window — the provider's commission is a **platform cost of accepting BNPL** and is **never** passed through to the nurse. > **This is a summary. Deep BNPL provider mechanics, the exact revert/cancel/settle API flows, commission-as-config, settlement-timing nuances, and provider-specific behavior are specified in `payments-and-installments.md` — cross-reference it for implementation detail.** ### (b) Iran-specific considerations - Provider-financed Iranian BNPLs (SnappPay, Digipay, Tara, Torob Pay) are uniformly **full-upfront, provider-bears-risk, interest-free-to-customer**; only bank-financed POS loans (Lendo) charge the customer interest and are a poor fit for short, cancellable nursing visits. - **Settlement timing is contract-defined and may be gated on the customer's first installment** (daily / T+1-3 / weekly / 15-day) — "full amount" does not mean "instant cash." Timing is config + a per-transaction `settled_at`; weekly nurse payout may key off settlement actually received, never an assumption. - **Commission rate is per-contract and not public** (anecdotal 7–15% for SnappPay; Torob Pay's published 6.6%) — always a config field read from the actual settlement, never hardcoded. - Onboarding requires جواز کسب **and** اینماد for the Balinyaar/partner entity, and whether a multi-vendor re-disbursing marketplace qualifies as a single BNPL merchant is publicly undocumented — an ops/contracting task, not a schema dependency. ### (c) MVP vs DEFERRED - **MVP:** full-upfront BNPL via one provider modeled as a single inbound settlement (`bnpl_transactions`); provider-mediated revert/cancel refunds; nurse payout decoupled from BNPL; commission + settlement timing as config. - **DEFERRED:** customer installment tracking (`installment_entries` — **cut**, owned by the provider); tranched settlement (`bnpl_settlement_entries` modeled-only, added if a future provider tranches); multiple BNPL providers. ### (d) Supporting database entities **`bnpl_transactions`** (replaces the old `installment_plans`; the old `installment_entries` is cut), `payment_transactions`, `payment_webhook_events`, `refunds` (`refund_channel = 'bnpl_revert'`, `external_revert_reference`, `expected_customer_refund_eta`), `ledger_entries`. See `payments-and-installments.md`. --- ## 10. Payouts to Nurses ### (a) Business requirements - Nurses are paid in **weekly batches**. A batch aggregates the amounts owed for completed, payout-eligible bookings/sessions and produces one payout per nurse with earnings in that window. - **Payout eligibility is gated on EVV completion AND a closed dispute window.** A booking/session enters a batch only when `status = 'completed'` AND `dispute_window_ends_at < now()` (the dispute window is config-driven, default 72h post-completion). This deliberately prevents paying a nurse before a dispute can surface, shrinking clawback frequency — important because an Iranian bank transfer, once sent, is effectively irreversible. - The nurse payout amount derives from `gross_price_irr − balinyaar_commission_irr` (never from a BNPL provider's net settlement). - **Clawbacks** (`nurse_clawbacks`) handle the refund-after-payout case: if a booking is refunded/disputed **after** the nurse was already paid, a clawback receivable is recorded (negative ledger entry against the nurse) and recovered by **netting against the nurse's next weekly batch**, or written off if uncollectable. The nurse's payable balance is **derived from the ledger** (it may go negative), and a batch can net prior clawbacks (`gross_earnings`, `clawback_applied`, `net_amount`). - **Each booking is paid at most once** (the payout↔booking link is unique), preventing double-pay across batches. - **Bank-holiday-aware scheduling.** Payout period-end and processing dates are shifted off bank-closed days using a shared `iranian_holidays` calendar — a weekly payout landing on a multi-day Nowruz closure would otherwise fail, since PAYA/SATNA transfers do not settle on closed days. - Payouts go to the nurse's **verified, registered primary IBAN**, with the IBAN snapshotted and a transfer reference stored for reconciliation. Each payout item carries a unique track id + (for batches) a batch id. ### (b) Iran-specific considerations - Payouts are **real bank transfers to registered IBANs** (PAYA/SATNA cycles, next-business-day on holidays) — there is no chargeback-style reversal, which is *why* the dispute window must close before payout and why clawback is a netting/receivable mechanism rather than an automatic reversal. - Provider settlement cut-offs (Toman/Jibit) mean payout must tolerate a provider being unavailable mid-cycle; the batch + reconciliation references survive a swap. - Each nurse must have a Shahkar/KYC-verified, IBAN-ownership-checked account registered as a beneficiary before any payout targets it. ### (c) MVP vs DEFERRED - **MVP:** weekly batches; EVV + dispute-window gating; per-session accrual for engagements; `nurse_clawbacks` with next-batch netting and write-off; unique booking↔payout link; `iranian_holidays`-aware scheduling; verified-IBAN payouts with reconciliation references. - **DEFERRED:** on-demand / instant nurse withdrawal; per-nurse configurable payout frequency; automated clawback recovery beyond netting. ### (d) Supporting database entities `nurse_payout_batches`, `nurse_payouts` (with `gross_earnings_irr`, `clawback_applied_irr`, `net_amount_irr`, `iban_snapshot`), `nurse_payout_booking_links` (unique per booking), **`nurse_clawbacks`**, `ledger_entries`, **`iranian_holidays`**, `bookings.dispute_window_ends_at`, `nurse_bank_accounts`. --- ## 11. Reviews, Trust & Safety ### (a) Business requirements - A customer can leave **one review per completed booking** (rating 1–5 + free text), tied to a verified, completed, on-platform booking. - **Moderation:** reviews enter `pending_moderation` and are not public until approved by an admin (or an AI moderator). Aggregate nurse rating/counts are recomputed on **every** review status transition — publish, **hide**, reject, unpublish — so hiding a 1-star review never leaves a stale, inflated average. - **Low-rating alerting:** a rating at or below a configurable threshold (default ≤ 2) with negative content automatically raises a `support_alerts` row for the support team to investigate. - **Incident handling:** rapid-response protocols with immediate suspension on credible complaints; structured family check-ins and easy in-app concern flagging (the patient is not the sole information source); high-acuity cases routed only to appropriately verified nurses. ### (b) Iran-specific considerations - The buyers are **vulnerable people** cared for **unobserved at home**; a single incident can destroy a fragile, trust-first brand — so moderation, low-rating alerting, and immediate suspension are core, not optional. - Verified-trust is the brand; reviews must be bound to real completed bookings to resist fake-review fraud (gig-marketplace fraud is ~2× elsewhere, mostly impersonation). ### (c) MVP vs DEFERRED - **MVP:** one-per-completed-booking customer reviews; moderation with full recompute-on-every-transition; low-rating `support_alerts`; manual incident suspension. - **DEFERRED:** two-way (nurse-reviews-customer) double-blind reviews with timed reveal; structured review-tag aggregation (`review_tags_master` / `review_tag_links` modeled but a phase-2 nicety); a dedicated `incidents` entity; ML fraud scoring. ### (d) Supporting database entities `reviews` (moderation status, recompute triggers), `review_tags_master`, `review_tag_links`, `support_alerts` (low-rating, fraud-signal), `nurse_profiles` (denormalized aggregates), `audit_logs`. --- ## 12. Messaging & On-Site Emergencies ### (a) Business requirements - **There is no live chat and no direct nurse↔customer messaging.** All post-booking communication runs through a structured **ticket** system that admin can read in full. This is a deliberate **anti-disintermediation** and **patient-safety** design: it protects vulnerable patients, creates a dispute paper trail, and prevents families and nurses pairing off-platform. - A **booking-scoped coordination ticket** is auto-created so the nurse and customer can coordinate logistics (arrival time, room location) under admin visibility. Internal admin-only notes are supported and never shown to users. - Tickets also carry refund conversations and any support request, and are the mandatory anchor for admin refunds (Section 7). - **On-site emergency playbook.** The ticket system is async and has no real-time channel, so the operational playbook is explicit: **in an emergency (no answer at the door, a medical emergency), the nurse calls the emergency-contact number surfaced in the app, then opens a ticket.** The emergency contact number is surfaced prominently in the booking UI (drawn from encrypted care instructions), so a nurse never needs to find the family's number by other means (which would break the platform's communication control). ### (b) Iran-specific considerations - Disintermediation is the predictable failure mode of recurring, relationship-based care; the ticket-only model retains value (escrow, dispute protection, backup coverage, insurance that only applies on-platform) instead of relying on punitive lock-in. - For unobserved in-home care of patients who cannot self-report, the controlled-but-auditable communication channel plus a clear emergency escalation path is a safety requirement. ### (c) MVP vs DEFERRED - **MVP:** ticket-only messaging (admin-readable); auto-created booking-coordination ticket; internal notes; prominent in-app emergency contact + documented playbook. - **DEFERRED:** real-time chat; a first-class `incidents`/emergency-event entity with SLA; push/real-time alerting. ### (d) Supporting database entities `tickets`, `ticket_participants`, `ticket_messages`, `booking_care_instructions` (encrypted emergency contact), `support_alerts`. --- ## 13. Tax, Invoicing & Legal ### (a) Business requirements - **The nurse is the taxable seller of the nursing service; Balinyaar is the taxable seller only of its commission.** This mirrors the Snapp/Tapsi sharing-economy precedent: the nurse's fee is the nurse's income (the nurse files their own income tax — out of Balinyaar's scope), and Balinyaar's commission is the company's VAT-relevant revenue. - **VAT is 10%** (configurable), applied to Balinyaar's commission line. The home-nursing **service's** own VAT treatment is **unconfirmed** (medical services are commonly exempt) — so the VAT field is config-driven and can be 0/exempt, keeping the model correct whichever way the ruling lands. Confirm with an Iranian tax advisor before launch. - **سامانه مودیان (taxpayer system) readiness, minimal footprint.** The platform produces a minimal `invoices` record per booking capturing the gross, the platform commission, any BNPL commission, VAT, and a place for the مودیان reference fields (22-digit fiscal number, memory tax id, status) and PDF. The seller issues the invoice (the buyer cannot), so Balinyaar issues only its own **commission** invoice; it does not issue the nurse's service invoice. - **e-namad (نماد اعتماد الکترونیکی)** is de-facto mandatory: a monetized Iranian site needs e-namad to obtain an online payment gateway from PSP/Shaparak. It is held by the legal launch entity. - **Partner licensed-center (Asanism-style) as the launch legal vehicle.** Home nursing is a **licensed healthcare activity** (MoH establishment permit پروانه تأسیس + technical-director license پروانه مسئول فنی via the Article-20 commission), in the **home-nursing-services-center** track (a nurse with BSc + ≥5 yrs experience can found/direct it). The fast, legal go-to-market is to **partner with already-licensed centers** while Balinyaar's own permit is pending. A `partner_centers` entity represents the licensed center that holds the جواز کسب + اینماد + MoH license, sponsors nurses, and **may be the merchant-of-record / invoice issuer** for payments — making BNPL and online payment legally feasible without each nurse holding a license. ### (b) Iran-specific considerations - Operating **without** a permit is the real legal risk (penalty ladder up to permanent revocation + judicial referral). The partner-center vehicle is the launch-critical mechanism that makes the whole money flow legal. - مودیان obligation phases in by revenue thresholds; most individual nurses fall below mandatory thresholds early, but the **platform's commission line is VAT/e-invoice-relevant** — so per-nurse مودیان obligation is a configurable flag and the platform's own commission invoicing is the in-scope obligation. - The licensed center (not Balinyaar-the-tech-company, initially) is plausibly the IPG merchant-of-record and the invoice issuer — the data model represents this explicitly. ### (c) MVP vs DEFERRED - **MVP:** `partner_centers` as the launch legal vehicle with merchant-of-record flag and nurse sponsorship; minimal per-booking `invoices` with 10% configurable VAT on commission and مودیان reference fields; e-namad held by the launch entity; nurse-as-taxable-seller / platform-as-commission-seller split. - **DEFERRED:** full مودیان e-invoice automation / digital-signature pipeline; nurse-side service-invoice issuance on the nurse's behalf; insurer/B2B-payor invoicing; the future employer-style `organizations` model. ### (d) Supporting database entities **`invoices`** (minimal, commission-focused, مودیان fields, VAT), **`partner_centers`** (MoH license, اینماد, merchant-of-record), `nurse_profiles.partner_center_id`, `payment_transactions` (Shaparak reference for reconciliation), `platform_configs` (VAT rate, merchant-of-record). --- ## 14. Notifications & Admin / Backoffice ### (a) Business requirements - **In-app notifications** to all user types for booking, payment, payout, review, verification, and alert events. Carried as typed in-app records the front-end fetches on load and uses to deep-link to the relevant entity. **No push notifications at launch.** - A retention job hard-deletes read notifications older than 90 days to keep the table bounded. - **Admin / backoffice tooling** must cover the operational spine: - **Verification queue** — review uploaded MoH/INO/criminal-record documents, record structured credential numbers/expiries, pass/fail steps, and flip `is_verified` transactionally. - **Refund tooling** — initiate admin-only, ticket-linked refunds with tiered policy application and fee-leg decomposition; for BNPL, trigger the provider revert/cancel. - **Payout tooling** — initiate/inspect weekly batches, see eligibility (EVV + closed dispute window), apply clawback netting, schedule around bank holidays, and reconcile transfer references. - **Support-alert console** — triage low-rating, no-show, location-mismatch, expiry, and fraud-signal alerts. - **RBAC** — admin roles (super_admin / admin / support / finance / moderator) scope who can verify, refund, pay out, and moderate. - An **append-only audit trail** records every state-changing operation on sensitive entities (bookings, payments, refunds, verifications, reviews, users), and config changes (e.g., the platform fee rate) are auditable. ### (b) Iran-specific considerations - No push at launch reflects a pragmatic MVP and the in-app polling norm; SMS-OTP already covers the critical auth path. - Back-office must reason over the Shamsi calendar and `iranian_holidays` for payout scheduling and deadline computation, and over the verification realities (manual MoH/INO checks, expiry-driven re-verification). - High-volume logs (`audit_logs`, `system_events`, `notifications`) need partitioning/retention planned before launch to avoid unbounded growth. ### (c) MVP vs DEFERRED - **MVP:** in-app notifications with 90-day retention; admin verification/refund/payout/alert tooling; RBAC; append-only `audit_logs`; config-change auditing. - **DEFERRED:** push notifications; SMS/email notification channels beyond OTP; a full analytics warehouse (`system_events` piped out rather than queried in the transactional DB); ML fraud console. ### (d) Supporting database entities `notifications`, `support_alerts`, `roles`, `user_roles`, `audit_logs`, `system_events`, `platform_configs`, plus the operational entities each tool acts on (`nurse_verifications` / `verification_steps` / `nurse_credentials`, `refunds`, `nurse_payout_batches` / `nurse_payouts` / `nurse_clawbacks`, `bookings`). --- ## Appendix — MVP vs Deferred at a glance | Area | MVP | Deferred | |---|---|---| | Onboarding | phone-OTP; customer/nurse/admin; patient split | customer KYC; org self-onboarding; push | | Verification | 6-step data-driven pipeline; `nurse_credentials`; IBAN ownership | MoH/INO API; liability-insurance step; ML fraud | | Catalog | admin categories/options; nurse variants & price units | holiday/surge pricing; companionship tier | | Search | geo + category; `nurse_search_index`; same-gender filter | map discovery; availability hard-filter | | Booking | request→accept→pay→confirm; `booking_sessions` multi-visit | recurring schedules; milestone-payment UX | | EVV | per-session GPS check-in/out; payout gating | geofencing; tele-check-ins; cameras | | Cancellation | tiered policy + snapshot; admin/ticket refunds; per-session | auto no-show penalty; self-service refunds | | Payments/Escrow | ledger escrow; `payment_webhook_events`; provider abstraction | nurse wallet; multi-PSP live; bank escrow product | | BNPL | full-upfront `bnpl_transactions`; provider-revert refunds | installment tracking (cut); tranched settlement; multi-provider | | Payouts | weekly batches; clawbacks; holiday-aware; verified IBAN | instant withdrawal; per-nurse frequency | | Reviews | one-per-booking; moderation; low-rating alerts | two-way reviews; tag aggregation; `incidents` | | Messaging | ticket-only; coordination ticket; emergency playbook | live chat; emergency-event entity | | Tax/Legal | `partner_centers`; minimal `invoices`; 10% VAT on commission; e-namad | full مودیان automation; nurse-side invoicing; B2B | | Notifications/Admin | in-app + retention; verify/refund/payout tooling; RBAC | push; analytics warehouse; ML console |