clean and refine product docs structure

This commit is contained in:
hamid
2026-06-24 01:32:46 +03:30
parent be07c703ec
commit 1df3cd9f64
113 changed files with 6078 additions and 4973 deletions
+15 -6
View File
@@ -21,18 +21,27 @@ The platform holds funds in an escrow-style ledger and pays nurses out weekly af
check-out. check-out.
Product/domain knowledge — business rules, the database model, payments/BNPL, escrow, the Product/domain knowledge — business rules, the database model, payments/BNPL, escrow, the
verification pipeline — is **not** in the code. It lives in [`product/`](product/): verification pipeline — is **not** in the code. It lives in [`product/`](product/), organized as a
**structured docs tree** (one topic per file; start at [product/index.md](product/index.md) or its
[README](product/README.md)):
| Doc | What it covers | | Folder | What it covers |
| --- | --- | | --- | --- |
| [product/business-requirements.md](product/business-requirements.md) | Full functional/business requirements | | [product/overview/](product/overview/platform-summary.md) | What Balinyaar is, the four cross-cutting ground truths, Persian glossary. **Read first.** |
| [product/database-model.md](product/database-model.md) | ~50-table SQL Server schema + ER diagrams + rationale | | [product/business/](product/business/index.md) | The 14 functional/business requirement areas, one file each |
| [product/payments-and-installments.md](product/payments-and-installments.md) | BNPL, escrow ledger, settlement, VAT (with sources) | | [product/data-model/](product/data-model/index.md) | The ~54-table SQL Server schema across 13 domains + [diagrams](product/data-model/diagrams.md) |
| [product/Home-Nursing-Platform-Research*.md](product/) | Market research (EN + FA) | | [product/payments/](product/payments/index.md) | BNPL, escrow ledger, settlement, VAT, integrations (with sources) |
| [product/research/](product/research/index.md) | Market/legal/verification research & go-to-market (EN) |
| [product/notes/](product/notes/open-questions.md) | Living notes: open questions, future ideas |
| [product/fa/](product/fa/index.html) | Farsi versions (research report + verification flow) |
**Read the relevant `product/` doc before designing any schema, API, or feature.** Don't infer **Read the relevant `product/` doc before designing any schema, API, or feature.** Don't infer
business rules from code — the code is young and the docs are the source of truth. business rules from code — the code is young and the docs are the source of truth.
> **Docs format:** the `.md` files are canonical; matching `.html` files are a generated, cross-linked
> browsing view (`cd product && node build-docs.mjs`). Edit the Markdown and regenerate — never
> hand-edit the `.html`. If you add/rename a `.md`, update the `NAV` manifest in `product/build-docs.mjs`.
--- ---
## Repository layout ## Repository layout
@@ -1,292 +0,0 @@
# ساخت پلتفرم پرستاری خصوصی در منزل در ایران — گزارش تحقیق و استراتژی
> **ایده:** پلتفرمی که به خانواده‌ها در ایران کمک می‌کند به‌سادگی پرستار خصوصی و احرازهویت‌شده برای عزیزانشان پیدا و استخدام کنند — مراقبت از سالمند، دورهٔ نقاهت پس از جراحی، مراقبت از نوزاد، و مدیریت بیماری‌های مزمن.
**تاریخ تهیه:** ۱۴۰۵/۰۳/۲۶ (2026-06-16) · **دامنه:** (۱) تحلیل بازار و رقبا، (۲) مشکلات و ریسک‌ها، (۳) احراز هویت و اعتبارسنجی صلاحیت پرستار، (۴) چارچوب حقوقی ایران، به‌علاوهٔ توصیه‌های عملی.
**یادداشتی دربارهٔ منابع.** این گزارش ترکیبی است از: (الف) یک مرحلهٔ تحقیق با راستی‌آزمایی متخاصمانه (adversarial) دربارهٔ **چارچوب حقوقی ایران و رقبای داخلی** (ادعاهایی که از فرایند رأی‌گیری سه‌گانه عبور کرده‌اند با **✅ تأییدشده** علامت خورده‌اند؛ ادعاهایی که *رد* شده‌اند صریحاً مشخص شده‌اند)، و (ب) تحقیق هدفمند وب دربارهٔ **پلتفرم‌های خارجی، نمونه‌های شکست/ریسک، و ابزارهای احراز هویت**. هرجا یک واقعیت از صفحهٔ تبلیغاتی خودِ یک شرکت آمده باشد، به‌عنوان «خوداظهاری/حسابرسی‌نشده» علامت خورده؛ و هرجا بر دانش مدل تکیه دارد (نه منبع واکشی‌شده)، با **[تأییدنشده — پیش از اتکا راستی‌آزمایی شود]** علامت خورده است. ارقام سرمایه‌گذاری و هر مقررات دهه‌های گذشته را «پیش از انتشار راستی‌آزمایی کنید».
---
## خلاصهٔ مدیریتی
**می‌توانید این کسب‌وکار را قانوناً در ایران بسازید — اما این یک *فعالیت درمانی دارای مجوز* است، نه یک مارکت‌پلیس آزاد برای راه‌اندازی.** اعتبار اصلی عبارت است از **پروانهٔ تأسیس** به‌علاوهٔ **پروانهٔ مسئول فنی** از وزارت بهداشت، که از طریق **معاونت درمان** و پس از تصویب **کمیسیون قانونی تشخیص امور پزشکی (موضوع مادهٔ ۲۰)** صادر می‌شود. **✅ تأییدشده**
**دو مسیر قانونی وجود دارد و انتخاب میان آن‌ها تعیین‌کننده است:**
- **مرکز خدمات پرستاری در منزل** (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل) — تحت نظر سازمان نظام پرستاری؛ یک **پرستار** (کارشناسی + ۵ سال سابقهٔ بالینی) می‌تواند مؤسس و مسئول فنی باشد. **این گزینهٔ درست برای ایدهٔ شماست.** **✅ تأییدشده**
- **مرکز خدمات و مراقبت‌های بالینی در منزل** — **هم مؤسس و هم مسئول فنی باید پزشک باشند.** مگر اینکه شریک پزشک داشته باشید، از این مسیر پرهیز کنید. **✅ تأییدشده**
**بازار واقعی و از پیش رقابتی است** — آسانیسم، اسنپ دکتر، سلامت اول و هیراد همگی امروز فعال‌اند — **اما عمدتاً در تهران/کرج متمرکزند و بیشتر به‌صورت اعزام مستقیم نیرو کار می‌کنند، نه به‌عنوان مارکت‌پلیس مبتنی بر اعتماد.** این، شکاف بازار شماست. **✅ تأییدشده**
**سخت‌ترین مسئله، اعتماد و ایمنی است، نه فناوری.** هر داستان عبرت‌آموز در خارج (جریمه‌های نظارتی Care.com، پروندهٔ کلاهبرداری هویتی «پرستار قلابی»، احکام طبقه‌بندی نادرست نیروی کار) به یک قاعده می‌رسد: **مالک فرایند احراز صلاحیت خودتان باشید؛ هرگز آن را به خانواده‌ها واگذار نکنید، و هرگز یک بررسی ایمنی که واقعاً انجام نمی‌دهید را تبلیغ نکنید.**
**خبر خوب دربارهٔ احراز هویت:** ایران یک بازار رقابتی از APIهای آمادهٔ احراز هویت (KYC) دارد (تطبیق شمارهٔ موبایل با کد ملی از طریق **شاهکار**، تطبیق چهره/زنده‌بودن با کارت ملی) که احراز هویت را به ساده‌ترین لایه تبدیل می‌کند. لایهٔ مجوز سخت‌تر است (API عمومی B2B وجود ندارد)، اما **پروانهٔ صلاحیت حرفه‌ای** پرستار از وزارت بهداشت همان اعتباری است که باید مطالبه کنید — چون از پیش شامل بررسی سوء‌پیشینه است.
**جمع‌بندی استراتژیک:** به‌عنوان **مرکز خدمات پرستاری در منزل** ثبت کنید، از همان ابتدا با مراکز دارای مجوز همکاری کنید (مدل آسانیسم) تا سریع حرکت کنید، **اعتماد احرازشده را به کل برند خود تبدیل کنید**، **شهرهای کم‌تر پوشش‌داده‌شده خارج از تهران** را هدف بگیرید، و روی درآمد B2B/نهادی (مسیرهای ترخیص بیمارستانی، بیمه‌گرها، مزایای کارکنان شرکت‌ها) علاوه بر پرداخت مستقیم خانواده‌ها بسازید.
---
# ۱. تحلیل بازار و رقبا
## ۱.۱ بازیگران ایرانی (کسانی که واقعاً با آن‌ها رقابت می‌کنید) ✅ تأییدشده
بازار داخلی **فعال و در حال رشد** است — تا سال ۱۳۹۸ حدود **۷۰۰ شرکت خدمات درمانی در منزل** ثبت شده بودند، با تلاش رسمی برای رساندن آن به حدود ۱٬۰۰۰ (که اکنون تقریباً مطمئناً بیشتر است). **✅ تأییدشده** (منبع واحد سال ۱۳۹۸؛ آن را یک کفِ تاریخی بدانید). رهبران بازار:
| بازیگر | مدل | بخش‌های هدف | نکات قابل‌توجه | قیمت‌گذاری |
|---|---|---|---|---|
| **آسانیسم** | مارکت‌پلیس/تطبیق که نیرو را **از طریق مراکز دارای مجوزِ همکار** تأمین می‌کند (مدل واسطه‌ای) | سالمند، کودک، پس از جراحی، مزمن، بالینی (تزریقات، پانسمان، تعویض سوند، خون‌گیری در منزل) | احراز هویت مراقبین، رعایت پروتکل‌های بهداشتی، سفتهٔ تضمین حدود ۴۰ میلیون تومان، و دورهٔ آزمایشی ۲۴–۴۸ ساعته را تبلیغ می‌کند. **تمرکز ~۹۹٪ در تهران/کرج**، ~۱٬۶۵۰ مراقب فعال در ۴ مرکز همکار (خوداظهاری، حسابرسی‌نشده) | فعلی (۱۴۰۴/۱۴۰۵) |
| **اسنپ دکتر** | عمودیِ سلامتِ اسنپ (بزرگ‌ترین سوپراَپ ایران)؛ اعزام مدیریت‌شده | سالمند، پس از جراحی (مراقبت از زخم، کشیدن بخیه)، نوزاد/کودک، مزمن (سکته مغزی، سرطان، پارکینسون، MS، آلزایمر) | فعال در تهران، کرج، قم، شیراز، کرمانشاه، اصفهان، مشهد. دارای **مجوز عمومی واسطه‌گری پزشکی آنلاین («پل ارتباطی»)****نه** مجوز اختصاصی پرستاری در منزل از وزارت بهداشت (این ادعا رد شد) | — |
| **سلامت اول** | **اعزام مستقیم پرستارهای خودش** (نه مارکت‌پلیس باز) — شرکت پرستار را انتخاب می‌کند | مراقبت از سالمند (ساعتی / روزانه / شبانه‌روزی) | **۳٬۰۰۰+ نیروی فعال**، مرکز تماس ۲۴/۷ (۱۵۲۷)، تهران + حومه (کرج، پردیس). دارای **پروانهٔ رسمی وزارت بهداشت شمارهٔ ۳-۳۸۸۱۸۰** | «توافقی»؛ شیفت‌های شبانه‌روزی به‌ازای هر ساعت ارزان‌تر |
| **هیراد** | اپ‌محور (کافه‌بازار، مایکت)؛ اعزام/کاریابی مدیریت‌شده | سالمند، کودک/نوزاد، پس از جراحی/نقاهت، تزریقات در منزل، آزمایش در منزل | هر دو سمت را نشان می‌دهد (خانواده‌ها درخواست می‌دهند؛ پرستاران «کارهای موجود» را می‌بینند)؛ «استخدام بدون هزینه» را تبلیغ می‌کند. اعلام می‌کند تحت مجوز وزارت بهداشت فعالیت می‌کند. اقبال محدود | — |
**نتیجه‌گیری برای شما:**
۱. **مدل غالب، اعزام مستقیم/مدیریت‌شده است، نه مارکت‌پلیس دوطرفهٔ واقعیِ مبتنی بر اعتماد.** حتی بازیگران «شبه‌مارکت‌پلیس» (آسانیسم، هیراد) عملاً مثل آژانس‌های نیروی مدیریت‌شده کار می‌کنند. یک تجربهٔ واقعاً شفاف، مبتنی بر نظرات کاربران، که در آن خانواده پرستار را انتخاب می‌کند، هنوز نسبتاً باز است.
۲. **تمرکز جغرافیایی شدید است.** تهران/کرج غالب‌اند؛ شهرهای ردهٔ دوم (مشهد، اصفهان، شیراز، تبریز، اهواز، قم) کم‌پوشش‌اند. **این روشن‌ترین فضای خالی بازار است.**
۳. **قیمت‌گذاری مبهم و توافقی است.** قیمت‌گذاری شفاف و از پیش‌اعلام‌شده یک تمایز ارزشمند برای خانواده‌هاست.
۴. **«دارای مجوز» یک سیگنال اعتماد واقعی است** — سلامت اول شمارهٔ پروانهٔ وزارت بهداشت خود را برجسته نمایش می‌دهد. شما هم باید این کار را بکنید.
> ⚠️ **ادعاهای ردشده که نباید تکرار شوند:** اسنپ دکتر مجوز اختصاصی پرستاری در منزل از وزارت بهداشت **ندارد** (فقط مجوز عمومی واسطه‌گری)؛ یک نمونهٔ قیمت‌گذاری به‌تفکیک شهر و به‌ازای هر خدمت که به آن نسبت داده شده بود نیز رد شد. اعداد نیروی انسانی رقبا (۱٬۶۵۰ / ۳٬۰۰۰) ارقام تبلیغاتی خوداظهاری‌اند.
## ۱.۲ پلتفرم‌های خارجی (مدل‌هایی برای یادگیری)
پلتفرم‌های خارجی در **چهار مدل ساختاری** دسته‌بندی می‌شوند — دانستن اینکه از کدام مدل تقلید می‌کنید، از هر ویژگی منفرد مهم‌تر است:
۱. **مارکت‌پلیس مصرف‌کنندهٔ خالص** — خانواده‌ها را مستقیم به مراقبینِ *خوداشتغال* وصل می‌کند؛ پلتفرم هیچ‌کس را استخدام نمی‌کند (Care.com، Curam). ارزان برای مقیاس‌پذیری، اما کنترل کیفیت ضعیف و ریسک حقوقی جدی بابت طبقه‌بندی نادرست نیروی کار.
۲. **مدیریت‌شده / نیروی استخدامی «تمام‌پشته» (full-stack)** — شرکت نیروهای خودش را استخدام، آموزش، احراز و اعزام می‌کند و فناوری را روی آن سوار می‌کند (Honor، Cera، Homage، Portea). کیفیت و دفاع‌پذیری بالاتر؛ سرمایه‌بَر.
۳. **پلتفرم تأمین نیرو برای مراکز** — شیفت‌های بیمارستان/خانهٔ سالمندان را پر می‌کند، نه مصرف‌کننده (Florence، Vivian Health).
۴. **تجمیع تقاضا + ادغام با پرداخت‌کننده (بیمه)** — مدل‌های جذب سرنخ / همراهی / بیمه (Papa، Pflege.de).
**روشن‌ترین درس از داده‌ها: سرمایه و قراردادهای پایدار به‌سمت مدل‌های مدیریت‌شده/تمام‌پشته و ادغام‌شده با بیمه جریان دارند، در حالی که مارکت‌پلیس‌های خالصِ پیمانکار مستقل مدام به سقف قانون کار برمی‌خورند.**
### جدول مقایسه (منتخب؛ ارقام سرمایه تقریبی — پیش از اتکا راستی‌آزمایی شود)
| پلتفرم | کشور | مدل | ویژگی شاخص | کسب درآمد | تمایز / دستاورد |
|---|---|---|---|---|---|
| **Care.com** | آمریکا | مارکت‌پلیس اشتراکی خالص | پروفایل، نظرات، بررسی پیشینهٔ *اختیاریِ پولی* | اشتراک خانواده + مراقب؛ افزونهٔ بررسی پیشینه؛ **بدون سهم از دستمزد** | بزرگ‌ترین/گسترده‌ترین. **داستان عبرت** — تسویهٔ ۸٫۵ میلیون دلاری FTC (۲۰۲۴)، ۱ میلیون دلار Marin DA (۲۰۲۰) |
| **Honor** | آمریکا | تمام‌پشتهٔ مدیریت‌شده + فرنچایز | پلتفرم فناوری+عملیات؛ جذب شبکهٔ جهانی Home Instead | B2B + فرنچایز؛ مراقبت ساعتی | یونیکورن (~۱٫۲۵ میلیارد دلار+)؛ ~۲٫۱ میلیارد دلار با Home Instead؛ ۱۰۰هزار+ مراقب |
| **Papa** | آمریکا | همراهی + مراقبتِ پرداخت‌شده توسط بیمه | «Papa Pals» همراهی برای تنهایی؛ راهبری مراقبت | **قرارداد B2B با Medicare Advantage / Medicaid / کارفرماها** | تنهایی را به یک نیاز سلامتیِ قابل‌صورت‌حساب تبدیل کرد؛ ۱۵۰ میلیون دلار Series D |
| **Cera** | بریتانیا | تمام‌پشتهٔ مدیریت‌شده + هوش مصنوعی پیش‌بین | پیش‌بینی زمین‌خوردن/بستری روزها قبل؛ ثبت علائم حیاتی توسط مراقب | **B2B با NHS و ۱۵۰+ شهرداری** | مالکیت هم‌زمان نیرو *و* داده؛ یونیکورن ~۱ میلیارد دلار (۲۰۲۵) |
| **Florence** | بریتانیا | مارکت‌پلیس تأمین نیرو برای مراکز | رزرو فوری شیفت؛ برنامه/حقوق/آموزش؛ بررسی DBS | کمیسیون به‌ازای شیفت + SaaS | حذف واسطه‌های گران آژانس پرستاری |
| **Curam** | بریتانیا | مارکت‌پلیس خالص (خوداشتغال) | بررسی DBS + احراز بیومتریک؛ بیمهٔ همراه | **کمیسیون ۱۲٫۵٪ + مالیات** (مراقب ~۸۵٪ نگه می‌دارد) | مدل کم‌کارمزدِ خوداشتغال |
| **Homage** | سنگاپور (+مالزی/استرالیا) | **مارکت‌پلیس گزینش‌شده + تطبیق انسانی** | الگوریتم نامزدها را پیشنهاد می‌دهد، *کارکنان* تطبیق نهایی را انجام می‌دهند؛ تله‌مدیسین؛ ادغام با یارانهٔ دولتی | حاشیهٔ ساعتی (~۳–۶ دلار سنگاپور) + بسته‌ها + B2B | شبکهٔ گزینش‌شدهٔ توانمند بالینی؛ ۳۰ میلیون دلار Series C (Temasek). **بهترین تناسب مدل برای ایران** |
| **Portea Medical** | هند | ارائه‌دهندهٔ بالینی مدیریت‌شده | فیزیوتراپی، پرستاری، ویزیت پزشک، آزمایش، **اجارهٔ تجهیزات**؛ بستهٔ «NRI» برای مهاجران | اشتراک + به‌ازای ویزیت + اجاره | بزرگ‌ترین در هند؛ ~۱۱۴ میلیون دلار جذب کرده |
| **Nightingales / Care24 / HCAH** | هند | ارائه‌دهندگان بالینی مدیریت‌شده | برنامه‌های مزمن/تخصصی؛ **صورت‌حساب بیمه‌ایِ بدون پرداخت نقدی** (HCAH، ۴۰+ بیمه‌گر) | اشتراک + به‌ازای ویزیت + B2B | بازار به‌سرعت در حال تجمیع (هر دو خریداری شدند) |
| **Manzil / NMC Homecare** | امارات | سلامت خانگی بالینی دارای مجوز | اعتباربخشی JCI؛ یکپارچه با بیمارستان؛ تزریق وریدی، فیزیوتراپی، مادر و نوزاد | حق‌الزحمه‌محور، **صورت‌حساب بیمه‌ای** | اعتبار بالینی درجه‌یک |
| **Veteranpoolen** | سوئد | تأمین نیرو با استخدام **بازنشستگان** | قیمت‌گذاری متناسب با کسر مالیاتی RUT (۵۰٪) سوئد | کارمزد یارانه‌ای RUT + فرنچایز | تأمین نیروی منحصربه‌فرد (بازنشستگان فعال) |
| **Bakıcıburada** | ترکیه | آگهی‌های طبقه‌بندی‌شدهٔ مراقب | تأیید هویت + سوءپیشینه؛ کشف روی نقشه | کارمزد آگهی/اشتراک | بدون سرمایهٔ ریسک‌پذیر؛ **نزدیک‌ترین آنالوگ به بازار واقع‌بینانهٔ مرحلهٔ اولیهٔ ایران** |
### مهم‌ترین سیگنال‌های منطقه‌ای
- **هند نزدیک‌ترین آنالوگ است** (جمعیت زیاد، پوشش عمومیِ کم، پرداخت از جیب خانواده). نکتهٔ گویا: **هیچ مارکت‌پلیس خالصِ خانواده‌به‌مراقب در آنجا غالب نیست** — همهٔ رهبران مدلِ بالینیِ مدیریت‌شده/استخدامی دارند، چون کشور فاقد آموزش ساختاریافتهٔ پیراپزشکی است، پس **احراز و کنترل کیفیت *خودِ محصول* است.**
- در **آلمان** تنها تلاش برای تطبیق مراقبِ مدیریت‌شده (Careship) **ورشکست شد**؛ بازماندگان مدل‌های کم‌سرمایهٔ جذب‌سرنخ/آگهی + کالای مصرفیِ یارانه‌ایِ بیمه‌اند.
- **ترکیه** عمدتاً آگهی‌های طبقه‌بندی‌شدهٔ خوداتکا و آژانس‌های کوچک است — تصویری واقع‌بینانه از آیندهٔ نزدیک ایران.
### پنج ایدهٔ قابل‌انتقال برای یک بنیان‌گذار ایرانی
۱. **یک «اوبر برای پرستارها»ی خالص از پیمانکاران مستقل نسازید.** روشن‌ترین شکست‌ها (ورشکستگی Careship؛ بازطبقه‌بندی نظافتچیان گیگِ Helpling به‌عنوان کارمند؛ رسوایی‌های کیفیت Care.com) همگی مدل‌های گیگ خالص‌اند. برای مراقبت، نقطهٔ بهینهٔ اثبات‌شده یک **مارکت‌پلیس گزینش‌شده + احراز انسانی** است (مدل **Homage**: الگوریتم نامزدها را رو می‌کند، *تیم شما* تطبیق نهایی را انجام می‌دهد و مالک احراز/آموزش است).
۲. **احراز و آموزش را به محصول اصلی تبدیل کنید، نه افزونهٔ پولی.** در هر بازاری با زیرساخت ضعیف صدور مجوز، برندگان مالک کیفیت مراقب‌اند. در ایران، **زیرساخت اعتماد، کلِ ارزش پیشنهادی است** — آن را به‌صورت پیش‌فرض بسته‌بندی کنید؛ مثل Care.com آن را به‌صورت آپ‌سل نفروشید.
۳. **زود به‌سمت پرداخت‌کنندگان نهادی B2B حرکت کنید.** ارزشمندترین خروجی‌ها از طریق نهادها کسب درآمد می‌کنند: Cera (NHS)، Papa (Medicare Advantage)، HCAH (بیمه‌گرها). آنالوگ‌های ایران: **سازمان تأمین اجتماعی، بیمهٔ سلامت/بیمه‌گرها، ارجاع‌های ترخیص بیمارستانی، و مزایای کارکنان شرکت‌ها.** ترخیص پس از جراحی/سکته یک کانال جذب با نیت بالاست.
۴. **دو موتور درآمدی را روی هم سوار کنید و دنبال یک قلابِ یارانه باشید.** (الف) کارمزد/حاشیهٔ ساعتی روی مراقبت مدیریت‌شده، به‌علاوهٔ (ب) اشتراک/جذب‌سرنخ. جعبهٔ کالای مصرفیِ بیمه‌ایِ آلمان و کسر مالیاتی ۵۰٪ RUT سوئد قدرت **اتصال به یک یارانهٔ موجود** را نشان می‌دهند تا خدمت برای خانواده ارزان به‌نظر برسد — بررسی کنید آیا بیمه‌گر، خیریه یا موقوفهٔ سالمندان ایرانی می‌تواند ویزیت‌ها را یارانه دهد.
۵. **یک ردهٔ سبک‌ترِ «همراهی / کمک در امور روزمره» را جداگانه محصول‌سازی کنید.** Papa یک کسب‌وکار در مسیر یونیکورن را نه روی پرستاری ماهر بلکه روی *همراهی سالمندانِ منزوی* ساخت — مهارت کمتر، تأمین نیروی آسان‌تر، بازار وسیع‌تر، و آپ‌سل به مراقبت بالینی هنگام تشدید نیاز. با توجه به دیاسپورای بزرگ ایران، زاویهٔ **«فرزندان دور که هزینهٔ مراقبت از والدینشان در وطن را می‌پردازند»** (بستهٔ NRI پورتیا؛ کاربران مهاجرِ Homage) مستقیماً مرتبط است.
> **کم‌ریسک‌ترین نقطهٔ ورود:** رویکرد «SaaS برای ارائه‌دهندگان» شرکت Birdie — فروش نرم‌افزار زمان‌بندی/انطباق/داشبورد خانواده *به* آژانس‌های موجود مراقبت در منزل ایران به‌جای رقابت مستقیم — اگر صدور مجوز/طبقه‌بندی نیروی کار در ابتدا مانعی جدی شد، ارزش نگه‌داشتن در آستین را دارد.
---
# ۲. مشکلات و ریسک‌ها
این حوزه دو ویژگی غیرعادی و خطرناک را با هم دارد: خریداران **افراد آسیب‌پذیرند** (سالمند، پس از جراحی، نوزاد، بیمار مزمن) و خدمت **بدون نظارت، داخل خانهٔ خصوصی** انجام می‌شود. این ترکیب هر ریسک معمول مارکت‌پلیس را تشدید می‌کند و ابعاد مرگ‌وزندگی به آن می‌افزاید.
**مهم‌ترین درس استراتژیک:** *پلتفرمی که ایمنی را تبلیغ کند ولی احراز واقعی را به خانواده‌ها واگذار کند، سرانجام با فاجعهٔ نظارتی، حقوقی و اعتباری روبه‌رو خواهد شد.*
## ۲.۱ شکست‌های اعتماد و ایمنی
**ریسک:** اتصال غریبه‌ها به افراد آسیب‌پذیر بدون احراز دقیقِ *تحت‌مالکیت پلتفرم*، راه را برای سرقت، سوءاستفاده، کلاهبرداری و آسیب مرگبار باز می‌کند — و افکار عمومی *پلتفرم* را مقصر می‌داند.
**نمونه‌های واقعی:**
- **Care.com / تحقیق وال‌استریت‌ژورنال (۲۰۱۹):** طی ~۶ سال، **۹ مراقب فهرست‌شده در Care.com که سابقهٔ پلیسی داشتند، بعداً به جرایمی متهم شدند که هنگام مراقبت از کودک یا سالمند رخ داد — از جمله سرقت، کودک‌آزاری، تجاوز جنسی و قتل.** سایت همچنین صدها آگهی مهدکودک داشت که به‌دروغ ادعای مجوز ایالتی می‌کردند. ([Daily Beast/WSJ](https://www.thedailybeast.com/wsj-kids-assaulted-died-in-hands-of-carecom-caregivers/))
- **پاک‌سازی انبوه آگهی‌ها:** Care.com حدود **۴۶٬۵۹۴ آگهی مهدکودک (~۴۵٪ آن پایگاه داده)** را پس از کشف جعلی/ناموجود بودن حذف کرد. ([Engadget](https://www.engadget.com/2019-03-31-care-com-pulls-47000-daycare-listings.html))
- **«پرستار قلابی» (Shannon Womack، ۲۰۲۵):** ادعا می‌شود با **۲۰+ نام مستعار و ۷ شمارهٔ تأمین اجتماعی**، با سرقت مدارک چهار پرستار واقعی، خود را پرستار جا زده و با **ارائهٔ مدارک جعلی از طریق آژانس‌های تأمین نیرو** در **۹+ مرکز** کار کرده — حتی یک شرکت قلابی برای خوداعزامی ساخته است. متهم به **۴۳ فقره** اتهام، از جمله به‌خطرانداختن فرد وابسته به مراقبت و سرقت دارو از سالمندان. ([Nurse.org](https://nurse.org/news/fake-nurse-arrested-shannon-womack-nursing-fraud/)) — *درس کلیدی برای یک مارکت‌پلیس پرستار: حتی آژانس‌هایی که فکر می‌کردند احراز می‌کنند، با هویت سرقتی + مدارک جعلی شکست خوردند.*
**راهکارهای کاهش ریسک:**
- **مالک احراز خودتان باشید؛ هرگز به خانواده‌ها واگذار نکنید.** احراز هویت + سوءپیشینه + اعتبارسنجی مجوز را به‌عنوان یک *دروازهٔ اجباریِ تحت‌مالکیت پلتفرم* پیش از قابل‌رزرو شدن هر پرستار قرار دهید.
- **اعتبار را در منبع رسمی راستی‌آزمایی کنید**، نه با فایل آپلودی (که دقیقاً همان چیزی است که جعل می‌شود). در ایران: سامانهٔ **سازمان نظام پرستاری** و **پروانهٔ صلاحیت حرفه‌ای** وزارت بهداشت (بخش ۳ را ببینید).
- **هر پروفایل را به کد ملی + سلفی زنده گره بزنید** تا الگوی نام‌های مستعار/هویت سرقتی خنثی شود.
- **به‌صورت دوره‌ای بازبینی کنید** (انقضای مجوز، تعلیق‌ها، سوابق جدید).
## ۲.۲ مسئولیت حقوقی و قرار گرفتن در معرض دعوا
**ریسک:** سه نوع قرارگیری در معرض ریسک روی هم انباشته می‌شوند — **(الف) طبقه‌بندی نادرست نیروی کار** (نامیدن پرستارها به‌عنوان «پیمانکار» در حالی که قانون آن‌ها را کارمند می‌داند)، **(ب) مسئولیت نیابتی / استخدام سهل‌انگارانه** (وقتی مراقب به بیمار آسیب می‌زند)، و **(ج) شکاف‌های بیمه‌ای**. دفاعِ «ما فقط یک پلتفرم فناوری بی‌طرفیم» در سراسر جهان در حال فرسایش است.
**نمونه‌های واقعی:**
- **حکم ۱۰ میلیون دلاری کالیفرنیا علیه TLC Home Care** بابت طبقه‌بندی نادرست نیروهای منزل به‌عنوان پیمانکار (۲۰۲۳). ([HRMorning](https://www.hrmorning.com/news/worker-misclassification-tlc-home-care/))
- دادگاه‌های فدرال مکرراً مراقبینِ منزل را **کارمند، نه پیمانکار** تشخیص می‌دهند — *هرچه مراقبت را برای کیفیت بیشتر استانداردسازی و نظارت کنید، بیشتر شبیه کارفرما به‌نظر می‌رسید.* ([Ogletree Deakins](https://ogletree.com/insights-resources/blog-posts/federal-court-finds-in-home-caregivers-were-employees-not-independent-contractors-under-economic-realities-control-test/))
**راهکارهای کاهش ریسک:**
- **مدل را آگاهانه انتخاب کنید:** یا یک *مارکت‌پلیس بی‌طرف واقعی* (کنترل حداقلی؛ خانواده کارفرماست) یا یک *مدل کامل آژانس/کارفرما* (حقوق، نظارت، بیمه). **میانهٔ خطرناک — کنترل زیاد برای «کیفیت» اما طبقه‌بندی پیمانکار برای «هزینه» — دقیقاً همان چیزی است که احکام طبقه‌بندی نادرست را فعال می‌کند.**
- **[تأییدنشده — با وکیل محلی بررسی شود]** تعهدات قانون کار و تأمین اجتماعی ایران به رابطهٔ استخدامی تعلق می‌گیرند؛ *پیش* از راه‌اندازی، طبقه‌بندی را درست انجام دهید. (به شکاف قانون کار برای پرستاران منزل در بخش ۴.۵ توجه کنید — این مسئله دوسویه است: هزینهٔ الزامیِ کمتر، اما وضعیت حل‌نشده.)
- **بیمهٔ مسئولیت عمومی + حرفه‌ای در سطح پلتفرم داشته باشید**، و از پرستارها هم بخواهید بیمهٔ خود را داشته باشند.
- **هر مرحلهٔ احراز را مستند کنید** — هم پیشگیری است و هم دفاع حقوقی شما در برابر دعاوی استخدام سهل‌انگارانه.
## ۲.۳ مشکلات عملیاتی و کنترل کیفیت
**ریسک:** جابه‌جایی شدید مراقب، غیبت‌هایی که بیمار آسیب‌پذیر را بی‌سرپرست می‌گذارند، تنوع گستردهٔ کیفیت، نظارت از راه دور تقریباً غیرممکن، و **حذف واسطه (disintermediation)** (جفت‌شدن خانواده + پرستار خارج از پلتفرم برای فرار از کارمزد).
**داده‌های واقعی:**
- جابه‌جایی مراقب در ۲۰۲۴ به **~۷۹٪** رسید، با **~۷۰٪ ترک کار طی ۱۰۰ روز اول**؛ هر خروج **۲٬۶۰۰ تا ۵٬۰۰۰ دلار** هزینه دارد و مشتری اغلب همراه مراقب می‌رود. ([ShiftCare](https://shiftcare.com/us/blog/caregiver-retention-in-2026-what-the-data-tells-us-about-turnover))
- **حذف واسطه، حالت شکستِ قابل‌پیش‌بینی** برای خدمات تکراری و مبتنی بر رابطه است — وقتی اعتماد شکل گرفت، خانواده و پرستار خصوصی معامله می‌کنند. تاکتیک‌های تنبیهی ضدِ حذف واسطه معمولاً نتیجهٔ معکوس می‌دهند. ([Sharetribe](https://www.sharetribe.com/academy/how-to-discourage-people-from-going-around-your-payment-system/))
**راهکارهای کاهش ریسک:**
- **تأیید الکترونیکی ویزیت (EVV):** ورود/خروج با GPS و مهر زمانی، با هشدار خودکار ویزیت ازدست‌رفته، تا غیبت‌ها فوری اعزام جایگزین را فعال کنند.
- **تضمین پوشش/جایگزین:** یک ذخیرهٔ پرستار آماده و وعدهٔ پرکردن سریع غیبت — دلیل اصلی استفاده از شما به‌جای استخدام خصوصی.
- **با ارزش‌آفرینیِ ماندگار بر حذف واسطه غلبه کنید، نه با قفل‌کردن:** زمان‌بندی/پرداخت یکپارچه، تضمین جایگزین، بیمه‌ای که *فقط* روی رزروهای داخل پلتفرم اعمال می‌شود، و نظرات/حمایت در اختلافات که با خروج از پلتفرم از بین می‌رود.
- **تطبیق مبتنی بر تداوم:** یک پرستار اصلی + جایگزین مشخص برای هر بیمار؛ تداوم را به‌عنوان یک KPI ردیابی کنید.
## ۲.۴ ریسک‌های پرداخت و کلاهبرداری
**ریسک:** پرداخت خارج از پلتفرم (سمت مالیِ حذف واسطه)، نظرات جعلی، کلاهبرداری هویتی، جعل مدرک، و **سوءاستفادهٔ مالی از سالمند.**
**داده‌های واقعی:**
- کلاهبرداری در مارکت‌پلیس‌های گیگ حدود **۲ برابر** سایر جاهاست؛ یک گزارش ۲۰۲۵ افزایش ۲۱٪ سالانه را گزارش کرد که **>۹۰٪ آن جعل هویت بود**. ([Security Boulevard](https://securityboulevard.com/2024/05/when-the-gig-is-fraud-building-trust-for-online-marketplaces-with-identity-verification/))
- **سوءاستفادهٔ مالی از سالمند:** بررسی CFPB نشان داد جایی که قربانی مرتکب را می‌شناخت، **۱ نفر از هر ۹ نفر یک مراقب غیرخانوادگی بود، با میانگین خسارت ۵۷٬۸۰۰ دلار.** ([AARP](https://www.aarp.org/money/scams-fraud/financial-abuse-home-care-aide/))
- **جریمه‌های Care.com:** **۲۰۲۰ — ۱ میلیون دلار Marin County DA** (ادعای دروغین که بررسی‌ها رجیستری ملی متخلفان جنسی را جست‌وجو می‌کنند؛ تمدیدهای خودکار نادرست)؛ **۲۰۲۴ — ۸٫۵ میلیون دلار FTC** (تورم تعداد مشاغل موجود — بیش از نیمی از آگهی‌ها از کاربرانی بود که نمی‌توانستند واقعاً استخدام کنند — به‌علاوهٔ الگوی فریبندهٔ لغو اشتراک). ([CNBC](https://www.cnbc.com/2024/08/26/carecom-reaches-8point5-million-us-ftc-settlement-over-job-listings-renewals-.html))
**راهکارهای کاهش ریسک:**
- **احراز هویت قوی هنگام ثبت‌نام** (گره به کد ملی + تشخیص زنده‌بودن) برای *هم* پرستار *و هم* خانوادهٔ پرداخت‌کننده.
- **نظرات را به رزروهای کامل‌شده و احرازشده داخل پلتفرم گره بزنید.**
- **پرداخت امانی (escrow) داخل پلتفرم با حل اختلاف** — هم کلاهبرداری را کم می‌کند *و هم* قوی‌ترین اهرم ضدِ حذف واسطه است.
- **از دارایی مالی مشتریان محافظت کنید** (به خانواده‌ها توصیه کنید: کارت‌ها را امن نگه دارند، دسترسی فقط‌خواندنی، مراقب تغییرات ناگهانی وکالت/وصیت باشند)؛ ضمانت پرستار در برابر سرقت را در نظر بگیرید.
- **هرگز تضمین یا بررسی‌ای که انجام نمی‌دهید را تبلیغ نکنید، و لغو اشتراک را واقعاً آسان کنید** — هر جریمهٔ Care.com به تبلیغ فریبندهٔ ایمنی یا الگوهای تاریک برمی‌گردد.
## ۲.۵ پویایی‌های اعتماد ویژهٔ مراقبت از افراد آسیب‌پذیر در منزل
خدمت **به‌تنهایی، بدون مشاهده، داخل خانه** و به افرادی ارائه می‌شود که اغلب **نمی‌توانند به‌طور قابل‌اتکا گزارش دهند** چه رخ داده (نوزاد؛ بیماران دمانس، پس از بیهوشی، یا دارای اختلال شناختی). عدم تقارن اطلاعات شدید است و یک حادثهٔ منفرد می‌تواند یک برند شکننده را نابود کند.
**راهکارها:** جبران عدم‌مشاهده با **نظارت ساختاریافته** — EVV، تماس‌های نظارتیِ دوره‌ای توسط پرستار ارشد، گزارش‌های مراقبتیِ قابل‌رؤیت برای خانواده، دوربین‌های داخل منزل با رضایت در فضاهای مشترک؛ یک **حلقهٔ بازخورد دوطرفه** که بیمار تنها منبع آن نباشد؛ **پروتکل‌های واکنش سریع به حادثه** با تعلیق فوری در صورت شکایت معتبر؛ و **تطبیق صلاحیت با حدّت بیماری** (موارد پرحدّت پس از جراحی/تنفسی فقط به پرستارهای احرازشده؛ همراهی‌های سبک به مراقبان سطح پایین‌تر).
---
# ۳. احراز هویت و اعتبارسنجی صلاحیت پرستار
**پرسش «آیا این پرستار واقعاً همان است که می‌گوید و واقعاً دارای مجوز است؟» به دو بررسی تقسیم می‌شود که باید مراحل جداگانهٔ خط لوله باشند:**
- **بررسی مجوز** — *آیا پرستار رسمی است؟* (سامانهٔ ثبت حرفه‌ای)
- **بررسی هویت + پیشینه** — *آیا همان است که ادعا می‌کند، بدون سابقهٔ ردکننده؟* (KYC + سوءپیشینه)
## ۳.۱ مدل‌های مرجع جهانی (بهترین رویه‌ها برای الگوبرداری)
- **آمریکا — Nursys / e-Notify (استاندارد طلایی):** تنها پایگاه دادهٔ ملی مجوز، تغذیه‌شده توسط هیئت‌های ایالتی پرستاری؛ **e-Notify تغییرات وضعیت مجوز/انضباطی را *پوش* می‌کند** به کارفرمایان ثبت‌نام‌شده از طریق یک **API**. — *درس: نظارت پیوسته، نه احراز یک‌باره.*
- **بریتانیا — سامانهٔ NMC + DBS:** سامانهٔ آنلاین NMC (رایگان، به‌روزرسانی روزانه) به پرسش *«آیا دارای مجوز است؟»* پاسخ می‌دهد؛ بررسی جداگانهٔ سوءپیشینهٔ **DBS** به *«آیا ایمن است؟»**درس: دو بررسی را مجزا نگه دارید.*
- **شرکت‌های بررسی پیشینه (Checkr، Sterling):** API-محور، ساخته‌شده برای جاسازی در جریان‌های گیگ/مارکت‌پلیس؛ یک بررسی مراقب شامل سابقهٔ کیفری، اعتبارسنجی مجوز، تحریم‌های درمانی، رجیستری سوءاستفاده، اشتغال/تحصیلات، و بازبینی مجدد است.
**یک خط لولهٔ مستحکم = رضایت ← احراز هویت ← اعتبارسنجی مجوز (منبع اصلی) ← بررسی سوءپیشینه + رجیستری سوءاستفاده ← اشتغال/تحصیلات ← نظارت پیوسته.**
## ۳.۲ ابزارهای مخصوص ایران (بخش عملیاتی)
ایران یک پشتهٔ قابل‌استفاده دارد، اما **میان نهادهای ناظر پراکنده است**، و حساس‌ترین بررسی (سوءپیشینه) **محدود به رضایت فرد** است، نه قابل‌استخراج آزاد توسط یک شرکت.
### الف) مجوز حرفه‌ای — «آیا این یک پرستار واقعی است؟» (دو مرجع، هر دو را بررسی کنید)
- **پروانهٔ صلاحیت حرفه‌ای وزارت بهداشت** در **Rn.behdasht.gov.ir** — اعتبارِ جدیدتر و **معتبرتر**. صدور آن از پیش وضعیت **علمی، اخلاقی، سلامت، و سوءپیشینهٔ** پرستار را بررسی می‌کند، و وزارت بهداشت اعلام کرده که این پروانه **حتی برای پرستاری خصوصی در منزل لازم است.** **[مهم‌ترین اعتبار برای مطالبه — چون شامل بررسی سوءپیشینه است]** ([behdasht.gov.ir](https://behdasht.gov.ir/))
- **شمارهٔ نظام پرستاریِ سازمان نظام پرستاری** از طریق `ino.ir` / `membership.ino1.ir`. طبق گزارش‌ها امکان استعلام/اعتبارسنجی شمارهٔ عضویت یک پرستار توسط شخص ثالث وجود دارد؛ به‌عنوان **بررسی متقاطع** استفاده کنید. ([heyvagroup](https://www.heyvagroup.com/shownews/11343/))
- **برای هیچ‌کدام یک API عمومی B2B یافت نشد** — استفادهٔ واقع‌بینانهٔ امروزی **مطالبهٔ آپلود + راستی‌آزمایی دستی در برابر سابقهٔ رسمی** است. (جست‌وجوی عضو عمومیِ نظام پزشکی در `membersearch.irimc.org` نشان می‌دهد یک جست‌وجوی معادل پرستاری چطور می‌تواند باشد.) **[نبود API «یافت نشد» است، نه قطعاً تأییدشده — از طریق یک پورتال B2B بررسی شود]**
### ب) احراز هویت — لایهٔ *آسان* (APIهای آماده وجود دارند)
یک بازار رقابتی از **فروشندگان e-KYC** ایرانی APIهای آماده می‌فروشند — **این را بخرید، نسازید:**
- **شاهکار:** سرویس دولتی تطبیق **شمارهٔ موبایل ↔ کد ملی**؛ توسط سازمان تنظیم مقررات (CRA). نتیجه در <۱ ثانیه. **دسترسی محدود است** (تأیید + قرارداد + اتصال غیرمستقیم از طریق پلتفرم «سرو»)، پس **آن را از طریق یک فروشنده مصرف کنید**، نه مستقیم. ([fa.wikipedia](https://fa.wikipedia.org/wiki/سامانه_شاهکار))
- **صحت‌سنجی کد ملی:** نام + نام خانوادگی + کد ملی ← تطبیق.
- **تطبیق چهره/زنده‌بودن با عکس کارت ملی یا ثبت احوال:** ارائه‌شده توسط **فینوتک، یوآیدی، جیبیت، فراشناسا، ونیفای، کاوشک** و دیگران — زنده‌بودن + تطبیق چهره + OCR، اغلب با ۵–۱۳ میلیون+ سابقهٔ احراز. ([عصر تراکنش: ۸ شرکت ایرانی KYC](https://asretarakonesh.ir/index.php/2024/01/02/نگاهی-به-خدمات-۸-شرکت-ایرانی-فعال-در-حوز/))
- این فروشندگان اتصالات بالادستیِ محدودشده توسط ناظر را برای شما مدیریت می‌کنند؛ یک شرکت ثبت‌شده ثبت‌نام و APIهای REST را مصرف می‌کند.
### ج) سوءپیشینه — گواهی عدم سوء پیشینه (محدود به رضایت، بدون API شرکتی)
- گواهی رسمی «عدم سوءپیشینه»، که توسط **خودِ فرد** به‌صورت آنلاین از طریق **adliran.ir** با رمز شخصی **ثنا** یا حضوری از طریق **پلیس +۱۰** دریافت می‌شود. ([heyvalaw](https://www.heyvalaw.com/web/articles/view/1865/))
- **یک پلتفرم نمی‌تواند آن را استخراج کند** — هیچ API شخص‌ثالث/کارفرما وجود ندارد؛ صدور به رمز شخصی ثنای فرد گره خورده است. **طراحی واقع‌بینانه: از پرستار بخواهید گواهی خود را دریافت و آپلود کند، سپس به‌صورت دوره‌ای دوباره درخواست شود***و توجه کنید این بررسی از پیش در پروانهٔ صلاحیت حرفه‌ای وزارت بهداشت گنجانده شده*، پس مطالبهٔ آن پروانه بخشی از این را پوشش می‌دهد.
### د) ریل‌های پشتیبان
- **ثنا:** سامانهٔ هویت/ابلاغ الکترونیک قوهٔ قضائیه — عمدتاً به‌عنوان **دروازهٔ دریافت گواهی عدم سوء پیشینه** مرتبط است.
- **سجام:** KYC بازار سرمایه (اوراق بهادار) — **عمدتاً نامرتبط** اینجا، جز به‌عنوان گواهی بر اینکه ریل‌های قویِ e-KYC غیرحضوری در ایران وجود دارند.
## ۳.۳ خط لولهٔ پیشنهادیِ احراز برای پلتفرم شما
| مرحله | هدف | ابزار ایران / روش | برنامه‌پذیر؟ |
|---|---|---|---|
| **۰. رضایت** | مبنای قانونی برای احراز + ذخیرهٔ داده | رضایت صریح داخل اپ هنگام ثبت‌نام | — |
| **۱. هویت** | تطبیق فرد ↔ کد ملی ↔ موبایل ↔ چهره | **شاهکار** + **صحت‌سنجی کد ملی** + **تطبیق زنده‌بودن ویدیو/عکس با کارت ملی**، از طریق **یک فروشندهٔ KYC** (فینوتک / یوآیدی / جیبیت / فراشناسا / ونیفای) | **بله — API آماده** |
| **۲. مجوز** | اعتبارسنجی صلاحیت پرستاری در منبع | **پروانهٔ صلاحیت حرفه‌ای وزارت بهداشت** (Rn.behdasht.gov.ir) به‌عنوان اصلی **+** **شمارهٔ نظام پرستاری** (ino.ir) به‌عنوان بررسی متقاطع | **دستی** (API عمومی یافت نشد) — آپلود + راستی‌آزمایی |
| **۳. سوءپیشینه** | بدون سابقهٔ ردکننده | **عدم سوء پیشینه** — پرستار خودش از adliran.ir/ثنا درخواست و آپلود می‌کند؛ *بخشی* با پروانهٔ وزارت بهداشت پوشش داده می‌شود | **بدون API شرکتی** — محدود به رضایت، آپلود توسط پرستار |
| **۴. نظارت پیوسته** | کشف لغو/انقضا | راستی‌آزمایی دوره‌ای اعتبار مجوز + درخواست مجدد عدم سوء پیشینه (مثلاً سالانه)؛ اجرای مجدد شاهکار هنگام تغییر موبایل | نیمه‌دستی؛ تقلید از Nursys e-Notify |
**قواعد عملی:** (۱) **احراز هویت را بخرید** از طریق یک ارائه‌دهندهٔ KYC — این بار دسترسیِ محدودشدهٔ شاهکار/ثبت احوال را به فروشنده‌ای منتقل می‌کند که از پیش قراردادها را دارد. (۲) **بررسی مجوز را روی پروانهٔ صلاحیت حرفه‌ای وزارت بهداشت لنگر کنید** (الزامی دولتی برای پرستاری در منزل و شامل بررسی سوءپیشینه). (۳) **گواهی سوءپیشینه را خوداظهاری + محدود به رضایت بدانید.** (۴) **نظارت پیوسته بسازید**، نه یک‌باره. (۵) **مراقب قرارگیری در معرض حفاظت داده باشید** — مسیریابی از طریق یک واسط KYC دارای مجوز شما را منطبق نگه می‌دارد.
---
# ۴. چارچوب حقوقی در ایران
**پاسخ کوتاه: هیچ قانونی *علیه* این ایده وجود ندارد — اما این یک فعالیت درمانی نظارت‌شده است که نیازمند مجوز وزارت بهداشت است. فعالیتِ بدون پروانه همان چیزی است که غیرقانونی است، و جریمه‌ها تا لغو دائم و ارجاع قضایی تشدید می‌شوند.** **✅ تأییدشده**
## ۴.۱ چارچوب حاکم ✅ تأییدشده
- صدور مجوز از طریق **معاونت درمان وزارت بهداشت**، پس از تصویب **کمیسیون قانونی تشخیص امور پزشکی (موضوع مادهٔ ۲۰)**، تحت **قانون امور پزشکی مصوب ۱۳۳۴ (اصلاحیهٔ ۱۳۶۷)** و **آیین‌نامهٔ مراقبت در منزل مصوب ۱۳۷۸/۷/۱۷** (۲۱ ماده، ۶ تبصره) جریان دارد.
- **به هر مرکز یک پروانهٔ تأسیس و یک پروانهٔ مسئول فنی اعطا می‌شود.**
- منابع: [arakmu.ac.ir](https://arakmu.ac.ir/vct/fa/regulation/1063/)، [mcls.gov.ir/fa/law/61](https://www.mcls.gov.ir/fa/law/61)، [qavanin.ir (مادهٔ ۲۰)](https://qavanin.ir/Law/TreeText/83385).
## ۴.۲ دو مسیر — مسیر پرستاری را انتخاب کنید ✅ تأییدشده
| | **مرکز خدمات پرستاری در منزل** (گزینهٔ شما) | مرکز خدمات و مراقبت‌های بالینی در منزل |
|---|---|---|
| نام | مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل | مرکز خدمات و مراقبت‌های بالینی در منزل |
| تحت نظر | سازمان نظام پرستاری | مستقیماً وزارت بهداشت |
| چه کسی مؤسس/مسئول فنی شود | **یک پرستار** — کارشناسی پرستاری + **۵ سال سابقهٔ بالینی** (می‌تواند هم مؤسس و هم مسئول فنی باشد) | **هم مؤسس و هم مسئول فنی باید پزشک باشند** |
| تناسب با ایدهٔ شما | ✅ پرستاری در منزل برای سالمند / پس از جراحی / نوزاد / مزمن | فقط اگر شریک پزشک داشته باشید |
> ⚠️ ادعای «مؤسس/مسئول فنی برای *همهٔ* مراقبت‌های منزل باید پزشک باشند» **رد شد** — این قاعده **فقط برای مسیر بالینی** است. مسیر خدمات پرستاری یک پرستار واجد شرایط را مجاز می‌داند. منابع: [mcls.gov.ir/fa/law/61](https://www.mcls.gov.ir/fa/law/61)، [irannurse.ir](https://irannurse.ir)، [vct.iums.ac.ir](https://vct.iums.ac.ir).
## ۴.۳ نحوهٔ عملکرد الزامیِ مدل ✅ تأییدشده
- **مراقبت باید در منزل بیمار ارائه شود؛ انجام خدمات (تزریقات، پانسمان، واکسیناسیون، ویزیت) در محل ستادی مرکز ممنوع است.** بنابراین مرکز دارای مجوز یک **نهاد اعزام/هماهنگی است، نه درمانگاه مراجعه‌حضوری** — که از نظر ساختاری *با یک پلتفرم تطبیق/اعزام سازگار است.*
- پس از **موافقت اصولی**، مؤسس **حداکثر یک سال** فرصت دارد مرکز را برای بازدید نهایی آماده کند.
## ۴.۴ الزام تجارت آنلاین — نماد اعتماد الکترونیکی (e-namad) ✅ تأییدشده
- یک **نماد اعتماد الکترونیکی** برای سایت ایرانی‌ای که خدمات/فروش آنلاین ارائه می‌دهد لازم است — که شامل پلتفرم شما می‌شود. **تنها توسط مرکز توسعه تجارت الکترونیکی** زیر نظر وزارت صنعت، معدن و تجارت صادر می‌شود.
- برای یک سایت درآمدزا **عملاً الزامی است** چون قواعد PSP/شاپرک برای دریافت درگاه پرداخت اینترنتی (IPG) نیاز به نماد دارند. (توجه: وضعیت «الزامی» نوساناتی نظارتی داشته.) منابع: [ecommerce.gov.ir](https://ecommerce.gov.ir)، [راهنمای نت‌افراز](https://www.netafraz.com/blog/getting-enamad-complete-guide/).
## ۴.۵ شکاف قانون کار و به‌رسمیت‌شناختن بازار (⚠️ اطمینان متوسط)
- **پرستاران منزل خارج از شمول رژیم «مشاغل سخت و زیان‌آور»اند** که از حقوق بیمه/بازنشستگی پرستاران بیمارستانی بهره‌مند می‌کند، چون قانون به‌طور خاص از کارکنان شرکت‌های مراقبت در منزل نام نبرده. تا سال ۱۳۹۸، **~۷۰۰ شرکت خدمات درمانی در منزل** ثبت شده بودند (هدف ~۱٬۰۰۰)؛ این شکاف طبق گزارش‌ها تا ۱۴۰۲–۱۴۰۴ بدون قانونگذاری حل‌کننده ادامه داشت. منبع: [مصاحبهٔ ایلنا با عضو شورای‌عالی نظام پرستاری](https://www.ilna.ir/بخش-کارگری-9/797233). *(منبع واحد ۱۳۹۸؛ ارقام کفِ تاریخی‌اند — وضعیت فعلی را بررسی کنید.)*
## ۴.۶ سایر تعهداتی که باید برنامه‌ریزی کنید
- **مالیات و ثبت شرکت** (ثبت شرکت، پروندهٔ مالیاتی، ارزش افزوده در صورت لزوم) — استاندارد برای هر کسب‌وکار ایرانی. **[جزئیات با حسابدار بررسی شود]**
- **بیمه/تأمین اجتماعی** پرستارها بسته به اینکه آن‌ها را کارمند یا پیمانکار طبقه‌بندی کنید متفاوت است (بخش ۲.۲ را ببینید). **[مشاورهٔ قانون کار بگیرید — مهم‌ترین تصمیم ساختاری]**
- **نردبان جریمهٔ عدم انطباق:** تذکر شفاهی/کتبی ← تعطیلی ۱–۳ ماه ← تعطیلی ۳ ماه–۱ سال ← **لغو دائم پروانه + ارجاع به مراجع قضایی.** فعالیتِ بدون مجوز ریسک حقوقی واقعی است. **✅ تأییدشده**
---
# ۵. توصیه‌های عملی و راهبرد ورود به بازار
**۱. اکنون قالب قانونی را انتخاب کنید: یک «مرکز خدمات پرستاری در منزل» ثبت کنید.** یا خودتان (اگر پرستار با کارشناسی + ۵ سال سابقه هستید) یا یک هم‌بنیان‌گذار پرستار به‌عنوان مؤسس/مسئول فنی. اگر بعداً می‌خواهید خدمات بالینیِ زیرنظر پزشک ارائه دهید، یک شریک پزشک و مسیر بالینی را جداگانه اضافه کنید.
**۲. سریع وارد بازار شوید با مدل آسانیسم — با مراکز دارای مجوز همکاری کنید** در حالی که پروانهٔ خودتان در فرایند است. این به شما اجازه می‌دهد لایهٔ فناوری/برند/مارکت‌پلیس را قانونی و سریع راه‌اندازی کنید، سپس به‌مرور تأمین نیرو را داخلی کنید.
**۳. اعتماد احرازشده را به کلِ برند خود تبدیل کنید.** یک نشان احرازِ قابل‌رؤیت را بسته‌بندی (نه آپ‌سل) کنید: ✓ هویت احرازشده (شاهکار + تطبیق چهره)، ✓ پروانهٔ صلاحیت حرفه‌ای وزارت بهداشت تأییدشده، ✓ شمارهٔ نظام پرستاری، ✓ عدم سوء پیشینه در پرونده، ✓ دورهٔ آزمایشی + تضمین. شمارهٔ پروانهٔ خود را مثل سلامت اول نمایش دهید.
**۴. جغرافیایی را ببرید که دیگران نادیده می‌گیرند.** تهران/کرج اشباع و متمرکزند؛ **شهرهای ردهٔ دوم** (مشهد، اصفهان، شیراز، تبریز، اهواز، قم) را هدف بگیرید که رقبا در آن‌ها کم‌حضورند.
**۵. احراز را بخرید، نسازید.** یک فروشندهٔ KYC (فینوتک یا یوآیدی) را برای شاهکار + کد ملی + تشخیص زنده‌بودن یکپارچه کنید؛ پروانهٔ صلاحیت حرفه‌ای + شمارهٔ نظام پرستاری را برای لایهٔ مجوز مطالبه کنید؛ عدم سوء پیشینهٔ آپلودشده توسط پرستار را بخواهید.
**۶. مدل استخدام را پیش از مقیاس‌دهی با وکیل تصمیم بگیرید** — مارکت‌پلیس بی‌طرف در برابر کارفرما/آژانس. از دام «کنترل برای کیفیت + پیمانکار برای هزینه» که مسئولیت طبقه‌بندی نادرست را فعال می‌کند پرهیز کنید. صرف‌نظر از انتخاب، بیمهٔ مسئولیت پلتفرم داشته باشید.
**۷. از روز اول علیه حذف واسطه مهندسی کنید:** پرداخت امانی + حل اختلاف داخل پلتفرم، تضمین پوشش پرستار جایگزین، EVV ورود/خروج، و حمایت‌هایی که فقط داخل پلتفرم اعمال می‌شوند.
**۸. زود چرخهٔ نهادی را بسازید:** مشارکت‌های ارجاع ترخیص بیمارستانی (پس از جراحی، پس از سکته)، و قراردادهای آزمایشی B2B با بیمه‌گرها (سلامت / تأمین اجتماعی)، خیریه‌ها یا کارفرمایان برای یارانه‌دادن ویزیت‌ها.
**۹. یک ردهٔ سبک‌ترِ «همراهی / کمک روزمره» اضافه کنید** (مدل Papa) — محدودیت تأمین نیروی کمتر، بازار وسیع‌تر، و خوراک‌دهنده به پرستاری ماهر هنگام تشدید نیاز. **دیاسپورا** را هدف بگیرید («برای مراقبت از والدینت در وطن هزینه کن»).
**۱۰. هرگز ایمنی را بیش از حد تبلیغ نکنید.** هر جریمهٔ Care.com به ادعای بررسی‌ای که انجام نشده یا لغو با الگوی تاریک برمی‌گردد. کمتر وعده دهید، بیشتر احراز کنید، لغو را آسان کنید.
---
## پرسش‌های باز / مواردی که باید پیش از راه‌اندازی راستی‌آزمایی شوند
۱. **تعداد فعلی (۱۴۰۴–۱۴۰۵) شرکت‌های ثبت‌شده** و وضعیت کنونی شکاف قانون کارِ سخت و زیان‌آور برای پرستاران منزل — آیا قانونی آن را حل کرده است؟
۲. **الزامات کامل سرمایه، مکان، نیروی انسانی و بیمه** به‌طور خاص برای مسیر مرکز خدمات پرستاری، و اینکه آیا یک **مارکت‌پلیس فناوری‌محور** می‌تواند با پیمانکاری *فقط* به مراکز دارای مجوزِ همکار (مدل آسانیسم) فعالیت کند بدون داشتن پروانهٔ خودش در ابتدا.
۳. آیا **نظام پرستاری / وزارت بهداشت هیچ API اعتبارسنجی B2B** پشت یک پورتال ارائه می‌دهند (تاکنون فقط از طریق جست‌وجوی عمومی «یافت نشد»).
۴. **جزئیات مالیات، ارزش افزوده و ساختار شرکت** با یک حسابدار محلی؛ **طبقه‌بندی استخدام** با یک وکیل قانون کار.
---
### منابع (منتخب)
**ایران — حقوقی و بازار داخلی (تأییدشده):** arakmu.ac.ir/vct/fa/regulation/1063/ · mcls.gov.ir/fa/law/61 · qavanin.ir/Law/TreeText/83385 · irannurse.ir · vct.iums.ac.ir · ilna.ir/بخش-کارگری-9/797233 · ecommerce.gov.ir · netafraz.com/blog/getting-enamad-complete-guide/ · asanism.com · snapp.doctor/home-nursing/ · salamateaval.com · myket.ir/app/hirad.sc.com
**پلتفرم‌های خارجی:** techcrunch.com (Honor، Cera، Vivian، Birdie، Portea) · ftc.gov و cnbc.com (Care.com FTC) · mobihealthnews.com (Papa) · florence.co.uk · techcrunch.com/technode.global (Homage) · tvmcapitalhealthcare.com (Manzil) · quartr.com (Veteranpoolen)
**ریسک‌ها و شکست‌ها:** thedailybeast.com و backgroundchecks.com (Care.com/WSJ) · engadget.com (پاک‌سازی آگهی‌ها) · nurse.org و washingtonpost.com (پرستار قلابی Womack) · hrmorning.com و ogletree.com (طبقه‌بندی نادرست) · shiftcare.com و axiscare.com (جابه‌جایی نیرو) · sharetribe.com (حذف واسطه) · aarp.org (سوءاستفادهٔ مالی از سالمند) · pymnts.com (Care.com ۱ میلیون دلار Marin)
**ابزار احراز:** ncsbn.org و nursys.com (Nursys) · nmc.org.uk (NMC) · checkr.com و sterlingcheck.app (شرکت‌های بررسی پیشینه) · behdasht.gov.ir و heyvagroup.com (مجوز وزارت بهداشت/نظام پرستاری) · fa.wikipedia.org/سامانه_شاهکار (شاهکار) · finnotech.ir (KYC) · asretarakonesh.ir (۸ شرکت ایرانی KYC) · heyvalaw.com (عدم سوء پیشینه از طریق ثنا)
*این گزارش از یک مرحلهٔ تحقیقِ راستی‌آزمایی‌شدهٔ متخاصمانه (چارچوب حقوقی ایران + رقبای داخلی) به‌علاوهٔ سه عامل تحقیقاتی هدفمند (رقبای خارجی، نمونه‌های ریسک/شکست، ابزار احراز) تدوین شده است. مقررات دهه‌های گذشته، آمار خوداظهاریِ رقبا و ارقام سرمایه را پیش از تصمیم‌گیری یا انتشار با منابع اولیهٔ روز راستی‌آزمایی کنید.*
-293
View File
@@ -1,293 +0,0 @@
# Building a Private Home-Nursing Platform in Iran — Research & Strategy Report
> **Idea:** A platform that helps families in Iran easily find and hire vetted private/home-care nurses for their loved ones — elderly care, post-surgery recovery, infant/newborn care, and chronic-illness management.
**Prepared:** 2026-06-16 · **Scope:** (1) competitor & market analysis, (2) problems & risks, (3) nurse identity & credential verification, (4) Iranian legal landscape, plus actionable recommendations.
**A note on sourcing.** This report combines (a) an adversarially fact-checked research pass on the **Iranian legal framework and local competitors** (claims that survived a 3-vote verification process are marked **✅ verified**; claims that were *disproven* are flagged explicitly), and (b) targeted web research on **foreign platforms, risk/failure cases, and verification tooling**. Where a fact comes from a company's own marketing page it is noted as self-reported/unaudited; where it leans on model knowledge rather than a fetched source it is flagged **[unverified — confirm before relying on it]**. Treat funding figures and any decades-old regulations as "verify before publishing."
---
## Executive Summary
**You can legally build this in Iran — but it is a *licensed healthcare activity*, not a free-to-launch marketplace.** The operative credential is a Ministry of Health **establishment permit (پروانه تأسیس)** plus a **technical-director license (پروانه مسئول فنی)**, granted by the MoH Treatment Deputy (معاونت درمان) after approval by the Article-20 medical-affairs commission. **✅ verified**
There are **two regulatory tracks, and the choice is decisive:**
- **Home *nursing* services center** (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل) — governed via the Iranian Nursing Organization; a **nurse** (BSc + 5 yrs clinical experience) can be founder and technical director. **This is the right vehicle for your idea.** **✅ verified**
- **Home *clinical* care center** (مرکز خدمات و مراقبت‌های بالینی در منزل) — **both founder and technical director must be physicians.** Avoid unless you bring a physician partner. **✅ verified**
**The market is real and already competitive** — Asanism, Snapp Doctor, Salamat Aval, and Hirad all operate today — **but they are heavily concentrated in Tehran/Karaj and run mostly as direct-dispatch staffing, not as trust-first marketplaces.** That is your gap. **✅ verified**
**The hardest problem is trust and safety, not technology.** Every cautionary tale abroad (Care.com's regulatory settlements, the "imposter nurse" credential-fraud case, gig-marketplace misclassification judgments) points to one rule: **own the vetting; never offload it to families, and never market a safety check you don't actually perform.**
**The good news on verification:** Iran has a competitive market of off-the-shelf KYC APIs (Shahkar phone↔national-ID matching, face/liveness matching against the national card) that make identity verification the *easy* layer. The license layer is harder (no public B2B API), but the MoH's **پروانه صلاحیت حرفه‌ای** nurse-competency license is the credential to demand — it already bundles a criminal-record screen.
**Bottom line strategy:** Register as a **home-nursing services center**, partner early with already-licensed centers (the Asanism model) to move fast, make **verified trust your entire brand**, target **under-served cities outside Tehran**, and build toward **B2B/institutional revenue** (hospital post-discharge pipelines, insurers, employer benefits) on top of consumer pay.
---
# 1. Competitor & Market Analysis
## 1.1 Iranian players (the people you'll actually compete with) ✅ verified
The local market is **active and growing** — as of 2019 roughly **700 home-medical-service companies** were registered, with an official push toward ~1,000 (almost certainly higher now). **✅ verified** (single 2019 source; treat as a historical floor). The leaders:
| Player | Model | Target segments | Notable facts | Pricing |
|---|---|---|---|---|
| **Asanism (آسانیسم)** | Matching/marketplace that supplies caregivers **through licensed partner centers** (intermediary model) | Elderly, childcare, post-surgical, chronic, clinical (injections, dressing, catheter, in-home blood draws) | Markets identity-vetting (احراز هویت), health-protocol compliance, a reported ~40M toman security promissory note, and 2448 hr trial periods. **~99% concentrated in Tehran/Karaj**, ~1,650 active caregivers across 4 partner facilities (self-reported, unaudited) | Listed, current (1404/1405) |
| **Snapp Doctor (اسنپ دکتر)** | Health vertical of Snapp (Iran's largest super-app); managed dispatch | Elderly, post-surgical (wound care, suture removal), infant/child, chronic (stroke, cancer, Parkinson's, MS, Alzheimer's) | Operates in Tehran, Karaj, Qom, Shiraz, Kermanshah, Isfahan, Mashhad. Holds a **general online-medical-intermediary ("پل ارتباطی") license****NOT** a specific home-nursing MoH authorization (this was a disproven claim) | — |
| **Salamat Aval (سلامت اول)** | **Direct dispatch of its own nurses** (not an open marketplace) — the company picks the nurse | Elderly care (hourly / daily / 24-hour) | **3,000+ active personnel**, 24/7 call center (1527), Tehran + suburbs (Karaj, Pardis). Holds **official MoH license no. 388180-3** | "توافقی" (negotiable); 24-hr shifts cost less per hour |
| **Hirad (هیراد)** | App-based (Cafe Bazaar, Myket) managed staffing/dispatch | Eldercare, childcare/infant, post-surgery/recovery, home injections, home lab tests | Shows both sides (families request; nurses "view available jobs"); advertises "استخدام بدون هزینه" (no placement fee). States it operates under MoH authorization. Modest adoption | — |
**What this tells you:**
1. **The dominant model is direct/managed dispatch, not a true trust-first two-sided marketplace.** Even "marketplace-ish" players (Asanism, Hirad) function as managed staffing agencies. A genuinely transparent, review-driven, family-chooses-the-nurse experience is still relatively open.
2. **Geographic concentration is extreme.** Tehran/Karaj dominate; second-tier cities (Mashhad, Isfahan, Shiraz, Tabriz, Ahvaz, Qom) are thinly served. **This is the clearest white space.**
3. **Pricing is opaque and negotiable (توافقی).** Transparent, upfront pricing is a differentiator families would value.
4. **"Licensed" is a real trust signal** — Salamat Aval advertises its MoH permit number prominently. You should too.
> ⚠️ **Disproven claims to not repeat:** Snapp Doctor does **not** hold a home-nursing-specific MoH license (only a general intermediary license); a per-procedure city-pricing example attributed to it was also disproven. Competitor headcounts (1,650 / 3,000) are self-reported marketing numbers.
## 1.2 Foreign platforms (models to learn from)
Foreign platforms cluster into **four structural models** — knowing which one you're imitating matters more than any single feature:
1. **Pure consumer marketplace** — connects families directly to *self-employed* caregivers; the platform employs no one (Care.com, Curam). Cheap to scale, weak quality control, serious worker-misclassification legal risk.
2. **Managed / employed "full-stack"** — company hires, trains, vets, and dispatches its own staff, with tech on top (Honor, Cera, Homage, Portea). Higher quality and defensibility; capital-intensive.
3. **Staffing platform for facilities** — fills hospital/care-home shifts, not consumer-facing (Florence, Vivian Health).
4. **Demand-aggregation + payor integration** — lead-gen / companionship / insurance plays (Papa, Pflege.de).
**The clearest lesson from the data: capital and durable contracts flow to the managed/full-stack and payor-integrated models, while pure independent-contractor marketplaces keep hitting a labor-law ceiling.**
### Comparison table (selected; funding figures approximate — verify before relying)
| Platform | Country | Model | Standout features | Monetization | Differentiator / outcome |
|---|---|---|---|---|---|
| **Care.com** | US | Pure subscription marketplace | Profiles, reviews, *optional paid* background checks | Family + caregiver subscriptions; check add-ons; **no cut of wages** | Largest/broadest. **Cautionary tale** — FTC $8.5M settlement (2024), Marin DA $1M (2020) |
| **Honor** | US | Managed full-stack + franchise | Tech+ops platform; absorbed Home Instead's global network | B2B + franchise; hourly care | Unicorn (~$1.25B+); ~$2.1B combined w/ Home Instead; 100k+ caregivers |
| **Papa** | US | Companionship + payor-billed | "Papa Pals" companionship for loneliness; care navigation | **B2B contracts w/ Medicare Advantage / Medicaid / employers** | Reframed loneliness as a billable health need; $150M Series D |
| **Cera** | UK | Managed full-stack + predictive AI | Predicts falls/hospitalizations days ahead; carers log vitals | **B2B w/ NHS & 150+ councils** | Owns workforce *and* data; ~$1B unicorn (2025) |
| **Florence** | UK | Staffing marketplace for facilities | Instant shift-booking; rota/payroll/training; DBS vetting | Per-shift commission + SaaS | Disintermediates expensive nursing agencies |
| **Curam** | UK | Pure marketplace (self-employed) | DBS + biometric ID checks; bundled insurance | **12.5% + VAT commission** (carers keep ~85%) | Lowest-fee self-employed model |
| **Homage** | Singapore (+MY/AU) | **Curated marketplace + human matching** | Algorithm surfaces candidates, *staff* makes final match; telehealth; gov-subsidy integration | Per-hour spread (~S$36/hr) + packages + B2B | Clinically-capable curated network; $30M Series C (Temasek). **Best model fit for Iran** |
| **Portea Medical** | India | Managed clinical provider | Physio, nursing, doctor visits, labs, **equipment rental**; diaspora "NRI package" | Subscription + per-visit + rental | Largest in India; ~$114M raised |
| **Nightingales / Care24 / HCAH** | India | Managed clinical providers | Chronic/specialty programs; **insurance-billed cashless** (HCAH, 40+ insurers) | Subscription + per-visit + B2B | Market consolidating fast (both acquired) |
| **Manzil / NMC Homecare** | UAE | Licensed clinical home-health | JCI-accredited; hospital-integrated; IV, physio, mother & baby | Fee-for-service, **insurance-billed** | Premium clinical credibility |
| **Veteranpoolen** | Sweden | Staffing employing **retirees** | Priced for Sweden's RUT 50% tax deduction | RUT-subsidized fees + franchise | Unique labor supply (active pensioners) |
| **Bakıcıburada** | Turkey | Caregiver classifieds | ID + criminal-record verification; map discovery | Listing/subscription fees | Bootstrapped; **closest analog to a realistic early-stage Iran market** |
### Most relevant regional signals
- **India is the closest comparator** (large population, low public coverage, family-pays-out-of-pocket). Tellingly, **no pure family-to-caregiver marketplace dominates there** — every leader runs a managed/employed clinical model, because the country lacks structured paramedical training, so **vetting and quality control *are* the product.**
- **Germany's** one attempt at managed carer-matching (Careship) went **insolvent**; the survivors are capital-light lead-gen/classifieds + insurance-subsidized consumables.
- **Turkey** is mostly bootstrapped classifieds and small agencies — a realistic near-term picture for Iran.
### Five transferable ideas for an Iran-based founder
1. **Don't build a pure "Uber-for-nurses" of independent contractors.** The clearest blow-ups (Careship insolvency; Helpling's gig cleaners reclassified as employees; Care.com's quality scandals) are all pure gig models. For care, the proven sweet spot is a **curated marketplace + human vetting** hybrid (the **Homage** model: algorithm surfaces candidates, *your team* makes the final match and owns screening/training).
2. **Make vetting & training the core product, not a paid add-on.** In every market with weak licensing infrastructure, winners *own* caregiver quality (background/ID checks, training academies, continuity of carer). In Iran, **trust infrastructure is the entire value proposition** — bundle it in; don't upsell it the way Care.com did.
3. **Build toward B2B/institutional payors early.** The highest-value outcomes monetize through institutions: Cera (NHS), Papa (Medicare Advantage), HCAH (insurers). Iran's analogs: **Social Security Organization (تأمین اجتماعی), Salamat/health insurers, hospital post-discharge referrals, and corporate employee benefits.** Hospital post-surgery/post-stroke discharge is a high-intent acquisition channel.
4. **Stack two revenue engines and look for a subsidy hook.** (a) per-hour take-rate/markup on managed care, plus (b) subscription/lead-gen. Germany's insurance-funded consumables box and Sweden's RUT 50% tax deduction show the power of **plugging into an existing subsidy so the service feels cheap to the family** — scout whether any Iranian insurer, charity, or elder-care endowment could subsidize visits.
5. **Productize "companionship / daily-living help" as a separate, lighter tier.** Papa built a unicorn-track business on *companionship for isolated seniors*, not skilled nursing — lower-skill, easier to staff, broader market, and upsells to clinical care as needs escalate. Given Iran's large diaspora, a **"remote children paying for a parent's care back home"** angle (Portea's NRI package; Homage's diaspora users) is directly relevant.
> **Lowest-risk entry wedge:** Birdie's "SaaS-for-providers" approach — sell scheduling/compliance/family-dashboard software *to* existing Iranian home-care agencies rather than competing head-on — is worth keeping in your back pocket if licensing/labor classification proves to be a hard early barrier.
---
# 2. Problems & Risks
This sector pairs two unusually dangerous features: the buyers are **vulnerable people** (elderly, post-surgical, infants, chronically ill) and the service happens **unsupervised, inside a private home**. That combination amplifies every standard marketplace risk and adds life-and-death stakes.
**The single most important strategic lesson:** *a platform that markets safety while pushing the actual vetting onto families will eventually face regulatory, legal, and reputational catastrophe.*
## 2.1 Trust & safety failures
**Risk:** Connecting strangers to vulnerable people without rigorous *platform-owned* vetting enables theft, abuse, fraud, and fatal harm — and the public blames the *platform*.
**Real cases:**
- **Care.com / Wall Street Journal (2019):** Over ~6 years, **nine caregivers listed on Care.com who had police records were later accused of crimes while a child or elder was in their care — including theft, abuse, sexual assault, and murder.** The site also carried hundreds of day-care listings falsely claiming state licensing. Standard membership performed only a "preliminary screening," not a real background check; stronger checks cost extra. ([Daily Beast/WSJ](https://www.thedailybeast.com/wsj-kids-assaulted-died-in-hands-of-carecom-caregivers/), [BackgroundChecks.com](https://www.backgroundchecks.com/blog/care-com-comes-under-fire-for-background-check-policies))
- **Mass listing purge:** Care.com pulled **~46,594 day-care listings (~45% of that database)** after many were found to be false, nonexistent, or falsely claiming licensing. ([Engadget](https://www.engadget.com/2019-03-31-care-com-pulls-47000-daycare-listings.html))
- **The "imposter nurse" (Shannon Womack, 2025):** Allegedly posed as a nurse using **20+ aliases and 7 SSNs**, stealing four real nurses' credentials, and worked at **9+ facilities** by submitting **forged documents through staffing agencies** — even creating a fake LLC to self-deploy. Charged with **43 counts** including endangering a care-dependent person and stealing medication from seniors. ([Nurse.org](https://nurse.org/news/fake-nurse-arrested-shannon-womack-nursing-fraud/), [Washington Post](https://www.washingtonpost.com/nation/2025/07/23/pennsylvania-fake-nurse-shannon-womack/)) — *the key cautionary tale for a nurse marketplace: even agencies that thought they were verifying were defeated by stolen-identity + forged documents.*
**Mitigations:**
- **Own the vetting; never delegate it to families.** Make identity + criminal-record + license verification a *platform-performed, non-optional* gate before any nurse is bookable.
- **Verify credentials at the authoritative source**, not via uploaded PDFs (which are exactly what gets forged). In Iran: the **Iranian Nursing Organization** registry and the MoH **پروانه صلاحیت حرفه‌ای** (see §3).
- **Bind every profile to the national ID + a liveness selfie** to defeat the aliases/stolen-identity pattern.
- **Re-verify periodically** (license expiry, suspensions, new records).
## 2.2 Liability & legal exposure
**Risk:** Three exposures stack — **(a) worker misclassification** (calling nurses "contractors" when the law treats them as employees), **(b) vicarious liability / negligent hiring** (sued when a caregiver harms a patient), and **(c) insurance gaps**. The "we're just a neutral tech platform" defense is eroding worldwide.
**Real cases:**
- **$10M California judgment against TLC Home Care** for misclassifying in-home workers as contractors (2023). ([HRMorning](https://www.hrmorning.com/news/worker-misclassification-tlc-home-care/))
- Federal courts repeatedly find in-home caregivers are **employees, not contractors**, under the "economic realities/control" test — *the more you standardize and supervise care for quality, the more you look like an employer.* ([Ogletree Deakins](https://ogletree.com/insights-resources/blog-posts/federal-court-finds-in-home-caregivers-were-employees-not-independent-contractors-under-economic-realities-control-test/))
- Home-care agencies are routinely held liable under *respondeat superior* and for **negligent hiring/supervision**. ([Nursing Home Law Center](https://www.nursinghomelawcenter.org/news/home-health-aide-lawsuit/))
**Mitigations:**
- **Decide the model deliberately:** either a *true neutral marketplace* (minimal control; family is the employer) or a *full agency/employer model* (payroll, supervision, insurance). **The dangerous middle — heavy control for "quality" but contractor classification for cost — is exactly what triggers misclassification judgments.**
- **[unverified — confirm with local counsel]** Iranian labor law (قانون کار) and social-security (تأمین اجتماعی) obligations attach to employment relationships; classify correctly *before* launch. (Note the documented labor-law gap for home-care nurses — see §4.5 — cuts both ways: less mandated cost, but unresolved status.)
- **Carry platform-level general + professional liability insurance**, and require nurses to carry their own.
- **Document every vetting step** — it's both prevention and your legal defense against negligent-hiring claims.
## 2.3 Operational & quality-control problems
**Risk:** Extreme caregiver churn, no-shows that strand a vulnerable patient, wide quality variance, near-impossible remote monitoring, and **disintermediation** (families + nurses pairing off-platform to dodge fees).
**Real data:**
- Caregiver turnover hit **~79% in 2024**, with **~70% of new hires quitting within 100 days**; each departure costs **$2,600$5,000** and clients often leave with the caregiver. ([ShiftCare](https://shiftcare.com/us/blog/caregiver-retention-in-2026-what-the-data-tells-us-about-turnover), [AxisCare](https://axiscare.com/blog/understanding-the-90-day-turnover/))
- **Disintermediation is the predictable failure mode** for recurring, relationship-based services — once trust forms, families and nurses transact privately. Punitive anti-leakage tactics tend to backfire. ([Sharetribe](https://www.sharetribe.com/academy/how-to-discourage-people-from-going-around-your-payment-system/))
**Mitigations:**
- **Electronic Visit Verification (EVV):** GPS/time-stamped clock-in/out with automated missed-visit alerts, so no-shows trigger an instant backup dispatch.
- **Backup/coverage guarantee:** a bench of available nurses and a promise to fill no-shows fast — a core reason to use you instead of hiring privately.
- **Beat leakage with retained value, not lock-in:** integrated scheduling/payments, the backup guarantee, insurance that *only* applies to on-platform bookings, and reviews/dispute protection that vanish if they go offline.
- **Continuity-first matching:** a primary nurse + named backup per patient; track continuity as a KPI.
## 2.4 Payment & fraud risks
**Risk:** Off-platform payment (the financial side of leakage), fake reviews, identity fraud, credential forgery, and **financial elder abuse.**
**Real data:**
- Gig-marketplace fraud runs ~**2× the rate** elsewhere; one 2025 report cited a 21% YoY rise, **>90% of it impersonation**. ([Security Boulevard](https://securityboulevard.com/2024/05/when-the-gig-is-fraud-building-trust-for-online-marketplaces-with-identity-verification/))
- **Financial elder abuse:** a CFPB review found that where the victim knew the perpetrator, **1 in 9 was a non-family caregiver, average loss $57,800.** ([AARP](https://www.aarp.org/money/scams-fraud/financial-abuse-home-care-aide/))
- **Care.com penalties:** **2020 — $1M Marin County DA** (falsely claimed checks searched the National Sex Offender Registry; improper auto-renewals); **2024 — $8.5M FTC** (inflated available-job counts — more than half of postings came from users who couldn't actually hire — plus dark-pattern cancellation). ([CNBC](https://www.cnbc.com/2024/08/26/carecom-reaches-8point5-million-us-ftc-settlement-over-job-listings-renewals-.html), [PYMNTS](https://www.pymnts.com/legal/2020/care-com-pays-1m-settlement-over-auto-renewal-background-check-allegations/))
**Mitigations:**
- **Strong identity verification at onboarding** (national-ID binding + liveness) for both nurses *and* paying families.
- **Tie reviews to verified, completed, on-platform bookings.**
- **In-platform escrow/payment with dispute resolution** — reduces fraud *and* is your strongest anti-leakage lever (buyer protection only if they pay through you).
- **Protect clients' finances** (advise families: secure cards, view-only monitoring, watch for sudden POA/will changes); consider bonding nurses against theft.
- **Never advertise a guarantee or check you don't deliver, and make cancellation genuinely easy** — every Care.com penalty traces to deceptive safety marketing or dark patterns.
## 2.5 Trust dynamics unique to caring for vulnerable people at home
The service is delivered **alone, unobserved, inside the home**, to people who often **cannot reliably report** what happened (infants; dementia, post-anesthesia, cognitively impaired patients). Information asymmetry is extreme and a single incident can destroy a fragile brand.
**Mitigations:** compensate for unobservability with **structured oversight** — EVV, periodic supervisory tele-check-ins by a senior nurse, family-visible care logs, consented in-home cameras in common areas; a **two-way feedback loop** the patient isn't the sole source of (structured family check-ins, easy in-app concern flagging, monitoring for AARP "red flags"); **rapid-response incident protocols** with immediate suspension on credible complaints; and **match qualification to acuity** (route high-acuity post-surgical/ventilator cases only to verified RNs; reserve aide-level providers for companionship).
---
# 3. Nurse Identity & Credential Verification
**The question "is this nurse really who they say, and really licensed?" splits into two checks that should be separate pipeline stages:**
- **License check** — *are they a registered nurse?* (professional registry)
- **Identity + background check** — *are they who they claim, with no disqualifying record?* (KYC + criminal record)
## 3.1 Global reference models (best practices to emulate)
- **USA — Nursys / e-Notify (the gold standard):** the only national license database, fed by state Boards of Nursing; **e-Notify *pushes* license/discipline status changes** to enrolled employers via a documented **API**. ([NCSBN](https://www.ncsbn.org/nursing-regulation/licensure/license-verification.page), [Nursys](https://www.nursys.com/EN/ENDefault.aspx)) — *lesson: continuous monitoring, not one-time vetting.*
- **UK — NMC register + DBS:** the NMC online register (free, updated daily, search by 8-char PIN) answers *"are they licensed?"*; the separate **DBS** criminal-record check answers *"are they safe?"**lesson: keep the two checks distinct.*
- **Background-check vendors (Checkr, Sterling):** API-first, built to embed in gig/marketplace flows; a caregiver check bundles criminal history, license verification, healthcare sanctions/exclusions, abuse-registry, employment/education, and re-screening. ([Checkr](https://checkr.com/our-technology/background-check-api), [Sterling](https://apidocs.sterlingcheck.app/))
**A robust pipeline = consent → identity verification → license verification (primary source) → criminal + abuse-registry checks → employment/education → ongoing monitoring.**
## 3.2 Iran-specific tooling (the operative part)
Iran has a usable stack, but it's **fragmented across regulators**, and the most sensitive check (criminal record) is **consent-gated to the individual**, not freely pullable by a company.
### A) Professional license — "is this a real nurse?" (two authorities, check both)
- **MoH professional-competency license — پروانه صلاحیت حرفه‌ای** at **Rn.behdasht.gov.ir** — the newer, **more authoritative** credential. Issuing it already vets the nurse's **scientific, ethical, health, AND criminal-record (سوء پیشینه)** standing, and the MoH states it is **required even for private in-home nursing.** **[the single most important credential to demand — it bundles a criminal-record screen]** ([behdasht.gov.ir](https://behdasht.gov.ir/), [heyvagroup](https://www.heyvagroup.com/shownews/12145/))
- **Iranian Nursing Organization (سازمان نظام پرستاری) — نظام پرستاری number** via `ino.ir` / `membership.ino1.ir`. Reportedly allows third-party lookup/validation of a nurse's membership number; use as a **cross-check.** ([heyvagroup](https://www.heyvagroup.com/shownews/11343/))
- **No public B2B API was found for either** — realistic use today is **require upload + manual verification against the official record.** (The physician council's public `membersearch.irimc.org` shows what an equivalent nurse search could look like.) **[absence of API is "not found," not positively confirmed — verify via a B2B portal]**
### B) Identity verification — the *easy* layer (turnkey APIs exist)
A competitive market of Iranian **e-KYC vendors** sells ready APIs — **buy this, don't build it:**
- **Shahkar (شاهکار):** government service matching a **mobile SIM ↔ national ID (کد ملی)**; run by the CRA. Result in <1 sec. **Access is gated** (approval + agreement + indirect connection via the "سرو/Sarva" platform), so **consume it via a reseller** rather than integrating directly. ([fa.wikipedia](https://fa.wikipedia.org/wiki/سامانه_شاهکار), [Finnotech](https://finnotech.ir/))
- **National-ID validity & name matching (صحت‌سنجی کد ملی):** name + surname + کد ملی → match.
- **Face/liveness matching against the national-card or civil-registry (ثبت احوال) photo:** offered by **Finnotech, U-ID (یوآیدی), Jibbit (جیبیت), Farashensa (فراشناسا), Verify (ونیفای), Kavoshak (کاوشک)** and others — liveness + face match + OCR, often 513M+ verifications of track record. ([Asr-e Tarakonesh: 8 Iranian KYC firms](https://asretarakonesh.ir/index.php/2024/01/02/نگاهی-به-خدمات-۸-شرکت-ایرانی-فعال-در-حوز/))
- These vendors handle the regulator-gated upstream connections for you; a registered company signs up and consumes REST APIs.
### C) Criminal record — گواهی عدم سوء پیشینه (consent-gated, no company API)
- The official "no criminal record" certificate, obtained by the **individual** online via **adliran.ir** using their personal **ثنا (Sana)** password, or in person via **پلیس +۱۰**. ([heyvalaw](https://www.heyvalaw.com/web/articles/view/1865/))
- **A platform cannot pull it** — there is **no third-party/employer API**; issuance is bound to the person's own ثنا password. **Realistic design: require the nurse to obtain their own certificate and upload it, then re-request periodically***and note it's already embedded in the MoH پروانه صلاحیت حرفه‌ای*, so demanding that license partly covers it.
### D) Supporting rails
- **ثنا (Sana):** the judiciary's e-identity/notification system — relevant mainly as the **gateway to the عدم سوء پیشینه certificate.**
- **سجام (Sejam):** capital-market (securities) KYC — **largely irrelevant** here except as proof that strong non-in-person e-KYC rails exist in Iran.
## 3.3 Recommended verification pipeline for your platform
| Stage | Goal | Iran tool / how | Programmatic? |
|---|---|---|---|
| **0. Consent** | Lawful basis to verify + store data | Explicit in-app consent at onboarding | n/a |
| **1. Identity** | Match person ↔ کد ملی ↔ phone ↔ face | **Shahkar** + **national-ID validity** + **video/photo liveness vs. national card**, via **one KYC vendor** (Finnotech / U-ID / Jibbit / Farashensa / Verify) | **Yes — off-the-shelf API** |
| **2. License** | Verify nursing credential at source | **MoH پروانه صلاحیت حرفه‌ای** (Rn.behdasht.gov.ir) as primary **+** **INO نظام پرستاری number** (ino.ir) as cross-check | **Manual** (no public API found) — require upload + verify |
| **3. Criminal record** | No disqualifying record | **عدم سوء پیشینه** — nurse self-requests via adliran.ir/ثنا and uploads; *partly covered* by the MoH license | **No company API** — consent-gated, nurse-uploaded |
| **4. Ongoing monitoring** | Catch revocations/expiry | Periodic re-verification of license validity + re-request of عدم سوء پیشینه (e.g. annually); re-run Shahkar on phone change | Semi-manual; emulate Nursys e-Notify |
**Practical rules:** (1) **Buy identity verification** through one KYC provider — it shifts the regulator-gated Shahkar/ثبت احوال access burden onto a vendor that already holds the agreements. (2) **Anchor the license check on the MoH پروانه صلاحیت حرفه‌ای** (it's State-mandated for in-home nursing and bundles a criminal screen). (3) **Treat the criminal certificate as nurse-supplied + consent-gated.** (4) **Build continuous monitoring**, not one-and-done. (5) **Mind data-protection exposure** — routing through a licensed KYC intermediary keeps you compliant.
---
# 4. Legal Landscape in Iran
**Short answer: there is no law *against* the idea — but it is a regulated healthcare activity that requires Ministry of Health licensing. Operating without a permit is what's illegal, and penalties escalate to permanent revocation and judicial referral.** **✅ verified**
## 4.1 The governing framework ✅ verified
- Licensing flows through the **MoH Treatment Deputy (معاونت درمان)**, after approval by the **Article-20 medical-affairs commission** (کمیسیون قانونی تشخیص امور پزشکی موضوع ماده ۲۰), under the **Medical Affairs Law of 1334 (amended 1367)** and the **home-care bylaw approved 1378/7/17 (9 Oct 1999)** — 21 articles, 6 notes.
- **Each center receives one establishment permit (پروانه تأسیس) and one technical-director license (پروانه مسئول فنی).**
- Sources: [arakmu.ac.ir bylaw](https://arakmu.ac.ir/vct/fa/regulation/1063/), [mcls.gov.ir/fa/law/61](https://www.mcls.gov.ir/fa/law/61), [qavanin.ir (Article-20)](https://qavanin.ir/Law/TreeText/83385).
## 4.2 The two tracks — pick the nursing track ✅ verified
| | **Home Nursing Services Center** (your vehicle) | Home Clinical Care Center |
|---|---|---|
| Persian name | مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل | مرکز خدمات و مراقبت‌های بالینی در منزل |
| Governed via | Iranian Nursing Organization (نظام پرستاری) | MoH directly |
| Who can found / direct | **A nurse** — BSc nursing + **≥5 years clinical experience** (can be both founder & technical director) | **Both founder & technical director must be physicians** |
| Fit for your idea | ✅ Elderly / post-surgery / infant / chronic home nursing | Only if you bring a physician partner |
> ⚠️ A claim that "founder/director must be physicians for *all* home care" was **disproven** — that rule applies **only to the clinical-care track.** The nursing-services track allows a qualified nurse. Sources: [mcls.gov.ir/fa/law/61](https://www.mcls.gov.ir/fa/law/61), [irannurse.ir](https://irannurse.ir), [vct.iums.ac.ir](https://vct.iums.ac.ir).
## 4.3 How the model must operate ✅ verified
- **Care must be delivered in the patient's home; performing services (injections, dressing, vaccination, visits) at the center's HQ is prohibited.** The licensed center is therefore a **dispatch/coordination entity, not a walk-in clinic** — which structurally *fits a matchmaking/dispatch platform.*
- After **principal approval (موافقت اصولی)**, the founder has **up to one year** to ready the center for final inspection before operating.
## 4.4 Online-commerce requirement — e-namad ✅ verified
- An **e-namad (نماد اعتماد الکترونیکی, electronic trust symbol)** is required for an Iranian site providing online services/sales — which includes your platform. Issued **only by the Center for E-Commerce Development (مرکز توسعه تجارت الکترونیکی)** under the Ministry of Industry, Mine and Trade.
- It is **de facto mandatory for a monetized site** because PSP/Shaparak rules require e-namad to obtain an online payment gateway (IPG). (Note: "mandatory" status has had some regulatory flux.) Sources: [ecommerce.gov.ir](https://ecommerce.gov.ir), [netafraz guide](https://www.netafraz.com/blog/getting-enamad-complete-guide/).
## 4.5 Labor-law gap & market recognition (⚠️ medium confidence)
- **Home-care nurses fall outside the "arduous/hazardous work" (سخت و زیان‌آور) regime** that benefits hospital nurses' insurance/retirement, because the law doesn't specifically name staff of home-care companies. As of 2019, **~700 home-medical-service companies were registered** (target ~1,000); the gap reportedly persisted into 14021404 with no closing legislation. Source: [ILNA interview w/ INO Supreme Council member](https://www.ilna.ir/بخش-کارگری-9/797233). *(Single 2019 source; figures are a historical floor — confirm current status.)*
## 4.6 Other obligations to plan for
- **Taxation & company registration** (ثبت شرکت, tax file, VAT where applicable) — standard for any Iranian business. **[confirm specifics with an accountant]**
- **Insurance/social-security (تأمین اجتماعی)** treatment of nurses depends on whether you classify them as employees or contractors (see §2.2). **[get labor-law counsel — this is the highest-stakes structural decision]**
- **Penalty ladder for non-compliance:** verbal/written warning → 13 month closure → 3 month1 year closure → **permanent revocation + referral to judicial authorities.** Operating unlicensed is the real legal risk. **✅ verified**
---
# 5. Actionable Recommendations & Go-To-Market
**1. Choose the legal vehicle now: register a *Home Nursing Services Center*.** Either you (if a nurse with BSc + 5 yrs experience) or a nurse co-founder serves as founder/technical director. If you want to offer physician-supervised clinical services later, add a physician partner and the clinical-care track separately.
**2. Go to market fast via the Asanism model — partner with already-licensed centers** while your own permit is in process. This lets you launch the tech/brand/marketplace layer legally and quickly, then bring supply in-house over time.
**3. Make verified trust your entire brand.** Bundle (not upsell) a visible vetting badge: ✓ identity verified (Shahkar + face match), ✓ MoH پروانه صلاحیت حرفه‌ای confirmed, ✓ نظام پرستاری number, ✓ عدم سوء پیشینه on file, ✓ trial period + security guarantee. Display your own license number like Salamat Aval does.
**4. Win the geography others ignore.** Tehran/Karaj are saturated and concentrated; **target second-tier cities** (Mashhad, Isfahan, Shiraz, Tabriz, Ahvaz, Qom) where incumbents are thin.
**5. Buy verification, don't build it.** Integrate one KYC vendor (Finnotech or U-ID) for Shahkar + national-ID + liveness; require the MoH competency license + INO number for the license layer; require nurse-uploaded عدم سوء پیشینه.
**6. Decide the employment model with counsel before scaling** — neutral marketplace vs. employer/agency. Avoid the "control-for-quality + contractor-for-cost" trap that triggers misclassification liability. Carry platform liability insurance regardless.
**7. Engineer against disintermediation from day one:** in-platform escrow payment + dispute resolution, a backup-nurse coverage guarantee, EVV check-in/out, and protections that only apply on-platform.
**8. Build the institutional flywheel early:** hospital post-discharge referral partnerships (post-surgery, post-stroke), and pilot B2B contracts with insurers (Salamat / تأمین اجتماعی), charities, or employers to subsidize visits.
**9. Add a lighter "companionship / daily-living" tier** (the Papa model) — lower supply constraint, broader market, and a feeder into skilled-nursing as needs escalate. Court the **diaspora** ("pay for your parent's care back home").
**10. Never over-market safety.** Every Care.com penalty traces to claiming a check it didn't perform or a dark-pattern cancellation. Under-promise, over-verify, make cancellation easy.
---
## Key Open Questions / To Verify Before Launch
1. **Current (14041405) registered-company count** and the present status of the سخت و زیان‌آور labor-law gap — has any legislation closed it?
2. **Full capital, facility, staffing, and insurance requirements** for the nursing-services-center track specifically, and whether a **tech-first marketplace** can operate by subcontracting *only* to already-licensed partner centers (the Asanism model) without holding its own permit initially.
3. Whether the **INO / MoH offer any B2B verification API** behind a portal (only "not found" via public search so far).
4. **Tax, VAT, and company-structure specifics** with a local accountant; **employment classification** with a labor lawyer.
---
### Sources (selected)
**Iran — legal & local market (verified):** arakmu.ac.ir/vct/fa/regulation/1063/ · mcls.gov.ir/fa/law/61 · qavanin.ir/Law/TreeText/83385 · irannurse.ir · vct.iums.ac.ir · ilna.ir/بخش-کارگری-9/797233 · ecommerce.gov.ir · netafraz.com/blog/getting-enamad-complete-guide/ · asanism.com · snapp.doctor/home-nursing/ · salamateaval.com · myket.ir/app/hirad.sc.com
**Foreign platforms:** techcrunch.com (Honor, Cera, Vivian, Birdie, Portea) · ftc.gov & cnbc.com (Care.com FTC) · mobihealthnews.com (Papa) · florence.co.uk · techcrunch.com/technode.global (Homage) · tvmcapitalhealthcare.com (Manzil) · quartr.com (Veteranpoolen)
**Risks & failures:** thedailybeast.com & backgroundchecks.com (Care.com/WSJ) · engadget.com (listing purge) · nurse.org & washingtonpost.com (Womack imposter nurse) · hrmorning.com & ogletree.com (misclassification) · shiftcare.com & axiscare.com (turnover) · sharetribe.com (disintermediation) · aarp.org (financial elder abuse) · pymnts.com (Care.com $1M Marin)
**Verification tooling:** ncsbn.org & nursys.com (Nursys) · nmc.org.uk (NMC) · checkr.com & sterlingcheck.app (background vendors) · behdasht.gov.ir & heyvagroup.com (MoH/INO licensing) · fa.wikipedia.org/سامانه_شاهکار (Shahkar) · finnotech.ir (KYC) · asretarakonesh.ir (8 Iranian KYC firms) · heyvalaw.com (عدم سوء پیشینه via ثنا)
*Report compiled from an adversarially-verified research pass (Iranian legal framework + local competitors) plus three targeted research agents (foreign competitors, risk/failure cases, verification tooling). Verify decades-old regulations, self-reported competitor stats, and funding figures against current primary sources before making decisions or publishing.*
+63
View File
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>product/ — Balinyaar product &amp; domain knowledge — Balinyaar docs</title>
<link rel="stylesheet" href="assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="index.html">Docs home</a></li><li><a href="overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="business/index.html">Overview &amp; MVP scope</a></li><li><a href="business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="data-model/index.html">Overview &amp; decisions</a></li><li><a href="data-model/diagrams.html">Diagrams</a></li><li><a href="data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="data-model/02-geography.html">2. Geography</a></li><li><a href="data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="data-model/07-payouts.html">7. Payouts</a></li><li><a href="data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="data-model/09-messaging.html">9. Messaging</a></li><li><a href="data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="data-model/11-notifications.html">11. Notifications</a></li><li><a href="data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="payments/index.html">Overview &amp; exec summary</a></li><li><a href="payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="research/index.html">Overview &amp; exec summary</a></li><li><a href="research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="research/verification.html">Verification (research)</a></li><li><a href="research/legal-landscape.html">Legal landscape</a></li><li><a href="research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="notes/open-questions.html">Open questions</a></li><li><a href="notes/future-ideas.html">Future ideas</a></li><li><a href="wireframes/index.html">Wireframes</a></li><li><a href="fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="product-balinyaar-product-domain-knowledge"><code>product/</code> — Balinyaar product &amp; domain knowledge</h1>
<p>This folder is the <strong>source of truth</strong> for Balinyaar's business rules, data model, payments design, and market/legal research. The code is young; <strong>these docs are the decisions</strong>. Read the relevant doc before designing any schema, API, or feature — don't infer business rules from code.</p>
<blockquote><p><strong>For humans:</strong> open <a href="index.html"><code>index.md</code></a> (or the generated <a href="index.html"><code>index.html</code></a>) — it's the hub that links everything.</p>
</blockquote>
<h2 id="layout">Layout <a class="anchor" href="#layout" aria-hidden="true">#</a></h2>
<div class="table-wrap"><table><thead><tr><th>Path</th><th>What's in it</th></tr></thead><tbody>
<tr><td><a href="overview/platform-summary.html"><code>overview/</code></a></td><td>What Balinyaar is, the four cross-cutting ground truths, IRR/Toman rule, Persian glossary. <strong>Read first.</strong></td></tr>
<tr><td><a href="business/index.html"><code>business/</code></a></td><td>The 14 functional requirement areas (onboarding → admin), each with rules / Iran considerations / MVP-vs-deferred / supporting entities.</td></tr>
<tr><td><a href="data-model/index.html"><code>data-model/</code></a></td><td>The ~54-table schema across 13 domains + <a href="data-model/diagrams.html">diagrams</a>, design principles, design decisions.</td></tr>
<tr><td><a href="payments/index.html"><code>payments/</code></a></td><td>Fintech deep-dive with sources: payment reality, escrow ledger, BNPL, cancellation/payout, integrations.</td></tr>
<tr><td><a href="research/index.html"><code>research/</code></a></td><td>Market, risks, verification, legal landscape, go-to-market — adversarially fact-checked, cited.</td></tr>
<tr><td><a href="notes/open-questions.html"><code>notes/</code></a></td><td>Living notes: <a href="notes/open-questions.html">open questions</a>, <a href="notes/future-ideas.html">future ideas</a>.</td></tr>
<tr><td><a href="wireframes/index.html"><code>wireframes/</code></a></td><td>Screen wireframes (HTML).</td></tr>
<tr><td><a href="fa/index.html"><code>fa/</code></a></td><td>Farsi-language docs kept in parallel (research report + verification flow).</td></tr>
<tr><td><code>assets/</code></td><td>Shared CSS for the generated HTML view.</td></tr>
</tbody></table></div>
<h2 id="markdown-is-canonical-html-is-generated">Markdown is canonical; HTML is generated <a class="anchor" href="#markdown-is-canonical-html-is-generated" aria-hidden="true">#</a></h2>
<p>Every <code>.md</code> file is the editable source. The matching <code>.html</code> files are a <strong>generated</strong>, brand-styled, cross-linked browsing view (sidebar nav, Mermaid diagrams, dark mode). <strong>Never edit the <code>.html</code> by hand</strong> — edit the Markdown and regenerate.</p>
<h3 id="regenerating-the-html-view">Regenerating the HTML view <a class="anchor" href="#regenerating-the-html-view" aria-hidden="true">#</a></h3>
<p>The generator is dependency-free — plain Node, no <code>npm install</code>:</p>
<pre><code>cd product
node build-docs.mjs</code></pre>
<p>It walks every <code>.md</code> file, converts it to a styled <code>.html</code> at the same path, builds the sidebar from the manifest inside <code>build-docs.mjs</code>, and rewrites internal <code>…/foo.md</code> links to <code>…/foo.html</code>. If you add, remove, or rename a <code>.md</code> file, update the <code>NAV</code> manifest at the top of <a href="build-docs.mjs"><code>build-docs.mjs</code></a> so it appears in the sidebar.</p>
<h2 id="conventions">Conventions <a class="anchor" href="#conventions" aria-hidden="true">#</a></h2>
<ul>
<li>Each <code>.md</code> starts with a single <code># H1</code> (the generator uses it as the page title).</li>
<li>Cross-doc links are <strong>relative and use the <code>.md</code> extension</strong> (the generator rewrites them to</li>
</ul>
<p> <code>.html</code>); this keeps links working both in raw Markdown and in the rendered site.</p>
<ul>
<li>Languages: <strong>English is canonical.</strong> Farsi versions live under <code>fa/</code> and are linked, not inlined.</li>
<li>Money is <strong>IRR Rials</strong>; see <a href="overview/platform-summary.html">the ground truths</a>.</li>
</ul>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+50
View File
@@ -0,0 +1,50 @@
# `product/` — Balinyaar product & domain knowledge
This folder is the **source of truth** for Balinyaar's business rules, data model, payments design,
and market/legal research. The code is young; **these docs are the decisions**. Read the relevant
doc before designing any schema, API, or feature — don't infer business rules from code.
> **For humans:** open [`index.md`](index.md) (or the generated [`index.html`](index.html)) — it's
> the hub that links everything.
## Layout
| Path | What's in it |
| --- | --- |
| [`overview/`](overview/platform-summary.md) | What Balinyaar is, the four cross-cutting ground truths, IRR/Toman rule, Persian glossary. **Read first.** |
| [`business/`](business/index.md) | The 14 functional requirement areas (onboarding → admin), each with rules / Iran considerations / MVP-vs-deferred / supporting entities. |
| [`data-model/`](data-model/index.md) | The ~54-table schema across 13 domains + [diagrams](data-model/diagrams.md), design principles, design decisions. |
| [`payments/`](payments/index.md) | Fintech deep-dive with sources: payment reality, escrow ledger, BNPL, cancellation/payout, integrations. |
| [`research/`](research/index.md) | Market, risks, verification, legal landscape, go-to-market — adversarially fact-checked, cited. |
| [`notes/`](notes/open-questions.md) | Living notes: [open questions](notes/open-questions.md), [future ideas](notes/future-ideas.md). |
| [`wireframes/`](wireframes/index.html) | Screen wireframes (HTML). |
| [`fa/`](fa/index.html) | Farsi-language docs kept in parallel (research report + verification flow). |
| `assets/` | Shared CSS for the generated HTML view. |
## Markdown is canonical; HTML is generated
Every `.md` file is the editable source. The matching `.html` files are a **generated**,
brand-styled, cross-linked browsing view (sidebar nav, Mermaid diagrams, dark mode). **Never edit
the `.html` by hand** — edit the Markdown and regenerate.
### Regenerating the HTML view
The generator is dependency-free — plain Node, no `npm install`:
```bash
cd product
node build-docs.mjs
```
It walks every `.md` file, converts it to a styled `.html` at the same path,
builds the sidebar from the manifest inside `build-docs.mjs`, and rewrites internal `…/foo.md` links
to `…/foo.html`. If you add, remove, or rename a `.md` file, update the `NAV` manifest at the top of
[`build-docs.mjs`](build-docs.mjs) so it appears in the sidebar.
## Conventions
- Each `.md` starts with a single `# H1` (the generator uses it as the page title).
- Cross-doc links are **relative and use the `.md` extension** (the generator rewrites them to
`.html`); this keeps links working both in raw Markdown and in the rendered site.
- Languages: **English is canonical.** Farsi versions live under `fa/` and are linked, not inlined.
- Money is **IRR Rials**; see [the ground truths](overview/platform-summary.md).
-10
View File
@@ -1,10 +0,0 @@
1.(برای آینده) فلوی قیمت باید سمت ما باشه:
- ما وقتی فرد میخواد دستمزد ساعتی دریافتی و روزانه اش رو مشخص کنه باید یه رنجی از بازار بهش نشون بدیم بنظرم و چندتا نکته بنویسیم اگر زیاد گذاشت یا کم که آقا رنج مناسبی نذاشتی و بگیم که مشتریات کم میشه + از بابت اینکه نسبت به سابقه و مهارت ها و ... میتونیم یه عدد پیشنهادی تو بازه بهش نشون بدیم که کار رو راحت تر کنه
- در آینده باید داستان بوست رو برای هر دو طرف مشخص کنیم یعنی اگر فرد بخواد زودتر کسی رو پیدا کنه، چه پرستار بخواد زودتر کار بگیره (مرحله خیلی بعد)
- کلا پروسه بید زدن پرستار هارو بزاریم برای بعدا چون مشتری رو ناراضی میکنه الان وقتش نیست
2. سیستم اقساطی باید بصرفه یعنی نباید برای یک روز ما خدمات قساطی بدیم، برای درخواستی بالای سه روز باید باشه که عددش معنی دار بشه شاید هم حتی بالاتر - کسی نمیاد 4-5 تومن رو قطی بده دیگه (این گمان هست باید دیتا بیشتر ببینم)
پس نیاز داریم که بتونیم برای بازه های قیمتی متفاوت گزینه های پرداخت رو فعال یا غیر فعال کنیم.
3. برای آینده، یک بلاگ در نظر داشته باشیم
+146
View File
@@ -0,0 +1,146 @@
/* Balinyaar product docs — generated HTML view. Edit Markdown + regenerate; do not hand-edit .html. */
:root {
--teal: #1d4a40;
--teal-bright: #2a6b5c;
--terracotta: #d98c6a;
--bg: #faf9f5;
--surface: #ffffff;
--surface-2: #f3efe9;
--border: #e4ddd2;
--text: #23211c;
--text-soft: #5d574c;
--link: #1d6b5a;
--code-bg: #f3efe9;
--shadow: 0 1px 3px rgba(0, 0, 0, .08);
--sidebar-w: 290px;
--mono: ui-monospace, "SF Mono", "Cascadia Code", "JetBrains Mono", Menlo, Consolas, monospace;
--sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Tahoma, sans-serif;
}
:root[data-theme="dark"] {
--teal: #4fd1b5;
--teal-bright: #6fe0c8;
--terracotta: #e8a888;
--bg: #14130f;
--surface: #1d1c17;
--surface-2: #262420;
--border: #34322b;
--text: #ece8df;
--text-soft: #a8a294;
--link: #6fe0c8;
--code-bg: #262420;
--shadow: 0 1px 3px rgba(0, 0, 0, .4);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: var(--sans);
background: var(--bg);
color: var(--text);
line-height: 1.65;
-webkit-font-smoothing: antialiased;
}
.layout { display: flex; min-height: 100vh; align-items: flex-start; }
/* Sidebar */
.sidebar {
width: var(--sidebar-w);
flex: 0 0 var(--sidebar-w);
position: sticky;
top: 0;
align-self: flex-start;
height: 100vh;
overflow-y: auto;
background: var(--teal);
color: #f3efe9;
padding: 22px 18px 40px;
}
.sidebar .brand {
display: flex; align-items: center; gap: 10px;
font-weight: 700; font-size: 1.15rem; letter-spacing: .2px;
color: #fff; text-decoration: none; margin-bottom: 4px;
}
.sidebar .brand .dot { width: 11px; height: 11px; border-radius: 50%; background: var(--terracotta); flex: 0 0 auto; }
.sidebar .tagline { font-size: .72rem; color: #bcd6cd; margin: 0 0 18px 21px; }
.sidebar nav .group { margin-bottom: 16px; }
.sidebar nav .group > .label {
font-size: .68rem; text-transform: uppercase; letter-spacing: .12em;
color: #8fb5aa; margin: 0 0 6px 4px; font-weight: 700;
}
.sidebar nav ul { list-style: none; margin: 0; padding: 0; }
.sidebar nav a {
display: block; padding: 4px 10px; border-radius: 7px;
color: #d8e6e1; text-decoration: none; font-size: .855rem; line-height: 1.4;
}
.sidebar nav a:hover { background: rgba(255, 255, 255, .09); color: #fff; }
.sidebar nav a.active { background: var(--terracotta); color: #23211c; font-weight: 600; }
/* Main */
.main { flex: 1 1 auto; min-width: 0; display: flex; justify-content: center; padding: 0 36px; }
.content { width: 100%; max-width: 860px; padding: 38px 0 90px; }
.topbar { display: flex; justify-content: flex-end; margin-bottom: 6px; }
.theme-toggle {
background: var(--surface); border: 1px solid var(--border); color: var(--text-soft);
border-radius: 8px; padding: 5px 11px; font-size: .8rem; cursor: pointer; font-family: var(--sans);
}
.theme-toggle:hover { border-color: var(--teal); color: var(--teal); }
.content h1, .content h2, .content h3, .content h4 { line-height: 1.25; scroll-margin-top: 20px; }
.content h1 { font-size: 2rem; margin: .2em 0 .6em; color: var(--teal); font-weight: 750; }
.content h2 { font-size: 1.4rem; margin: 1.8em 0 .5em; padding-bottom: .25em; border-bottom: 2px solid var(--border); }
.content h3 { font-size: 1.13rem; margin: 1.5em 0 .4em; color: var(--teal-bright); }
.content h4 { font-size: 1rem; margin: 1.3em 0 .3em; color: var(--text-soft); }
.content h2 a.anchor, .content h3 a.anchor { opacity: 0; text-decoration: none; color: var(--terracotta); margin-left: .35em; font-weight: 400; }
.content h2:hover a.anchor, .content h3:hover a.anchor { opacity: 1; }
.content p { margin: .7em 0; }
.content a { color: var(--link); text-decoration: none; border-bottom: 1px solid transparent; }
.content a:hover { border-bottom-color: var(--link); }
.content ul, .content ol { padding-left: 1.5em; margin: .6em 0; }
.content li { margin: .25em 0; }
.content li > ul, .content li > ol { margin: .2em 0; }
.content hr { border: none; border-top: 1px solid var(--border); margin: 2.2em 0; }
.content strong { font-weight: 680; }
.content del { color: var(--text-soft); }
/* Inline + block code */
.content code {
font-family: var(--mono); font-size: .86em;
background: var(--code-bg); padding: .12em .38em; border-radius: 5px;
color: var(--teal-bright); word-break: break-word;
}
.content pre {
background: var(--code-bg); border: 1px solid var(--border); border-radius: 10px;
padding: 14px 16px; overflow-x: auto; margin: 1em 0; line-height: 1.5;
}
.content pre code { background: none; padding: 0; color: var(--text); font-size: .82rem; }
.content pre.mermaid {
background: var(--surface); text-align: center; border-style: dashed; color: var(--text);
}
/* Tables */
.table-wrap { overflow-x: auto; margin: 1.1em 0; }
.content table { border-collapse: collapse; width: 100%; font-size: .87rem; }
.content th, .content td { border: 1px solid var(--border); padding: 7px 11px; text-align: left; vertical-align: top; }
.content th { background: var(--surface-2); font-weight: 650; }
.content tbody tr:nth-child(even) { background: var(--surface-2); }
/* Blockquote → callout */
.content blockquote {
margin: 1.1em 0; padding: 12px 16px; background: var(--surface);
border-left: 4px solid var(--terracotta); border-radius: 0 8px 8px 0;
color: var(--text-soft); box-shadow: var(--shadow);
}
.content blockquote p { margin: .3em 0; }
.back-to-top { display: inline-block; margin-top: 2.5em; font-size: .82rem; color: var(--text-soft); }
/* RTL / Persian passages render acceptably inside LTR layout; force-direction helper if needed */
.content [dir="rtl"] { direction: rtl; text-align: right; }
@media (max-width: 880px) {
.layout { flex-direction: column; }
.sidebar { position: static; width: 100%; flex-basis: auto; height: auto; }
.sidebar nav { columns: 2; }
.main { padding: 0 18px; }
}
File diff suppressed because it is too large Load Diff
-85
View File
@@ -1,85 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>nursing — Seed Deck</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #faf9f5;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
#__bundler_loading {
position: fixed;
bottom: 20px;
right: 20px;
font: 13px/1.4 -apple-system, BlinkMacSystemFont, sans-serif;
color: #666;
background: #fff;
padding: 8px 14px;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
z-index: 10000;
}
#__bundler_thumbnail {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #faf9f5;
z-index: 9999;
}
#__bundler_thumbnail svg {
width: 100%;
height: 100%;
object-fit: contain;
}
#__bundler_placeholder {
color: #999;
font-size: 14px;
}
</style>
<noscript>
<style>
#__bundler_loading {
display: none;
}
</style>
<div
style="position:fixed;bottom:12px;left:12px;font:13px/1.4 -apple-system,BlinkMacSystemFont,sans-serif;color:#999;background:rgba(255,255,255,0.9);padding:6px 12px;border-radius:6px;box-shadow:0 1px 4px rgba(0,0,0,0.08);z-index:10000;">
This page requires JavaScript to display.
</div>
</noscript>
</head>
<body>
<div id="__bundler_thumbnail">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="#1d4a40"></rect>
<text x="30" y="58" font-family="Space Grotesk, sans-serif" font-size="34" font-weight="700"
fill="#f3efe9">n</text>
<circle cx="62" cy="52" r="6" fill="#d98c6a"></circle>
</svg>
</div>
<div id="__bundler_loading">Unpacking...</div>
</body>
</html>
+319
View File
@@ -0,0 +1,319 @@
#!/usr/bin/env node
/*
* Balinyaar product-docs generator (zero dependency).
* cd product && node build-docs.mjs
* Walks every .md file, renders a brand-styled, cross-linked .html beside it,
* builds the sidebar from NAV below, and rewrites internal `…/foo.md` links to `…/foo.html`.
* Markdown is the source of truth — never hand-edit the generated .html.
*/
import { readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, posix } from 'node:path';
const ROOT = dirname(fileURLToPath(import.meta.url));
const SEP = String.fromCharCode(0); // collision-proof placeholder delimiter for code spans
/* ---- Sidebar manifest. Add/rename .md files here so they show in the nav. ---- */
const NAV = [
{ label: 'Start here', items: [
{ path: 'index.md', title: 'Docs home' },
{ path: 'overview/platform-summary.md', title: 'Platform summary & ground truths' },
]},
{ label: 'Business requirements', items: [
{ path: 'business/index.md', title: 'Overview & MVP scope' },
{ path: 'business/01-actors-and-onboarding.md', title: '1. Actors & onboarding' },
{ path: 'business/02-nurse-verification.md', title: '2. Nurse verification' },
{ path: 'business/03-service-catalog-and-pricing.md', title: '3. Service catalog & pricing' },
{ path: 'business/04-search-and-matching.md', title: '4. Search & matching' },
{ path: 'business/05-booking-and-scheduling.md', title: '5. Booking & scheduling' },
{ path: 'business/06-evv-and-service-delivery.md', title: '6. EVV / service delivery' },
{ path: 'business/07-cancellation-and-refunds.md', title: '7. Cancellation & refunds' },
{ path: 'business/08-payments-and-escrow.md', title: '8. Payments & escrow' },
{ path: 'business/09-installments-bnpl.md', title: '9. Installments / BNPL' },
{ path: 'business/10-payouts.md', title: '10. Payouts to nurses' },
{ path: 'business/11-reviews-trust-and-safety.md', title: '11. Reviews, trust & safety' },
{ path: 'business/12-messaging-and-emergencies.md', title: '12. Messaging & emergencies' },
{ path: 'business/13-tax-invoicing-and-legal.md', title: '13. Tax, invoicing & legal' },
{ path: 'business/14-notifications-and-admin.md', title: '14. Notifications & admin' },
]},
{ label: 'Database model', items: [
{ path: 'data-model/index.md', title: 'Overview & decisions' },
{ path: 'data-model/diagrams.md', title: 'Diagrams' },
{ path: 'data-model/01-identity-and-access.md', title: '1. Identity & access' },
{ path: 'data-model/02-geography.md', title: '2. Geography' },
{ path: 'data-model/03-services-and-pricing.md', title: '3. Services & pricing' },
{ path: 'data-model/04-verification-and-credentials.md', title: '4. Verification & credentials' },
{ path: 'data-model/05-booking-and-scheduling.md', title: '5. Booking & scheduling' },
{ path: 'data-model/06-payments-ledger-and-refunds.md', title: '6. Payments, ledger & refunds' },
{ path: 'data-model/07-payouts.md', title: '7. Payouts' },
{ path: 'data-model/08-bnpl.md', title: '8. BNPL / installments' },
{ path: 'data-model/09-messaging.md', title: '9. Messaging' },
{ path: 'data-model/10-reviews-and-records.md', title: '10. Reviews & records' },
{ path: 'data-model/11-notifications.md', title: '11. Notifications' },
{ path: 'data-model/12-audit-config-and-reference.md', title: '12. Audit, config & reference' },
{ path: 'data-model/13-partner-centers-and-future.md', title: '13. Partner centers & future' },
]},
{ label: 'Payments deep-dive', items: [
{ path: 'payments/index.md', title: 'Overview & exec summary' },
{ path: 'payments/iranian-payment-reality.md', title: 'Iranian payment reality' },
{ path: 'payments/escrow-ledger.md', title: 'Escrow as a ledger' },
{ path: 'payments/bnpl-landscape.md', title: 'BNPL landscape & finding' },
{ path: 'payments/cancellation-and-payout.md', title: 'Cancellation & nurse payout' },
{ path: 'payments/integration-notes.md', title: 'Integration & schema touchpoints' },
{ path: 'payments/sources.md', title: 'Recommendations & sources' },
]},
{ label: 'Research & strategy', items: [
{ path: 'research/index.md', title: 'Overview & exec summary' },
{ path: 'research/market-and-competitors.md', title: 'Market & competitors' },
{ path: 'research/problems-and-risks.md', title: 'Problems & risks' },
{ path: 'research/verification.md', title: 'Verification (research)' },
{ path: 'research/legal-landscape.md', title: 'Legal landscape' },
{ path: 'research/go-to-market.md', title: 'Go-to-market & sources' },
]},
{ label: 'Notes & more', items: [
{ path: 'notes/open-questions.md', title: 'Open questions' },
{ path: 'notes/future-ideas.md', title: 'Future ideas' },
{ path: 'wireframes/index.html', title: 'Wireframes' },
{ path: 'fa/index.html', title: 'Farsi documents' },
]},
];
/* ---------------------------- tiny markdown renderer ---------------------------- */
const esc = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const escAttr = (s) => esc(s).replace(/"/g, '&quot;');
function slug(text) {
return text.toLowerCase().trim()
.replace(/[`*~]/g, '')
.replace(/[^\w؀-ۿ\s-]/g, '')
.replace(/\s+/g, '-').replace(/-+/g, '-');
}
function rewriteHref(url) {
if (/^(https?:|mailto:|#|\/\/)/.test(url)) return url;
return url.replace(/\.md(#.*)?$/i, '.html$1');
}
// Inline: protect code spans with NUL-delimited placeholders, escape, then links/emphasis/strike.
function inline(text) {
const codes = [];
text = text.replace(/`([^`]+)`/g, (_, c) => { codes.push(c); return SEP + (codes.length - 1) + SEP; });
text = esc(text);
text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, url) =>
'<a href="' + escAttr(rewriteHref(url.trim())) + '">' + label + '</a>');
text = text.replace(/\*\*([^*]+?)\*\*/g, '<strong>$1</strong>');
text = text.replace(/(^|[^*])\*([^*\n]+?)\*(?!\*)/g, '$1<em>$2</em>');
text = text.replace(/~~([^~]+?)~~/g, '<del>$1</del>');
const restore = new RegExp(SEP + '(\\d+)' + SEP, 'g');
text = text.replace(restore, (_, i) => '<code>' + esc(codes[+i]) + '</code>');
return text;
}
function renderList(lines, i, indent) {
const reItem = /^(\s*)([-*+]|\d+[.)])\s+(.*)$/;
let html = '';
let ordered = null;
while (i < lines.length) {
const m = lines[i].match(reItem);
if (!m) break;
const ind = m[1].length;
if (ind < indent) break;
if (ind > indent) break;
const thisOrdered = /\d/.test(m[2]);
if (ordered === null) ordered = thisOrdered;
let itemHtml = inline(m[3]);
i++;
if (i < lines.length) {
const mn = lines[i].match(reItem);
if (mn && mn[1].length > indent) {
const [sub, ni] = renderList(lines, i, mn[1].length);
itemHtml += sub;
i = ni;
}
}
html += '<li>' + itemHtml + '</li>\n';
}
const tag = ordered ? 'ol' : 'ul';
return ['<' + tag + '>\n' + html + '</' + tag + '>\n', i];
}
function mdToHtml(md) {
const lines = md.replace(/\r\n/g, '\n').split('\n');
let out = '';
let i = 0;
const reItem = /^(\s*)([-*+]|\d+[.)])\s+(.*)$/;
while (i < lines.length) {
let line = lines[i];
if (line.trim() === '') { i++; continue; }
const fence = line.match(/^```\s*(\w+)?\s*$/);
if (fence) {
const lang = (fence[1] || '').toLowerCase();
const buf = [];
i++;
while (i < lines.length && !/^```\s*$/.test(lines[i])) { buf.push(lines[i]); i++; }
i++;
const body = esc(buf.join('\n'));
out += lang === 'mermaid'
? '<pre class="mermaid">' + body + '</pre>\n'
: '<pre><code>' + body + '</code></pre>\n';
continue;
}
const h = line.match(/^(#{1,6})\s+(.*)$/);
if (h) {
const lvl = h[1].length;
const txt = inline(h[2].replace(/\s+#+\s*$/, ''));
const id = slug(h[2]);
const anchor = lvl >= 2 && lvl <= 3 ? ' <a class="anchor" href="#' + id + '" aria-hidden="true">#</a>' : '';
out += '<h' + lvl + ' id="' + id + '">' + txt + anchor + '</h' + lvl + '>\n';
i++;
continue;
}
if (/^(\s*)(-{3,}|\*{3,}|_{3,})\s*$/.test(line)) { out += '<hr>\n'; i++; continue; }
if (line.includes('|') && i + 1 < lines.length && /^\s*\|?\s*:?-{2,}/.test(lines[i + 1]) && lines[i + 1].includes('-')) {
const splitRow = (r) => {
let s = r.trim().replace(/^\|/, '').replace(/\|$/, '');
const cells = []; let cur = ''; let escd = false;
for (const ch of s) {
if (escd) { cur += ch; escd = false; }
else if (ch === '\\') { escd = true; cur += ch; }
else if (ch === '|') { cells.push(cur); cur = ''; }
else cur += ch;
}
cells.push(cur);
return cells.map((c) => c.trim());
};
const headers = splitRow(line);
i += 2;
let body = '';
while (i < lines.length && lines[i].includes('|') && lines[i].trim() !== '') {
const cells = splitRow(lines[i]);
body += '<tr>' + cells.map((c) => '<td>' + inline(c.replace(/\\\|/g, '|')) + '</td>').join('') + '</tr>\n';
i++;
}
const head = '<tr>' + headers.map((c) => '<th>' + inline(c.replace(/\\\|/g, '|')) + '</th>').join('') + '</tr>';
out += '<div class="table-wrap"><table><thead>' + head + '</thead><tbody>\n' + body + '</tbody></table></div>\n';
continue;
}
if (/^\s*>/.test(line)) {
const buf = [];
while (i < lines.length && /^\s*>/.test(lines[i])) { buf.push(lines[i].replace(/^\s*>\s?/, '')); i++; }
out += '<blockquote>' + mdToHtml(buf.join('\n')) + '</blockquote>\n';
continue;
}
if (reItem.test(line)) {
const ind = line.match(reItem)[1].length;
const [html, ni] = renderList(lines, i, ind);
out += html;
i = ni;
continue;
}
const para = [];
while (i < lines.length && lines[i].trim() !== '' &&
!/^(#{1,6}\s|```|\s*>|\s*(-{3,}|\*{3,}|_{3,})\s*$)/.test(lines[i]) &&
!reItem.test(lines[i]) &&
!(lines[i].includes('|') && i + 1 < lines.length && /^\s*\|?\s*:?-{2,}/.test(lines[i + 1]))) {
para.push(lines[i]); i++;
}
if (para.length) out += '<p>' + inline(para.join(' ')) + '</p>\n';
}
return out;
}
/* ---------------------------- page template ---------------------------- */
function relHref(fromPath, toPath) {
const rel = posix.relative(posix.dirname(fromPath), toPath);
return rel || posix.basename(toPath);
}
function firstH1(md) {
const m = md.match(/^#\s+(.+)$/m);
return m ? m[1].replace(/[`*~]/g, '').trim() : 'Balinyaar';
}
function sidebar(currentMdPath) {
const currentHtml = currentMdPath.replace(/\.md$/, '.html');
let html = '';
for (const group of NAV) {
html += '<div class="group"><div class="label">' + esc(group.label) + '</div><ul>';
for (const it of group.items) {
const targetHtml = it.path.replace(/\.md$/, '.html');
const active = targetHtml === currentHtml ? ' class="active"' : '';
html += '<li><a' + active + ' href="' + escAttr(relHref(currentHtml, targetHtml)) + '">' + esc(it.title) + '</a></li>';
}
html += '</ul></div>';
}
return html;
}
function page(mdPath, md) {
const htmlPath = mdPath.replace(/\.md$/, '.html');
const title = firstH1(md);
const cssHref = escAttr(relHref(htmlPath, 'assets/doc.css'));
const homeHref = escAttr(relHref(htmlPath, 'index.html'));
const body = mdToHtml(md);
const mermaidScript = body.includes('class="mermaid"')
? '<script type="module">\n'
+ " import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';\n"
+ " const dark = document.documentElement.getAttribute('data-theme') === 'dark';\n"
+ " mermaid.initialize({ startOnLoad: true, theme: dark ? 'dark' : 'neutral' });\n"
+ '</script>'
: '';
return '<!DOCTYPE html>\n'
+ '<html lang="en">\n<head>\n'
+ '<meta charset="utf-8">\n'
+ '<meta name="viewport" content="width=device-width, initial-scale=1">\n'
+ '<title>' + esc(title) + ' — Balinyaar docs</title>\n'
+ '<link rel="stylesheet" href="' + cssHref + '">\n'
+ '</head>\n<body>\n'
+ '<div class="layout">\n'
+ '<aside class="sidebar">\n'
+ ' <a class="brand" href="' + homeHref + '"><span class="dot"></span> Balinyaar docs</a>\n'
+ ' <p class="tagline">Trust-first home-nursing marketplace · Iran</p>\n'
+ ' <nav>' + sidebar(mdPath) + '</nav>\n'
+ '</aside>\n'
+ '<main class="main"><div class="content">\n'
+ ' <div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>\n'
+ body
+ ' <a class="back-to-top" href="#">↑ Back to top</a>\n'
+ '</div></main>\n</div>\n'
+ '<script>\n'
+ " (function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);\n"
+ " if(s)document.documentElement.setAttribute('data-theme',s);\n"
+ " else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();\n"
+ " function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';\n"
+ " d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}\n"
+ '</script>\n'
+ mermaidScript + '\n'
+ '</body>\n</html>\n';
}
/* ---------------------------- walk + build ---------------------------- */
function walk(dir, acc = []) {
for (const name of readdirSync(dir)) {
const full = join(dir, name);
if (statSync(full).isDirectory()) {
if (name === 'assets' || name === 'node_modules' || name.startsWith('.')) continue;
walk(full, acc);
} else if (name.endsWith('.md')) {
acc.push(full);
}
}
return acc;
}
const files = walk(ROOT);
let n = 0;
for (const full of files) {
const rel = relative(ROOT, full).split('\\').join('/');
const md = readFileSync(full, 'utf8');
writeFileSync(full.replace(/\.md$/, '.html'), page(rel, md), 'utf8');
n++;
}
console.log('Generated ' + n + ' HTML pages from Markdown.');
-397
View File
@@ -1,397 +0,0 @@
# 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 ~710 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 715% 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 15 + 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 |
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>1. Actors &amp; Onboarding — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a class="active" href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="1-actors-onboarding">1. Actors &amp; Onboarding</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li>Three actor types: <strong>customer</strong> (the family member / payer), <strong>nurse</strong> (the independent caregiver / seller), and <strong>admin</strong> (Balinyaar back-office staff: support, finance, moderation, super-admin).</li>
<li><strong>Phone number is the primary login credential.</strong> Authentication is <strong>phone-OTP</strong> (one-time code by SMS). Email is optional/secondary (required only for admin accounts).</li>
<li>The <strong>patient</strong> (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.</li>
<li><strong>KYC timing is role- and risk-staged, not up-front-for-everyone:</strong><ul>
<li>A <strong>customer</strong> can register and browse with only a verified phone (OTP). National-ID KYC for customers is anti-fraud only and is <strong>deferred</strong> at launch.</li>
<li>A <strong>nurse</strong> must complete the full verification pipeline (Section 2) before any of their service variants become bookable. <code>national_id</code> is populated only after the identity step passes.</li>
<li>An <strong>admin</strong> is provisioned internally with RBAC roles.</li>
</ul>
</li>
<li>Each successful login creates a refresh-token session that can be revoked (logout, stolen-token detection).</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>Phone-OTP is the dominant Iranian login norm and is also the anchor for <strong>Shahkar</strong> SIM↔national-ID binding (Section 2).</li>
<li>Storing <code>national_id</code> only post-KYC matches the reality that identity is verified through gated vendor APIs, not collected casually at signup.</li>
<li>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.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> phone-OTP login; customer/nurse/admin roles; customer→patient (1:N); session management; admin RBAC; nurse onboarding gated on verification.</li>
<li><strong>DEFERRED:</strong> customer national-ID KYC (<code>customer_profiles.national_id_verified_at</code> exists but is optional/unused at launch); push notifications; social login; nursing-company (organization) self-onboarding.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>users</code>, <code>user_sessions</code>, <code>roles</code>, <code>user_roles</code>, <code>nurse_profiles</code>, <code>customer_profiles</code>, <code>patients</code>, <code>customer_addresses</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/01-identity-and-access.html">Identity &amp; Access</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,27 @@
# 1. Actors & Onboarding
[← Business Requirements](index.md)
## (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`.
> **Related:** Data model — [Identity & Access](../data-model/01-identity-and-access.md).
@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>2. Nurse Verification &amp; Credentials — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a class="active" href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="2-nurse-verification-credentials">2. Nurse Verification &amp; Credentials</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<p>Verified trust is the <strong>entire brand</strong>. Vetting is <strong>platform-owned, non-optional, and performed at the authoritative source</strong> — never delegated to families, and never marketed as a check the platform does not actually perform. A nurse is bookable only after all <em>required</em> verification steps pass.</p>
<p>The pipeline is <strong>data-driven</strong>: the set of steps lives as rows in <code>verification_step_types</code> (not a code enum), so a new regulatory requirement (e.g., professional liability insurance) is one INSERT, not a migration. Each step can be <strong>automated</strong> (a KYC vendor API call) or <strong>manual</strong> (admin reviews an uploaded document). The aggregate <code>nurse_verifications</code> record rolls the step outcomes into a single status; <code>nurse_profiles.is_verified</code> flips to true <strong>only inside the same transaction</strong> that confirms every required step is <code>passed</code>.</p>
<p>The verification steps:</p>
<ol>
<li><strong>Identity (KYC) — automated.</strong> Match person ↔ کد ملی (national ID) ↔ phone ↔ face via one Iranian KYC vendor: national-ID validity/name match + photo/video <strong>liveness</strong> 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.</li>
<li><strong>Shahkar phone↔national-id binding — automated.</strong> Confirm the login SIM is registered to the nurse's own کد ملی. The binding result (when, which vendor, the reference) is recorded, and <strong>re-verification is triggered on phone change</strong>. The shared-SIM failure mode (a SIM owned by a family member) is an explicit, handled state, not an undefined edge case.</li>
<li><strong>MoH پروانه صلاحیت حرفه‌ای (professional-competency license) — the single most important credential.</strong> It is the MoH-mandated license for in-home nursing and <strong>already bundles the criminal-record (سوء پیشینه) screen</strong> 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 <strong>nurse-uploaded document + manual admin verification against the official record</strong>.</li>
<li><strong>نظام پرستاری (Iranian Nursing Organization / INO) membership — cross-check.</strong> The INO membership number is captured and cross-checked (ino.ir) as a second source. Manual at launch.</li>
<li><strong>عدم سوء پیشینه (criminal-record certificate).</strong> Consent-gated to the individual (obtained by the nurse via adliran.ir / their own ثنا password); <strong>no company/employer API exists</strong>. The nurse uploads it; it is <strong>time-limited</strong> — on expiry the step reverts to pending and a support alert is raised. Partly covered already by credential #3.</li>
<li><strong>IBAN ownership verification.</strong> 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 <strong>first payout</strong>, not merely an admin eyeballing the number. Prevents paying a nurse's earnings into a third party's account (money-mule risk).</li>
</ol>
<p><strong>Structured credential registry.</strong> Beyond opaque uploaded files, the actual license <strong>numbers</strong>, issuing authority, holder-name-as-printed, and issue/expiry dates are stored as typed, queryable rows in <code>nurse_credentials</code>. 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.</p>
<p><strong>Continuous monitoring</strong>, 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 <code>support_alerts</code>.</p>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>The license layer is <strong>fragmented across regulators</strong> (MoH vs INO) and has <strong>no public B2B API</strong> — manual verification against the official portal is the realistic MVP method; the structured registry makes that defensible and renewable.</li>
<li>The criminal-record check is <strong>consent-gated to the person</strong> and cannot be pulled by a company — hence nurse-uploaded + re-requested periodically, leaning on the MoH license which already embeds it.</li>
<li>Identity (Shahkar, liveness, national-ID match) is the <strong>easy</strong> layer because a competitive market of Iranian e-KYC vendors (Finnotech, U-ID, Jibbit, Farashensa, Verify, Kavoshak) already holds the regulator-gated upstream agreements. <strong>Buy this, don't build it.</strong></li>
<li>Document forgery is the documented attack (the "imposter nurse" pattern): verify at source, bind to national ID + liveness, never trust an uploaded PDF alone.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> all six steps; data-driven <code>verification_step_types</code>; structured <code>nurse_credentials</code> registry; manual MoH/INO verification; nurse-uploaded عدم سوء پیشینه with expiry; automated identity + Shahkar + IBAN-ownership via one KYC vendor; expiry-driven re-verification alerts; transactional <code>is_verified</code>.</li>
<li><strong>DEFERRED:</strong> automated MoH/INO license lookup (pending a B2B API); ML-driven fraud scoring (<code>fraud_flags</code> is modeled but inactive); professional-liability-insurance step (addable as a row when required).</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>nurse_verifications</code>, <code>verification_step_types</code>, <code>verification_steps</code>, <code>verification_documents</code>, <strong><code>nurse_credentials</code></strong> (structured license registry), <code>nurse_bank_accounts</code> (IBAN ownership), <code>support_alerts</code> (expiry/renewal), <code>audit_logs</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/04-verification-and-credentials.html">Verification &amp; Credentials</a>; Research — <a href="../research/verification.html">Verification</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+36
View File
@@ -0,0 +1,36 @@
# 2. Nurse Verification & Credentials
[← Business Requirements](index.md)
## (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`.
> **Related:** Data model — [Verification & Credentials](../data-model/04-verification-and-credentials.md); Research — [Verification](../research/verification.md).
@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>3. Service Catalog &amp; Pricing — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a class="active" href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="3-service-catalog-pricing">3. Service Catalog &amp; Pricing</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li><strong>Admin defines the catalog skeleton:</strong> top-level <strong>service categories</strong> (e.g., مراقبت از سالمند / Elderly Care, مراقبت پس از جراحی / Post-Surgery Recovery, مراقبت از نوزاد / Infant Care, مدیریت بیماری مزمن / Chronic Illness Management) and <strong>configurable option dimensions</strong> as admin-managed <strong>option groups</strong> (e.g., تعداد بیمار / patient count, نوع شیفت / shift type) each with concrete <strong>option values</strong> (e.g., ۱ نفر, ۲ نفر, شبانه‌روزی). Admin can add new dimensions without a schema change.</li>
<li><strong>Each nurse defines their own offerings as variants.</strong> A <strong>variant</strong> is the atomic bookable unit: a category + a chosen combination of option values + the nurse's <strong>own price</strong> and <strong>price unit</strong>. A nurse may have many variants per category, one per combination they choose to offer and price independently.</li>
<li><strong>Price units</strong> must support the real shapes of home nursing: <code>per_hour</code>, <code>per_session</code>, <code>per_half_day</code>, <code>per_day</code>, and <code>per_24h</code> (شبانه‌روزی / live-in). For hourly variants an estimated duration helps the customer estimate total cost.</li>
<li>The variant <code>display_name</code> auto-generates from option labels but is nurse-editable. Nurses can deactivate (not delete) a variant; deactivated variants cannot be booked.</li>
<li>Catalog and prices are <strong>snapshotted onto the booking</strong> at booking time (<code>variant_snapshot_json</code>) so historical records survive later edits.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>Iranian competitors sell exactly these shapes — hourly / daily / 24-hour (شبانه‌روزی) shifts and multi-day packages — so <code>per_24h</code> and <code>per_day</code> are first-class, not edge cases.</li>
<li>Competitor pricing is opaque and "توافقی" (negotiable); <strong>transparent, upfront, nurse-set pricing is a deliberate differentiator</strong> families value.</li>
<li>All catalog tables carry <code>name_fa</code> / <code>name_en</code> pairs (Persian primary).</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> admin categories + option groups/values; nurse variants with own price + price unit across all five units; activate/deactivate; snapshotting.</li>
<li><strong>DEFERRED:</strong> holiday/surge pricing rules; a lighter "companionship / daily-living" tier (modeled as a future category); dynamic/tiered commission per category.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>service_categories</code>, <code>service_option_groups</code>, <code>service_option_values</code>, <code>nurse_service_variants</code> (carries <code>price</code>, <code>price_unit</code>), <code>nurse_service_variant_options</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/03-services-and-pricing.html">Services &amp; Pricing</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,24 @@
# 3. Service Catalog & Pricing
[← Business Requirements](index.md)
## (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`.
> **Related:** Data model — [Services & Pricing](../data-model/03-services-and-pricing.md).
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>4. Search &amp; Matching — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a class="active" href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="4-search-matching">4. Search &amp; Matching</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li>Families search by <strong>service category</strong>, <strong>geography</strong> (city, and optionally district), price, and availability, with results sortable by rating.</li>
<li><strong>Geography</strong> is driven by nurse-declared <strong>service areas</strong>: a nurse covers one or more cities, optionally specific districts; a city-level row (no district) means the whole city.</li>
<li><strong>Search must be cheap from day one.</strong> The naive query joins nurse profile (verified + accepting) → variants (category/price) → variant options → service areas → rating across 4+ tables. Instead a <strong>denormalized <code>nurse_search_index</code></strong> holds one flat row per active, bookable variant with all search-relevant fields, maintained on write. A row exists <strong>only</strong> when the nurse is <code>is_verified</code> and not suspended and the variant <code>is_active</code>. This is far cheaper than introducing Elasticsearch at MVP stage.</li>
<li><strong>Same-gender caregiver matching</strong> 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 (<code>required_caregiver_gender</code>), and nurse gender is an exposed search filter so families can narrow to same-gender caregivers up front. The patient's gender (<code>patients.gender</code>) and the nurse's gender support this matching.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>District granularity varies: in Tehran, districts map to the 22 official municipal مناطق; in smaller cities they are major neighborhoods. Districts are optional.</li>
<li><strong>Same-gender matching is the single most Iran-specific matching constraint</strong> — every real elder/post-surgical bodily-care request implies it. It must be surfaced before booking, not discovered after.</li>
<li>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).</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> category + city/district geo search; <code>nurse_search_index</code> denormalization; same-gender filter via <code>required_caregiver_gender</code>; rating sort.</li>
<li><strong>DEFERRED:</strong> 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.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>nurse_service_areas</code>, <code>cities</code>, <code>districts</code>, <strong><code>nurse_search_index</code></strong>, <code>nurse_service_variants</code>, <code>nurse_profiles</code> (rating, gender via <code>users</code>), <code>patients.gender</code>; <code>booking_requests.required_caregiver_gender</code> (the requested constraint).</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/03-services-and-pricing.html">Services &amp; Pricing</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,23 @@
# 4. Search & Matching
[← Business Requirements](index.md)
## (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).
> **Related:** Data model — [Services & Pricing](../data-model/03-services-and-pricing.md).
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>5. Booking &amp; Scheduling — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a class="active" href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="5-booking-scheduling">5. Booking &amp; Scheduling</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<p>The lifecycle has two phases separated into two tables so each table's invariants stay clean: a <strong>request phase</strong> (no money) and a <strong>booking phase</strong> (always implies captured payment).</p>
<p><strong>Request → accept → pay → confirm lifecycle:</strong></p>
<ol>
<li>Customer submits a <strong>booking request</strong> (nurse, patient, variant, address, date/time, requested caregiver gender, customer notes). Status <code>pending_nurse_response</code>.</li>
<li>The nurse must respond before a <strong>response deadline</strong> (<code>nurse_response_deadline_at</code>, computed from config and frozen on the request). The nurse <strong>accepts</strong><code>accepted_awaiting_payment</code>, or <strong>rejects</strong><code>rejected_by_nurse</code>, or the deadline passes → <code>expired_no_response</code>.</li>
<li>On accept, a <strong>30-minute payment window</strong> opens (<code>payment_deadline_at</code>). The customer pays within it → a <code>bookings</code> row is created (<code>confirmed</code>). If the window lapses → <code>payment_deadline_expired</code>.</li>
</ol>
<p><strong>Single-visit AND multi-session / long-duration engagements must both be representable.</strong> 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 <code>session_count</code> and owns <strong>N <code>booking_sessions</code></strong> (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.</p>
<p><strong>Booking lifecycle:</strong> <code>pending_payment</code><code>confirmed</code> (payment captured) → <code>in_progress</code> (first/relevant session check-in) → <code>completed</code> (sessions checked out) → optionally <code>disputed</code><code>closed</code>; or <code>cancelled</code> before service. Allowed transitions are guarded explicitly so the booking and EVV state machines cannot silently contradict.</p>
<p><strong>Snapshots:</strong> <code>variant_snapshot_json</code> and <code>address_snapshot_json</code> freeze the service and address at booking time.</p>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>Multi-session and شبانه‌روزی live-in care is the <strong>dominant</strong> elder-care shape in Iran, not a niche — modeling only single visits would fail to represent demand.</li>
<li>Heavy platform control over multi-visit scheduling <strong>strengthens a worker-misclassification argument</strong> under labor law; this is flagged for counsel, and the platform deliberately keeps the nurse's accept/reject autonomy per request.</li>
<li>Availability slots/exceptions are <strong>soft guidance only</strong> (informing search), not hard blocks — the nurse still individually accepts or rejects each request, which also fits the Shamsi week and holiday rhythm.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> request→accept→pay→confirm lifecycle with response deadline + 30-min payment window; single-visit bookings; <code>booking_sessions</code> for multi-session/long-duration engagements with per-session EVV and payout; explicit status-transition guards; snapshots; soft availability slots/exceptions.</li>
<li><strong>DEFERRED:</strong> open-ended recurring schedules (<code>recurring_booking_schedules</code> modeled, inactive — launch is all finite engagements); milestone/progress-payment UX beyond per-session accrual; hard availability-based booking blocks.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>booking_requests</code> (carries <code>nurse_response_deadline_at</code>, <code>payment_deadline_at</code>, <code>required_caregiver_gender</code>), <code>bookings</code> (carries <code>session_count</code>, <code>dispute_window_ends_at</code>, fee split), <strong><code>booking_sessions</code></strong>, <code>booking_care_instructions</code>, <code>nurse_availability_slots</code>, <code>nurse_availability_exceptions</code>, <code>nurse_service_variants</code>, <code>patients</code>, <code>customer_addresses</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/05-booking-and-scheduling.html">Booking &amp; Scheduling</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,31 @@
# 5. Booking & Scheduling
[← Business Requirements](index.md)
## (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`.
> **Related:** Data model — [Booking & Scheduling](../data-model/05-booking-and-scheduling.md).
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>6. EVV / Service Delivery — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a class="active" href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="6-evv-service-delivery">6. EVV / Service Delivery</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li><strong>Electronic Visit Verification (EVV)</strong> is the authoritative record that a visit actually happened, for how long, and where. The nurse <strong>clocks in and out via the app per session</strong>, capturing GPS coordinates and timestamps.</li>
<li>An <strong>address-match tolerance</strong> check computes whether the nurse's GPS at check-in falls within an acceptable radius of the booking address (<code>evv_location_tolerance_meters</code>). A mismatch is <strong>advisory</strong> — it raises a support alert / review flag but does <strong>not</strong> auto-cancel; it does not silently block the visit.</li>
<li>If the nurse has not checked in by a configurable threshold after the scheduled start, a <strong>no-show / late support alert</strong> is created and the family is notified.</li>
<li><strong>Payout is gated on EVV completion.</strong> A session/booking becomes payout-eligible only after EVV check-out <strong>and</strong> 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.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>EVV is the core operational-trust mitigation for <strong>unobserved in-home care</strong> of vulnerable patients who often cannot reliably report what happened (infants, dementia, post-anesthesia) — the platform compensates for unobservability with structured proof of service.</li>
<li>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.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> per-session GPS check-in/out, timestamps, address-match tolerance flag, no-show alerting, payout gated on EVV completion + closed dispute window.</li>
<li><strong>DEFERRED:</strong> continuous geofencing during a live-in shift; supervisory tele-check-ins; family-visible live care logs; consented in-home cameras.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>visit_verifications</code> (per session, with check-in/out GPS, timestamps, <code>check_in_address_match</code>, status), <code>booking_sessions</code>, <code>support_alerts</code> (no-show / location-mismatch), <code>platform_configs</code> (<code>evv_location_tolerance_meters</code>).</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/05-booking-and-scheduling.html">Booking &amp; Scheduling</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,22 @@
# 6. EVV / Service Delivery
[← Business Requirements](index.md)
## (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`).
> **Related:** Data model — [Booking & Scheduling](../data-model/05-booking-and-scheduling.md).
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>7. Cancellation &amp; Refunds — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a class="active" href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="7-cancellation-refunds">7. Cancellation &amp; Refunds</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li>Cancellation/refund rules are <strong>tiered and structured</strong>, not a single blunt "default 100%". The platform defines <code>cancellation_policies</code> tiers by <strong>lead time</strong> and <strong>initiating actor</strong>:<ul>
<li><strong>Free</strong> cancellation more than 24h before start.</li>
<li><strong>Partial</strong> refund (e.g., 50%) under 24h.</li>
<li><strong>Customer no-show:</strong> up to 100% charge.</li>
<li><strong>Nurse no-show:</strong> full refund to the customer <strong>and</strong> a penalty/forfeiture for the nurse.</li>
</ul>
</li>
<li>The <strong>applicable policy is snapshotted onto the booking</strong> at booking time (mirroring the per-booking fee-rate snapshot), so later policy edits never rewrite history. The <strong>resolved</strong> cancellation fee / refund percentage is recorded on the refund event.</li>
<li>For multi-session engagements, <strong>cancellation is per remaining session:</strong> cancelling mid-engagement refunds only the un-started sessions, while completed-and-verified sessions remain payout-eligible.</li>
<li><strong>Refunds are admin-only</strong> — there is no customer self-service refund. A refund is initiated by an admin and <strong>must be linked to a support ticket</strong> (<code>tickets</code>) that holds the conversation and dispute evidence.</li>
<li>A refund <strong>decomposes across the two fee legs</strong> — how much of the platform commission and how much of the nurse payout is being reversed — because the booking gross is <code>platform commission + nurse payout</code>.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>A flat percentage is too blunt for شبانه‌روزی live-in engagements and Iranian holiday-period bookings; tiered, snapshotted policy reduces dispute load.</li>
<li><strong>The refund money path depends on whether the nurse has already been paid</strong> (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.</li>
<li>For BNPL bookings, the refund <strong>never</strong> goes nurse→customer or Balinyaar→customer directly — it is initiated through the BNPL provider's revert/cancel API (Section 8/9).</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> tiered <code>cancellation_policies</code>; 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.</li>
<li><strong>DEFERRED:</strong> automated nurse no-show penalty (manual admin action at launch); self-service partial-refund UI; holiday-specific cancellation overrides.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><strong><code>cancellation_policies</code></strong>, <code>bookings</code> (policy snapshot, <code>dispute_window_ends_at</code>), <code>refunds</code> (admin-only, <code>ticket_id</code>, fee-leg decomposition, <code>refund_channel</code>), <code>tickets</code>, <code>nurse_clawbacks</code> (post-payout case), <code>ledger_entries</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/06-payments-ledger-and-refunds.html">Payments Ledger &amp; Refunds</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,28 @@
# 7. Cancellation & Refunds
[← Business Requirements](index.md)
## (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`.
> **Related:** Data model — [Payments Ledger & Refunds](../data-model/06-payments-ledger-and-refunds.md).
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>8. Payments &amp; Escrow — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a class="active" href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="8-payments-escrow">8. Payments &amp; Escrow</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li>The family pays the <strong>gross</strong> booking price <strong>through the platform</strong> by card via a licensed PSP's IPG. The platform is the <strong>merchant-of-record</strong>; the payment lands net of provider/Shaparak fees.</li>
<li><strong>Escrow is an internal ledger state, not platform-held cash.</strong> The platform models money state with a minimal <strong>double-entry <code>ledger_entries</code></strong> ledger: each money event posts <strong>balanced</strong> legs grouped by a transaction group. Account types: <code>escrow_held</code>, <code>platform_revenue</code>, <code>nurse_payable</code>, <code>refund_payable</code>, <code>bnpl_fee_expense</code>, <code>nurse_clawback_receivable</code>. The ledger is the <strong>single source of truth</strong> 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.<ul>
<li>On a successful card payment: debit <code>escrow_held</code> (gross), credit <code>platform_revenue</code> (Balinyaar commission), credit <code>nurse_payable</code> (nurse payout).</li>
</ul>
</li>
<li><strong>Settlement-sharing (تسهیم).</strong> The compliant marketplace primitive is splitting one incoming card payment across multiple <strong>registered IBANs</strong> (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.</li>
<li><strong>Per-booking the three amounts are stored separately and never conflated:</strong> <code>gross_price_irr</code> (what the customer is charged), <code>balinyaar_commission_irr</code> (platform's cut — drives the nurse payout), and (for BNPL) <code>bnpl_commission_irr</code> (the provider's merchant discount — a platform expense). <code>nurse_payout_amount = gross_price_irr balinyaar_commission_irr</code>.</li>
<li><strong>Webhook idempotency is mandatory before money moves.</strong> Every PSP/BNPL callback is stored raw and <strong>deduplicated by a unique external event id</strong> in <code>payment_webhook_events</code> before any money state mutates — preventing double-confirmed bookings and double-settlements from at-least-once, retried callbacks.</li>
<li><strong>Payment uniqueness:</strong> at most one <code>succeeded</code> payment transaction per booking, and the Shaparak reference is unique — enforced so a retried success webhook cannot double-confirm.</li>
<li><strong>Multi-provider failover.</strong> 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.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li><strong>The load-bearing legal constraint:</strong> a پرداخت‌یار may <strong>not</strong> 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 <strong>internal ledger over funds custodied at the licensed provider/partner bank</strong>, and pay out by provider-side settlement to <strong>verified, registered nurse IBANs</strong>. 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.</li>
<li><strong>PSP received ≠ cash in bank.</strong> 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.</li>
<li>Toman/PSP units differ from internal Rials; convert only at the API boundary. Amounts are BIGINT IRR internally to avoid float/rounding bugs.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> card payment via one licensed PSP; internal double-entry <code>ledger_entries</code> escrow; per-booking three-way amount split; تسهیم-style commission/nurse-share modeling; <code>payment_webhook_events</code> idempotency; single-succeeded-transaction-per-booking guard; provider abstraction for failover.</li>
<li><strong>DEFERRED:</strong> 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.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>payment_gateways</code>, <code>payment_transactions</code> (unique Shaparak ref, single-succeeded-per-booking), <strong><code>payment_webhook_events</code></strong>, <strong><code>ledger_entries</code></strong>, <code>bookings</code> (<code>gross_price_irr</code>, <code>balinyaar_commission_irr</code>, <code>platform_fee_rate</code>, <code>nurse_payout_amount</code>), <code>refunds</code>, <code>nurse_bank_accounts</code> (verified registered IBANs).</p>
<blockquote><p><strong>Related:</strong> Deep fintech detail — <a href="../payments/escrow-ledger.html">Escrow Ledger</a>. Data model — <a href="../data-model/06-payments-ledger-and-refunds.html">Payments Ledger &amp; Refunds</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,27 @@
# 8. Payments & Escrow
[← Business Requirements](index.md)
## (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).
> **Related:** Deep fintech detail — [Escrow Ledger](../payments/escrow-ledger.md). Data model — [Payments Ledger & Refunds](../data-model/06-payments-ledger-and-refunds.md).
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>9. Installments / BNPL — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a class="active" href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="9-installments-bnpl">9. Installments / BNPL</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li>BNPL is offered as an alternative checkout. The decisive, verified model is <strong>full-upfront settlement</strong>: on approval the BNPL provider pays Balinyaar the <strong>full booking amount in one lump, net of the provider's merchant commission</strong>, and <strong>bears 100% of customer-default risk</strong>. The customer's interest-free installment repayment (typically a 4-installment plan) is <strong>owned entirely by the provider</strong> and is <strong>decoupled</strong> from Balinyaar's escrow/EVV/payout cycle.</li>
<li><strong>Therefore a BNPL order is, in Balinyaar's books, identical to a card payment that lands net-of-fee in one inbound settlement.</strong> Balinyaar <strong>does NOT track customer installments, per-installment webhooks, or default propagation</strong> — that fragile subsystem is intentionally not built.</li>
<li>A BNPL order is recorded once as a single inbound settlement in <code>bnpl_transactions</code> (1:1 with a payment transaction), capturing the provider, the merchant-of-record (Balinyaar), the external payment token / transaction id, <code>order_amount_irr</code>, <code>settled_amount_irr</code> (net of provider commission), <code>bnpl_commission_irr</code>, currency (converted at the boundary), an idempotent status state-machine (<code>eligible</code>/<code>token_issued</code>/<code>verified</code>/<code>settled</code>/<code>reverted</code>/<code>cancelled</code>/<code>failed</code>), <code>installment_count</code> (informational, default 4), <code>settled_at</code>, and the revert fields.</li>
<li><strong>BNPL refunds flow only customer ↔ provider ↔ Balinyaar</strong> — 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 ~710 business days (asynchronous, owned by the provider). The refund still decomposes across the platform-fee and nurse-payout legs in Balinyaar's ledger.</li>
<li><strong>The nurse's payout is unchanged by BNPL:</strong> computed from <code>gross_price_irr balinyaar_commission_irr</code>, paid weekly after EVV + dispute window — the provider's commission is a <strong>platform cost of accepting BNPL</strong> and is <strong>never</strong> passed through to the nurse.</li>
</ul>
<blockquote><p><strong>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 the payments docs — cross-reference the <a href="../payments/bnpl-landscape.html">BNPL landscape</a> and <a href="../payments/cancellation-and-payout.html">cancellation &amp; payout</a> for implementation detail.</strong></p>
</blockquote>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>Provider-financed Iranian BNPLs (SnappPay, Digipay, Tara, Torob Pay) are uniformly <strong>full-upfront, provider-bears-risk, interest-free-to-customer</strong>; only bank-financed POS loans (Lendo) charge the customer interest and are a poor fit for short, cancellable nursing visits.</li>
<li><strong>Settlement timing is contract-defined and may be gated on the customer's first installment</strong> (daily / T+1-3 / weekly / 15-day) — "full amount" does not mean "instant cash." Timing is config + a per-transaction <code>settled_at</code>; weekly nurse payout may key off settlement actually received, never an assumption.</li>
<li><strong>Commission rate is per-contract and not public</strong> (anecdotal 715% for SnappPay; Torob Pay's published 6.6%) — always a config field read from the actual settlement, never hardcoded.</li>
<li>Onboarding requires جواز کسب <strong>and</strong> اینماد 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.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> full-upfront BNPL via one provider modeled as a single inbound settlement (<code>bnpl_transactions</code>); provider-mediated revert/cancel refunds; nurse payout decoupled from BNPL; commission + settlement timing as config.</li>
<li><strong>DEFERRED:</strong> customer installment tracking (<code>installment_entries</code><strong>cut</strong>, owned by the provider); tranched settlement (<code>bnpl_settlement_entries</code> modeled-only, added if a future provider tranches); multiple BNPL providers.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><strong><code>bnpl_transactions</code></strong> (replaces the old <code>installment_plans</code>; the old <code>installment_entries</code> is cut), <code>payment_transactions</code>, <code>payment_webhook_events</code>, <code>refunds</code> (<code>refund_channel = 'bnpl_revert'</code>, <code>external_revert_reference</code>, <code>expected_customer_refund_eta</code>), <code>ledger_entries</code>. See the <a href="../payments/bnpl-landscape.html">BNPL landscape</a> and <a href="../payments/cancellation-and-payout.html">cancellation &amp; payout</a> payments docs.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/08-bnpl.html">BNPL</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+27
View File
@@ -0,0 +1,27 @@
# 9. Installments / BNPL
[← Business Requirements](index.md)
## (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 ~710 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 the payments docs — cross-reference the [BNPL landscape](../payments/bnpl-landscape.md) and [cancellation & payout](../payments/cancellation-and-payout.md) 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 715% 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 the [BNPL landscape](../payments/bnpl-landscape.md) and [cancellation & payout](../payments/cancellation-and-payout.md) payments docs.
> **Related:** Data model — [BNPL](../data-model/08-bnpl.md).
+57
View File
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>10. Payouts to Nurses — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a class="active" href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="10-payouts-to-nurses">10. Payouts to Nurses</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li>Nurses are paid in <strong>weekly batches</strong>. A batch aggregates the amounts owed for completed, payout-eligible bookings/sessions and produces one payout per nurse with earnings in that window.</li>
<li><strong>Payout eligibility is gated on EVV completion AND a closed dispute window.</strong> A booking/session enters a batch only when <code>status = 'completed'</code> AND <code>dispute_window_ends_at &lt; now()</code> (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.</li>
<li>The nurse payout amount derives from <code>gross_price_irr balinyaar_commission_irr</code> (never from a BNPL provider's net settlement).</li>
<li><strong>Clawbacks</strong> (<code>nurse_clawbacks</code>) handle the refund-after-payout case: if a booking is refunded/disputed <strong>after</strong> the nurse was already paid, a clawback receivable is recorded (negative ledger entry against the nurse) and recovered by <strong>netting against the nurse's next weekly batch</strong>, or written off if uncollectable. The nurse's payable balance is <strong>derived from the ledger</strong> (it may go negative), and a batch can net prior clawbacks (<code>gross_earnings</code>, <code>clawback_applied</code>, <code>net_amount</code>).</li>
<li><strong>Each booking is paid at most once</strong> (the payout↔booking link is unique), preventing double-pay across batches.</li>
<li><strong>Bank-holiday-aware scheduling.</strong> Payout period-end and processing dates are shifted off bank-closed days using a shared <code>iranian_holidays</code> calendar — a weekly payout landing on a multi-day Nowruz closure would otherwise fail, since PAYA/SATNA transfers do not settle on closed days.</li>
<li>Payouts go to the nurse's <strong>verified, registered primary IBAN</strong>, with the IBAN snapshotted and a transfer reference stored for reconciliation. Each payout item carries a unique track id + (for batches) a batch id.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>Payouts are <strong>real bank transfers to registered IBANs</strong> (PAYA/SATNA cycles, next-business-day on holidays) — there is no chargeback-style reversal, which is <em>why</em> the dispute window must close before payout and why clawback is a netting/receivable mechanism rather than an automatic reversal.</li>
<li>Provider settlement cut-offs (Toman/Jibit) mean payout must tolerate a provider being unavailable mid-cycle; the batch + reconciliation references survive a swap.</li>
<li>Each nurse must have a Shahkar/KYC-verified, IBAN-ownership-checked account registered as a beneficiary before any payout targets it.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> weekly batches; EVV + dispute-window gating; per-session accrual for engagements; <code>nurse_clawbacks</code> with next-batch netting and write-off; unique booking↔payout link; <code>iranian_holidays</code>-aware scheduling; verified-IBAN payouts with reconciliation references.</li>
<li><strong>DEFERRED:</strong> on-demand / instant nurse withdrawal; per-nurse configurable payout frequency; automated clawback recovery beyond netting.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>nurse_payout_batches</code>, <code>nurse_payouts</code> (with <code>gross_earnings_irr</code>, <code>clawback_applied_irr</code>, <code>net_amount_irr</code>, <code>iban_snapshot</code>), <code>nurse_payout_booking_links</code> (unique per booking), <strong><code>nurse_clawbacks</code></strong>, <code>ledger_entries</code>, <strong><code>iranian_holidays</code></strong>, <code>bookings.dispute_window_ends_at</code>, <code>nurse_bank_accounts</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/07-payouts.html">Payouts</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+26
View File
@@ -0,0 +1,26 @@
# 10. Payouts to Nurses
[← Business Requirements](index.md)
## (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`.
> **Related:** Data model — [Payouts](../data-model/07-payouts.md).
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>11. Reviews, Trust &amp; Safety — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a class="active" href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="11-reviews-trust-safety">11. Reviews, Trust &amp; Safety</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li>A customer can leave <strong>one review per completed booking</strong> (rating 15 + free text), tied to a verified, completed, on-platform booking.</li>
<li><strong>Moderation:</strong> reviews enter <code>pending_moderation</code> and are not public until approved by an admin (or an AI moderator). Aggregate nurse rating/counts are recomputed on <strong>every</strong> review status transition — publish, <strong>hide</strong>, reject, unpublish — so hiding a 1-star review never leaves a stale, inflated average.</li>
<li><strong>Low-rating alerting:</strong> a rating at or below a configurable threshold (default ≤ 2) with negative content automatically raises a <code>support_alerts</code> row for the support team to investigate.</li>
<li><strong>Incident handling:</strong> 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.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>The buyers are <strong>vulnerable people</strong> cared for <strong>unobserved at home</strong>; a single incident can destroy a fragile, trust-first brand — so moderation, low-rating alerting, and immediate suspension are core, not optional.</li>
<li>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).</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> one-per-completed-booking customer reviews; moderation with full recompute-on-every-transition; low-rating <code>support_alerts</code>; manual incident suspension.</li>
<li><strong>DEFERRED:</strong> two-way (nurse-reviews-customer) double-blind reviews with timed reveal; structured review-tag aggregation (<code>review_tags_master</code> / <code>review_tag_links</code> modeled but a phase-2 nicety); a dedicated <code>incidents</code> entity; ML fraud scoring.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>reviews</code> (moderation status, recompute triggers), <code>review_tags_master</code>, <code>review_tag_links</code>, <code>support_alerts</code> (low-rating, fraud-signal), <code>nurse_profiles</code> (denormalized aggregates), <code>audit_logs</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/10-reviews-and-records.html">Reviews &amp; Records</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,22 @@
# 11. Reviews, Trust & Safety
[← Business Requirements](index.md)
## (a) Business requirements
- A customer can leave **one review per completed booking** (rating 15 + 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`.
> **Related:** Data model — [Reviews & Records](../data-model/10-reviews-and-records.md).
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>12. Messaging &amp; On-Site Emergencies — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a class="active" href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="12-messaging-on-site-emergencies">12. Messaging &amp; On-Site Emergencies</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li><strong>There is no live chat and no direct nurse↔customer messaging.</strong> All post-booking communication runs through a structured <strong>ticket</strong> system that admin can read in full. This is a deliberate <strong>anti-disintermediation</strong> and <strong>patient-safety</strong> design: it protects vulnerable patients, creates a dispute paper trail, and prevents families and nurses pairing off-platform.</li>
<li>A <strong>booking-scoped coordination ticket</strong> 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.</li>
<li>Tickets also carry refund conversations and any support request, and are the mandatory anchor for admin refunds (Section 7).</li>
<li><strong>On-site emergency playbook.</strong> The ticket system is async and has no real-time channel, so the operational playbook is explicit: <strong>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.</strong> 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).</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>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.</li>
<li>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.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> ticket-only messaging (admin-readable); auto-created booking-coordination ticket; internal notes; prominent in-app emergency contact + documented playbook.</li>
<li><strong>DEFERRED:</strong> real-time chat; a first-class <code>incidents</code>/emergency-event entity with SLA; push/real-time alerting.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>tickets</code>, <code>ticket_participants</code>, <code>ticket_messages</code>, <code>booking_care_instructions</code> (encrypted emergency contact), <code>support_alerts</code>.</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/09-messaging.html">Messaging</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,22 @@
# 12. Messaging & On-Site Emergencies
[← Business Requirements](index.md)
## (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`.
> **Related:** Data model — [Messaging](../data-model/09-messaging.md).
@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>13. Tax, Invoicing &amp; Legal — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a class="active" href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="13-tax-invoicing-legal">13. Tax, Invoicing &amp; Legal</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li><strong>The nurse is the taxable seller of the nursing service; Balinyaar is the taxable seller only of its commission.</strong> 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.</li>
<li><strong>VAT is 10%</strong> (configurable), applied to Balinyaar's commission line. The home-nursing <strong>service's</strong> own VAT treatment is <strong>unconfirmed</strong> (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.</li>
<li><strong>سامانه مودیان (taxpayer system) readiness, minimal footprint.</strong> The platform produces a minimal <code>invoices</code> 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 <strong>commission</strong> invoice; it does not issue the nurse's service invoice.</li>
<li><strong>e-namad (نماد اعتماد الکترونیکی)</strong> 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.</li>
<li><strong>Partner licensed-center (Asanism-style) as the launch legal vehicle.</strong> Home nursing is a <strong>licensed healthcare activity</strong> (MoH establishment permit پروانه تأسیس + technical-director license پروانه مسئول فنی via the Article-20 commission), in the <strong>home-nursing-services-center</strong> track (a nurse with BSc + ≥5 yrs experience can found/direct it). The fast, legal go-to-market is to <strong>partner with already-licensed centers</strong> while Balinyaar's own permit is pending. A <code>partner_centers</code> entity represents the licensed center that holds the جواز کسب + اینماد + MoH license, sponsors nurses, and <strong>may be the merchant-of-record / invoice issuer</strong> for payments — making BNPL and online payment legally feasible without each nurse holding a license.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>Operating <strong>without</strong> 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.</li>
<li>مودیان obligation phases in by revenue thresholds; most individual nurses fall below mandatory thresholds early, but the <strong>platform's commission line is VAT/e-invoice-relevant</strong> — so per-nurse مودیان obligation is a configurable flag and the platform's own commission invoicing is the in-scope obligation.</li>
<li>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.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> <code>partner_centers</code> as the launch legal vehicle with merchant-of-record flag and nurse sponsorship; minimal per-booking <code>invoices</code> 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.</li>
<li><strong>DEFERRED:</strong> 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 <code>organizations</code> model.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><strong><code>invoices</code></strong> (minimal, commission-focused, مودیان fields, VAT), <strong><code>partner_centers</code></strong> (MoH license, اینماد, merchant-of-record), <code>nurse_profiles.partner_center_id</code>, <code>payment_transactions</code> (Shaparak reference for reconciliation), <code>platform_configs</code> (VAT rate, merchant-of-record).</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/13-partner-centers-and-future.html">Partner Centers &amp; Future</a>; Research — <a href="../research/legal-landscape.html">Legal Landscape</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,24 @@
# 13. Tax, Invoicing & Legal
[← Business Requirements](index.md)
## (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).
> **Related:** Data model — [Partner Centers & Future](../data-model/13-partner-centers-and-future.md); Research — [Legal Landscape](../research/legal-landscape.md).
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>14. Notifications &amp; Admin / Backoffice — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a class="active" href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="14-notifications-admin-backoffice">14. Notifications &amp; Admin / Backoffice</h1>
<p><a href="index.html">← Business Requirements</a></p>
<h2 id="a-business-requirements">(a) Business requirements <a class="anchor" href="#a-business-requirements" aria-hidden="true">#</a></h2>
<ul>
<li><strong>In-app notifications</strong> 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. <strong>No push notifications at launch.</strong></li>
<li>A retention job hard-deletes read notifications older than 90 days to keep the table bounded.</li>
<li><strong>Admin / backoffice tooling</strong> must cover the operational spine:<ul>
<li><strong>Verification queue</strong> — review uploaded MoH/INO/criminal-record documents, record structured credential numbers/expiries, pass/fail steps, and flip <code>is_verified</code> transactionally.</li>
<li><strong>Refund tooling</strong> — initiate admin-only, ticket-linked refunds with tiered policy application and fee-leg decomposition; for BNPL, trigger the provider revert/cancel.</li>
<li><strong>Payout tooling</strong> — initiate/inspect weekly batches, see eligibility (EVV + closed dispute window), apply clawback netting, schedule around bank holidays, and reconcile transfer references.</li>
<li><strong>Support-alert console</strong> — triage low-rating, no-show, location-mismatch, expiry, and fraud-signal alerts.</li>
<li><strong>RBAC</strong> — admin roles (super_admin / admin / support / finance / moderator) scope who can verify, refund, pay out, and moderate.</li>
</ul>
</li>
<li>An <strong>append-only audit trail</strong> 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.</li>
</ul>
<h2 id="b-iran-specific-considerations">(b) Iran-specific considerations <a class="anchor" href="#b-iran-specific-considerations" aria-hidden="true">#</a></h2>
<ul>
<li>No push at launch reflects a pragmatic MVP and the in-app polling norm; SMS-OTP already covers the critical auth path.</li>
<li>Back-office must reason over the Shamsi calendar and <code>iranian_holidays</code> for payout scheduling and deadline computation, and over the verification realities (manual MoH/INO checks, expiry-driven re-verification).</li>
<li>High-volume logs (<code>audit_logs</code>, <code>system_events</code>, <code>notifications</code>) need partitioning/retention planned before launch to avoid unbounded growth.</li>
</ul>
<h2 id="c-mvp-vs-deferred">(c) MVP vs DEFERRED <a class="anchor" href="#c-mvp-vs-deferred" aria-hidden="true">#</a></h2>
<ul>
<li><strong>MVP:</strong> in-app notifications with 90-day retention; admin verification/refund/payout/alert tooling; RBAC; append-only <code>audit_logs</code>; config-change auditing.</li>
<li><strong>DEFERRED:</strong> push notifications; SMS/email notification channels beyond OTP; a full analytics warehouse (<code>system_events</code> piped out rather than queried in the transactional DB); ML fraud console.</li>
</ul>
<h2 id="d-supporting-database-entities">(d) Supporting database entities <a class="anchor" href="#d-supporting-database-entities" aria-hidden="true">#</a></h2>
<p><code>notifications</code>, <code>support_alerts</code>, <code>roles</code>, <code>user_roles</code>, <code>audit_logs</code>, <code>system_events</code>, <code>platform_configs</code>, plus the operational entities each tool acts on (<code>nurse_verifications</code> / <code>verification_steps</code> / <code>nurse_credentials</code>, <code>refunds</code>, <code>nurse_payout_batches</code> / <code>nurse_payouts</code> / <code>nurse_clawbacks</code>, <code>bookings</code>).</p>
<blockquote><p><strong>Related:</strong> Data model — <a href="../data-model/12-audit-config-and-reference.html">Audit, Config &amp; Reference</a>.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,28 @@
# 14. Notifications & Admin / Backoffice
[← Business Requirements](index.md)
## (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`).
> **Related:** Data model — [Audit, Config & Reference](../data-model/12-audit-config-and-reference.md).
+80
View File
@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Business Requirements — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a class="active" href="index.html">Overview &amp; MVP scope</a></li><li><a href="01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="02-nurse-verification.html">2. Nurse verification</a></li><li><a href="03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="10-payouts.html">10. Payouts to nurses</a></li><li><a href="11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="business-requirements">Business Requirements</h1>
<blockquote><p><strong>Purpose.</strong> This document specifies the business requirements for <strong>Balinyaar</strong>, 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 <em>through</em> 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 <strong>not naive</strong> about Iranian payment law, tax, and the realities of caring for vulnerable people at home. All monetary values are in <strong>IRR (Rials)</strong>; Toman is a display concern only and is converted to/from Rials solely at an external provider's API boundary.</p>
</blockquote>
<p><strong>Date:</strong> 2026-06-20</p>
<p>These sections assume the four <a href="../overview/platform-summary.html">cross-cutting ground truths</a>.</p>
<hr>
<h2 id="how-to-read-this-document">How to read this document <a class="anchor" href="#how-to-read-this-document" aria-hidden="true">#</a></h2>
<p>Each section covers one business area and states, in order:</p>
<ul>
<li><strong>(a) Business requirements</strong> — what the platform must do.</li>
<li><strong>(b) Iran-specific considerations</strong> — the local legal, fiscal, cultural, and infrastructural realities that shape the requirement.</li>
<li><strong>(c) MVP vs DEFERRED</strong> — an explicit callout of what ships at launch and what is intentionally postponed.</li>
<li><strong>(d) Supporting database entities</strong> — the entities (using the final names from the refined data model) that implement the requirement.</li>
</ul>
<hr>
<h2 id="areas">Areas <a class="anchor" href="#areas" aria-hidden="true">#</a></h2>
<ol>
<li><a href="01-actors-and-onboarding.html">Actors &amp; Onboarding</a> — three actor types, phone-OTP login, the customer/patient split, and role-staged KYC.</li>
<li><a href="02-nurse-verification.html">Nurse Verification &amp; Credentials</a> — the platform-owned, six-step verification pipeline and the structured credential registry.</li>
<li><a href="03-service-catalog-and-pricing.html">Service Catalog &amp; Pricing</a> — admin-defined catalog skeleton, nurse-priced variants, and the five price units.</li>
<li><a href="04-search-and-matching.html">Search &amp; Matching</a> — geo/category search, the denormalized search index, and same-gender caregiver matching.</li>
<li><a href="05-booking-and-scheduling.html">Booking &amp; Scheduling</a> — the request→accept→pay→confirm lifecycle and multi-session engagements.</li>
<li><a href="06-evv-and-service-delivery.html">EVV / Service Delivery</a> — Electronic Visit Verification check-in/out and payout gating on proof of service.</li>
<li><a href="07-cancellation-and-refunds.html">Cancellation &amp; Refunds</a> — tiered, snapshotted policies and admin-only, ticket-linked refunds.</li>
<li><a href="08-payments-and-escrow.html">Payments &amp; Escrow</a> — merchant-of-record card flow, the internal double-entry ledger, and webhook idempotency.</li>
<li><a href="09-installments-bnpl.html">Installments / BNPL</a> — full-upfront, provider-financed BNPL modeled as a single inbound settlement.</li>
<li><a href="10-payouts.html">Payouts to Nurses</a> — weekly batches gated on EVV + dispute window, clawbacks, and holiday-aware scheduling.</li>
<li><a href="11-reviews-trust-and-safety.html">Reviews, Trust &amp; Safety</a> — one-per-booking moderated reviews, low-rating alerting, and incident handling.</li>
<li><a href="12-messaging-and-emergencies.html">Messaging &amp; On-Site Emergencies</a> — ticket-only communication and the on-site emergency playbook.</li>
<li><a href="13-tax-invoicing-and-legal.html">Tax, Invoicing &amp; Legal</a> — nurse-as-seller / platform-as-commission-seller split, VAT, and the partner-center launch vehicle.</li>
<li><a href="14-notifications-and-admin.html">Notifications &amp; Admin / Backoffice</a> — in-app notifications, the admin operational spine, RBAC, and the audit trail.</li>
</ol>
<hr>
<h2 id="appendix-mvp-vs-deferred-at-a-glance">Appendix — MVP vs Deferred at a glance <a class="anchor" href="#appendix-mvp-vs-deferred-at-a-glance" aria-hidden="true">#</a></h2>
<div class="table-wrap"><table><thead><tr><th>Area</th><th>MVP</th><th>Deferred</th></tr></thead><tbody>
<tr><td>Onboarding</td><td>phone-OTP; customer/nurse/admin; patient split</td><td>customer KYC; org self-onboarding; push</td></tr>
<tr><td>Verification</td><td>6-step data-driven pipeline; <code>nurse_credentials</code>; IBAN ownership</td><td>MoH/INO API; liability-insurance step; ML fraud</td></tr>
<tr><td>Catalog</td><td>admin categories/options; nurse variants &amp; price units</td><td>holiday/surge pricing; companionship tier</td></tr>
<tr><td>Search</td><td>geo + category; <code>nurse_search_index</code>; same-gender filter</td><td>map discovery; availability hard-filter</td></tr>
<tr><td>Booking</td><td>request→accept→pay→confirm; <code>booking_sessions</code> multi-visit</td><td>recurring schedules; milestone-payment UX</td></tr>
<tr><td>EVV</td><td>per-session GPS check-in/out; payout gating</td><td>geofencing; tele-check-ins; cameras</td></tr>
<tr><td>Cancellation</td><td>tiered policy + snapshot; admin/ticket refunds; per-session</td><td>auto no-show penalty; self-service refunds</td></tr>
<tr><td>Payments/Escrow</td><td>ledger escrow; <code>payment_webhook_events</code>; provider abstraction</td><td>nurse wallet; multi-PSP live; bank escrow product</td></tr>
<tr><td>BNPL</td><td>full-upfront <code>bnpl_transactions</code>; provider-revert refunds</td><td>installment tracking (cut); tranched settlement; multi-provider</td></tr>
<tr><td>Payouts</td><td>weekly batches; clawbacks; holiday-aware; verified IBAN</td><td>instant withdrawal; per-nurse frequency</td></tr>
<tr><td>Reviews</td><td>one-per-booking; moderation; low-rating alerts</td><td>two-way reviews; tag aggregation; <code>incidents</code></td></tr>
<tr><td>Messaging</td><td>ticket-only; coordination ticket; emergency playbook</td><td>live chat; emergency-event entity</td></tr>
<tr><td>Tax/Legal</td><td><code>partner_centers</code>; minimal <code>invoices</code>; 10% VAT on commission; e-namad</td><td>full مودیان automation; nurse-side invoicing; B2B</td></tr>
<tr><td>Notifications/Admin</td><td>in-app + retention; verify/refund/payout tooling; RBAC</td><td>push; analytics warehouse; ML console</td></tr>
</tbody></table></div>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+58
View File
@@ -0,0 +1,58 @@
# 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
These sections assume the four [cross-cutting ground truths](../overview/platform-summary.md).
---
## 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.
---
## Areas
1. [Actors & Onboarding](01-actors-and-onboarding.md) — three actor types, phone-OTP login, the customer/patient split, and role-staged KYC.
2. [Nurse Verification & Credentials](02-nurse-verification.md) — the platform-owned, six-step verification pipeline and the structured credential registry.
3. [Service Catalog & Pricing](03-service-catalog-and-pricing.md) — admin-defined catalog skeleton, nurse-priced variants, and the five price units.
4. [Search & Matching](04-search-and-matching.md) — geo/category search, the denormalized search index, and same-gender caregiver matching.
5. [Booking & Scheduling](05-booking-and-scheduling.md) — the request→accept→pay→confirm lifecycle and multi-session engagements.
6. [EVV / Service Delivery](06-evv-and-service-delivery.md) — Electronic Visit Verification check-in/out and payout gating on proof of service.
7. [Cancellation & Refunds](07-cancellation-and-refunds.md) — tiered, snapshotted policies and admin-only, ticket-linked refunds.
8. [Payments & Escrow](08-payments-and-escrow.md) — merchant-of-record card flow, the internal double-entry ledger, and webhook idempotency.
9. [Installments / BNPL](09-installments-bnpl.md) — full-upfront, provider-financed BNPL modeled as a single inbound settlement.
10. [Payouts to Nurses](10-payouts.md) — weekly batches gated on EVV + dispute window, clawbacks, and holiday-aware scheduling.
11. [Reviews, Trust & Safety](11-reviews-trust-and-safety.md) — one-per-booking moderated reviews, low-rating alerting, and incident handling.
12. [Messaging & On-Site Emergencies](12-messaging-and-emergencies.md) — ticket-only communication and the on-site emergency playbook.
13. [Tax, Invoicing & Legal](13-tax-invoicing-and-legal.md) — nurse-as-seller / platform-as-commission-seller split, VAT, and the partner-center launch vehicle.
14. [Notifications & Admin / Backoffice](14-notifications-and-admin.md) — in-app notifications, the admin operational spine, RBAC, and the audit trail.
---
## 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 |
@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 1 — Identity &amp; Access — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a class="active" href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-1-identity-access">Domain 1 — Identity &amp; Access</h1>
<p><a href="index.html">← Database Model</a></p>
<p><strong>Related:</strong> business requirements — <a href="../business/01-actors-and-onboarding.html">Actors &amp; onboarding</a>.</p>
<h3 id="users-core"><code>users</code> [CORE] <a class="anchor" href="#users-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The single identity record for every human actor — nurse, customer, admin. <code>role</code> decides which profile sub-table is populated. Phone is the primary login credential (OTP); national ID is filled only after KYC.</p>
<p><strong>Why:</strong> One identity table avoids three near-duplicate user tables and lets auth, audit, and notifications treat everyone uniformly. Phone-as-primary matches Iranian OTP norms and is the key Shahkar matches against. National ID stays NULL until verified so an unverified registration can't masquerade as KYC-complete.</p>
<p>Fields unchanged from baseline: <code>id</code>, <code>email</code> (enc, nullable), <code>phone</code> (enc, unique), <code>national_id</code> (enc, nullable), <code>national_id_verified_at</code>, <code>first_name</code>, <code>last_name</code>, <code>gender</code> <em>(promoted here — see note)</em>, <code>avatar_url</code>, <code>role</code> (<code>nurse</code>/<code>customer</code>/<code>admin</code>), <code>is_active</code>, <code>email_verified_at</code>, <code>phone_verified_at</code>, <code>last_login_at</code>, <code>last_login_ip</code>, <code>preferred_language</code>, <code>created_at</code>, <code>updated_at</code>, <code>deleted_at</code>.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>gender</code></td><td>NVARCHAR(10) NULL</td><td><strong>NEW/clarified</strong><code>male</code>/<code>female</code>. Needed because <strong>same-gender caregiving is a near-hard requirement</strong> in Iranian bodily-care; nurse gender (from here) is matched against <code>booking_requests.required_caregiver_gender</code>.</td></tr>
<tr><td><code>shahkar_verified_at</code></td><td>DATETIME2 NULL</td><td><strong>NEW</strong> — when the phone↔national-id binding was confirmed via Shahkar. Re-set to NULL (re-verify) on phone change.</td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> 1:1 → <code>nurse_profiles</code> / <code>customer_profiles</code> (by role); 1:N → <code>user_sessions</code>, <code>user_roles</code>, <code>notifications</code>, <code>ticket_participants</code>. Admin users are referenced across the schema as <code>*_by_admin_id</code>.</p>
<h3 id="user_sessions-core"><code>user_sessions</code> [CORE] <a class="anchor" href="#user_sessions-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Refresh-token session records. <strong>Why:</strong> Enables logout-everywhere and stolen-token revocation without a heavyweight session store. Unchanged: <code>id</code>, <code>user_id</code>, <code>refresh_token_hash</code>, <code>device_info</code>, <code>ip_address</code>, <code>is_revoked</code>, <code>revoked_at</code>, <code>expires_at</code>, <code>created_at</code>. <strong>Relations:</strong> N:1 → <code>users</code>.</p>
<h3 id="roles-user_roles-core"><code>roles</code> / <code>user_roles</code> [CORE] <a class="anchor" href="#roles-user_roles-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> RBAC for admin staff only (nurses/customers use <code>users.role</code>). <strong>Why:</strong> A small admin team still needs separable finance/support/moderation permissions and a revocation history. <code>user_roles</code> keeps <code>granted_by</code>/<code>granted_at</code>/<code>revoked_at</code> for an audit trail. <strong>Relations:</strong> <code>users</code> N:N <code>roles</code> via <code>user_roles</code>.</p>
<h3 id="nurse_profiles-core"><code>nurse_profiles</code> [CORE] <a class="anchor" href="#nurse_profiles-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Extended data for nurses, plus denormalized search/quality aggregates. <strong>Why separated from <code>users</code>:</strong> keeps the base identity table lean and isolates the (large) nurse-only attributes and the aggregates that search reads on every query.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>user_id</code></td><td>BIGINT FK → users UNIQUE</td><td>1:1</td></tr>
<tr><td><code>partner_center_id</code></td><td>BIGINT FK → partner_centers NULL</td><td><strong>NEW</strong> — the licensed center that legally sponsors this nurse at launch (Asanism model). NULL once Balinyaar holds its own permit.</td></tr>
<tr><td><code>bio</code>, <code>years_of_experience</code>, <code>education_level</code>, <code>education_field</code>, <code>specializations_json</code></td><td></td><td>Unchanged.</td></tr>
<tr><td><code>is_verified</code></td><td>BIT NOT NULL DEFAULT 0</td><td><strong>Guarded</strong> — set <strong>only</strong> inside the transaction that confirms all required <code>verification_steps.status='passed'</code>. No direct write API (Principle 12).</td></tr>
<tr><td><del><code>verification_status</code></del></td><td></td><td><strong>CUT</strong> — duplicated <code>nurse_verifications.status</code>; two copies drifted. <code>nurse_verifications.status</code> is now the single source of truth.</td></tr>
<tr><td><code>is_accepting_bookings</code></td><td>BIT NOT NULL DEFAULT 0</td><td>Nurse can pause without losing verified status.</td></tr>
<tr><td><code>average_rating</code>, <code>total_reviews</code>, <code>total_completed_bookings</code></td><td></td><td>Denormalized. <strong>Recompute rule now documented</strong>: updated on <strong>every</strong> review status transition (publish → +, hide/reject/unpublish → ) and on booking completion/dispute-reversal, plus a nightly reconciliation job. Fixes the "hide a 1★ review → rating stays inflated" drift.</td></tr>
<tr><td><del><code>response_rate</code>, <code>avg_response_time_hours</code>, <code>profile_completion_score</code></del></td><td></td><td><strong>CUT for MVP</strong> — analytics columns on no money/safety path, each needing a maintenance job. Compute offline later.</td></tr>
<tr><td><code>created_at</code>, <code>updated_at</code>, <code>deleted_at</code></td><td></td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> 1:1 → <code>users</code>, <code>nurse_verifications</code>; 1:N → <code>nurse_service_variants</code>, <code>nurse_service_areas</code>, <code>nurse_bank_accounts</code>, <code>nurse_credentials</code>, <code>bookings</code>, <code>nurse_payouts</code>, <code>nurse_clawbacks</code>; N:1 → <code>partner_centers</code>.</p>
<h3 id="customer_profiles-core"><code>customer_profiles</code> [CORE] <a class="anchor" href="#customer_profiles-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Lightweight extension for customers. <strong>Why intentionally thin:</strong> most customer reality lives in their <code>patients</code>, <code>customer_addresses</code>, and <code>bookings</code>. KYC for customers is deferred. Unchanged: <code>id</code>, <code>user_id</code> (unique), <code>default_emergency_contact_name</code>/<code>_phone</code> (enc), <code>created_at</code>, <code>updated_at</code>. <strong>CUT for MVP:</strong> <code>national_id_verified_at</code> (anti-fraud customer KYC — add when actually built). <strong>Relations:</strong> 1:1 → <code>users</code>; 1:N → <code>patients</code>, <code>customer_addresses</code>, <code>booking_requests</code>, <code>bookings</code>.</p>
<h3 id="patients-core"><code>patients</code> [CORE] <a class="anchor" href="#patients-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The person receiving care, <strong>separate from the payer</strong>. <strong>Why:</strong> the payer (adult child, spouse) is usually not the patient (elderly parent, newborn, post-surgical adult); one customer registers many patients, each with its own clinical baseline and longitudinal record. Unchanged: <code>id</code>, <code>customer_id</code>, <code>display_name</code>, <code>first_name</code>, <code>last_name</code>, <code>birth_date</code>, <code>gender</code>, <code>blood_type</code>, <code>initial_medical_notes</code> (enc), <code>is_active</code>, timestamps. <strong>Relations:</strong> N:1 → <code>customer_profiles</code>; 1:N → <code>booking_requests</code>, <code>patient_care_records</code>. <strong>Tenancy invariant:</strong> a <code>booking_request.patient_id</code> must belong to the same <code>customer_id</code>.</p>
<h3 id="customer_addresses-core"><code>customer_addresses</code> [CORE] <a class="anchor" href="#customer_addresses-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Saved service locations; the encrypted address + coordinates for EVV distance checks. <strong>Why coordinates:</strong> EVV check-in compares the nurse's GPS against the booking address within tolerance. Unchanged fields, plus: <strong>filtered <code>UNIQUE(customer_id) WHERE is_primary=1</code></strong> so exactly one primary exists (prevents ambiguous default). <strong>Relations:</strong> N:1 → <code>customer_profiles</code>, <code>cities</code>, <code>districts</code>; referenced by <code>booking_requests</code>/<code>bookings</code>.</p>
<h3 id="nurse_bank_accounts-core"><code>nurse_bank_accounts</code> [CORE] <a class="anchor" href="#nurse_bank_accounts-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Payout destination (IBAN/Sheba). <strong>Why hardened:</strong> the IBAN is the single place real money leaves the platform — the original "admin eyeballs the IBAN" check is exactly the forgeable, money-mule-risk link the research warns about.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code>, <code>nurse_id</code>, <code>bank_name</code>, <code>account_holder_name</code> (enc), <code>iban</code> (enc), <code>is_primary</code>, <code>is_verified</code>, <code>verified_by_admin_id</code>, <code>verified_at</code>, timestamps</td><td></td><td>Baseline.</td></tr>
<tr><td><code>iban_hash</code></td><td>NVARCHAR(64)</td><td><strong>NEW</strong> — deterministic hash for a <strong>UNIQUE</strong> constraint (same IBAN must not silently serve two nurses).</td></tr>
<tr><td><code>matched_national_id</code></td><td>BIT NULL</td><td><strong>NEW</strong> — result of an automated <strong>IBAN-owner ↔ national-id inquiry (استعلام شبا)</strong> via a KYC vendor. First payout is gated on a match, not on admin eyeballing.</td></tr>
<tr><td><code>account_holder_from_bank</code></td><td>NVARCHAR(200) NULL</td><td><strong>NEW</strong> — name returned by the bank inquiry, snapshot.</td></tr>
<tr><td><code>ownership_vendor_ref</code></td><td>NVARCHAR(200) NULL</td><td><strong>NEW</strong> — vendor transaction id for audit.</td></tr>
</tbody></table></div>
<p>Constraints: <strong>filtered <code>UNIQUE(nurse_id) WHERE is_primary=1</code></strong>; <code>UNIQUE(iban_hash)</code>. <strong>Relations:</strong> N:1 → <code>nurse_profiles</code>; 1:N → <code>nurse_payouts</code>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,65 @@
# Domain 1 — Identity & Access
[← Database Model](index.md)
**Related:** business requirements — [Actors & onboarding](../business/01-actors-and-onboarding.md).
### `users` [CORE]
**Role:** The single identity record for every human actor — nurse, customer, admin. `role` decides which profile sub-table is populated. Phone is the primary login credential (OTP); national ID is filled only after KYC.
**Why:** One identity table avoids three near-duplicate user tables and lets auth, audit, and notifications treat everyone uniformly. Phone-as-primary matches Iranian OTP norms and is the key Shahkar matches against. National ID stays NULL until verified so an unverified registration can't masquerade as KYC-complete.
Fields unchanged from baseline: `id`, `email` (enc, nullable), `phone` (enc, unique), `national_id` (enc, nullable), `national_id_verified_at`, `first_name`, `last_name`, `gender` *(promoted here — see note)*, `avatar_url`, `role` (`nurse`/`customer`/`admin`), `is_active`, `email_verified_at`, `phone_verified_at`, `last_login_at`, `last_login_ip`, `preferred_language`, `created_at`, `updated_at`, `deleted_at`.
| Field | Type | Notes |
|---|---|---|
| `gender` | NVARCHAR(10) NULL | **NEW/clarified**`male`/`female`. Needed because **same-gender caregiving is a near-hard requirement** in Iranian bodily-care; nurse gender (from here) is matched against `booking_requests.required_caregiver_gender`. |
| `shahkar_verified_at` | DATETIME2 NULL | **NEW** — when the phone↔national-id binding was confirmed via Shahkar. Re-set to NULL (re-verify) on phone change. |
**Relations:** 1:1 → `nurse_profiles` / `customer_profiles` (by role); 1:N → `user_sessions`, `user_roles`, `notifications`, `ticket_participants`. Admin users are referenced across the schema as `*_by_admin_id`.
### `user_sessions` [CORE]
**Role:** Refresh-token session records. **Why:** Enables logout-everywhere and stolen-token revocation without a heavyweight session store. Unchanged: `id`, `user_id`, `refresh_token_hash`, `device_info`, `ip_address`, `is_revoked`, `revoked_at`, `expires_at`, `created_at`. **Relations:** N:1 → `users`.
### `roles` / `user_roles` [CORE]
**Role:** RBAC for admin staff only (nurses/customers use `users.role`). **Why:** A small admin team still needs separable finance/support/moderation permissions and a revocation history. `user_roles` keeps `granted_by`/`granted_at`/`revoked_at` for an audit trail. **Relations:** `users` N:N `roles` via `user_roles`.
### `nurse_profiles` [CORE]
**Role:** Extended data for nurses, plus denormalized search/quality aggregates. **Why separated from `users`:** keeps the base identity table lean and isolates the (large) nurse-only attributes and the aggregates that search reads on every query.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `user_id` | BIGINT FK → users UNIQUE | 1:1 |
| `partner_center_id` | BIGINT FK → partner_centers NULL | **NEW** — the licensed center that legally sponsors this nurse at launch (Asanism model). NULL once Balinyaar holds its own permit. |
| `bio`, `years_of_experience`, `education_level`, `education_field`, `specializations_json` | … | Unchanged. |
| `is_verified` | BIT NOT NULL DEFAULT 0 | **Guarded** — set **only** inside the transaction that confirms all required `verification_steps.status='passed'`. No direct write API (Principle 12). |
| ~~`verification_status`~~ | — | **CUT** — duplicated `nurse_verifications.status`; two copies drifted. `nurse_verifications.status` is now the single source of truth. |
| `is_accepting_bookings` | BIT NOT NULL DEFAULT 0 | Nurse can pause without losing verified status. |
| `average_rating`, `total_reviews`, `total_completed_bookings` | … | Denormalized. **Recompute rule now documented**: updated on **every** review status transition (publish → +, hide/reject/unpublish → ) and on booking completion/dispute-reversal, plus a nightly reconciliation job. Fixes the "hide a 1★ review → rating stays inflated" drift. |
| ~~`response_rate`, `avg_response_time_hours`, `profile_completion_score`~~ | — | **CUT for MVP** — analytics columns on no money/safety path, each needing a maintenance job. Compute offline later. |
| `created_at`, `updated_at`, `deleted_at` | … | |
**Relations:** 1:1 → `users`, `nurse_verifications`; 1:N → `nurse_service_variants`, `nurse_service_areas`, `nurse_bank_accounts`, `nurse_credentials`, `bookings`, `nurse_payouts`, `nurse_clawbacks`; N:1 → `partner_centers`.
### `customer_profiles` [CORE]
**Role:** Lightweight extension for customers. **Why intentionally thin:** most customer reality lives in their `patients`, `customer_addresses`, and `bookings`. KYC for customers is deferred. Unchanged: `id`, `user_id` (unique), `default_emergency_contact_name`/`_phone` (enc), `created_at`, `updated_at`. **CUT for MVP:** `national_id_verified_at` (anti-fraud customer KYC — add when actually built). **Relations:** 1:1 → `users`; 1:N → `patients`, `customer_addresses`, `booking_requests`, `bookings`.
### `patients` [CORE]
**Role:** The person receiving care, **separate from the payer**. **Why:** the payer (adult child, spouse) is usually not the patient (elderly parent, newborn, post-surgical adult); one customer registers many patients, each with its own clinical baseline and longitudinal record. Unchanged: `id`, `customer_id`, `display_name`, `first_name`, `last_name`, `birth_date`, `gender`, `blood_type`, `initial_medical_notes` (enc), `is_active`, timestamps. **Relations:** N:1 → `customer_profiles`; 1:N → `booking_requests`, `patient_care_records`. **Tenancy invariant:** a `booking_request.patient_id` must belong to the same `customer_id`.
### `customer_addresses` [CORE]
**Role:** Saved service locations; the encrypted address + coordinates for EVV distance checks. **Why coordinates:** EVV check-in compares the nurse's GPS against the booking address within tolerance. Unchanged fields, plus: **filtered `UNIQUE(customer_id) WHERE is_primary=1`** so exactly one primary exists (prevents ambiguous default). **Relations:** N:1 → `customer_profiles`, `cities`, `districts`; referenced by `booking_requests`/`bookings`.
### `nurse_bank_accounts` [CORE]
**Role:** Payout destination (IBAN/Sheba). **Why hardened:** the IBAN is the single place real money leaves the platform — the original "admin eyeballs the IBAN" check is exactly the forgeable, money-mule-risk link the research warns about.
| Field | Type | Notes |
|---|---|---|
| `id`, `nurse_id`, `bank_name`, `account_holder_name` (enc), `iban` (enc), `is_primary`, `is_verified`, `verified_by_admin_id`, `verified_at`, timestamps | … | Baseline. |
| `iban_hash` | NVARCHAR(64) | **NEW** — deterministic hash for a **UNIQUE** constraint (same IBAN must not silently serve two nurses). |
| `matched_national_id` | BIT NULL | **NEW** — result of an automated **IBAN-owner ↔ national-id inquiry (استعلام شبا)** via a KYC vendor. First payout is gated on a match, not on admin eyeballing. |
| `account_holder_from_bank` | NVARCHAR(200) NULL | **NEW** — name returned by the bank inquiry, snapshot. |
| `ownership_vendor_ref` | NVARCHAR(200) NULL | **NEW** — vendor transaction id for audit. |
Constraints: **filtered `UNIQUE(nurse_id) WHERE is_primary=1`**; `UNIQUE(iban_hash)`. **Relations:** N:1 → `nurse_profiles`; 1:N → `nurse_payouts`.
+36
View File
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 2 — Geographic Data — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a class="active" href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-2-geographic-data">Domain 2 — Geographic Data</h1>
<p><a href="index.html">← Database Model</a></p>
<h3 id="provinces-cities-districts-coremvp"><code>provinces</code> / <code>cities</code> / <code>districts</code> [CORE]/[MVP] <a class="anchor" href="#provinces-cities-districts-coremvp" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The geo hierarchy backing service areas, addresses, and search. <strong>Why a table, not a static list:</strong> new cities/districts launch without a deploy, and <code>sort_order</code>/<code>is_active</code> drive ordered, toggleable dropdowns. <code>districts</code> map to Tehran's 22 municipal districts or major neighborhoods elsewhere; they are <strong>optional</strong> (a nurse can cover a whole city). Fields unchanged. <strong>Relations:</strong> <code>provinces</code> 1:N <code>cities</code> 1:N <code>districts</code>; referenced by <code>customer_addresses</code> and <code>nurse_service_areas</code>.</p>
<h3 id="nurse_service_areas-core"><code>nurse_service_areas</code> [CORE] <a class="anchor" href="#nurse_service_areas-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Where a nurse will travel. A row with <code>district_id = NULL</code> means the entire city. <strong>Why a join table (not a radius):</strong> Iranian nurses think in named districts, not GPS radii; this also drives the geographic filter in search cheaply. Unchanged, with <code>UNIQUE(nurse_id, city_id, district_id)</code>. <strong>Relations:</strong> N:1 → <code>nurse_profiles</code>, <code>cities</code>, <code>districts</code>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
# Domain 2 — Geographic Data
[← Database Model](index.md)
### `provinces` / `cities` / `districts` [CORE]/[MVP]
**Role:** The geo hierarchy backing service areas, addresses, and search. **Why a table, not a static list:** new cities/districts launch without a deploy, and `sort_order`/`is_active` drive ordered, toggleable dropdowns. `districts` map to Tehran's 22 municipal districts or major neighborhoods elsewhere; they are **optional** (a nurse can cover a whole city). Fields unchanged. **Relations:** `provinces` 1:N `cities` 1:N `districts`; referenced by `customer_addresses` and `nurse_service_areas`.
### `nurse_service_areas` [CORE]
**Role:** Where a nurse will travel. A row with `district_id = NULL` means the entire city. **Why a join table (not a radius):** Iranian nurses think in named districts, not GPS radii; this also drives the geographic filter in search cheaply. Unchanged, with `UNIQUE(nurse_id, city_id, district_id)`. **Relations:** N:1 → `nurse_profiles`, `cities`, `districts`.
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 3 — Services &amp; Pricing — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a class="active" href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-3-services-pricing">Domain 3 — Services &amp; Pricing</h1>
<p><a href="index.html">← Database Model</a></p>
<p>The service model keeps the original three admin layers (category → option group → option value) and two nurse layers (variant → variant option). This <strong>EAV-style configurability is deliberately kept</strong> — it lets admins add a new pricing dimension (e.g. "شبانه‌روزی / live-in", "number of patients") without a migration, and lets each nurse price every combination independently. The only addition is a denormalized read model for search.</p>
<h3 id="service_categories-core"><code>service_categories</code> [CORE] <a class="anchor" href="#service_categories-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Admin-managed top-level care types (Elderly, Post-Surgery, Infant, Chronic, Companionship). The primary search dimension. <strong>Why admin-managed rows:</strong> the catalog is a business lever, not a code constant. Fields unchanged. <strong>Relations:</strong> 1:N → <code>service_option_groups</code>, <code>nurse_service_variants</code>.</p>
<h3 id="service_option_groups-core-service_option_values-core"><code>service_option_groups</code> [CORE] / <code>service_option_values</code> [CORE] <a class="anchor" href="#service_option_groups-core-service_option_values-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The configurable dimensions (group, e.g. "نوع شیفت") and their concrete choices (value, e.g. "شبانه‌روزی"). A NULL <code>service_category_id</code> on a group = cross-category (e.g. shift type applies everywhere). <strong>Why two tables:</strong> separating dimension from choice lets a dimension be <code>is_required</code> and reused across categories. Fields unchanged. <strong>Relations:</strong> <code>service_categories</code> 1:N <code>service_option_groups</code> 1:N <code>service_option_values</code>.</p>
<h3 id="nurse_service_variants-core"><code>nurse_service_variants</code> [CORE] <a class="anchor" href="#nurse_service_variants-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The atomic <strong>bookable unit</strong> — a specific nurse offering a category with a chosen option combination at a price. <strong>Why this is the bookable unit (not the nurse):</strong> a nurse offers many priced combinations; search and booking operate on the exact thing the customer pays for. The <code>price_unit</code> (<code>per_hour</code>/<code>per_session</code>/<code>per_half_day</code>/<code>per_day</code>/<code>per_24h</code>) determines display and, with <code>session_count</code>, the engagement total. Fields unchanged. <strong>Consider</strong> a uniqueness strategy on <code>(nurse_id, category, option-set)</code> to prevent duplicate identical listings. <strong>Relations:</strong> N:1 → <code>nurse_profiles</code>, <code>service_categories</code>; 1:N → <code>nurse_service_variant_options</code>, <code>booking_requests</code>.</p>
<h3 id="nurse_service_variant_options-core"><code>nurse_service_variant_options</code> [CORE] <a class="anchor" href="#nurse_service_variant_options-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The option values that define a variant's configuration. <strong>Why:</strong> one row per dimension makes the variant's meaning explicit and queryable. <code>UNIQUE(variant_id, option_group_id)</code> — one value per dimension. <strong>Relations:</strong> N:1 → <code>nurse_service_variants</code>, <code>service_option_groups</code>, <code>service_option_values</code>.</p>
<h3 id="nurse_search_index-core-new"><code>nurse_search_index</code> [CORE] — <strong>NEW</strong> <a class="anchor" href="#nurse_search_index-core-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> A denormalized, one-row-per-bookable-variant read model holding every search-relevant field flat: nurse (verified + accepting), variant (category, price, unit), areas (city/district), gender, rating, partner center. <strong>Why:</strong> nurse search otherwise needs 4+ joins (<code>nurse_profiles → variants → variant_options → service_areas</code>) plus a rating sort from day one — slow at modest scale. A maintained-on-write flat table is far cheaper than adding Elasticsearch at MVP stage.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>variant_id</code></td><td>BIGINT FK → nurse_service_variants</td><td></td></tr>
<tr><td><code>nurse_id</code></td><td>BIGINT FK → nurse_profiles</td><td></td></tr>
<tr><td><code>service_category_id</code></td><td>BIGINT FK</td><td></td></tr>
<tr><td><code>price</code>, <code>price_unit</code></td><td></td><td>Copied from variant</td></tr>
<tr><td><code>city_id</code>, <code>district_id</code></td><td>BIGINT</td><td>One row per covered area (fan-out)</td></tr>
<tr><td><code>nurse_gender</code></td><td>NVARCHAR(10)</td><td>For same-gender filtering</td></tr>
<tr><td><code>average_rating</code>, <code>total_reviews</code>, <code>total_completed_bookings</code></td><td></td><td>Copied from profile</td></tr>
<tr><td><code>is_searchable</code></td><td>BIT</td><td>True <strong>only</strong> when nurse <code>is_verified=1</code>, not suspended, accepting, and variant <code>is_active=1</code></td></tr>
<tr><td><code>updated_at</code></td><td>DATETIME2</td><td></td></tr>
</tbody></table></div>
<p><strong>Relations (read-only projection):</strong> maintained on writes to <code>nurse_profiles</code>, <code>nurse_service_variants</code>, <code>nurse_service_areas</code>, <code>reviews</code>. <strong>Invariant:</strong> a row is <code>is_searchable=1</code> only when its source nurse/variant are bookable.</p>
<h3 id="nurse_availability_slots-mvp-nurse_availability_exceptions-mvp"><code>nurse_availability_slots</code> [MVP] / <code>nurse_availability_exceptions</code> [MVP] <a class="anchor" href="#nurse_availability_slots-mvp-nurse_availability_exceptions-mvp" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Recurring weekly windows + date overrides. <strong>Why soft-constraint:</strong> these are <strong>guidance only</strong> — the nurse still accepts/rejects each request; they inform search but never block a request. <code>day_of_week</code> uses the Shamsi week (0=Saturday … 6=Friday). Fields unchanged, with CHECK <code>end_time &gt; start_time</code>. <strong>Relations:</strong> N:1 → <code>nurse_profiles</code>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,38 @@
# Domain 3 — Services & Pricing
[← Database Model](index.md)
The service model keeps the original three admin layers (category → option group → option value) and two nurse layers (variant → variant option). This **EAV-style configurability is deliberately kept** — it lets admins add a new pricing dimension (e.g. "شبانه‌روزی / live-in", "number of patients") without a migration, and lets each nurse price every combination independently. The only addition is a denormalized read model for search.
### `service_categories` [CORE]
**Role:** Admin-managed top-level care types (Elderly, Post-Surgery, Infant, Chronic, Companionship). The primary search dimension. **Why admin-managed rows:** the catalog is a business lever, not a code constant. Fields unchanged. **Relations:** 1:N → `service_option_groups`, `nurse_service_variants`.
### `service_option_groups` [CORE] / `service_option_values` [CORE]
**Role:** The configurable dimensions (group, e.g. "نوع شیفت") and their concrete choices (value, e.g. "شبانه‌روزی"). A NULL `service_category_id` on a group = cross-category (e.g. shift type applies everywhere). **Why two tables:** separating dimension from choice lets a dimension be `is_required` and reused across categories. Fields unchanged. **Relations:** `service_categories` 1:N `service_option_groups` 1:N `service_option_values`.
### `nurse_service_variants` [CORE]
**Role:** The atomic **bookable unit** — a specific nurse offering a category with a chosen option combination at a price. **Why this is the bookable unit (not the nurse):** a nurse offers many priced combinations; search and booking operate on the exact thing the customer pays for. The `price_unit` (`per_hour`/`per_session`/`per_half_day`/`per_day`/`per_24h`) determines display and, with `session_count`, the engagement total. Fields unchanged. **Consider** a uniqueness strategy on `(nurse_id, category, option-set)` to prevent duplicate identical listings. **Relations:** N:1 → `nurse_profiles`, `service_categories`; 1:N → `nurse_service_variant_options`, `booking_requests`.
### `nurse_service_variant_options` [CORE]
**Role:** The option values that define a variant's configuration. **Why:** one row per dimension makes the variant's meaning explicit and queryable. `UNIQUE(variant_id, option_group_id)` — one value per dimension. **Relations:** N:1 → `nurse_service_variants`, `service_option_groups`, `service_option_values`.
### `nurse_search_index` [CORE] — **NEW**
**Role:** A denormalized, one-row-per-bookable-variant read model holding every search-relevant field flat: nurse (verified + accepting), variant (category, price, unit), areas (city/district), gender, rating, partner center. **Why:** nurse search otherwise needs 4+ joins (`nurse_profiles → variants → variant_options → service_areas`) plus a rating sort from day one — slow at modest scale. A maintained-on-write flat table is far cheaper than adding Elasticsearch at MVP stage.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `variant_id` | BIGINT FK → nurse_service_variants | |
| `nurse_id` | BIGINT FK → nurse_profiles | |
| `service_category_id` | BIGINT FK | |
| `price`, `price_unit` | … | Copied from variant |
| `city_id`, `district_id` | BIGINT | One row per covered area (fan-out) |
| `nurse_gender` | NVARCHAR(10) | For same-gender filtering |
| `average_rating`, `total_reviews`, `total_completed_bookings` | … | Copied from profile |
| `is_searchable` | BIT | True **only** when nurse `is_verified=1`, not suspended, accepting, and variant `is_active=1` |
| `updated_at` | DATETIME2 | |
**Relations (read-only projection):** maintained on writes to `nurse_profiles`, `nurse_service_variants`, `nurse_service_areas`, `reviews`. **Invariant:** a row is `is_searchable=1` only when its source nurse/variant are bookable.
### `nurse_availability_slots` [MVP] / `nurse_availability_exceptions` [MVP]
**Role:** Recurring weekly windows + date overrides. **Why soft-constraint:** these are **guidance only** — the nurse still accepts/rejects each request; they inform search but never block a request. `day_of_week` uses the Shamsi week (0=Saturday … 6=Friday). Fields unchanged, with CHECK `end_time > start_time`. **Relations:** N:1 → `nurse_profiles`.
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 4 — Verification &amp; Credentials — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a class="active" href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-4-verification-credentials">Domain 4 — Verification &amp; Credentials</h1>
<p><a href="index.html">← Database Model</a></p>
<p><strong>Related:</strong> business requirements — <a href="../business/02-nurse-verification.html">Nurse verification</a>.</p>
<p>The pipeline stays <strong>data-driven</strong>: step types are rows, so a new regulatory requirement (e.g. professional liability insurance) is one INSERT. This revision adds a <strong>structured credential registry</strong> because the brand <em>is</em> "verified trust" and renewal tracking needs queryable license numbers, not opaque PDFs.</p>
<h3 id="nurse_verifications-core"><code>nurse_verifications</code> [CORE] <a class="anchor" href="#nurse_verifications-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The master per-nurse verification record; aggregates step outcomes into one status (the single source of truth for verification state). <strong>Why a header table:</strong> one place to drive the overall lifecycle and the <code>is_verified</code> flip. Fields unchanged: <code>id</code>, <code>nurse_id</code> (unique), <code>status</code> (<code>not_started</code>/<code>pending</code>/<code>in_review</code>/<code>approved</code>/<code>rejected</code>/<code>suspended</code>), <code>submitted_at</code>, <code>approved_at</code>, <code>rejected_at</code>, <code>suspended_at</code>, <code>rejection_reason</code>, <code>reviewed_by_admin_id</code>, <code>internal_notes</code>, timestamps. <strong>Relations:</strong> 1:1 → <code>nurse_profiles</code>; 1:N → <code>verification_steps</code>.</p>
<h3 id="verification_step_types-core"><code>verification_step_types</code> [CORE] <a class="anchor" href="#verification_step_types-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Admin catalog of pipeline steps with stable machine <code>code</code>s (<code>identity_kyc</code>, <code>shahkar_match</code>, <code>moh_competency_license</code>, <code>ino_membership</code>, <code>criminal_record</code>, <code>bank_account_verification</code>). <strong>Why rows + <code>is_automated</code>/<code>automation_provider</code>:</strong> the Iranian credential reality is fragmented across regulators and partly automatable (Shahkar, liveness) and partly manual (license PDF) — data-driving it absorbs that without code changes. Fields unchanged. <strong>Relations:</strong> 1:N → <code>verification_steps</code>.</p>
<h3 id="verification_steps-core"><code>verification_steps</code> [CORE] <a class="anchor" href="#verification_steps-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> One row per step per nurse; tracks status, the raw <code>external_response_json</code> (KYC vendor audit), and <code>expires_at</code> for time-limited steps (the عدم سوء پیشینه certificate expires → step reverts to <code>pending</code> + raises a <code>support_alert</code>). <strong>Why snapshot <code>is_automated</code>:</strong> historical records survive later step-type edits. Fields unchanged, with <code>UNIQUE(nurse_verification_id, step_type_id)</code>. <strong>Relations:</strong> N:1 → <code>nurse_verifications</code>, <code>verification_step_types</code>; 1:N → <code>verification_documents</code>.</p>
<h3 id="verification_documents-core"><code>verification_documents</code> [CORE] <a class="anchor" href="#verification_documents-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Uploaded evidence metadata (object-storage key + integrity hash); files live in S3-compatible storage behind signed URLs, never public. <strong>Why metadata-only:</strong> keeps PII bytes out of the DB and access controlled. Fields unchanged. <strong>Relations:</strong> N:1 → <code>verification_steps</code>.</p>
<h3 id="nurse_credentials-mvp-new"><code>nurse_credentials</code> [MVP] — <strong>NEW</strong> <a class="anchor" href="#nurse_credentials-mvp-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Structured, queryable registry of the actual Iranian credentials — beyond the opaque document uploads. <strong>Why:</strong> no public B2B API exists for MoH/INO, so an admin manually verifies an uploaded credential against the official portal — but the old model gave them <strong>nowhere to record the verified license number</strong> for renewal alerts, the public trust badge, or cross-check. This makes the badge and expiry monitoring real and survives a future INO/MoH API.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>nurse_id</code></td><td>BIGINT FK → nurse_profiles</td><td></td></tr>
<tr><td><code>credential_type</code></td><td>NVARCHAR(50)</td><td><code>moh_competency_license</code> (پروانه صلاحیت حرفه‌ای) / <code>ino_membership</code> (نظام پرستاری) / <code>criminal_record</code> (عدم سوء پیشینه)</td></tr>
<tr><td><code>credential_number</code></td><td>NVARCHAR(100) (enc)</td><td>License/membership number</td></tr>
<tr><td><code>holder_name_snapshot</code></td><td>NVARCHAR(200)</td><td>Name as printed, for ID cross-check</td></tr>
<tr><td><code>issuing_authority</code></td><td>NVARCHAR(200)</td><td></td></tr>
<tr><td><code>issued_at</code>, <code>expires_at</code></td><td>DATE NULL</td><td>Drives renewal alerts</td></tr>
<tr><td><code>verification_source</code></td><td>NVARCHAR(300) NULL</td><td>Portal URL / method</td></tr>
<tr><td><code>verification_method</code></td><td>NVARCHAR(20)</td><td><code>manual</code> / <code>portal</code> / <code>api</code></td></tr>
<tr><td><code>verified_by_admin_id</code></td><td>BIGINT FK → users NULL</td><td></td></tr>
<tr><td><code>created_at</code>, <code>updated_at</code></td><td></td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>nurse_profiles</code>. Cross-referenced by the relevant <code>verification_steps</code>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,38 @@
# Domain 4 — Verification & Credentials
[← Database Model](index.md)
**Related:** business requirements — [Nurse verification](../business/02-nurse-verification.md).
The pipeline stays **data-driven**: step types are rows, so a new regulatory requirement (e.g. professional liability insurance) is one INSERT. This revision adds a **structured credential registry** because the brand *is* "verified trust" and renewal tracking needs queryable license numbers, not opaque PDFs.
### `nurse_verifications` [CORE]
**Role:** The master per-nurse verification record; aggregates step outcomes into one status (the single source of truth for verification state). **Why a header table:** one place to drive the overall lifecycle and the `is_verified` flip. Fields unchanged: `id`, `nurse_id` (unique), `status` (`not_started`/`pending`/`in_review`/`approved`/`rejected`/`suspended`), `submitted_at`, `approved_at`, `rejected_at`, `suspended_at`, `rejection_reason`, `reviewed_by_admin_id`, `internal_notes`, timestamps. **Relations:** 1:1 → `nurse_profiles`; 1:N → `verification_steps`.
### `verification_step_types` [CORE]
**Role:** Admin catalog of pipeline steps with stable machine `code`s (`identity_kyc`, `shahkar_match`, `moh_competency_license`, `ino_membership`, `criminal_record`, `bank_account_verification`). **Why rows + `is_automated`/`automation_provider`:** the Iranian credential reality is fragmented across regulators and partly automatable (Shahkar, liveness) and partly manual (license PDF) — data-driving it absorbs that without code changes. Fields unchanged. **Relations:** 1:N → `verification_steps`.
### `verification_steps` [CORE]
**Role:** One row per step per nurse; tracks status, the raw `external_response_json` (KYC vendor audit), and `expires_at` for time-limited steps (the عدم سوء پیشینه certificate expires → step reverts to `pending` + raises a `support_alert`). **Why snapshot `is_automated`:** historical records survive later step-type edits. Fields unchanged, with `UNIQUE(nurse_verification_id, step_type_id)`. **Relations:** N:1 → `nurse_verifications`, `verification_step_types`; 1:N → `verification_documents`.
### `verification_documents` [CORE]
**Role:** Uploaded evidence metadata (object-storage key + integrity hash); files live in S3-compatible storage behind signed URLs, never public. **Why metadata-only:** keeps PII bytes out of the DB and access controlled. Fields unchanged. **Relations:** N:1 → `verification_steps`.
### `nurse_credentials` [MVP] — **NEW**
**Role:** Structured, queryable registry of the actual Iranian credentials — beyond the opaque document uploads. **Why:** no public B2B API exists for MoH/INO, so an admin manually verifies an uploaded credential against the official portal — but the old model gave them **nowhere to record the verified license number** for renewal alerts, the public trust badge, or cross-check. This makes the badge and expiry monitoring real and survives a future INO/MoH API.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `nurse_id` | BIGINT FK → nurse_profiles | |
| `credential_type` | NVARCHAR(50) | `moh_competency_license` (پروانه صلاحیت حرفه‌ای) / `ino_membership` (نظام پرستاری) / `criminal_record` (عدم سوء پیشینه) |
| `credential_number` | NVARCHAR(100) (enc) | License/membership number |
| `holder_name_snapshot` | NVARCHAR(200) | Name as printed, for ID cross-check |
| `issuing_authority` | NVARCHAR(200) | |
| `issued_at`, `expires_at` | DATE NULL | Drives renewal alerts |
| `verification_source` | NVARCHAR(300) NULL | Portal URL / method |
| `verification_method` | NVARCHAR(20) | `manual` / `portal` / `api` |
| `verified_by_admin_id` | BIGINT FK → users NULL | |
| `created_at`, `updated_at` | … | |
**Relations:** N:1 → `nurse_profiles`. Cross-referenced by the relevant `verification_steps`.
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 5 — Booking &amp; Scheduling — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a class="active" href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-5-booking-scheduling">Domain 5 — Booking &amp; Scheduling</h1>
<p><a href="index.html">← Database Model</a></p>
<p><strong>Related:</strong> business requirements — <a href="../business/05-booking-and-scheduling.html">Booking &amp; scheduling</a>.</p>
<p>Two distinct phases: the <strong>request phase</strong> (pre-payment intent) and the <strong>booking phase</strong> (post-payment commitment). The previous model's biggest domain gap — <strong>single-visit-only bookings</strong> — is fixed here with <code>booking_sessions</code>, because elder care is dominantly multi-day / live-in.</p>
<h3 id="booking_requests-core"><code>booking_requests</code> [CORE] <a class="anchor" href="#booking_requests-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> A customer's pre-payment intent for a nurse, service, date, and time. No money involved. <strong>Why separate from <code>bookings</code>:</strong> a request may be rejected, expire, or have its payment window lapse without a booking ever existing — merging would mean many nullable fields and tangled status logic. The deadlines are <strong>computed once and stored</strong> so they're immune to later config changes.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code>, <code>customer_id</code>, <code>nurse_id</code>, <code>patient_id</code>, <code>variant_id</code>, <code>customer_address_id</code></td><td></td><td>Baseline FKs. <strong>Tenancy invariant:</strong> patient &amp; address belong to <code>customer_id</code>; variant belongs to <code>nurse_id</code>.</td></tr>
<tr><td><code>required_caregiver_gender</code></td><td>NVARCHAR(10) NULL</td><td><strong>NEW</strong><code>male</code>/<code>female</code>/<code>any</code>. Same-gender care is decisive in Iranian bodily-care; surfaced as a first-class filter and matched against nurse gender.</td></tr>
<tr><td><code>requested_date</code>, <code>requested_time_start</code>, <code>requested_time_end</code></td><td></td><td>For multi-day engagements these are the engagement start; sessions carry the per-visit schedule.</td></tr>
<tr><td><code>customer_notes</code></td><td>NVARCHAR(1000) NULL</td><td><strong>Unencrypted, request-stage only</strong> — the <em>only</em> clinical context the nurse sees before accepting (Principle 6).</td></tr>
<tr><td><code>status</code></td><td>NVARCHAR(50)</td><td><code>pending_nurse_response</code><code>accepted_awaiting_payment</code><code>converted</code> / <code>rejected_by_nurse</code> / <code>expired_no_response</code> / <code>payment_deadline_expired</code> / <code>cancelled_by_customer</code></td></tr>
<tr><td><code>nurse_response_deadline_at</code></td><td>DATETIME2</td><td>From config at creation; auto-expire after.</td></tr>
<tr><td><code>payment_deadline_at</code></td><td>DATETIME2 NULL</td><td>Set on accept; 30-min window.</td></tr>
<tr><td><code>nurse_rejection_reason</code></td><td>NVARCHAR(500) NULL</td><td></td></tr>
<tr><td>timestamps</td><td></td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>customer_profiles</code>, <code>nurse_profiles</code>, <code>patients</code>, <code>nurse_service_variants</code>, <code>customer_addresses</code>; 1:1 → <code>bookings</code> (on conversion).</p>
<h3 id="bookings-core"><code>bookings</code> [CORE] <a class="anchor" href="#bookings-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The confirmed engagement — exists <strong>only</strong> when the nurse accepted <strong>and</strong> payment was captured. Source of truth for the service event and its money split. <strong>Why snapshots:</strong> <code>variant_snapshot_json</code> and <code>address_snapshot_json</code> freeze the service and address at booking time, so later edits/deletes can't corrupt history or disputes.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>booking_request_id</code></td><td>BIGINT FK UNIQUE</td><td>1:1 — the request that created it</td></tr>
<tr><td><code>customer_id</code>, <code>nurse_id</code>, <code>patient_id</code>, <code>variant_id</code>, <code>customer_address_id</code></td><td></td><td>Denormalized for query performance</td></tr>
<tr><td><code>variant_snapshot_json</code></td><td>NVARCHAR(MAX)</td><td>Variant + option labels at booking time</td></tr>
<tr><td><code>address_snapshot_json</code></td><td>NVARCHAR(MAX) (enc)</td><td>Full address at booking time</td></tr>
<tr><td><code>partner_center_id</code></td><td>BIGINT FK → partner_centers NULL</td><td><strong>NEW</strong> — the licensed center legally covering this visit / merchant-of-record</td></tr>
<tr><td><code>gross_price_irr</code></td><td>BIGINT</td><td><strong>CHANGED (renamed)</strong> — total charged to customer</td></tr>
<tr><td><code>balinyaar_commission_irr</code></td><td>BIGINT</td><td><strong>CHANGED (renamed from <code>platform_fee_amount</code>)</strong> — platform's own cut</td></tr>
<tr><td><code>platform_fee_rate</code></td><td>DECIMAL(5,4)</td><td>Rate snapshot for audit</td></tr>
<tr><td><code>nurse_payout_amount</code></td><td>BIGINT</td><td><code>= gross_price_irr balinyaar_commission_irr</code>. <strong>CHECK enforced.</strong></td></tr>
<tr><td><code>psp_fee_amount</code></td><td>BIGINT NULL</td><td><strong>NEW</strong> — gateway cost on this payment, for true margin/reconciliation</td></tr>
<tr><td><code>session_count</code></td><td>SMALLINT NOT NULL DEFAULT 1</td><td><strong>NEW</strong> — 1 = single visit; &gt;1 = multi-session engagement</td></tr>
<tr><td><code>scheduled_date</code>, <code>scheduled_time_start</code>, <code>scheduled_time_end</code></td><td></td><td>Engagement-level; per-visit lives in <code>booking_sessions</code></td></tr>
<tr><td><code>status</code></td><td>NVARCHAR(30)</td><td><code>pending_payment</code><code>confirmed</code><code>in_progress</code><code>completed</code> → (<code>disputed</code><code>closed</code>) / <code>cancelled</code>. <strong>Now guarded by an allowed-transition table/CHECK</strong> so it can't contradict EVV.</td></tr>
<tr><td><code>confirmed_at</code>, <code>cancelled_at</code>, <code>cancellation_reason</code>, <code>cancelled_by</code>, <code>completed_at</code></td><td></td><td></td></tr>
<tr><td><code>dispute_window_ends_at</code></td><td>DATETIME2 NULL</td><td><strong>NEW</strong><code>completed_at + config(dispute_window_hours, default 72)</code>. Payout eligible only after this passes with no open dispute.</td></tr>
<tr><td><del><code>payout_released</code></del></td><td></td><td><strong>CUT</strong> — second source of truth for "paid"; now derived from a <code>nurse_payout_booking_links</code> row + ledger.</td></tr>
<tr><td>timestamps</td><td></td><td></td></tr>
</tbody></table></div>
<p>CHECK: <code>gross_price_irr = balinyaar_commission_irr + nurse_payout_amount</code>; all amounts ≥ 0. <strong>Relations:</strong> 1:1 ← <code>booking_requests</code>; 1:N → <code>booking_sessions</code>, <code>payment_transactions</code>, <code>ledger_entries</code>; 1:1 → <code>booking_care_instructions</code>, <code>visit_verifications</code> <em>(see note)</em>, <code>reviews</code>, <code>invoices</code>; referenced by <code>nurse_payout_booking_links</code>, <code>refunds</code>, <code>nurse_clawbacks</code>.</p>
<h3 id="booking_sessions-mvp-new"><code>booking_sessions</code> [MVP] — <strong>NEW</strong> <a class="anchor" href="#booking_sessions-mvp-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> One row per <strong>visit</strong> within a booking. A 10-day post-op package or a month of nightly شبانه‌روزی care is <strong>one booking with N sessions</strong>, each with its own schedule, EVV, and payout eligibility. <strong>Why:</strong> the single-visit model literally cannot represent the dominant elder-care engagement; and money for a long engagement must release <strong>per completed session</strong>, not as one whole-month escrow held for weeks. Mid-engagement cancellation then cleanly refunds only the un-started sessions.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>booking_id</code></td><td>BIGINT FK → bookings</td><td></td></tr>
<tr><td><code>session_index</code></td><td>INT</td><td>1-based ordinal</td></tr>
<tr><td><code>scheduled_date</code>, <code>scheduled_time_start</code>, <code>scheduled_time_end</code></td><td></td><td>Per-visit</td></tr>
<tr><td><code>visit_payout_amount</code></td><td>BIGINT</td><td>Portion of <code>nurse_payout_amount</code> for this session</td></tr>
<tr><td><code>status</code></td><td>NVARCHAR(20)</td><td><code>scheduled</code> / <code>in_progress</code> / <code>completed</code> / <code>missed</code> / <code>cancelled</code></td></tr>
<tr><td><code>payout_eligible_at</code></td><td>DATETIME2 NULL</td><td>Per-session dispute-window close</td></tr>
<tr><td><code>cancellation_event_id</code></td><td>BIGINT NULL</td><td>If this session was cancelled</td></tr>
<tr><td>timestamps</td><td></td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>bookings</code>; 1:1 → <code>visit_verifications</code>. <strong>Note:</strong> for a single-visit booking, exactly one session is created so the EVV/payout path is uniform.</p>
<h3 id="booking_care_instructions-core"><code>booking_care_instructions</code> [CORE] <a class="anchor" href="#booking_care_instructions-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Encrypted clinical/logistical context provided at booking time, visible <strong>only post-confirmation</strong> to the assigned nurse and admin. <strong>Why separate + encrypted:</strong> keeps the financial/scheduling table clean and enforces the two-stage disclosure boundary (Principle 6) with stricter access controls. Fields unchanged (current conditions, medications, allergies, special instructions, emergency contact — all enc). <strong>Relations:</strong> 1:1 → <code>bookings</code>.</p>
<h3 id="visit_verifications-core"><code>visit_verifications</code> [CORE] <a class="anchor" href="#visit_verifications-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Electronic Visit Verification — the authoritative record that a visit happened and for how long; <strong>required for payout</strong>. <strong>Why:</strong> in-home care is unobserved; GPS + timestamped check-in/out is the proof that safely releases escrow. <code>check_in_address_match</code> is advisory (a mismatch triggers admin review, not auto-cancel). <strong>CHANGED:</strong> the FK moves to <strong><code>booking_session_id</code></strong> so each visit in a multi-session engagement is verified independently; the mapping between <code>visit_verifications.status</code> and the parent <code>bookings.status</code> is documented so the two state machines cannot silently diverge. Fields otherwise unchanged. <strong>Relations:</strong> 1:1 → <code>booking_sessions</code>.</p>
<h3 id="cancellation_policies-mvp-new"><code>cancellation_policies</code> [MVP] — <strong>NEW</strong> <a class="anchor" href="#cancellation_policies-mvp-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Config-driven, snapshot-able cancellation/refund tiers by lead time and initiating actor. <strong>Why:</strong> "default 100% refund" is naive — a free cancel 24h ahead, a 50% charge inside 24h, and a nurse-no-show full refund + nurse penalty are different money flows, and the applicable rule must be <strong>frozen onto the booking</strong> at cancel time (the same snapshot discipline used for <code>platform_fee_rate</code>).</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>code</code></td><td>NVARCHAR(50) UNIQUE</td><td>e.g. <code>standard_24h</code></td></tr>
<tr><td><code>applies_to</code></td><td>NVARCHAR(20)</td><td><code>customer</code> / <code>nurse</code> / <code>admin</code></td></tr>
<tr><td><code>hours_before_start_min</code>, <code>hours_before_start_max</code></td><td>INT NULL</td><td>Tier bounds</td></tr>
<tr><td><code>refund_percentage</code></td><td>DECIMAL(5,2)</td><td>0100</td></tr>
<tr><td><code>fee_amount_or_rate</code></td><td></td><td>Cancellation fee / nurse penalty</td></tr>
<tr><td><code>is_active</code>, timestamps</td><td></td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> referenced (snapshot) by <code>refunds</code> and the <code>cancellation_event</code> recorded on a session/booking.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,88 @@
# Domain 5 — Booking & Scheduling
[← Database Model](index.md)
**Related:** business requirements — [Booking & scheduling](../business/05-booking-and-scheduling.md).
Two distinct phases: the **request phase** (pre-payment intent) and the **booking phase** (post-payment commitment). The previous model's biggest domain gap — **single-visit-only bookings** — is fixed here with `booking_sessions`, because elder care is dominantly multi-day / live-in.
### `booking_requests` [CORE]
**Role:** A customer's pre-payment intent for a nurse, service, date, and time. No money involved. **Why separate from `bookings`:** a request may be rejected, expire, or have its payment window lapse without a booking ever existing — merging would mean many nullable fields and tangled status logic. The deadlines are **computed once and stored** so they're immune to later config changes.
| Field | Type | Notes |
|---|---|---|
| `id`, `customer_id`, `nurse_id`, `patient_id`, `variant_id`, `customer_address_id` | … | Baseline FKs. **Tenancy invariant:** patient & address belong to `customer_id`; variant belongs to `nurse_id`. |
| `required_caregiver_gender` | NVARCHAR(10) NULL | **NEW**`male`/`female`/`any`. Same-gender care is decisive in Iranian bodily-care; surfaced as a first-class filter and matched against nurse gender. |
| `requested_date`, `requested_time_start`, `requested_time_end` | … | For multi-day engagements these are the engagement start; sessions carry the per-visit schedule. |
| `customer_notes` | NVARCHAR(1000) NULL | **Unencrypted, request-stage only** — the *only* clinical context the nurse sees before accepting (Principle 6). |
| `status` | NVARCHAR(50) | `pending_nurse_response``accepted_awaiting_payment``converted` / `rejected_by_nurse` / `expired_no_response` / `payment_deadline_expired` / `cancelled_by_customer` |
| `nurse_response_deadline_at` | DATETIME2 | From config at creation; auto-expire after. |
| `payment_deadline_at` | DATETIME2 NULL | Set on accept; 30-min window. |
| `nurse_rejection_reason` | NVARCHAR(500) NULL | |
| timestamps | … | |
**Relations:** N:1 → `customer_profiles`, `nurse_profiles`, `patients`, `nurse_service_variants`, `customer_addresses`; 1:1 → `bookings` (on conversion).
### `bookings` [CORE]
**Role:** The confirmed engagement — exists **only** when the nurse accepted **and** payment was captured. Source of truth for the service event and its money split. **Why snapshots:** `variant_snapshot_json` and `address_snapshot_json` freeze the service and address at booking time, so later edits/deletes can't corrupt history or disputes.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `booking_request_id` | BIGINT FK UNIQUE | 1:1 — the request that created it |
| `customer_id`, `nurse_id`, `patient_id`, `variant_id`, `customer_address_id` | … | Denormalized for query performance |
| `variant_snapshot_json` | NVARCHAR(MAX) | Variant + option labels at booking time |
| `address_snapshot_json` | NVARCHAR(MAX) (enc) | Full address at booking time |
| `partner_center_id` | BIGINT FK → partner_centers NULL | **NEW** — the licensed center legally covering this visit / merchant-of-record |
| `gross_price_irr` | BIGINT | **CHANGED (renamed)** — total charged to customer |
| `balinyaar_commission_irr` | BIGINT | **CHANGED (renamed from `platform_fee_amount`)** — platform's own cut |
| `platform_fee_rate` | DECIMAL(5,4) | Rate snapshot for audit |
| `nurse_payout_amount` | BIGINT | `= gross_price_irr balinyaar_commission_irr`. **CHECK enforced.** |
| `psp_fee_amount` | BIGINT NULL | **NEW** — gateway cost on this payment, for true margin/reconciliation |
| `session_count` | SMALLINT NOT NULL DEFAULT 1 | **NEW** — 1 = single visit; >1 = multi-session engagement |
| `scheduled_date`, `scheduled_time_start`, `scheduled_time_end` | … | Engagement-level; per-visit lives in `booking_sessions` |
| `status` | NVARCHAR(30) | `pending_payment``confirmed``in_progress``completed` → (`disputed``closed`) / `cancelled`. **Now guarded by an allowed-transition table/CHECK** so it can't contradict EVV. |
| `confirmed_at`, `cancelled_at`, `cancellation_reason`, `cancelled_by`, `completed_at` | … | |
| `dispute_window_ends_at` | DATETIME2 NULL | **NEW**`completed_at + config(dispute_window_hours, default 72)`. Payout eligible only after this passes with no open dispute. |
| ~~`payout_released`~~ | — | **CUT** — second source of truth for "paid"; now derived from a `nurse_payout_booking_links` row + ledger. |
| timestamps | … | |
CHECK: `gross_price_irr = balinyaar_commission_irr + nurse_payout_amount`; all amounts ≥ 0. **Relations:** 1:1 ← `booking_requests`; 1:N → `booking_sessions`, `payment_transactions`, `ledger_entries`; 1:1 → `booking_care_instructions`, `visit_verifications` *(see note)*, `reviews`, `invoices`; referenced by `nurse_payout_booking_links`, `refunds`, `nurse_clawbacks`.
### `booking_sessions` [MVP] — **NEW**
**Role:** One row per **visit** within a booking. A 10-day post-op package or a month of nightly شبانه‌روزی care is **one booking with N sessions**, each with its own schedule, EVV, and payout eligibility. **Why:** the single-visit model literally cannot represent the dominant elder-care engagement; and money for a long engagement must release **per completed session**, not as one whole-month escrow held for weeks. Mid-engagement cancellation then cleanly refunds only the un-started sessions.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `booking_id` | BIGINT FK → bookings | |
| `session_index` | INT | 1-based ordinal |
| `scheduled_date`, `scheduled_time_start`, `scheduled_time_end` | … | Per-visit |
| `visit_payout_amount` | BIGINT | Portion of `nurse_payout_amount` for this session |
| `status` | NVARCHAR(20) | `scheduled` / `in_progress` / `completed` / `missed` / `cancelled` |
| `payout_eligible_at` | DATETIME2 NULL | Per-session dispute-window close |
| `cancellation_event_id` | BIGINT NULL | If this session was cancelled |
| timestamps | … | |
**Relations:** N:1 → `bookings`; 1:1 → `visit_verifications`. **Note:** for a single-visit booking, exactly one session is created so the EVV/payout path is uniform.
### `booking_care_instructions` [CORE]
**Role:** Encrypted clinical/logistical context provided at booking time, visible **only post-confirmation** to the assigned nurse and admin. **Why separate + encrypted:** keeps the financial/scheduling table clean and enforces the two-stage disclosure boundary (Principle 6) with stricter access controls. Fields unchanged (current conditions, medications, allergies, special instructions, emergency contact — all enc). **Relations:** 1:1 → `bookings`.
### `visit_verifications` [CORE]
**Role:** Electronic Visit Verification — the authoritative record that a visit happened and for how long; **required for payout**. **Why:** in-home care is unobserved; GPS + timestamped check-in/out is the proof that safely releases escrow. `check_in_address_match` is advisory (a mismatch triggers admin review, not auto-cancel). **CHANGED:** the FK moves to **`booking_session_id`** so each visit in a multi-session engagement is verified independently; the mapping between `visit_verifications.status` and the parent `bookings.status` is documented so the two state machines cannot silently diverge. Fields otherwise unchanged. **Relations:** 1:1 → `booking_sessions`.
### `cancellation_policies` [MVP] — **NEW**
**Role:** Config-driven, snapshot-able cancellation/refund tiers by lead time and initiating actor. **Why:** "default 100% refund" is naive — a free cancel 24h ahead, a 50% charge inside 24h, and a nurse-no-show full refund + nurse penalty are different money flows, and the applicable rule must be **frozen onto the booking** at cancel time (the same snapshot discipline used for `platform_fee_rate`).
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `code` | NVARCHAR(50) UNIQUE | e.g. `standard_24h` |
| `applies_to` | NVARCHAR(20) | `customer` / `nurse` / `admin` |
| `hours_before_start_min`, `hours_before_start_max` | INT NULL | Tier bounds |
| `refund_percentage` | DECIMAL(5,2) | 0100 |
| `fee_amount_or_rate` | … | Cancellation fee / nurse penalty |
| `is_active`, timestamps | … | |
**Relations:** referenced (snapshot) by `refunds` and the `cancellation_event` recorded on a session/booking.
@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 6 — Payments, Ledger &amp; Refunds — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a class="active" href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-6-payments-ledger-refunds">Domain 6 — Payments, Ledger &amp; Refunds</h1>
<p><a href="index.html">← Database Model</a></p>
<p><strong>Related:</strong> business requirements — <a href="../business/08-payments-and-escrow.html">Payments &amp; escrow</a>. Ledger postings are explained in depth in <a href="../payments/escrow-ledger.html">Escrow ledger</a>.</p>
<p>This is the most-changed domain. The previous model <strong>inferred</strong> money state from scattered status flags; this revision makes a <strong>double-entry ledger</strong> the source of truth and adds the <strong>idempotency</strong> and <strong>clawback</strong> primitives that any real-money platform needs before launch.</p>
<h3 id="payment_gateways-core"><code>payment_gateways</code> [CORE] <a class="anchor" href="#payment_gateways-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Config per connected PSP/BNPL provider; credentials encrypted. <strong>Why <code>type</code>:</strong> multiple gateways run at once (standard IPG, a BNPL provider, a failover) and <code>type</code> (<code>standard</code>/<code>bnpl</code>) selects the flow. <strong>Why this matters for Iran:</strong> provider cut-offs happen (Toman/Jibit were abruptly suspended in Nov 2024), so the gateway is abstracted to be swappable. BNPL provider secrets (client_id/secret, merchant number, base_url, sandbox flag) live encrypted in <code>config_json</code>. Fields unchanged. <strong>Relations:</strong> 1:N → <code>payment_transactions</code>, <code>payment_webhook_events</code>.</p>
<h3 id="payment_transactions-core"><code>payment_transactions</code> [CORE] <a class="anchor" href="#payment_transactions-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Every payment attempt against a booking; the <code>succeeded</code> row triggers confirmation. Stores the full <code>gateway_response_json</code> and the <strong>Shaparak reference code</strong> (definitive proof) for reconciliation and chargebacks. <strong>Why hardened:</strong> a retried PSP webhook could otherwise insert a second <code>succeeded</code> row and double-confirm.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td>baseline fields</td><td></td><td><code>id</code>, <code>booking_id</code>, <code>customer_id</code>, <code>gateway_id</code>, <code>amount</code>, <code>currency</code>, <code>status</code>, <code>gateway_transaction_id</code>, <code>gateway_reference_code</code>, <code>gateway_response_code</code>, <code>gateway_response_json</code>, <code>is_installment</code>, <code>ip_address</code>, <code>user_agent</code>, timestamps</td></tr>
<tr><td><strong>constraints</strong></td><td></td><td><strong>NEW:</strong> <code>UNIQUE(gateway_reference_code) WHERE NOT NULL</code>; filtered <code>UNIQUE(booking_id) WHERE status='succeeded'</code> — at most one capturing transaction per booking.</td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>bookings</code>, <code>payment_gateways</code>; 1:1 → <code>bnpl_transactions</code> (if BNPL); 1:N → <code>refunds</code>, <code>ledger_entries</code>.</p>
<h3 id="payment_webhook_events-core-new"><code>payment_webhook_events</code> [CORE] — <strong>NEW</strong> <a class="anchor" href="#payment_webhook_events-core-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Raw, deduplicated store of every PSP/BNPL callback. <strong>Why mandatory:</strong> callbacks are at-least-once and retried; without a unique store keyed on the provider's event id, a replayed "payment succeeded" double-confirms a booking and a replayed "settled" double-counts money. The handler <strong>upserts here first</strong> and no-ops on a duplicate, inside the same transaction that mutates payment state.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>provider_code</code></td><td>NVARCHAR(50)</td><td><code>zarinpal</code> / <code>snapppay</code> / …</td></tr>
<tr><td><code>external_event_id</code></td><td>NVARCHAR(200)</td><td><strong>UNIQUE(provider_code, external_event_id)</strong></td></tr>
<tr><td><code>event_type</code></td><td>NVARCHAR(80)</td><td></td></tr>
<tr><td><code>signature_valid</code></td><td>BIT</td><td></td></tr>
<tr><td><code>payload_json</code></td><td>NVARCHAR(MAX)</td><td>Raw callback</td></tr>
<tr><td><code>processing_status</code></td><td>NVARCHAR(20)</td><td><code>received</code> / <code>processed</code> / <code>failed</code> / <code>ignored</code></td></tr>
<tr><td><code>related_payment_transaction_id</code></td><td>BIGINT NULL</td><td></td></tr>
<tr><td><code>received_at</code>, <code>processed_at</code></td><td>DATETIME2</td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>payment_gateways</code>; optional → <code>payment_transactions</code>.</p>
<h3 id="refunds-core"><code>refunds</code> [CORE] <a class="anchor" href="#refunds-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Admin-initiated refunds (no customer self-service), always linked to a support ticket. <strong>Why these changes:</strong> the previous model treated refunds as 1:1 with a transaction and as a single undecomposed amount — but partials exist (shortened visit) and a refund must say how much reverses the <strong>platform fee</strong> vs the <strong>nurse payout</strong>, and how the money actually moves (card vs BNPL revert).</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td>baseline</td><td></td><td><code>id</code>, <code>payment_transaction_id</code>, <code>booking_id</code>, <code>requested_by_customer_id</code>, <code>ticket_id</code>, <code>amount</code>, <code>refund_percentage</code>, <code>reason_category</code>, <code>reason_notes</code>, <code>status</code>, approval/rejection fields, <code>gateway_refund_reference</code>, <code>processed_at</code>, <code>admin_notes</code>, timestamps</td></tr>
<tr><td><strong>cardinality</strong></td><td></td><td><strong>CHANGED to 1:N</strong> per <code>payment_transaction</code> (app invariant: Σ refunded ≤ captured). The old "1:1" relationship summary was wrong.</td></tr>
<tr><td><code>platform_fee_refunded_irr</code></td><td>BIGINT</td><td><strong>NEW</strong> — fee-leg decomposition</td></tr>
<tr><td><code>nurse_payout_refunded_irr</code></td><td>BIGINT</td><td><strong>NEW</strong> — payout-leg decomposition (drives clawback if nurse already paid)</td></tr>
<tr><td><code>refund_channel</code></td><td>NVARCHAR(20)</td><td><strong>NEW</strong><code>psp_card</code> / <code>bnpl_revert</code> / <code>manual_bank</code></td></tr>
<tr><td><code>external_revert_reference</code></td><td>NVARCHAR(200) NULL</td><td><strong>NEW</strong> — BNPL revert id</td></tr>
<tr><td><code>expected_customer_refund_eta</code></td><td>DATE NULL</td><td><strong>NEW</strong> — the ~710 business-day BNPL window, surfaced in UI/reconciliation</td></tr>
<tr><td><code>cancellation_policy_code</code> / <code>refund_percentage_applied</code></td><td></td><td><strong>NEW</strong> — snapshot of the policy that produced this refund</td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>payment_transactions</code>, <code>bookings</code>, <code>customer_profiles</code>, <code>tickets</code>; 1:1 → <code>nurse_clawbacks</code> (only when refunding a booking whose nurse was already paid).</p>
<h3 id="ledger_entries-core-new"><code>ledger_entries</code> [CORE] — <strong>NEW</strong> <a class="anchor" href="#ledger_entries-core-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> The append-only, double-entry financial <strong>source of truth</strong>. Every money event posts <strong>balanced</strong> rows sharing a <code>transaction_group_id</code> (Σ debit = Σ credit). Per-nurse payable balance derives by filtering <code>account_type='nurse_payable'</code> + <code>nurse_id</code>. <strong>Why:</strong> a marketplace that holds escrow and pays out weekly minus commission, with refunds and clawbacks, is exactly the shape double-entry was invented for. The alternative (more money columns + status booleans) cannot answer "how much do we owe nurses right now" or reconcile against the bank, and makes refund/clawback second-class. Cost: one table + posting discipline.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>transaction_group_id</code></td><td>UNIQUEIDENTIFIER</td><td>Groups the balanced legs of one event</td></tr>
<tr><td><code>account_type</code></td><td>NVARCHAR(40)</td><td><code>escrow_held</code> / <code>platform_revenue</code> / <code>nurse_payable</code> / <code>refund_payable</code> / <code>bnpl_fee_expense</code> / <code>psp_fee_expense</code> / <code>nurse_clawback_receivable</code> / <code>bad_debt</code></td></tr>
<tr><td><code>nurse_id</code></td><td>BIGINT FK NULL</td><td>Set for <code>nurse_payable</code>/<code>nurse_clawback_receivable</code></td></tr>
<tr><td><code>direction</code></td><td>NVARCHAR(6)</td><td><code>debit</code> / <code>credit</code></td></tr>
<tr><td><code>amount_irr</code></td><td>BIGINT</td><td>Always positive; <code>direction</code> carries the sign</td></tr>
<tr><td><code>booking_id</code></td><td>BIGINT FK NULL</td><td></td></tr>
<tr><td><code>source_ref_type</code></td><td>NVARCHAR(40)</td><td><code>payment_transaction</code> / <code>refund</code> / <code>nurse_payout</code> / <code>bnpl_transaction</code> / <code>clawback</code></td></tr>
<tr><td><code>source_ref_id</code></td><td>BIGINT</td><td></td></tr>
<tr><td><code>memo</code></td><td>NVARCHAR(300) NULL</td><td></td></tr>
<tr><td><code>created_at</code></td><td>DATETIME2</td><td>Append-only; never updated</td></tr>
</tbody></table></div>
<p><strong>Canonical postings:</strong></p>
<div class="table-wrap"><table><thead><tr><th>Event</th><th>Debit</th><th>Credit</th></tr></thead><tbody>
<tr><td>Card capture</td><td><code>escrow_held</code> (gross)</td><td><code>platform_revenue</code> (commission) + <code>nurse_payable</code> (payout)</td></tr>
<tr><td>BNPL settle</td><td>as card, <strong>plus</strong> <code>bnpl_fee_expense</code> (provider commission)</td><td><code>escrow_held</code> (provider commission) → escrow reflects net cash actually received</td></tr>
<tr><td>Refund (pre-payout)</td><td><code>nurse_payable</code> + <code>platform_revenue</code> (decomposed legs)</td><td><code>refund_payable</code>; later <code>refund_payable</code><code>escrow_held</code> on confirm</td></tr>
<tr><td>Clawback (post-payout)</td><td><code>nurse_clawback_receivable</code> (+ <code>platform_revenue</code> leg)</td><td><code>refund_payable</code></td></tr>
<tr><td>Clawback recovered</td><td><code>nurse_payable</code> (next batch)</td><td><code>nurse_clawback_receivable</code></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>bookings</code>; logical links to <code>payment_transactions</code>/<code>refunds</code>/<code>nurse_payouts</code>/<code>bnpl_transactions</code> via <code>source_ref_*</code>.</p>
<h3 id="nurse_clawbacks-core-new"><code>nurse_clawbacks</code> [CORE] — <strong>NEW</strong> <a class="anchor" href="#nurse_clawbacks-core-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> A first-class receivable when a booking is refunded/disputed <strong>after</strong> the nurse was already paid. <strong>Why:</strong> this was the model's own flagged critical gap — Iranian payouts are real, hard-to-reverse bank transfers, so paying before the dispute window closes can create uncollectable loss with nowhere to record it. Closing it = gate payout on <code>dispute_window_ends_at</code> <strong>and</strong> record any post-payout recovery here.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>nurse_id</code></td><td>BIGINT FK → nurse_profiles</td><td></td></tr>
<tr><td><code>booking_id</code></td><td>BIGINT FK → bookings</td><td></td></tr>
<tr><td><code>refund_id</code></td><td>BIGINT FK → refunds</td><td></td></tr>
<tr><td><code>original_payout_id</code></td><td>BIGINT FK → nurse_payouts NULL</td><td></td></tr>
<tr><td><code>amount_irr</code></td><td>BIGINT</td><td></td></tr>
<tr><td><code>status</code></td><td>NVARCHAR(30)</td><td><code>pending</code> / <code>recovered</code> / <code>written_off</code></td></tr>
<tr><td><code>recovered_in_payout_id</code></td><td>BIGINT FK NULL</td><td>Batch that netted it</td></tr>
<tr><td><code>created_at</code>, <code>resolved_at</code></td><td>DATETIME2</td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>nurse_profiles</code>, <code>bookings</code>; 1:1 → <code>refunds</code>; → <code>nurse_payouts</code> (original and recovering).</p>
<h3 id="invoices-mvp-new"><code>invoices</code> [MVP] — <strong>NEW</strong> <a class="anchor" href="#invoices-mvp-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Minimal official-invoice/receipt record per booking. <strong>Why:</strong> Iranian commission marketplaces face VAT/مودیان obligations on <strong>their commission</strong> (the Snapp/Tapsi precedent: the provider's earnings are the provider's own income; the platform's commission is the platform's taxable revenue). The smallest footprint that satisfies bookkeeping without a full tax engine. <strong>VAT is 10%</strong> (rose from 9% in 1403) and stored as a <strong>config-driven rate</strong> so a future exemption ruling on the nursing service itself is just a value change. Nurse-side income tax is the nurse's own responsibility.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>booking_id</code></td><td>BIGINT FK → bookings</td><td></td></tr>
<tr><td><code>invoice_number</code></td><td>NVARCHAR(40) UNIQUE</td><td>Official sequential number</td></tr>
<tr><td><code>issuing_entity_type</code></td><td>NVARCHAR(20)</td><td><code>platform</code> / <code>partner_center</code></td></tr>
<tr><td><code>gross_irr</code></td><td>BIGINT</td><td></td></tr>
<tr><td><code>platform_commission_irr</code></td><td>BIGINT</td><td>The VAT-relevant line</td></tr>
<tr><td><code>bnpl_commission_irr</code></td><td>BIGINT NULL</td><td></td></tr>
<tr><td><code>vat_rate</code></td><td>DECIMAL(5,4)</td><td>Config-driven (0.10)</td></tr>
<tr><td><code>vat_irr</code></td><td>BIGINT</td><td></td></tr>
<tr><td><code>moadian_reference_number</code></td><td>NVARCHAR(40) NULL</td><td>سامانه مودیان 22-digit ref when issued</td></tr>
<tr><td><code>moadian_status</code></td><td>NVARCHAR(20) NULL</td><td></td></tr>
<tr><td><code>pdf_storage_key</code></td><td>NVARCHAR(512) NULL</td><td></td></tr>
<tr><td><code>issued_at</code></td><td>DATETIME2</td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> 1:1 → <code>bookings</code>; N:1 → <code>partner_centers</code> (when issuer).</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,120 @@
# Domain 6 — Payments, Ledger & Refunds
[← Database Model](index.md)
**Related:** business requirements — [Payments & escrow](../business/08-payments-and-escrow.md). Ledger postings are explained in depth in [Escrow ledger](../payments/escrow-ledger.md).
This is the most-changed domain. The previous model **inferred** money state from scattered status flags; this revision makes a **double-entry ledger** the source of truth and adds the **idempotency** and **clawback** primitives that any real-money platform needs before launch.
### `payment_gateways` [CORE]
**Role:** Config per connected PSP/BNPL provider; credentials encrypted. **Why `type`:** multiple gateways run at once (standard IPG, a BNPL provider, a failover) and `type` (`standard`/`bnpl`) selects the flow. **Why this matters for Iran:** provider cut-offs happen (Toman/Jibit were abruptly suspended in Nov 2024), so the gateway is abstracted to be swappable. BNPL provider secrets (client_id/secret, merchant number, base_url, sandbox flag) live encrypted in `config_json`. Fields unchanged. **Relations:** 1:N → `payment_transactions`, `payment_webhook_events`.
### `payment_transactions` [CORE]
**Role:** Every payment attempt against a booking; the `succeeded` row triggers confirmation. Stores the full `gateway_response_json` and the **Shaparak reference code** (definitive proof) for reconciliation and chargebacks. **Why hardened:** a retried PSP webhook could otherwise insert a second `succeeded` row and double-confirm.
| Field | Type | Notes |
|---|---|---|
| baseline fields | … | `id`, `booking_id`, `customer_id`, `gateway_id`, `amount`, `currency`, `status`, `gateway_transaction_id`, `gateway_reference_code`, `gateway_response_code`, `gateway_response_json`, `is_installment`, `ip_address`, `user_agent`, timestamps |
| **constraints** | | **NEW:** `UNIQUE(gateway_reference_code) WHERE NOT NULL`; filtered `UNIQUE(booking_id) WHERE status='succeeded'` — at most one capturing transaction per booking. |
**Relations:** N:1 → `bookings`, `payment_gateways`; 1:1 → `bnpl_transactions` (if BNPL); 1:N → `refunds`, `ledger_entries`.
### `payment_webhook_events` [CORE] — **NEW**
**Role:** Raw, deduplicated store of every PSP/BNPL callback. **Why mandatory:** callbacks are at-least-once and retried; without a unique store keyed on the provider's event id, a replayed "payment succeeded" double-confirms a booking and a replayed "settled" double-counts money. The handler **upserts here first** and no-ops on a duplicate, inside the same transaction that mutates payment state.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `provider_code` | NVARCHAR(50) | `zarinpal` / `snapppay` / … |
| `external_event_id` | NVARCHAR(200) | **UNIQUE(provider_code, external_event_id)** |
| `event_type` | NVARCHAR(80) | |
| `signature_valid` | BIT | |
| `payload_json` | NVARCHAR(MAX) | Raw callback |
| `processing_status` | NVARCHAR(20) | `received` / `processed` / `failed` / `ignored` |
| `related_payment_transaction_id` | BIGINT NULL | |
| `received_at`, `processed_at` | DATETIME2 | |
**Relations:** N:1 → `payment_gateways`; optional → `payment_transactions`.
### `refunds` [CORE]
**Role:** Admin-initiated refunds (no customer self-service), always linked to a support ticket. **Why these changes:** the previous model treated refunds as 1:1 with a transaction and as a single undecomposed amount — but partials exist (shortened visit) and a refund must say how much reverses the **platform fee** vs the **nurse payout**, and how the money actually moves (card vs BNPL revert).
| Field | Type | Notes |
|---|---|---|
| baseline | … | `id`, `payment_transaction_id`, `booking_id`, `requested_by_customer_id`, `ticket_id`, `amount`, `refund_percentage`, `reason_category`, `reason_notes`, `status`, approval/rejection fields, `gateway_refund_reference`, `processed_at`, `admin_notes`, timestamps |
| **cardinality** | | **CHANGED to 1:N** per `payment_transaction` (app invariant: Σ refunded ≤ captured). The old "1:1" relationship summary was wrong. |
| `platform_fee_refunded_irr` | BIGINT | **NEW** — fee-leg decomposition |
| `nurse_payout_refunded_irr` | BIGINT | **NEW** — payout-leg decomposition (drives clawback if nurse already paid) |
| `refund_channel` | NVARCHAR(20) | **NEW**`psp_card` / `bnpl_revert` / `manual_bank` |
| `external_revert_reference` | NVARCHAR(200) NULL | **NEW** — BNPL revert id |
| `expected_customer_refund_eta` | DATE NULL | **NEW** — the ~710 business-day BNPL window, surfaced in UI/reconciliation |
| `cancellation_policy_code` / `refund_percentage_applied` | … | **NEW** — snapshot of the policy that produced this refund |
**Relations:** N:1 → `payment_transactions`, `bookings`, `customer_profiles`, `tickets`; 1:1 → `nurse_clawbacks` (only when refunding a booking whose nurse was already paid).
### `ledger_entries` [CORE] — **NEW**
**Role:** The append-only, double-entry financial **source of truth**. Every money event posts **balanced** rows sharing a `transaction_group_id` (Σ debit = Σ credit). Per-nurse payable balance derives by filtering `account_type='nurse_payable'` + `nurse_id`. **Why:** a marketplace that holds escrow and pays out weekly minus commission, with refunds and clawbacks, is exactly the shape double-entry was invented for. The alternative (more money columns + status booleans) cannot answer "how much do we owe nurses right now" or reconcile against the bank, and makes refund/clawback second-class. Cost: one table + posting discipline.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `transaction_group_id` | UNIQUEIDENTIFIER | Groups the balanced legs of one event |
| `account_type` | NVARCHAR(40) | `escrow_held` / `platform_revenue` / `nurse_payable` / `refund_payable` / `bnpl_fee_expense` / `psp_fee_expense` / `nurse_clawback_receivable` / `bad_debt` |
| `nurse_id` | BIGINT FK NULL | Set for `nurse_payable`/`nurse_clawback_receivable` |
| `direction` | NVARCHAR(6) | `debit` / `credit` |
| `amount_irr` | BIGINT | Always positive; `direction` carries the sign |
| `booking_id` | BIGINT FK NULL | |
| `source_ref_type` | NVARCHAR(40) | `payment_transaction` / `refund` / `nurse_payout` / `bnpl_transaction` / `clawback` |
| `source_ref_id` | BIGINT | |
| `memo` | NVARCHAR(300) NULL | |
| `created_at` | DATETIME2 | Append-only; never updated |
**Canonical postings:**
| Event | Debit | Credit |
|---|---|---|
| Card capture | `escrow_held` (gross) | `platform_revenue` (commission) + `nurse_payable` (payout) |
| BNPL settle | as card, **plus** `bnpl_fee_expense` (provider commission) | `escrow_held` (provider commission) → escrow reflects net cash actually received |
| Refund (pre-payout) | `nurse_payable` + `platform_revenue` (decomposed legs) | `refund_payable`; later `refund_payable``escrow_held` on confirm |
| Clawback (post-payout) | `nurse_clawback_receivable` (+ `platform_revenue` leg) | `refund_payable` |
| Clawback recovered | `nurse_payable` (next batch) | `nurse_clawback_receivable` |
**Relations:** N:1 → `bookings`; logical links to `payment_transactions`/`refunds`/`nurse_payouts`/`bnpl_transactions` via `source_ref_*`.
### `nurse_clawbacks` [CORE] — **NEW**
**Role:** A first-class receivable when a booking is refunded/disputed **after** the nurse was already paid. **Why:** this was the model's own flagged critical gap — Iranian payouts are real, hard-to-reverse bank transfers, so paying before the dispute window closes can create uncollectable loss with nowhere to record it. Closing it = gate payout on `dispute_window_ends_at` **and** record any post-payout recovery here.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `nurse_id` | BIGINT FK → nurse_profiles | |
| `booking_id` | BIGINT FK → bookings | |
| `refund_id` | BIGINT FK → refunds | |
| `original_payout_id` | BIGINT FK → nurse_payouts NULL | |
| `amount_irr` | BIGINT | |
| `status` | NVARCHAR(30) | `pending` / `recovered` / `written_off` |
| `recovered_in_payout_id` | BIGINT FK NULL | Batch that netted it |
| `created_at`, `resolved_at` | DATETIME2 | |
**Relations:** N:1 → `nurse_profiles`, `bookings`; 1:1 → `refunds`; → `nurse_payouts` (original and recovering).
### `invoices` [MVP] — **NEW**
**Role:** Minimal official-invoice/receipt record per booking. **Why:** Iranian commission marketplaces face VAT/مودیان obligations on **their commission** (the Snapp/Tapsi precedent: the provider's earnings are the provider's own income; the platform's commission is the platform's taxable revenue). The smallest footprint that satisfies bookkeeping without a full tax engine. **VAT is 10%** (rose from 9% in 1403) and stored as a **config-driven rate** so a future exemption ruling on the nursing service itself is just a value change. Nurse-side income tax is the nurse's own responsibility.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `booking_id` | BIGINT FK → bookings | |
| `invoice_number` | NVARCHAR(40) UNIQUE | Official sequential number |
| `issuing_entity_type` | NVARCHAR(20) | `platform` / `partner_center` |
| `gross_irr` | BIGINT | |
| `platform_commission_irr` | BIGINT | The VAT-relevant line |
| `bnpl_commission_irr` | BIGINT NULL | |
| `vat_rate` | DECIMAL(5,4) | Config-driven (0.10) |
| `vat_irr` | BIGINT | |
| `moadian_reference_number` | NVARCHAR(40) NULL | سامانه مودیان 22-digit ref when issued |
| `moadian_status` | NVARCHAR(20) NULL | |
| `pdf_storage_key` | NVARCHAR(512) NULL | |
| `issued_at` | DATETIME2 | |
**Relations:** 1:1 → `bookings`; N:1 → `partner_centers` (when issuer).
+46
View File
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 7 — Payouts to Nurses — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a class="active" href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-7-payouts-to-nurses">Domain 7 — Payouts to Nurses</h1>
<p><a href="index.html">← Database Model</a></p>
<p><strong>Related:</strong> business requirements — <a href="../business/10-payouts.html">Payouts</a>.</p>
<h3 id="nurse_payout_batches-core"><code>nurse_payout_batches</code> [CORE] <a class="anchor" href="#nurse_payout_batches-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Weekly aggregation of amounts owed for completed, payout-eligible, unpaid bookings/sessions. <strong>Why batched:</strong> matches the operational rhythm and the PAYA settlement cycle; an admin (or scheduled job) initiates it. <strong>Holiday-aware:</strong> <code>period_end</code>/processing dates shift off bank-closed days using <code>iranian_holidays</code> (a weekly payout landing on a multi-day Nowruz closure would otherwise fail). Fields unchanged: period, <code>total_amount</code>, <code>payout_count</code>, <code>status</code>, <code>initiated_by_admin_id</code>, <code>processed_at</code>, <code>failure_notes</code>, timestamps. CHECK: <code>total_amount = Σ payouts</code>. <strong>Relations:</strong> 1:N → <code>nurse_payouts</code>.</p>
<h3 id="nurse_payouts-core"><code>nurse_payouts</code> [CORE] <a class="anchor" href="#nurse_payouts-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> One row per nurse per batch — the exact amount transferred, the IBAN snapshot, and the bank transfer reference. <strong>Why these additions:</strong> a batch must be able to <strong>net prior clawbacks</strong> so it doesn't overpay a nurse who owes money back.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td>baseline</td><td></td><td><code>id</code>, <code>batch_id</code>, <code>nurse_id</code>, <code>bank_account_id</code>, <code>iban_snapshot</code> (enc), <code>amount</code>, <code>booking_count</code>, <code>status</code>, <code>transfer_reference</code>, <code>paid_at</code>, <code>failure_reason</code>, <code>created_at</code></td></tr>
<tr><td><code>gross_earnings_irr</code></td><td>BIGINT</td><td><strong>NEW</strong> — sum of eligible session/booking payouts</td></tr>
<tr><td><code>clawback_applied_irr</code></td><td>BIGINT</td><td><strong>NEW</strong> — clawbacks netted this batch</td></tr>
<tr><td><code>net_amount_irr</code></td><td>BIGINT</td><td><strong>NEW</strong><code>gross_earnings clawback</code>; <code>amount</code> = actually transferred net</td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> N:1 → <code>nurse_payout_batches</code>, <code>nurse_profiles</code>, <code>nurse_bank_accounts</code>; 1:N → <code>nurse_payout_booking_links</code>; referenced by <code>nurse_clawbacks</code>.</p>
<h3 id="nurse_payout_booking_links-core"><code>nurse_payout_booking_links</code> [CORE] <a class="anchor" href="#nurse_payout_booking_links-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Join from a payout to the specific bookings it covers, with <code>booking_id</code> <strong>UNIQUE</strong> to guarantee a booking is paid in exactly one batch. <strong>Why:</strong> per-booking reconciliation and the structural anti-double-pay guard (the previous model's strongest correctness feature — kept). Fields unchanged. <strong>Relations:</strong> N:1 → <code>nurse_payouts</code>; 1:1 → <code>bookings</code>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+23
View File
@@ -0,0 +1,23 @@
# Domain 7 — Payouts to Nurses
[← Database Model](index.md)
**Related:** business requirements — [Payouts](../business/10-payouts.md).
### `nurse_payout_batches` [CORE]
**Role:** Weekly aggregation of amounts owed for completed, payout-eligible, unpaid bookings/sessions. **Why batched:** matches the operational rhythm and the PAYA settlement cycle; an admin (or scheduled job) initiates it. **Holiday-aware:** `period_end`/processing dates shift off bank-closed days using `iranian_holidays` (a weekly payout landing on a multi-day Nowruz closure would otherwise fail). Fields unchanged: period, `total_amount`, `payout_count`, `status`, `initiated_by_admin_id`, `processed_at`, `failure_notes`, timestamps. CHECK: `total_amount = Σ payouts`. **Relations:** 1:N → `nurse_payouts`.
### `nurse_payouts` [CORE]
**Role:** One row per nurse per batch — the exact amount transferred, the IBAN snapshot, and the bank transfer reference. **Why these additions:** a batch must be able to **net prior clawbacks** so it doesn't overpay a nurse who owes money back.
| Field | Type | Notes |
|---|---|---|
| baseline | … | `id`, `batch_id`, `nurse_id`, `bank_account_id`, `iban_snapshot` (enc), `amount`, `booking_count`, `status`, `transfer_reference`, `paid_at`, `failure_reason`, `created_at` |
| `gross_earnings_irr` | BIGINT | **NEW** — sum of eligible session/booking payouts |
| `clawback_applied_irr` | BIGINT | **NEW** — clawbacks netted this batch |
| `net_amount_irr` | BIGINT | **NEW**`gross_earnings clawback`; `amount` = actually transferred net |
**Relations:** N:1 → `nurse_payout_batches`, `nurse_profiles`, `nurse_bank_accounts`; 1:N → `nurse_payout_booking_links`; referenced by `nurse_clawbacks`.
### `nurse_payout_booking_links` [CORE]
**Role:** Join from a payout to the specific bookings it covers, with `booking_id` **UNIQUE** to guarantee a booking is paid in exactly one batch. **Why:** per-booking reconciliation and the structural anti-double-pay guard (the previous model's strongest correctness feature — kept). Fields unchanged. **Relations:** N:1 → `nurse_payouts`; 1:1 → `bookings`.
+59
View File
@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 8 — BNPL / Installments — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a class="active" href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-8-bnpl-installments">Domain 8 — BNPL / Installments</h1>
<p><a href="index.html">← Database Model</a></p>
<p><strong>Related:</strong> business requirements — <a href="../business/09-installments-bnpl.html">Installments / BNPL</a>. Settlement and reversal detail are explained in depth in the payments docs — <a href="../payments/bnpl-landscape.html">BNPL landscape</a> and <a href="../payments/cancellation-and-payout.html">Cancellation &amp; payout</a>.</p>
<p><strong>Resolved.</strong> Because verified research shows Iranian provider-financed BNPL settles the <strong>full amount to the merchant in one lump</strong> (provider owns the customer's installments and default risk), a BNPL order is — in our books — a card payment that lands net-of-fee. The original <code>installment_plans</code> + <code>installment_entries</code> subsystem (which tried to track the customer's repayment schedule and default) is <strong>deleted</strong>: it modeled a receivable Balinyaar never owns and a risk it never bears.</p>
<h3 id="bnpl_transactions-mvp-new-replaces-installment_plans"><code>bnpl_transactions</code> [MVP] — <strong>NEW (replaces <code>installment_plans</code>)</strong> <a class="anchor" href="#bnpl_transactions-mvp-new-replaces-installment_plans" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> One row per BNPL order, 1:1 with its <code>payment_transaction</code> — the single inbound settlement to reconcile, plus the revert path. <strong>Why one row, not a plan+entries tree:</strong> there is nothing to amortize on our side; we track the settlement, the provider's commission, and the reversal.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>payment_transaction_id</code></td><td>BIGINT FK UNIQUE</td><td>1:1</td></tr>
<tr><td><code>provider_code</code></td><td>NVARCHAR(50)</td><td><code>snapppay</code> / <code>digipay</code> / <code>tara</code> / <code>torobpay</code></td></tr>
<tr><td><code>merchant_of_record</code></td><td>NVARCHAR(40)</td><td>Balinyaar entity or partner center</td></tr>
<tr><td><code>external_payment_token</code></td><td>NVARCHAR(200)</td><td>For verify/settle/revert</td></tr>
<tr><td><code>external_transaction_id</code></td><td>NVARCHAR(200)</td><td></td></tr>
<tr><td><code>eligibility_status</code></td><td>NVARCHAR(30)</td><td></td></tr>
<tr><td><code>order_amount_irr</code></td><td>BIGINT</td><td>Gross order</td></tr>
<tr><td><code>settled_amount_irr</code></td><td>BIGINT</td><td>Net of provider commission actually received</td></tr>
<tr><td><code>bnpl_commission_irr</code></td><td>BIGINT</td><td>Provider's merchant discount = platform <strong>expense</strong> (never the nurse's)</td></tr>
<tr><td><code>currency</code></td><td>NVARCHAR(5)</td><td><code>IRR</code>/<code>TOMAN</code> at boundary; convert in</td></tr>
<tr><td><code>installment_count</code></td><td>TINYINT</td><td>Informational (default 4) — owned by the provider</td></tr>
<tr><td><code>status</code></td><td>NVARCHAR(30)</td><td>State machine: <code>eligible</code>/<code>token_issued</code>/<code>verified</code>/<code>settled</code>/<code>reverted</code>/<code>cancelled</code>/<code>failed</code></td></tr>
<tr><td><code>settled_at</code></td><td>DATETIME2 NULL</td><td><strong>Per-transaction</strong> — timing is contract-defined (daily/T+1-3/weekly), never assumed instant</td></tr>
<tr><td><code>revert_transaction_id</code>, <code>reverted_amount_irr</code>, <code>reverted_at</code></td><td></td><td>Reversal path</td></tr>
<tr><td><code>refund_channel</code></td><td>NVARCHAR(20)</td><td></td></tr>
<tr><td><code>callback_payload_json</code></td><td>NVARCHAR(MAX)</td><td>Raw verify/settle payload</td></tr>
<tr><td>timestamps</td><td></td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> 1:1 → <code>payment_transactions</code>. <strong>State-machine guard</strong> on <code>status</code> for idempotency.</p>
<h3 id="bnpl_settlement_entries-deferred"><code>bnpl_settlement_entries</code> [DEFERRED] <a class="anchor" href="#bnpl_settlement_entries-deferred" aria-hidden="true">#</a></h3>
<p><strong>Role/Why:</strong> Only needed if a future provider uses <strong>tranched</strong> settlement (pays the platform over time). No mainstream Iranian provider does today, so it's modeled-but-inactive; adding it later is a purely additive migration.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+36
View File
@@ -0,0 +1,36 @@
# Domain 8 — BNPL / Installments
[← Database Model](index.md)
**Related:** business requirements — [Installments / BNPL](../business/09-installments-bnpl.md). Settlement and reversal detail are explained in depth in the payments docs — [BNPL landscape](../payments/bnpl-landscape.md) and [Cancellation & payout](../payments/cancellation-and-payout.md).
**Resolved.** Because verified research shows Iranian provider-financed BNPL settles the **full amount to the merchant in one lump** (provider owns the customer's installments and default risk), a BNPL order is — in our books — a card payment that lands net-of-fee. The original `installment_plans` + `installment_entries` subsystem (which tried to track the customer's repayment schedule and default) is **deleted**: it modeled a receivable Balinyaar never owns and a risk it never bears.
### `bnpl_transactions` [MVP] — **NEW (replaces `installment_plans`)**
**Role:** One row per BNPL order, 1:1 with its `payment_transaction` — the single inbound settlement to reconcile, plus the revert path. **Why one row, not a plan+entries tree:** there is nothing to amortize on our side; we track the settlement, the provider's commission, and the reversal.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `payment_transaction_id` | BIGINT FK UNIQUE | 1:1 |
| `provider_code` | NVARCHAR(50) | `snapppay` / `digipay` / `tara` / `torobpay` |
| `merchant_of_record` | NVARCHAR(40) | Balinyaar entity or partner center |
| `external_payment_token` | NVARCHAR(200) | For verify/settle/revert |
| `external_transaction_id` | NVARCHAR(200) | |
| `eligibility_status` | NVARCHAR(30) | |
| `order_amount_irr` | BIGINT | Gross order |
| `settled_amount_irr` | BIGINT | Net of provider commission actually received |
| `bnpl_commission_irr` | BIGINT | Provider's merchant discount = platform **expense** (never the nurse's) |
| `currency` | NVARCHAR(5) | `IRR`/`TOMAN` at boundary; convert in |
| `installment_count` | TINYINT | Informational (default 4) — owned by the provider |
| `status` | NVARCHAR(30) | State machine: `eligible`/`token_issued`/`verified`/`settled`/`reverted`/`cancelled`/`failed` |
| `settled_at` | DATETIME2 NULL | **Per-transaction** — timing is contract-defined (daily/T+1-3/weekly), never assumed instant |
| `revert_transaction_id`, `reverted_amount_irr`, `reverted_at` | … | Reversal path |
| `refund_channel` | NVARCHAR(20) | |
| `callback_payload_json` | NVARCHAR(MAX) | Raw verify/settle payload |
| timestamps | … | |
**Relations:** 1:1 → `payment_transactions`. **State-machine guard** on `status` for idempotency.
### `bnpl_settlement_entries` [DEFERRED]
**Role/Why:** Only needed if a future provider uses **tranched** settlement (pays the platform over time). No mainstream Iranian provider does today, so it's modeled-but-inactive; adding it later is a purely additive migration.
+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 9 — Messaging (Ticket System) — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a class="active" href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-9-messaging-ticket-system">Domain 9 — Messaging (Ticket System)</h1>
<p><a href="index.html">← Database Model</a></p>
<h3 id="tickets-ticket_participants-ticket_messages-core"><code>tickets</code> / <code>ticket_participants</code> / <code>ticket_messages</code> [CORE] <a class="anchor" href="#tickets-ticket_participants-ticket_messages-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> All post-booking communication, admin-readable, with no direct nurse↔customer channel. <strong>Why intentionally constrained:</strong> it protects vulnerable patients, creates dispute evidence, and prevents disintermediation (families and nurses pairing off-platform). <code>ticket_messages.is_internal</code> keeps admin-only notes out of user view. <code>reference_code</code> is the human-facing support id. <strong>On-site emergencies</strong> stay an operational playbook ("call the emergency contact from the app, then open a ticket") — surfaced prominently in the booking UI; no schema change, but documented so nurses don't seek the family's number off-platform. Fields unchanged; <code>UNIQUE(ticket_id, user_id)</code> on participants. <strong>Relations:</strong> <code>tickets</code> 1:N <code>ticket_participants</code>/<code>ticket_messages</code>; <code>tickets</code> optionally ↔ <code>bookings</code>, <code>refunds</code>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+6
View File
@@ -0,0 +1,6 @@
# Domain 9 — Messaging (Ticket System)
[← Database Model](index.md)
### `tickets` / `ticket_participants` / `ticket_messages` [CORE]
**Role:** All post-booking communication, admin-readable, with no direct nurse↔customer channel. **Why intentionally constrained:** it protects vulnerable patients, creates dispute evidence, and prevents disintermediation (families and nurses pairing off-platform). `ticket_messages.is_internal` keeps admin-only notes out of user view. `reference_code` is the human-facing support id. **On-site emergencies** stay an operational playbook ("call the emergency contact from the app, then open a ticket") — surfaced prominently in the booking UI; no schema change, but documented so nurses don't seek the family's number off-platform. Fields unchanged; `UNIQUE(ticket_id, user_id)` on participants. **Relations:** `tickets` 1:N `ticket_participants`/`ticket_messages`; `tickets` optionally ↔ `bookings`, `refunds`.
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 10 — Reviews &amp; Patient Records — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a class="active" href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-10-reviews-patient-records">Domain 10 — Reviews &amp; Patient Records</h1>
<p><a href="index.html">← Database Model</a></p>
<h3 id="reviews-core"><code>reviews</code> [CORE] <a class="anchor" href="#reviews-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> One customer review per <strong>completed</strong> booking; enters <code>pending_moderation</code>, published only after admin/AI approval; a low rating raises a <code>support_alert</code>. <strong>Why these guards:</strong> (a) review creation is allowed <strong>only for completed/closed bookings</strong> (a review for a cancelled booking is nonsense); (b) <strong>every</strong> status transition (publish/hide/reject/unpublish) recomputes <code>nurse_profiles</code> aggregates, fixing the inflated-rating-after-hide drift. Fields unchanged (rating 15 with CHECK, body, status, moderation fields). <strong>Relations:</strong> 1:1 → <code>bookings</code>; N:1 → <code>customer_profiles</code>, <code>nurse_profiles</code>; 1:N → <code>review_tag_links</code>.</p>
<h3 id="review_tags_master-mvp-review_tag_links-mvp"><code>review_tags_master</code> [MVP] / <code>review_tag_links</code> [MVP] <a class="anchor" href="#review_tags_master-mvp-review_tag_links-mvp" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Standardized tags for quantitative aggregation of qualitative feedback (e.g. "% punctual"). <strong>Why MVP-not-core:</strong> free-text + rating is enough to launch; structured tags are a phase-2 analytics nicety (additive leaf tables). <strong>Relations:</strong> <code>reviews</code> N:N <code>review_tags_master</code>.</p>
<h3 id="patient_care_records-mvp"><code>patient_care_records</code> [MVP] <a class="anchor" href="#patient_care_records-mvp" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Nurse-authored clinical notes after a visit, accumulating into a <strong>patient-scoped longitudinal history</strong> (not booking-scoped). <strong>Why patient-scoped:</strong> when a different nurse takes over, they read the history before accepting, enabling continuity of care without the family repeating everything. Strict access: owning customer, nurses with a confirmed booking for that patient, admin. All fields encrypted. <strong>Relations:</strong> N:1 → <code>patients</code>, <code>bookings</code>, <code>nurse_profiles</code>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,12 @@
# Domain 10 — Reviews & Patient Records
[← Database Model](index.md)
### `reviews` [CORE]
**Role:** One customer review per **completed** booking; enters `pending_moderation`, published only after admin/AI approval; a low rating raises a `support_alert`. **Why these guards:** (a) review creation is allowed **only for completed/closed bookings** (a review for a cancelled booking is nonsense); (b) **every** status transition (publish/hide/reject/unpublish) recomputes `nurse_profiles` aggregates, fixing the inflated-rating-after-hide drift. Fields unchanged (rating 15 with CHECK, body, status, moderation fields). **Relations:** 1:1 → `bookings`; N:1 → `customer_profiles`, `nurse_profiles`; 1:N → `review_tag_links`.
### `review_tags_master` [MVP] / `review_tag_links` [MVP]
**Role:** Standardized tags for quantitative aggregation of qualitative feedback (e.g. "% punctual"). **Why MVP-not-core:** free-text + rating is enough to launch; structured tags are a phase-2 analytics nicety (additive leaf tables). **Relations:** `reviews` N:N `review_tags_master`.
### `patient_care_records` [MVP]
**Role:** Nurse-authored clinical notes after a visit, accumulating into a **patient-scoped longitudinal history** (not booking-scoped). **Why patient-scoped:** when a different nurse takes over, they read the history before accepting, enabling continuity of care without the family repeating everything. Strict access: owning customer, nurses with a confirmed booking for that patient, admin. All fields encrypted. **Relations:** N:1 → `patients`, `bookings`, `nurse_profiles`.
+36
View File
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 11 — Notifications — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a class="active" href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-11-notifications">Domain 11 — Notifications</h1>
<p><a href="index.html">← Database Model</a></p>
<h3 id="notifications-core"><code>notifications</code> [CORE] <a class="anchor" href="#notifications-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> In-app notifications (no push at launch); <code>data_json</code> carries a typed payload for front-end navigation. <strong>Why polled, not pushed:</strong> push is out of MVP scope; a retention job hard-deletes read notifications older than 90 days to bound growth. Fields unchanged. <strong>Relations:</strong> N:1 → <code>users</code>.</p>
<h3 id="support_alerts-core"><code>support_alerts</code> [CORE] <a class="anchor" href="#support_alerts-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Internal-only alerts (low ratings, EVV no-shows, expired verification steps, EVV location mismatch, payment anomalies), with an owner and resolution trail. <strong>Why distinct from notifications:</strong> these are staff worklist items, never shown to users. Fields unchanged. <strong>Relations:</strong> polymorphic (<code>entity_type</code>,<code>entity_id</code>) — validated at the application layer; consider nullable typed FKs (<code>booking_id</code>,<code>review_id</code>) for the common cases.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
# Domain 11 — Notifications
[← Database Model](index.md)
### `notifications` [CORE]
**Role:** In-app notifications (no push at launch); `data_json` carries a typed payload for front-end navigation. **Why polled, not pushed:** push is out of MVP scope; a retention job hard-deletes read notifications older than 90 days to bound growth. Fields unchanged. **Relations:** N:1 → `users`.
### `support_alerts` [CORE]
**Role:** Internal-only alerts (low ratings, EVV no-shows, expired verification steps, EVV location mismatch, payment anomalies), with an owner and resolution trail. **Why distinct from notifications:** these are staff worklist items, never shown to users. Fields unchanged. **Relations:** polymorphic (`entity_type`,`entity_id`) — validated at the application layer; consider nullable typed FKs (`booking_id`,`review_id`) for the common cases.
@@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 12 — Audit, Config &amp; Reference — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a class="active" href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-12-audit-config-reference">Domain 12 — Audit, Config &amp; Reference</h1>
<p><a href="index.html">← Database Model</a></p>
<h3 id="audit_logs-core"><code>audit_logs</code> [CORE] <a class="anchor" href="#audit_logs-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Immutable, append-only record of every state change on sensitive entities — now explicitly <strong>including <code>platform_configs</code></strong> (so finance can prove the commission rate at any moment). <strong>Why:</strong> compliance and accountability; <code>changed_fields_json</code> enables fast filtering. Plan month-partitioning + 23yr cold-storage archival before launch. Fields unchanged. <strong>Relations:</strong> polymorphic, append-only.</p>
<h3 id="system_events-mvp"><code>system_events</code> [MVP] <a class="anchor" href="#system_events-mvp" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> High-volume behavioral/analytics event log. <strong>Why kept but de-emphasized:</strong> product analytics, not compliance. It grows unbounded — at scale, pipe it to an analytics sink/warehouse rather than the transactional DB. Fields unchanged.</p>
<h3 id="platform_configs-core"><code>platform_configs</code> [CORE] <a class="anchor" href="#platform_configs-core" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Key-value runtime business parameters — change without a deploy. <strong>Why typed values:</strong> <code>data_type</code> tells the app how to parse. <strong>New keys</strong> this revision: <code>dispute_window_hours</code> (default 72), <code>vat_rate</code> (0.10), <code>bnpl_merchant_of_record</code>, <code>bnpl_provider_commission_rate</code>, <code>bnpl_settlement_timing</code>, cancellation-tier defaults — alongside the existing <code>platform_fee_rate</code>, <code>booking_payment_deadline_minutes</code>, <code>nurse_response_deadline_hours</code>, <code>nurse_payout_interval_days</code>, <code>evv_location_tolerance_meters</code>, <code>min_rating_for_support_alert</code>. <strong>Relations:</strong> referenced everywhere; changes audited.</p>
<h3 id="iranian_holidays-mvp-new"><code>iranian_holidays</code> [MVP] — <strong>NEW</strong> <a class="anchor" href="#iranian_holidays-mvp-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> Shared official/religious holiday calendar (movable, partly lunar-Hijri), with a <code>is_bank_closed</code> flag. <strong>Why a real table:</strong> Iran's holidays are numerous and partly movable, and they drive <strong>payout bank-closure scheduling</strong> (PAYA/SATNA closed → a weekly payout shifts to the next business day), optional holiday pricing, and business-hour deadline math — none of which a purely manual per-nurse availability exception can express.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>holiday_date</code></td><td>DATE</td><td></td></tr>
<tr><td><code>name_fa</code></td><td>NVARCHAR(200)</td><td></td></tr>
<tr><td><code>type</code></td><td>NVARCHAR(20)</td><td><code>official</code> / <code>religious</code> / <code>national</code></td></tr>
<tr><td><code>is_bank_closed</code></td><td>BIT</td><td>Drives payout date shifting</td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> referenced by payout scheduling and (optionally) pricing.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,25 @@
# Domain 12 — Audit, Config & Reference
[← Database Model](index.md)
### `audit_logs` [CORE]
**Role:** Immutable, append-only record of every state change on sensitive entities — now explicitly **including `platform_configs`** (so finance can prove the commission rate at any moment). **Why:** compliance and accountability; `changed_fields_json` enables fast filtering. Plan month-partitioning + 23yr cold-storage archival before launch. Fields unchanged. **Relations:** polymorphic, append-only.
### `system_events` [MVP]
**Role:** High-volume behavioral/analytics event log. **Why kept but de-emphasized:** product analytics, not compliance. It grows unbounded — at scale, pipe it to an analytics sink/warehouse rather than the transactional DB. Fields unchanged.
### `platform_configs` [CORE]
**Role:** Key-value runtime business parameters — change without a deploy. **Why typed values:** `data_type` tells the app how to parse. **New keys** this revision: `dispute_window_hours` (default 72), `vat_rate` (0.10), `bnpl_merchant_of_record`, `bnpl_provider_commission_rate`, `bnpl_settlement_timing`, cancellation-tier defaults — alongside the existing `platform_fee_rate`, `booking_payment_deadline_minutes`, `nurse_response_deadline_hours`, `nurse_payout_interval_days`, `evv_location_tolerance_meters`, `min_rating_for_support_alert`. **Relations:** referenced everywhere; changes audited.
### `iranian_holidays` [MVP] — **NEW**
**Role:** Shared official/religious holiday calendar (movable, partly lunar-Hijri), with a `is_bank_closed` flag. **Why a real table:** Iran's holidays are numerous and partly movable, and they drive **payout bank-closure scheduling** (PAYA/SATNA closed → a weekly payout shifts to the next business day), optional holiday pricing, and business-hour deadline math — none of which a purely manual per-nurse availability exception can express.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `holiday_date` | DATE | |
| `name_fa` | NVARCHAR(200) | |
| `type` | NVARCHAR(20) | `official` / `religious` / `national` |
| `is_bank_closed` | BIT | Drives payout date shifting |
**Relations:** referenced by payout scheduling and (optionally) pricing.
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Domain 13 — Partner Centers (launch) &amp; Future — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a class="active" href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="domain-13-partner-centers-launch-future">Domain 13 — Partner Centers (launch) &amp; Future</h1>
<p><a href="index.html">← Database Model</a></p>
<p><strong>Related:</strong> business requirements — <a href="../business/13-tax-invoicing-and-legal.html">Tax, invoicing &amp; legal</a>.</p>
<h3 id="partner_centers-mvp-new"><code>partner_centers</code> [MVP] — <strong>NEW</strong> <a class="anchor" href="#partner_centers-mvp-new" aria-hidden="true">#</a></h3>
<p><strong>Role:</strong> A licensed home-nursing center (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل) that <strong>sponsors</strong> nurses and is plausibly the <strong>merchant-of-record</strong> and invoice issuer at launch. <strong>Why this is the single most launch-critical addition:</strong> the research's #1 go-to-market recommendation is to operate by subcontracting to an already-licensed center (the Asanism model) while Balinyaar's own MoH permit is pending — the center is what makes the operation legal, may be who the IPG settles to, and clears the BNPL onboarding gate (which needs a جواز کسب + eNamad the company/center holds, not each nurse). Distinct from the future <code>organizations</code> (employer) table — this is the <strong>licensing/launch sponsor</strong>.</p>
<div class="table-wrap"><table><thead><tr><th>Field</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGINT PK</td><td></td></tr>
<tr><td><code>name</code></td><td>NVARCHAR(300)</td><td></td></tr>
<tr><td><code>legal_entity_type</code></td><td>NVARCHAR(30)</td><td></td></tr>
<tr><td><code>moh_establishment_permit_no</code></td><td>NVARCHAR(100)</td><td>پروانه تأسیس</td></tr>
<tr><td><code>technical_director_nurse_user_id</code></td><td>BIGINT FK → users NULL</td><td>مسئول فنی</td></tr>
<tr><td><code>technical_director_license_no</code></td><td>NVARCHAR(100) NULL</td><td></td></tr>
<tr><td><code>enamad_code</code></td><td>NVARCHAR(100) NULL</td><td></td></tr>
<tr><td><code>settlement_iban</code></td><td>NVARCHAR(34) (enc) NULL</td><td>If merchant-of-record</td></tr>
<tr><td><code>is_merchant_of_record</code></td><td>BIT</td><td></td></tr>
<tr><td><code>commission_rate</code></td><td>DECIMAL(5,4) NULL</td><td>Center's cut, if any</td></tr>
<tr><td><code>admin_user_id</code></td><td>BIGINT FK → users</td><td>Center's dashboard account</td></tr>
<tr><td><code>is_active</code>, <code>verified_at</code>, timestamps</td><td></td><td></td></tr>
</tbody></table></div>
<p><strong>Relations:</strong> 1:N → <code>nurse_profiles</code> (sponsors), <code>bookings</code> (legally covered by), <code>invoices</code> (issuer).</p>
<h3 id="organizations-organization_nurses-deferred"><code>organizations</code> / <code>organization_nurses</code> [DEFERRED] <a class="anchor" href="#organizations-organization_nurses-deferred" aria-hidden="true">#</a></h3>
<p><strong>Role/Why:</strong> The future <strong>employer</strong> model (nursing companies adding their employed nurses). Modeled-but-inactive — no launch table references them, so adding them later is a pure additive migration. Kept distinct from <code>partner_centers</code> (launch licensing) to avoid conflating "sponsor for legality" with "employer."</p>
<h3 id="fraud_flags-deferred"><code>fraud_flags</code> [DEFERRED] <a class="anchor" href="#fraud_flags-deferred" aria-hidden="true">#</a></h3>
<p><strong>Role/Why:</strong> Output of a future ML fraud service. Premature for a no-traffic MVP; <code>support_alerts</code> (<code>fraud_signal</code> type) covers rule-based signals manually. Inactive stub.</p>
<h3 id="recurring_booking_schedules-deferred"><code>recurring_booking_schedules</code> [DEFERRED] <a class="anchor" href="#recurring_booking_schedules-deferred" aria-hidden="true">#</a></h3>
<p><strong>Role/Why:</strong> RFC-5545 recurrence for repeating care patterns. Note: the concrete multi-day need is now met by <code>booking_sessions</code>; this remains deferred for true open-ended recurrence. Inactive stub.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,34 @@
# Domain 13 — Partner Centers (launch) & Future
[← Database Model](index.md)
**Related:** business requirements — [Tax, invoicing & legal](../business/13-tax-invoicing-and-legal.md).
### `partner_centers` [MVP] — **NEW**
**Role:** A licensed home-nursing center (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل) that **sponsors** nurses and is plausibly the **merchant-of-record** and invoice issuer at launch. **Why this is the single most launch-critical addition:** the research's #1 go-to-market recommendation is to operate by subcontracting to an already-licensed center (the Asanism model) while Balinyaar's own MoH permit is pending — the center is what makes the operation legal, may be who the IPG settles to, and clears the BNPL onboarding gate (which needs a جواز کسب + eNamad the company/center holds, not each nurse). Distinct from the future `organizations` (employer) table — this is the **licensing/launch sponsor**.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `name` | NVARCHAR(300) | |
| `legal_entity_type` | NVARCHAR(30) | |
| `moh_establishment_permit_no` | NVARCHAR(100) | پروانه تأسیس |
| `technical_director_nurse_user_id` | BIGINT FK → users NULL | مسئول فنی |
| `technical_director_license_no` | NVARCHAR(100) NULL | |
| `enamad_code` | NVARCHAR(100) NULL | |
| `settlement_iban` | NVARCHAR(34) (enc) NULL | If merchant-of-record |
| `is_merchant_of_record` | BIT | |
| `commission_rate` | DECIMAL(5,4) NULL | Center's cut, if any |
| `admin_user_id` | BIGINT FK → users | Center's dashboard account |
| `is_active`, `verified_at`, timestamps | … | |
**Relations:** 1:N → `nurse_profiles` (sponsors), `bookings` (legally covered by), `invoices` (issuer).
### `organizations` / `organization_nurses` [DEFERRED]
**Role/Why:** The future **employer** model (nursing companies adding their employed nurses). Modeled-but-inactive — no launch table references them, so adding them later is a pure additive migration. Kept distinct from `partner_centers` (launch licensing) to avoid conflating "sponsor for legality" with "employer."
### `fraud_flags` [DEFERRED]
**Role/Why:** Output of a future ML fraud service. Premature for a no-traffic MVP; `support_alerts` (`fraud_signal` type) covers rule-based signals manually. Inactive stub.
### `recurring_booking_schedules` [DEFERRED]
**Role/Why:** RFC-5545 recurrence for repeating care patterns. Note: the concrete multi-day need is now met by `booking_sessions`; this remains deferred for true open-ended recurrence. Inactive stub.
+164
View File
@@ -0,0 +1,164 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Diagrams — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="index.html">Overview &amp; decisions</a></li><li><a class="active" href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="diagrams">Diagrams</h1>
<p><a href="index.html">← Database Model</a></p>
<h3 id="1-domain-map-how-the-clusters-relate">1. Domain map — how the clusters relate <a class="anchor" href="#1-domain-map-how-the-clusters-relate" aria-hidden="true">#</a></h3>
<pre class="mermaid">flowchart LR
PARTNER["🏥 Partner Centers (launch)&lt;br/&gt;partner_centers"]
IDENTITY["🧑 Identity &amp; Access&lt;br/&gt;users · nurse_profiles · customer_profiles&lt;br/&gt;patients · customer_addresses · nurse_bank_accounts"]
GEO["📍 Geography&lt;br/&gt;provinces · cities · districts · nurse_service_areas"]
VERIFY["✅ Verification&lt;br/&gt;nurse_verifications · step_types · steps&lt;br/&gt;documents · nurse_credentials"]
SERVICES["🩺 Services &amp; Pricing&lt;br/&gt;service_categories · option_groups · option_values&lt;br/&gt;variants · variant_options · search_index · availability"]
BOOKING["📅 Booking &amp; Scheduling&lt;br/&gt;booking_requests · bookings · booking_sessions&lt;br/&gt;care_instructions · visit_verifications · cancellation_policies"]
PAY["💳 Payments &amp; Ledger&lt;br/&gt;payment_gateways · payment_transactions · webhook_events&lt;br/&gt;refunds · ledger_entries · nurse_clawbacks · invoices"]
BNPL["🧾 BNPL&lt;br/&gt;bnpl_transactions"]
PAYOUT["🏦 Payouts&lt;br/&gt;payout_batches · payouts · booking_links"]
REVIEW["⭐ Reviews &amp; Records&lt;br/&gt;reviews · review_tags · patient_care_records"]
MSG["💬 Messaging&lt;br/&gt;tickets · participants · messages"]
NOTIFY["🔔 Notifications&lt;br/&gt;notifications · support_alerts"]
AUDITCFG["📜 Audit &amp; Config&lt;br/&gt;audit_logs · system_events&lt;br/&gt;platform_configs · iranian_holidays"]
PARTNER -. "sponsors / merchant-of-record" .-&gt; VERIFY
IDENTITY --&gt; VERIFY
VERIFY --&gt; SERVICES
SERVICES --&gt; GEO
IDENTITY --&gt; BOOKING
SERVICES --&gt; BOOKING
BOOKING --&gt; PAY
PAY --&gt; BNPL
PAY --&gt; PAYOUT
BOOKING --&gt; REVIEW
BOOKING --&gt; MSG
PAY --&gt; NOTIFY
PAY --&gt; AUDITCFG</pre>
<h3 id="2-core-booking-spine-who-books-whom">2. Core booking spine (who books whom) <a class="anchor" href="#2-core-booking-spine-who-books-whom" aria-hidden="true">#</a></h3>
<pre class="mermaid">erDiagram
users ||--o| nurse_profiles : "role=nurse"
users ||--o| customer_profiles : "role=customer"
partner_centers ||--o{ nurse_profiles : "sponsors"
customer_profiles ||--o{ patients : "registers"
customer_profiles ||--o{ customer_addresses : "saves"
nurse_profiles ||--o{ nurse_service_variants : "offers"
customer_profiles ||--o{ booking_requests : "submits"
nurse_profiles ||--o{ booking_requests : "receives"
patients ||--o{ booking_requests : "for patient"
nurse_service_variants ||--o{ booking_requests : "selects variant"
booking_requests ||--o| bookings : "converts on payment"
bookings ||--o{ booking_sessions : "has visits"
booking_sessions ||--o| visit_verifications : "EVV per visit"
bookings ||--o| booking_care_instructions : "clinical (encrypted)"
bookings ||--o| reviews : "one review"
booking_requests {
bigint id PK
string status
string required_caregiver_gender
datetime nurse_response_deadline_at
datetime payment_deadline_at
}
bookings {
bigint id PK
bigint gross_price_irr
bigint balinyaar_commission_irr
bigint nurse_payout_amount
smallint session_count
datetime dispute_window_ends_at
string status
}
booking_sessions {
bigint id PK
int session_index
date scheduled_date
string status
datetime payout_eligible_at
}</pre>
<h3 id="3-payments-ledger-payouts">3. Payments, ledger &amp; payouts <a class="anchor" href="#3-payments-ledger-payouts" aria-hidden="true">#</a></h3>
<pre class="mermaid">erDiagram
bookings ||--o{ payment_transactions : "paid by (attempts)"
payment_gateways ||--o{ payment_transactions : "via"
payment_gateways ||--o{ payment_webhook_events : "emits"
payment_transactions ||--o| bnpl_transactions : "if BNPL"
payment_transactions ||--o{ refunds : "may be refunded"
refunds ||--o| nurse_clawbacks : "if after payout"
nurse_profiles ||--o{ nurse_clawbacks : "owes"
bookings ||--o{ ledger_entries : "money postings"
bookings ||--o| invoices : "billed"
nurse_payout_batches ||--o{ nurse_payouts : "groups"
nurse_profiles ||--o{ nurse_payouts : "receives"
nurse_bank_accounts ||--o{ nurse_payouts : "to IBAN"
nurse_payouts ||--o{ nurse_payout_booking_links : "covers"
bookings ||--o| nurse_payout_booking_links : "settled in one"
ledger_entries {
bigint id PK
uuid transaction_group_id
string account_type
string direction
bigint amount_irr
}
refunds {
bigint id PK
bigint platform_fee_refunded_irr
bigint nurse_payout_refunded_irr
string refund_channel
}
bnpl_transactions {
bigint id PK
string provider_code
bigint settled_amount_irr
bigint bnpl_commission_irr
string status
}</pre>
<h3 id="4-financial-lifecycle-escrow-payout-clawback">4. Financial lifecycle — escrow → payout → clawback <a class="anchor" href="#4-financial-lifecycle-escrow-payout-clawback" aria-hidden="true">#</a></h3>
<pre class="mermaid">flowchart TD
A["Family submits booking_request"] --&gt; B{"Nurse responds in time?"}
B --&gt;|"reject / expire"| X["request closed — no money moved"]
B --&gt;|"accept"| C["30-min payment window"]
C --&gt; D{"Payment method"}
D --&gt;|"Card (IPG)"| E["payment_transactions = succeeded"]
D --&gt;|"BNPL (SnappPay)"| F["bnpl_transactions = settled&lt;br/&gt;full amount minus provider commission"]
E --&gt; G["Ledger posting:&lt;br/&gt;DR escrow_held / CR nurse_payable + platform_revenue"]
F --&gt; G
G --&gt; H["Booking confirmed (escrow held)"]
H --&gt; I["Nurse EVV check-in / check-out per session"]
I --&gt; J["Booking completed"]
J --&gt; K["dispute_window_ends_at = completed_at + 72h"]
K --&gt; L{"Window passed &amp; no dispute?"}
L --&gt;|"yes"| M["payout_eligible"]
M --&gt; N["Weekly batch → PAYA to nurse IBAN&lt;br/&gt;payout = gross balinyaar_commission"]
K -.-&gt;|"refund BEFORE payout"| O["Clean ledger reversal&lt;br/&gt;PSP refund / bnpl_revert"]
N --&gt; P{"Refund AFTER payout?"}
P --&gt;|"yes"| Q["nurse_clawbacks receivable&lt;br/&gt;netted next batch or written off"]
P --&gt;|"no"| Z["Settled and reconciled"]</pre>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
const dark = document.documentElement.getAttribute('data-theme') === 'dark';
mermaid.initialize({ startOnLoad: true, theme: dark ? 'dark' : 'neutral' });
</script>
</body>
</html>
+147
View File
@@ -0,0 +1,147 @@
# Diagrams
[← Database Model](index.md)
### 1. Domain map — how the clusters relate
```mermaid
flowchart LR
PARTNER["🏥 Partner Centers (launch)<br/>partner_centers"]
IDENTITY["🧑 Identity & Access<br/>users · nurse_profiles · customer_profiles<br/>patients · customer_addresses · nurse_bank_accounts"]
GEO["📍 Geography<br/>provinces · cities · districts · nurse_service_areas"]
VERIFY["✅ Verification<br/>nurse_verifications · step_types · steps<br/>documents · nurse_credentials"]
SERVICES["🩺 Services & Pricing<br/>service_categories · option_groups · option_values<br/>variants · variant_options · search_index · availability"]
BOOKING["📅 Booking & Scheduling<br/>booking_requests · bookings · booking_sessions<br/>care_instructions · visit_verifications · cancellation_policies"]
PAY["💳 Payments & Ledger<br/>payment_gateways · payment_transactions · webhook_events<br/>refunds · ledger_entries · nurse_clawbacks · invoices"]
BNPL["🧾 BNPL<br/>bnpl_transactions"]
PAYOUT["🏦 Payouts<br/>payout_batches · payouts · booking_links"]
REVIEW["⭐ Reviews & Records<br/>reviews · review_tags · patient_care_records"]
MSG["💬 Messaging<br/>tickets · participants · messages"]
NOTIFY["🔔 Notifications<br/>notifications · support_alerts"]
AUDITCFG["📜 Audit & Config<br/>audit_logs · system_events<br/>platform_configs · iranian_holidays"]
PARTNER -. "sponsors / merchant-of-record" .-> VERIFY
IDENTITY --> VERIFY
VERIFY --> SERVICES
SERVICES --> GEO
IDENTITY --> BOOKING
SERVICES --> BOOKING
BOOKING --> PAY
PAY --> BNPL
PAY --> PAYOUT
BOOKING --> REVIEW
BOOKING --> MSG
PAY --> NOTIFY
PAY --> AUDITCFG
```
### 2. Core booking spine (who books whom)
```mermaid
erDiagram
users ||--o| nurse_profiles : "role=nurse"
users ||--o| customer_profiles : "role=customer"
partner_centers ||--o{ nurse_profiles : "sponsors"
customer_profiles ||--o{ patients : "registers"
customer_profiles ||--o{ customer_addresses : "saves"
nurse_profiles ||--o{ nurse_service_variants : "offers"
customer_profiles ||--o{ booking_requests : "submits"
nurse_profiles ||--o{ booking_requests : "receives"
patients ||--o{ booking_requests : "for patient"
nurse_service_variants ||--o{ booking_requests : "selects variant"
booking_requests ||--o| bookings : "converts on payment"
bookings ||--o{ booking_sessions : "has visits"
booking_sessions ||--o| visit_verifications : "EVV per visit"
bookings ||--o| booking_care_instructions : "clinical (encrypted)"
bookings ||--o| reviews : "one review"
booking_requests {
bigint id PK
string status
string required_caregiver_gender
datetime nurse_response_deadline_at
datetime payment_deadline_at
}
bookings {
bigint id PK
bigint gross_price_irr
bigint balinyaar_commission_irr
bigint nurse_payout_amount
smallint session_count
datetime dispute_window_ends_at
string status
}
booking_sessions {
bigint id PK
int session_index
date scheduled_date
string status
datetime payout_eligible_at
}
```
### 3. Payments, ledger & payouts
```mermaid
erDiagram
bookings ||--o{ payment_transactions : "paid by (attempts)"
payment_gateways ||--o{ payment_transactions : "via"
payment_gateways ||--o{ payment_webhook_events : "emits"
payment_transactions ||--o| bnpl_transactions : "if BNPL"
payment_transactions ||--o{ refunds : "may be refunded"
refunds ||--o| nurse_clawbacks : "if after payout"
nurse_profiles ||--o{ nurse_clawbacks : "owes"
bookings ||--o{ ledger_entries : "money postings"
bookings ||--o| invoices : "billed"
nurse_payout_batches ||--o{ nurse_payouts : "groups"
nurse_profiles ||--o{ nurse_payouts : "receives"
nurse_bank_accounts ||--o{ nurse_payouts : "to IBAN"
nurse_payouts ||--o{ nurse_payout_booking_links : "covers"
bookings ||--o| nurse_payout_booking_links : "settled in one"
ledger_entries {
bigint id PK
uuid transaction_group_id
string account_type
string direction
bigint amount_irr
}
refunds {
bigint id PK
bigint platform_fee_refunded_irr
bigint nurse_payout_refunded_irr
string refund_channel
}
bnpl_transactions {
bigint id PK
string provider_code
bigint settled_amount_irr
bigint bnpl_commission_irr
string status
}
```
### 4. Financial lifecycle — escrow → payout → clawback
```mermaid
flowchart TD
A["Family submits booking_request"] --> B{"Nurse responds in time?"}
B -->|"reject / expire"| X["request closed — no money moved"]
B -->|"accept"| C["30-min payment window"]
C --> D{"Payment method"}
D -->|"Card (IPG)"| E["payment_transactions = succeeded"]
D -->|"BNPL (SnappPay)"| F["bnpl_transactions = settled<br/>full amount minus provider commission"]
E --> G["Ledger posting:<br/>DR escrow_held / CR nurse_payable + platform_revenue"]
F --> G
G --> H["Booking confirmed (escrow held)"]
H --> I["Nurse EVV check-in / check-out per session"]
I --> J["Booking completed"]
J --> K["dispute_window_ends_at = completed_at + 72h"]
K --> L{"Window passed & no dispute?"}
L -->|"yes"| M["payout_eligible"]
M --> N["Weekly batch → PAYA to nurse IBAN<br/>payout = gross balinyaar_commission"]
K -.->|"refund BEFORE payout"| O["Clean ledger reversal<br/>PSP refund / bnpl_revert"]
N --> P{"Refund AFTER payout?"}
P -->|"yes"| Q["nurse_clawbacks receivable<br/>netted next batch or written off"]
P -->|"no"| Z["Settled and reconciled"]
```
+195
View File
@@ -0,0 +1,195 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Database Model — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a class="active" href="index.html">Overview &amp; decisions</a></li><li><a href="diagrams.html">Diagrams</a></li><li><a href="01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="02-geography.html">2. Geography</a></li><li><a href="03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="07-payouts.html">7. Payouts</a></li><li><a href="08-bnpl.html">8. BNPL / installments</a></li><li><a href="09-messaging.html">9. Messaging</a></li><li><a href="10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="11-notifications.html">11. Notifications</a></li><li><a href="12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="database-model">Database Model</h1>
<blockquote><p><strong>Revision 2 — 2026-06-20.</strong> This is a research-driven refinement of the original 13-domain model. It closes the financial-correctness gaps the previous version flagged in its own _Advices_ section, resolves the two open BNPL questions, and grounds every money decision in verified research on the Iranian payment landscape (SnappPay, Digipay, Tara, Torob Pay, Shaparak/پرداخت‌یار rules). The previous revision is preserved in git history.</p>
<p>Companion documents: <strong><a href="../business/index.html">business requirements</a></strong> (per-section product requirements) and <strong><a href="../payments/index.html">payments deep-dive</a></strong> (the BNPL/escrow deep-dive with sources).</p>
</blockquote>
<h2 id="contents">Contents <a class="anchor" href="#contents" aria-hidden="true">#</a></h2>
<ul>
<li><a href="diagrams.html">Diagrams</a></li>
<li><a href="01-identity-and-access.html">Domain 1 — Identity &amp; Access</a></li>
<li><a href="02-geography.html">Domain 2 — Geographic Data</a></li>
<li><a href="03-services-and-pricing.html">Domain 3 — Services &amp; Pricing</a></li>
<li><a href="04-verification-and-credentials.html">Domain 4 — Verification &amp; Credentials</a></li>
<li><a href="05-booking-and-scheduling.html">Domain 5 — Booking &amp; Scheduling</a></li>
<li><a href="06-payments-ledger-and-refunds.html">Domain 6 — Payments, Ledger &amp; Refunds</a></li>
<li><a href="07-payouts.html">Domain 7 — Payouts to Nurses</a></li>
<li><a href="08-bnpl.html">Domain 8 — BNPL / Installments</a></li>
<li><a href="09-messaging.html">Domain 9 — Messaging (Ticket System)</a></li>
<li><a href="10-reviews-and-records.html">Domain 10 — Reviews &amp; Patient Records</a></li>
<li><a href="11-notifications.html">Domain 11 — Notifications</a></li>
<li><a href="12-audit-config-and-reference.html">Domain 12 — Audit, Config &amp; Reference</a></li>
<li><a href="13-partner-centers-and-future.html">Domain 13 — Partner Centers (launch) &amp; Future</a></li>
</ul>
<hr>
<h2 id="platform-summary">Platform Summary <a class="anchor" href="#platform-summary" aria-hidden="true">#</a></h2>
<p>Balinyaar is a trust-first home-nursing marketplace in Iran. Independent, individually-verified nurses register, list configurable services with their own pricing, and pass a multi-step verification pipeline anchored on the MoH <strong>پروانه صلاحیت حرفه‌ای</strong> (professional-competency license). Families search — filtered by city/district <strong>and same-gender caregiver preference</strong> — pick a nurse and a service variant, submit a booking request, and pay <strong>through the platform</strong> after the nurse accepts. The platform records the money as an <strong>internal escrow ledger state</strong> (not platform-held cash — see Principle 2), the nurse performs one or more EVV-verified visits, and the platform pays the nurse <strong>weekly, after the dispute window closes</strong>, minus a platform commission. All post-booking communication runs through an admin-readable ticket system.</p>
<p>At launch the platform operates under a <strong>partner licensed home-nursing center (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل)</strong> — the Asanism-style model — which is the legal vehicle and the likely <strong>merchant-of-record</strong> for payments while Balinyaar's own MoH permit is in process.</p>
<hr>
<h2 id="what-changed-in-this-revision-decision-summary">What changed in this revision (decision summary) <a class="anchor" href="#what-changed-in-this-revision-decision-summary" aria-hidden="true">#</a></h2>
<div class="table-wrap"><table><thead><tr><th>#</th><th>Decision</th><th>Why</th><th>Schema effect</th></tr></thead><tbody>
<tr><td>1</td><td><strong>Escrow is a ledger _state_, not held cash</strong></td><td>An Iranian پرداخت‌یار (payment facilitator) is legally barred from custodying buyer funds; money flows card → PSP → Shaparak → registered IBANs.</td><td>New <code>ledger_entries</code> (double-entry); "escrow" derives from it.</td></tr>
<tr><td>2</td><td><strong>BNPL = full-upfront single settlement</strong></td><td>Verified: SnappPay/Digipay/Tara/Torob pay the <em>merchant</em> the whole amount minus commission in one lump and bear the customer-default risk.</td><td><strong>Cut</strong> <code>installment_plans</code>/<code>installment_entries</code>; <strong>replace</strong> with one <code>bnpl_transactions</code> row. No customer-installment tracking.</td></tr>
<tr><td>3</td><td><strong>Nurse paid by Balinyaar, on its own weekly schedule</strong></td><td>The customer's installments are owned by the BNPL provider and decoupled from our payout.</td><td>Three-way money split on <code>bookings</code>; payout independent of BNPL.</td></tr>
<tr><td>4</td><td><strong>Clawback is first-class</strong></td><td>A booking can be disputed/refunded after the nurse was already paid; the old model had nowhere to record the receivable.</td><td>New <code>nurse_clawbacks</code> + <code>dispute_window_ends_at</code> gating.</td></tr>
<tr><td>5</td><td><strong>Webhook idempotency before real money</strong></td><td>PSP/BNPL callbacks are at-least-once and retried.</td><td>New <code>payment_webhook_events</code> keyed on <code>external_event_id</code>.</td></tr>
<tr><td>6</td><td><strong>Multi-session engagements</strong></td><td>Elder care is dominantly multi-day / شبانه‌روزی (live-in); one-visit-per-booking can't model it.</td><td>New <code>booking_sessions</code>; EVV + payout move to the session.</td></tr>
<tr><td>7</td><td><strong>Partner licensed-center entity</strong></td><td>The recommended launch path is subcontracting to an MoH-licensed center; it may be the merchant-of-record/invoice issuer.</td><td>New <code>partner_centers</code> + <code>nurse_profiles.partner_center_id</code>.</td></tr>
<tr><td>8</td><td><strong>Structured credential registry</strong></td><td>The "verified" trust badge and renewal alerts need queryable license numbers/expiries, not just opaque PDF uploads.</td><td>New <code>nurse_credentials</code>.</td></tr>
<tr><td>9</td><td><strong>Cheaper search</strong></td><td>Nurse search needed 4+ joins from day one.</td><td>New denormalized <code>nurse_search_index</code>.</td></tr>
<tr><td>10</td><td><strong>Cancellation policy + tax/invoice</strong></td><td>"Default 100% refund" is naive; Iranian commission marketplaces owe VAT on commission.</td><td>New <code>cancellation_policies</code>, <code>invoices</code>; VAT <strong>10%</strong> (configurable).</td></tr>
<tr><td>11</td><td><strong>Integrity hardening</strong></td><td>Drift, double-pay, and tenancy-leak gaps the critiques found.</td><td>Drop duplicate <code>verification_status</code> &amp; <code>payout_released</code>; add uniqueness/CHECK/tenancy invariants.</td></tr>
</tbody></table></div>
<hr>
<h2 id="design-principles">Design Principles <a class="anchor" href="#design-principles" aria-hidden="true">#</a></h2>
<ol>
<li><strong>Money is <code>BIGINT</code> in Iranian Rials (IRR).</strong> Toman is a display concern only; conversion happens <strong>only at a provider's API boundary</strong> (e.g. SnappPay quotes Toman) and never internally. No floats anywhere on the money path.</li>
<li><strong>The platform never legally holds buyer cash.</strong> Funds settle through a licensed PSP/پرداخت‌یار to <strong>registered IBANs</strong> (the platform's commission IBAN and the nurse's IBAN, via تسهیم settlement-sharing, or to one merchant-of-record account). "Escrow" and "nurse balance" are <strong>derived ledger states</strong> over money custodied at the provider/partner bank — represented in <code>ledger_entries</code>, never as a Balinyaar-owned cash balance.</li>
<li><strong><code>ledger_entries</code> is the financial source of truth.</strong> Every capture, commission, payout, refund, and clawback posts <strong>balanced</strong> double-entry rows. Per-table money fields (e.g. <code>bookings.gross_price_irr</code>) remain the operational/pricing record; the ledger is the reconciliation truth that answers "how much do we owe nurses right now" and "how much is held but unreleased."</li>
<li><strong>Fee split is captured per booking and never derived from live config</strong>, so historical reporting survives commission-schedule changes. The booking stores three distinct amounts: <code>gross_price_irr</code>, <code>balinyaar_commission_irr</code>, <code>nurse_payout_amount</code>.</li>
<li><strong>PII fields</strong> (national ID, IBAN, phone, addresses, clinical data) are marked <strong>(encrypted)</strong> — column- or application-level. Clinical data has stricter access than financial data.</li>
<li><strong>Two-stage clinical disclosure is a hard rule, not a convention.</strong> At the request stage the nurse sees only <code>booking_requests.customer_notes</code>. The full encrypted <code>booking_care_instructions</code> are exposed <strong>only after</strong> the booking is confirmed. Enforced at the authorization layer.</li>
<li><strong>Soft deletes</strong> on <code>users</code>/<code>nurse_profiles</code> via <code>deleted_at</code>. Audit, payment, ledger, and payout records are <strong>never</strong> deleted.</li>
<li><strong>Audit trail is append-only.</strong> All state transitions on bookings, payments, refunds, payouts, verifications, reviews, and <code>platform_configs</code> produce an <code>audit_logs</code> row.</li>
<li><strong>Catalog/config tables are rows, not enums</strong> (service categories, verification step types, cancellation policies, Iranian holidays) so the business evolves without migrations. They carry <code>name_fa</code>/<code>name_en</code>.</li>
<li><strong>Idempotency is mandatory on the money path.</strong> Every PSP/BNPL callback is stored raw in <code>payment_webhook_events</code> and deduplicated on <code>external_event_id</code> <strong>before</strong> any money-state mutation.</li>
<li><strong>All timestamps are <code>DATETIME2(7)</code> UTC.</strong> Persian-calendar display is a UI concern — <strong>except</strong> that bank-closure scheduling uses the <code>iranian_holidays</code> table, because PAYA/SATNA transfers fail on holidays.</li>
<li><strong>Derived flags must not drift.</strong> <code>nurse_profiles.is_verified</code>, denormalized rating aggregates, and the search index are written <strong>only</strong> by the code path that owns their source of truth, inside the same transaction.</li>
<li><strong>Invariants are enforced, not just documented:</strong> CHECK constraints (<code>gross = commission + payout</code>, <code>rating BETWEEN 1 AND 5</code>, amounts ≥ 0, <code>end_time &gt; start_time</code>), filtered-UNIQUE for "one primary"/"one active", and tenancy checks (a booking's patient/address must belong to the same customer; its variant to the same nurse).</li>
</ol>
<hr>
<h2 id="the-two-questions-this-revision-answers">The two questions this revision answers <a class="anchor" href="#the-two-questions-this-revision-answers" aria-hidden="true">#</a></h2>
<p>These were the two hardest open questions (from <code>whatsInYourMind.txt</code>). Both are resolved against <strong>verified</strong> research that all mainstream Iranian provider-financed BNPLs use <strong>full-upfront settlement</strong> — the provider pays the merchant the whole amount minus commission and owns the customer's installments and default risk.</p>
<h3 id="q1-a-booking-paid-by-installments-bnpl-is-cancelled-or-refunded-mid-plan-what-happens">Q1 — A booking paid by installments (BNPL) is cancelled or refunded mid-plan. What happens? <a class="anchor" href="#q1-a-booking-paid-by-installments-bnpl-is-cancelled-or-refunded-mid-plan-what-happens" aria-hidden="true">#</a></h3>
<p>Money <strong>always</strong> flows <code>customer ↔ BNPL provider ↔ Balinyaar</code><strong>never</strong> nurse→customer, and <strong>never</strong> Balinyaar→customer directly for a BNPL order.</p>
<ol>
<li>Balinyaar initiates the reversal through the provider's API (SnappPay <code>revert</code> for full / <code>cancel</code>/<code>update</code> for partial, using the stored <code>external_payment_token</code>).</li>
<li>The provider then <strong>cancels the customer's unpaid installments</strong>, restores their credit, and <strong>refunds any already-paid installment to the customer's bank account in ~710 business days</strong> (asynchronous, owned by the provider).</li>
<li>Balinyaar records a <code>refunds</code> row with <code>refund_channel = 'bnpl_revert'</code>, carrying <code>external_revert_reference</code> and <code>expected_customer_refund_eta</code>; <code>refund_status</code> stays <code>processing</code> until a reconciliation job confirms.</li>
<li>The refund <strong>decomposes</strong> across the two fee legs — <code>platform_fee_refunded_irr</code> and <code>nurse_payout_refunded_irr</code> — and posts <strong>balanced ledger entries</strong>.</li>
<li><strong>If the nurse has not yet been paid</strong> (still inside the dispute window / not in a processed batch): the <code>nurse_payable</code> accrual is simply reversed; nothing leaves Balinyaar. Clean.</li>
<li><strong>If the nurse has already been paid:</strong> this is the <strong>clawback</strong> path — a <code>nurse_clawbacks</code> receivable + negative ledger entry; recovered from the next payout batch or written off.</li>
</ol>
<p>A shortened/partial visit maps to the provider's <code>update</code> endpoint with a reduced amount; record <code>refund_delta_irr</code> and reduce <code>bnpl_transactions.settled_amount_irr</code>.</p>
<h3 id="q2-under-bnpl-who-pays-the-nurse-and-when">Q2 — Under BNPL, who pays the nurse and when? <a class="anchor" href="#q2-under-bnpl-who-pays-the-nurse-and-when" aria-hidden="true">#</a></h3>
<p><strong>Balinyaar pays the nurse</strong>, on its <strong>own normal weekly payout schedule, after EVV completion and after the dispute window closes</strong><em>exactly the same path as a card-funded booking</em>. The BNPL provider never pays the nurse and is indifferent to the internal split.</p>
<p>The nurse's payout is computed from the booking's <strong><code>gross_price_irr</code> minus <code>balinyaar_commission_irr</code></strong><strong>never</strong> from the BNPL provider's net <code>settled_amount_irr</code>. The provider's commission (<code>bnpl_commission_irr</code>) is a <strong>platform cost of accepting BNPL</strong>, borne by Balinyaar, and must never touch the nurse's payout. Hence three separately stored amounts:</p>
<div class="table-wrap"><table><thead><tr><th>Amount</th><th>Meaning</th><th>Drives</th></tr></thead><tbody>
<tr><td><code>gross_price_irr</code></td><td>What the customer is charged (the booking price)</td><td>The invoice, the refund base</td></tr>
<tr><td><code>balinyaar_commission_irr</code></td><td>Platform's own cut</td><td>Platform revenue</td></tr>
<tr><td><code>bnpl_commission_irr</code></td><td>The BNPL provider's merchant discount (on <code>bnpl_transactions</code>)</td><td>Platform <strong>expense</strong> (never the nurse's)</td></tr>
</tbody></table></div>
<p><code>nurse_payout_amount = gross_price_irr balinyaar_commission_irr</code>. The nurse receives the identical amount and on the identical schedule whether the family paid by card or by SnappPay.</p>
<hr>
<h2 id="relationship-summary">Relationship Summary <a class="anchor" href="#relationship-summary" aria-hidden="true">#</a></h2>
<div class="table-wrap"><table><thead><tr><th>Relationship</th><th>Type</th><th>Notes</th></tr></thead><tbody>
<tr><td><code>users</code><code>nurse_profiles</code> / <code>customer_profiles</code></td><td>1:1</td><td>by <code>role</code></td></tr>
<tr><td><code>partner_centers</code><code>nurse_profiles</code></td><td>1:N</td><td>launch sponsor (NEW)</td></tr>
<tr><td><code>customer_profiles</code><code>patients</code> / <code>customer_addresses</code></td><td>1:N</td><td></td></tr>
<tr><td><code>nurse_profiles</code><code>nurse_service_variants</code> / <code>nurse_service_areas</code> / <code>nurse_bank_accounts</code> / <code>nurse_credentials</code></td><td>1:N</td><td></td></tr>
<tr><td><code>nurse_service_variants</code><code>nurse_service_variant_options</code></td><td>1:N</td><td>option combination</td></tr>
<tr><td><code>nurse_profiles</code><code>nurse_verifications</code></td><td>1:1</td><td></td></tr>
<tr><td><code>nurse_verifications</code><code>verification_steps</code><code>verification_documents</code></td><td>1:N → 1:N</td><td></td></tr>
<tr><td><code>booking_requests</code><code>bookings</code></td><td>1:1</td><td>on nurse-accept + payment</td></tr>
<tr><td><code>bookings</code><code>booking_sessions</code></td><td>1:N</td><td><strong>NEW</strong> — multi-visit engagements</td></tr>
<tr><td><code>booking_sessions</code><code>visit_verifications</code></td><td>1:1</td><td><strong>CHANGED</strong> — EVV per session</td></tr>
<tr><td><code>bookings</code><code>booking_care_instructions</code> / <code>reviews</code> / <code>invoices</code></td><td>1:1</td><td></td></tr>
<tr><td><code>bookings</code><code>payment_transactions</code></td><td>1:N</td><td>attempts</td></tr>
<tr><td><code>payment_transactions</code><code>bnpl_transactions</code></td><td>1:1</td><td>if BNPL (<strong>replaces</strong> installment_plans)</td></tr>
<tr><td><code>payment_transactions</code><code>refunds</code></td><td><strong>1:N</strong></td><td><strong>CHANGED</strong> — partials allowed</td></tr>
<tr><td><code>payment_gateways</code><code>payment_webhook_events</code></td><td>1:N</td><td><strong>NEW</strong> — idempotency</td></tr>
<tr><td><code>bookings</code> / nurses → <code>ledger_entries</code></td><td>1:N</td><td><strong>NEW</strong> — money source of truth</td></tr>
<tr><td><code>refunds</code><code>nurse_clawbacks</code></td><td>1:1 (opt)</td><td><strong>NEW</strong> — refund-after-payout</td></tr>
<tr><td><code>nurse_payout_batches</code><code>nurse_payouts</code><code>nurse_payout_booking_links</code></td><td>1:N → 1:N</td><td><code>booking_id</code> UNIQUE</td></tr>
<tr><td><code>nurse_payout_booking_links</code><code>bookings</code></td><td>1:1</td><td>exactly one payout per booking</td></tr>
<tr><td><code>patients</code><code>patient_care_records</code></td><td>1:N</td><td>longitudinal history</td></tr>
<tr><td><code>tickets</code><code>ticket_participants</code> / <code>ticket_messages</code></td><td>1:N</td><td></td></tr>
<tr><td>Sensitive entities → <code>audit_logs</code></td><td>*:N</td><td>append-only</td></tr>
</tbody></table></div>
<hr>
<h2 id="final-mvp-table-list">Final MVP table list <a class="anchor" href="#final-mvp-table-list" aria-hidden="true">#</a></h2>
<p><strong>Identity &amp; Access:</strong> <code>users</code> · <code>user_sessions</code> · <code>roles</code> · <code>user_roles</code> · <code>nurse_profiles</code> · <code>customer_profiles</code> · <code>patients</code> · <code>customer_addresses</code> · <code>nurse_bank_accounts</code> — all <strong>[CORE]</strong></p>
<p><strong>Geography:</strong> <code>provinces</code> · <code>cities</code> <strong>[CORE]</strong> · <code>districts</code> <strong>[MVP]</strong> · <code>nurse_service_areas</code> <strong>[CORE]</strong></p>
<p><strong>Services &amp; Pricing:</strong> <code>service_categories</code> · <code>service_option_groups</code> · <code>service_option_values</code> · <code>nurse_service_variants</code> · <code>nurse_service_variant_options</code> · <strong><code>nurse_search_index</code></strong> <em>(NEW)</em><strong>[CORE]</strong>; <code>nurse_availability_slots</code> · <code>nurse_availability_exceptions</code><strong>[MVP]</strong></p>
<p><strong>Verification:</strong> <code>nurse_verifications</code> · <code>verification_step_types</code> · <code>verification_steps</code> · <code>verification_documents</code> <strong>[CORE]</strong>; <strong><code>nurse_credentials</code></strong> <em>(NEW)</em> <strong>[MVP]</strong></p>
<p><strong>Booking &amp; Scheduling:</strong> <code>booking_requests</code> · <code>bookings</code> · <code>booking_care_instructions</code> · <code>visit_verifications</code> <strong>[CORE]</strong>; <strong><code>booking_sessions</code></strong> <em>(NEW)</em> · <strong><code>cancellation_policies</code></strong> <em>(NEW)</em> <strong>[MVP]</strong></p>
<p><strong>Payments &amp; Ledger:</strong> <code>payment_gateways</code> · <code>payment_transactions</code> · <strong><code>payment_webhook_events</code></strong> <em>(NEW)</em> · <code>refunds</code> · <strong><code>ledger_entries</code></strong> <em>(NEW)</em> · <strong><code>nurse_clawbacks</code></strong> <em>(NEW)</em> · <code>nurse_payout_batches</code> · <code>nurse_payouts</code> · <code>nurse_payout_booking_links</code> <strong>[CORE]</strong>; <strong><code>invoices</code></strong> <em>(NEW)</em> <strong>[MVP]</strong></p>
<p><strong>BNPL:</strong> <strong><code>bnpl_transactions</code></strong> <em>(NEW — replaces <code>installment_plans</code>)</em> <strong>[MVP]</strong>; <del><code>installment_plans</code></del> · <del><code>installment_entries</code></del> <strong>CUT</strong>; <code>bnpl_settlement_entries</code> <strong>[DEFERRED]</strong></p>
<p><strong>Messaging:</strong> <code>tickets</code> · <code>ticket_participants</code> · <code>ticket_messages</code> <strong>[CORE]</strong></p>
<p><strong>Reviews &amp; Records:</strong> <code>reviews</code> <strong>[CORE]</strong>; <code>review_tags_master</code> · <code>review_tag_links</code> · <code>patient_care_records</code> <strong>[MVP]</strong></p>
<p><strong>Notifications:</strong> <code>notifications</code> · <code>support_alerts</code> <strong>[CORE]</strong></p>
<p><strong>Audit &amp; Config:</strong> <code>audit_logs</code> <strong>[CORE]</strong> · <code>system_events</code> <strong>[MVP]</strong> · <code>platform_configs</code> <strong>[CORE]</strong> · <strong><code>iranian_holidays</code></strong> <em>(NEW)</em> <strong>[MVP]</strong></p>
<p><strong>Partner / Launch:</strong> <strong><code>partner_centers</code></strong> <em>(NEW)</em> <strong>[MVP]</strong></p>
<p><strong>Future (modeled, inactive):</strong> <code>organizations</code> · <code>organization_nurses</code> · <code>fraud_flags</code> · <code>recurring_booking_schedules</code> · <code>bnpl_settlement_entries</code> — all <strong>[DEFERRED]</strong></p>
<p><strong>Net change vs the original 45:</strong> 2 cut (<code>installment_plans</code> replaced, <code>installment_entries</code> removed), +10 added (<code>ledger_entries</code>, <code>nurse_clawbacks</code>, <code>payment_webhook_events</code>, <code>nurse_search_index</code>, <code>booking_sessions</code>, <code>cancellation_policies</code>, <code>invoices</code>, <code>partner_centers</code>, <code>nurse_credentials</code>, <code>iranian_holidays</code>), 1 replaced (<code>bnpl_transactions</code>). The financial core is now a single ledger, BNPL is one settlement row, and the clawback / dispute-window / idempotency / license / multi-session gaps are all closed.</p>
<hr>
<h2 id="key-design-decisions-the-reasoning-in-one-place">Key Design Decisions (the reasoning, in one place) <a class="anchor" href="#key-design-decisions-the-reasoning-in-one-place" aria-hidden="true">#</a></h2>
<ol>
<li><strong>Escrow as a ledger state, not platform cash</strong> — because an Iranian پرداخت‌یار legally cannot custody buyer funds. Everything else in the money domain follows from honestly representing "we don't hold the cash; we hold a claim/obligation tracked in the ledger over funds at a licensed provider." This is also why payouts are modeled as provider-side settlement to <strong>verified, ownership-checked</strong> IBANs.</li>
</ol>
<ol>
<li><strong>A BNPL order is a net-of-fee inbound payment, full stop</strong> — the verified full-upfront settlement model means there is no customer receivable, no default risk, and no installment schedule for Balinyaar to track. Deleting <code>installment_entries</code> removed an entire fragile subsystem and replaced it with one reconciliation row.</li>
</ol>
<ol>
<li><strong>Three separate money amounts</strong> so the platform's two fee deductions (its own commission, and the BNPL provider's discount) are never conflated, and the nurse is paid identically regardless of payment method.</li>
</ol>
<ol>
<li><strong>Double-entry over status flags</strong> — the previous model could not answer "how much do we owe nurses right now" without fragile joins, and had nowhere to record a refund-after-payout. One append-only ledger + a <code>nurse_clawbacks</code> receivable fixes both and makes bank/Shaparak reconciliation possible.</li>
</ol>
<ol>
<li><strong>Dispute window gates payout</strong> — preferring a <em>holding period</em> over a <em>clawback</em>, because clawback against an already-paid nurse IBAN is largely unenforceable. The clawback path exists for the cases that slip through.</li>
</ol>
<ol>
<li><strong>Idempotency before money</strong><code>payment_webhook_events</code> keyed on the provider event id, written first, is the cheapest insurance against the most damaging payments bug (double-confirm / double-settle on callback retries).</li>
</ol>
<ol>
<li><strong>Multi-session engagements are the norm, not an edge case</strong><code>booking_sessions</code> makes long elder-care arrangements representable, lets escrow release per completed visit instead of holding a month of money, and makes mid-engagement cancellation accounting clean.</li>
</ol>
<ol>
<li><strong>Partner center is launch-critical</strong> — it is the legal vehicle and likely merchant-of-record; without it the recommended go-to-market and the money flow are not representable.</li>
</ol>
<ol>
<li><strong>Verified-trust must be queryable</strong><code>nurse_credentials</code> turns the brand promise into renewal alerts, a real badge, and audit defensibility, surviving the future arrival of an INO/MoH API.</li>
</ol>
<ol>
<li><strong>Keep the configurable service EAV; cut the analytics scaffolding</strong> — the category/option model earns its complexity (admin-extensible pricing dimensions without migrations); <code>response_rate</code>/<code>profile_completion_score</code>/<code>system_events</code>-in-SQL do not, at launch.</li>
</ol>
<hr>
<h2 id="open-items-to-confirm-before-building-not-schema-blockers">Open items to confirm before building (not schema blockers) <a class="anchor" href="#open-items-to-confirm-before-building-not-schema-blockers" aria-hidden="true">#</a></h2>
<ul>
<li><strong>BNPL provider contract:</strong> does SnappPay/Digipay permit a multi-vendor marketplace re-disbursing to many nurses as a single merchant? (Publicly undocumented — confirm with sales.) The schema assumes <strong>one lump to Balinyaar/the center, internal allocation to nurses</strong>, so this is an ops confirmation, not a schema dependency.</li>
<li><strong>Commission %</strong> and <strong>settlement SLA</strong> per provider (and whether the provider returns its commission on a refund — full or pro-rata).</li>
<li><strong>PSP/تسهیم provider</strong> for MVP (ZarinPal Multiplexing vs Vandar vs Jibit) and whether it permits the hold-then-weekly-payout timing, or whether a bank-grade escrow (Vandar میندو) is needed.</li>
<li><strong>VAT exemption</strong> ruling on the nursing service itself (the commission line is taxable regardless) — <code>vat_rate</code> is config-driven so either ruling is a value change.</li>
<li><strong>مودیان</strong> enrollment thresholds for the platform and high-earning nurses.</li>
</ul>
<blockquote><p>Confirm decades-old regulations, provider fee/settlement specifics, and tax thresholds against current primary sources and the provider's compliance team before building the payment integration. See the <a href="../payments/index.html">payments deep-dive</a> for the full source-cited analysis.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+196
View File
@@ -0,0 +1,196 @@
# Database Model
> **Revision 2 — 2026-06-20.** This is a research-driven refinement of the original 13-domain model. It closes the financial-correctness gaps the previous version flagged in its own _Advices_ section, resolves the two open BNPL questions, and grounds every money decision in verified research on the Iranian payment landscape (SnappPay, Digipay, Tara, Torob Pay, Shaparak/پرداخت‌یار rules). The previous revision is preserved in git history.
>
> Companion documents: **[business requirements](../business/index.md)** (per-section product requirements) and **[payments deep-dive](../payments/index.md)** (the BNPL/escrow deep-dive with sources).
## Contents
- [Diagrams](diagrams.md)
- [Domain 1 — Identity & Access](01-identity-and-access.md)
- [Domain 2 — Geographic Data](02-geography.md)
- [Domain 3 — Services & Pricing](03-services-and-pricing.md)
- [Domain 4 — Verification & Credentials](04-verification-and-credentials.md)
- [Domain 5 — Booking & Scheduling](05-booking-and-scheduling.md)
- [Domain 6 — Payments, Ledger & Refunds](06-payments-ledger-and-refunds.md)
- [Domain 7 — Payouts to Nurses](07-payouts.md)
- [Domain 8 — BNPL / Installments](08-bnpl.md)
- [Domain 9 — Messaging (Ticket System)](09-messaging.md)
- [Domain 10 — Reviews & Patient Records](10-reviews-and-records.md)
- [Domain 11 — Notifications](11-notifications.md)
- [Domain 12 — Audit, Config & Reference](12-audit-config-and-reference.md)
- [Domain 13 — Partner Centers (launch) & Future](13-partner-centers-and-future.md)
---
## Platform Summary
Balinyaar is a trust-first home-nursing marketplace in Iran. Independent, individually-verified nurses register, list configurable services with their own pricing, and pass a multi-step verification pipeline anchored on the MoH **پروانه صلاحیت حرفه‌ای** (professional-competency license). Families search — filtered by city/district **and same-gender caregiver preference** — pick a nurse and a service variant, submit a booking request, and pay **through the platform** after the nurse accepts. The platform records the money as an **internal escrow ledger state** (not platform-held cash — see Principle 2), the nurse performs one or more EVV-verified visits, and the platform pays the nurse **weekly, after the dispute window closes**, minus a platform commission. All post-booking communication runs through an admin-readable ticket system.
At launch the platform operates under a **partner licensed home-nursing center (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل)** — the Asanism-style model — which is the legal vehicle and the likely **merchant-of-record** for payments while Balinyaar's own MoH permit is in process.
---
## What changed in this revision (decision summary)
| # | Decision | Why | Schema effect |
|---|---|---|---|
| 1 | **Escrow is a ledger _state_, not held cash** | An Iranian پرداخت‌یار (payment facilitator) is legally barred from custodying buyer funds; money flows card → PSP → Shaparak → registered IBANs. | New `ledger_entries` (double-entry); "escrow" derives from it. |
| 2 | **BNPL = full-upfront single settlement** | Verified: SnappPay/Digipay/Tara/Torob pay the *merchant* the whole amount minus commission in one lump and bear the customer-default risk. | **Cut** `installment_plans`/`installment_entries`; **replace** with one `bnpl_transactions` row. No customer-installment tracking. |
| 3 | **Nurse paid by Balinyaar, on its own weekly schedule** | The customer's installments are owned by the BNPL provider and decoupled from our payout. | Three-way money split on `bookings`; payout independent of BNPL. |
| 4 | **Clawback is first-class** | A booking can be disputed/refunded after the nurse was already paid; the old model had nowhere to record the receivable. | New `nurse_clawbacks` + `dispute_window_ends_at` gating. |
| 5 | **Webhook idempotency before real money** | PSP/BNPL callbacks are at-least-once and retried. | New `payment_webhook_events` keyed on `external_event_id`. |
| 6 | **Multi-session engagements** | Elder care is dominantly multi-day / شبانه‌روزی (live-in); one-visit-per-booking can't model it. | New `booking_sessions`; EVV + payout move to the session. |
| 7 | **Partner licensed-center entity** | The recommended launch path is subcontracting to an MoH-licensed center; it may be the merchant-of-record/invoice issuer. | New `partner_centers` + `nurse_profiles.partner_center_id`. |
| 8 | **Structured credential registry** | The "verified" trust badge and renewal alerts need queryable license numbers/expiries, not just opaque PDF uploads. | New `nurse_credentials`. |
| 9 | **Cheaper search** | Nurse search needed 4+ joins from day one. | New denormalized `nurse_search_index`. |
| 10 | **Cancellation policy + tax/invoice** | "Default 100% refund" is naive; Iranian commission marketplaces owe VAT on commission. | New `cancellation_policies`, `invoices`; VAT **10%** (configurable). |
| 11 | **Integrity hardening** | Drift, double-pay, and tenancy-leak gaps the critiques found. | Drop duplicate `verification_status` & `payout_released`; add uniqueness/CHECK/tenancy invariants. |
---
## Design Principles
1. **Money is `BIGINT` in Iranian Rials (IRR).** Toman is a display concern only; conversion happens **only at a provider's API boundary** (e.g. SnappPay quotes Toman) and never internally. No floats anywhere on the money path.
2. **The platform never legally holds buyer cash.** Funds settle through a licensed PSP/پرداخت‌یار to **registered IBANs** (the platform's commission IBAN and the nurse's IBAN, via تسهیم settlement-sharing, or to one merchant-of-record account). "Escrow" and "nurse balance" are **derived ledger states** over money custodied at the provider/partner bank — represented in `ledger_entries`, never as a Balinyaar-owned cash balance.
3. **`ledger_entries` is the financial source of truth.** Every capture, commission, payout, refund, and clawback posts **balanced** double-entry rows. Per-table money fields (e.g. `bookings.gross_price_irr`) remain the operational/pricing record; the ledger is the reconciliation truth that answers "how much do we owe nurses right now" and "how much is held but unreleased."
4. **Fee split is captured per booking and never derived from live config**, so historical reporting survives commission-schedule changes. The booking stores three distinct amounts: `gross_price_irr`, `balinyaar_commission_irr`, `nurse_payout_amount`.
5. **PII fields** (national ID, IBAN, phone, addresses, clinical data) are marked **(encrypted)** — column- or application-level. Clinical data has stricter access than financial data.
6. **Two-stage clinical disclosure is a hard rule, not a convention.** At the request stage the nurse sees only `booking_requests.customer_notes`. The full encrypted `booking_care_instructions` are exposed **only after** the booking is confirmed. Enforced at the authorization layer.
7. **Soft deletes** on `users`/`nurse_profiles` via `deleted_at`. Audit, payment, ledger, and payout records are **never** deleted.
8. **Audit trail is append-only.** All state transitions on bookings, payments, refunds, payouts, verifications, reviews, and `platform_configs` produce an `audit_logs` row.
9. **Catalog/config tables are rows, not enums** (service categories, verification step types, cancellation policies, Iranian holidays) so the business evolves without migrations. They carry `name_fa`/`name_en`.
10. **Idempotency is mandatory on the money path.** Every PSP/BNPL callback is stored raw in `payment_webhook_events` and deduplicated on `external_event_id` **before** any money-state mutation.
11. **All timestamps are `DATETIME2(7)` UTC.** Persian-calendar display is a UI concern — **except** that bank-closure scheduling uses the `iranian_holidays` table, because PAYA/SATNA transfers fail on holidays.
12. **Derived flags must not drift.** `nurse_profiles.is_verified`, denormalized rating aggregates, and the search index are written **only** by the code path that owns their source of truth, inside the same transaction.
13. **Invariants are enforced, not just documented:** CHECK constraints (`gross = commission + payout`, `rating BETWEEN 1 AND 5`, amounts ≥ 0, `end_time > start_time`), filtered-UNIQUE for "one primary"/"one active", and tenancy checks (a booking's patient/address must belong to the same customer; its variant to the same nurse).
---
## The two questions this revision answers
These were the two hardest open questions (from `whatsInYourMind.txt`). Both are resolved against **verified** research that all mainstream Iranian provider-financed BNPLs use **full-upfront settlement** — the provider pays the merchant the whole amount minus commission and owns the customer's installments and default risk.
### Q1 — A booking paid by installments (BNPL) is cancelled or refunded mid-plan. What happens?
Money **always** flows `customer ↔ BNPL provider ↔ Balinyaar`**never** nurse→customer, and **never** Balinyaar→customer directly for a BNPL order.
1. Balinyaar initiates the reversal through the provider's API (SnappPay `revert` for full / `cancel`/`update` for partial, using the stored `external_payment_token`).
2. The provider then **cancels the customer's unpaid installments**, restores their credit, and **refunds any already-paid installment to the customer's bank account in ~710 business days** (asynchronous, owned by the provider).
3. Balinyaar records a `refunds` row with `refund_channel = 'bnpl_revert'`, carrying `external_revert_reference` and `expected_customer_refund_eta`; `refund_status` stays `processing` until a reconciliation job confirms.
4. The refund **decomposes** across the two fee legs — `platform_fee_refunded_irr` and `nurse_payout_refunded_irr` — and posts **balanced ledger entries**.
5. **If the nurse has not yet been paid** (still inside the dispute window / not in a processed batch): the `nurse_payable` accrual is simply reversed; nothing leaves Balinyaar. Clean.
6. **If the nurse has already been paid:** this is the **clawback** path — a `nurse_clawbacks` receivable + negative ledger entry; recovered from the next payout batch or written off.
A shortened/partial visit maps to the provider's `update` endpoint with a reduced amount; record `refund_delta_irr` and reduce `bnpl_transactions.settled_amount_irr`.
### Q2 — Under BNPL, who pays the nurse and when?
**Balinyaar pays the nurse**, on its **own normal weekly payout schedule, after EVV completion and after the dispute window closes***exactly the same path as a card-funded booking*. The BNPL provider never pays the nurse and is indifferent to the internal split.
The nurse's payout is computed from the booking's **`gross_price_irr` minus `balinyaar_commission_irr`** — **never** from the BNPL provider's net `settled_amount_irr`. The provider's commission (`bnpl_commission_irr`) is a **platform cost of accepting BNPL**, borne by Balinyaar, and must never touch the nurse's payout. Hence three separately stored amounts:
| Amount | Meaning | Drives |
|---|---|---|
| `gross_price_irr` | What the customer is charged (the booking price) | The invoice, the refund base |
| `balinyaar_commission_irr` | Platform's own cut | Platform revenue |
| `bnpl_commission_irr` | The BNPL provider's merchant discount (on `bnpl_transactions`) | Platform **expense** (never the nurse's) |
`nurse_payout_amount = gross_price_irr balinyaar_commission_irr`. The nurse receives the identical amount and on the identical schedule whether the family paid by card or by SnappPay.
---
## Relationship Summary
| Relationship | Type | Notes |
|---|---|---|
| `users``nurse_profiles` / `customer_profiles` | 1:1 | by `role` |
| `partner_centers``nurse_profiles` | 1:N | launch sponsor (NEW) |
| `customer_profiles``patients` / `customer_addresses` | 1:N | |
| `nurse_profiles``nurse_service_variants` / `nurse_service_areas` / `nurse_bank_accounts` / `nurse_credentials` | 1:N | |
| `nurse_service_variants``nurse_service_variant_options` | 1:N | option combination |
| `nurse_profiles``nurse_verifications` | 1:1 | |
| `nurse_verifications``verification_steps``verification_documents` | 1:N → 1:N | |
| `booking_requests``bookings` | 1:1 | on nurse-accept + payment |
| `bookings``booking_sessions` | 1:N | **NEW** — multi-visit engagements |
| `booking_sessions``visit_verifications` | 1:1 | **CHANGED** — EVV per session |
| `bookings``booking_care_instructions` / `reviews` / `invoices` | 1:1 | |
| `bookings``payment_transactions` | 1:N | attempts |
| `payment_transactions``bnpl_transactions` | 1:1 | if BNPL (**replaces** installment_plans) |
| `payment_transactions``refunds` | **1:N** | **CHANGED** — partials allowed |
| `payment_gateways``payment_webhook_events` | 1:N | **NEW** — idempotency |
| `bookings` / nurses → `ledger_entries` | 1:N | **NEW** — money source of truth |
| `refunds``nurse_clawbacks` | 1:1 (opt) | **NEW** — refund-after-payout |
| `nurse_payout_batches``nurse_payouts``nurse_payout_booking_links` | 1:N → 1:N | `booking_id` UNIQUE |
| `nurse_payout_booking_links``bookings` | 1:1 | exactly one payout per booking |
| `patients``patient_care_records` | 1:N | longitudinal history |
| `tickets``ticket_participants` / `ticket_messages` | 1:N | |
| Sensitive entities → `audit_logs` | *:N | append-only |
---
## Final MVP table list
**Identity & Access:** `users` · `user_sessions` · `roles` · `user_roles` · `nurse_profiles` · `customer_profiles` · `patients` · `customer_addresses` · `nurse_bank_accounts` — all **[CORE]**
**Geography:** `provinces` · `cities` **[CORE]** · `districts` **[MVP]** · `nurse_service_areas` **[CORE]**
**Services & Pricing:** `service_categories` · `service_option_groups` · `service_option_values` · `nurse_service_variants` · `nurse_service_variant_options` · **`nurse_search_index`** *(NEW)***[CORE]**; `nurse_availability_slots` · `nurse_availability_exceptions`**[MVP]**
**Verification:** `nurse_verifications` · `verification_step_types` · `verification_steps` · `verification_documents` **[CORE]**; **`nurse_credentials`** *(NEW)* **[MVP]**
**Booking & Scheduling:** `booking_requests` · `bookings` · `booking_care_instructions` · `visit_verifications` **[CORE]**; **`booking_sessions`** *(NEW)* · **`cancellation_policies`** *(NEW)* **[MVP]**
**Payments & Ledger:** `payment_gateways` · `payment_transactions` · **`payment_webhook_events`** *(NEW)* · `refunds` · **`ledger_entries`** *(NEW)* · **`nurse_clawbacks`** *(NEW)* · `nurse_payout_batches` · `nurse_payouts` · `nurse_payout_booking_links` **[CORE]**; **`invoices`** *(NEW)* **[MVP]**
**BNPL:** **`bnpl_transactions`** *(NEW — replaces `installment_plans`)* **[MVP]**; ~~`installment_plans`~~ · ~~`installment_entries`~~ **CUT**; `bnpl_settlement_entries` **[DEFERRED]**
**Messaging:** `tickets` · `ticket_participants` · `ticket_messages` **[CORE]**
**Reviews & Records:** `reviews` **[CORE]**; `review_tags_master` · `review_tag_links` · `patient_care_records` **[MVP]**
**Notifications:** `notifications` · `support_alerts` **[CORE]**
**Audit & Config:** `audit_logs` **[CORE]** · `system_events` **[MVP]** · `platform_configs` **[CORE]** · **`iranian_holidays`** *(NEW)* **[MVP]**
**Partner / Launch:** **`partner_centers`** *(NEW)* **[MVP]**
**Future (modeled, inactive):** `organizations` · `organization_nurses` · `fraud_flags` · `recurring_booking_schedules` · `bnpl_settlement_entries` — all **[DEFERRED]**
**Net change vs the original 45:** 2 cut (`installment_plans` replaced, `installment_entries` removed), +10 added (`ledger_entries`, `nurse_clawbacks`, `payment_webhook_events`, `nurse_search_index`, `booking_sessions`, `cancellation_policies`, `invoices`, `partner_centers`, `nurse_credentials`, `iranian_holidays`), 1 replaced (`bnpl_transactions`). The financial core is now a single ledger, BNPL is one settlement row, and the clawback / dispute-window / idempotency / license / multi-session gaps are all closed.
---
## Key Design Decisions (the reasoning, in one place)
1. **Escrow as a ledger state, not platform cash** — because an Iranian پرداخت‌یار legally cannot custody buyer funds. Everything else in the money domain follows from honestly representing "we don't hold the cash; we hold a claim/obligation tracked in the ledger over funds at a licensed provider." This is also why payouts are modeled as provider-side settlement to **verified, ownership-checked** IBANs.
2. **A BNPL order is a net-of-fee inbound payment, full stop** — the verified full-upfront settlement model means there is no customer receivable, no default risk, and no installment schedule for Balinyaar to track. Deleting `installment_entries` removed an entire fragile subsystem and replaced it with one reconciliation row.
3. **Three separate money amounts** so the platform's two fee deductions (its own commission, and the BNPL provider's discount) are never conflated, and the nurse is paid identically regardless of payment method.
4. **Double-entry over status flags** — the previous model could not answer "how much do we owe nurses right now" without fragile joins, and had nowhere to record a refund-after-payout. One append-only ledger + a `nurse_clawbacks` receivable fixes both and makes bank/Shaparak reconciliation possible.
5. **Dispute window gates payout** — preferring a *holding period* over a *clawback*, because clawback against an already-paid nurse IBAN is largely unenforceable. The clawback path exists for the cases that slip through.
6. **Idempotency before money**`payment_webhook_events` keyed on the provider event id, written first, is the cheapest insurance against the most damaging payments bug (double-confirm / double-settle on callback retries).
7. **Multi-session engagements are the norm, not an edge case**`booking_sessions` makes long elder-care arrangements representable, lets escrow release per completed visit instead of holding a month of money, and makes mid-engagement cancellation accounting clean.
8. **Partner center is launch-critical** — it is the legal vehicle and likely merchant-of-record; without it the recommended go-to-market and the money flow are not representable.
9. **Verified-trust must be queryable**`nurse_credentials` turns the brand promise into renewal alerts, a real badge, and audit defensibility, surviving the future arrival of an INO/MoH API.
10. **Keep the configurable service EAV; cut the analytics scaffolding** — the category/option model earns its complexity (admin-extensible pricing dimensions without migrations); `response_rate`/`profile_completion_score`/`system_events`-in-SQL do not, at launch.
---
## Open items to confirm before building (not schema blockers)
- **BNPL provider contract:** does SnappPay/Digipay permit a multi-vendor marketplace re-disbursing to many nurses as a single merchant? (Publicly undocumented — confirm with sales.) The schema assumes **one lump to Balinyaar/the center, internal allocation to nurses**, so this is an ops confirmation, not a schema dependency.
- **Commission %** and **settlement SLA** per provider (and whether the provider returns its commission on a refund — full or pro-rata).
- **PSP/تسهیم provider** for MVP (ZarinPal Multiplexing vs Vandar vs Jibit) and whether it permits the hold-then-weekly-payout timing, or whether a bank-grade escrow (Vandar میندو) is needed.
- **VAT exemption** ruling on the nursing service itself (the commission line is taxable regardless) — `vat_rate` is config-driven so either ruling is a value change.
- **مودیان** enrollment thresholds for the platform and high-earning nurses.
> Confirm decades-old regulations, provider fee/settlement specifics, and tax thresholds against current primary sources and the provider's compliance team before building the payment integration. See the [payments deep-dive](../payments/index.md) for the full source-cited analysis.
-835
View File
@@ -1,835 +0,0 @@
# Balinyaar — Database Model (Refined Core)
> **Revision 2 — 2026-06-20.** This is a research-driven refinement of the original 13-domain model. It closes the financial-correctness gaps the previous version flagged in its own _Advices_ section, resolves the two open BNPL questions, and grounds every money decision in verified research on the Iranian payment landscape (SnappPay, Digipay, Tara, Torob Pay, Shaparak/پرداخت‌یار rules). The previous revision is preserved in git history.
>
> Companion documents: **`business-requirements.md`** (per-section product requirements) and **`payments-and-installments.md`** (the BNPL/escrow deep-dive with sources).
---
## Platform Summary
Balinyaar is a trust-first home-nursing marketplace in Iran. Independent, individually-verified nurses register, list configurable services with their own pricing, and pass a multi-step verification pipeline anchored on the MoH **پروانه صلاحیت حرفه‌ای** (professional-competency license). Families search — filtered by city/district **and same-gender caregiver preference** — pick a nurse and a service variant, submit a booking request, and pay **through the platform** after the nurse accepts. The platform records the money as an **internal escrow ledger state** (not platform-held cash — see Principle 2), the nurse performs one or more EVV-verified visits, and the platform pays the nurse **weekly, after the dispute window closes**, minus a platform commission. All post-booking communication runs through an admin-readable ticket system.
At launch the platform operates under a **partner licensed home-nursing center (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل)** — the Asanism-style model — which is the legal vehicle and the likely **merchant-of-record** for payments while Balinyaar's own MoH permit is in process.
---
## What changed in this revision (decision summary)
| # | Decision | Why | Schema effect |
|---|---|---|---|
| 1 | **Escrow is a ledger _state_, not held cash** | An Iranian پرداخت‌یار (payment facilitator) is legally barred from custodying buyer funds; money flows card → PSP → Shaparak → registered IBANs. | New `ledger_entries` (double-entry); "escrow" derives from it. |
| 2 | **BNPL = full-upfront single settlement** | Verified: SnappPay/Digipay/Tara/Torob pay the *merchant* the whole amount minus commission in one lump and bear the customer-default risk. | **Cut** `installment_plans`/`installment_entries`; **replace** with one `bnpl_transactions` row. No customer-installment tracking. |
| 3 | **Nurse paid by Balinyaar, on its own weekly schedule** | The customer's installments are owned by the BNPL provider and decoupled from our payout. | Three-way money split on `bookings`; payout independent of BNPL. |
| 4 | **Clawback is first-class** | A booking can be disputed/refunded after the nurse was already paid; the old model had nowhere to record the receivable. | New `nurse_clawbacks` + `dispute_window_ends_at` gating. |
| 5 | **Webhook idempotency before real money** | PSP/BNPL callbacks are at-least-once and retried. | New `payment_webhook_events` keyed on `external_event_id`. |
| 6 | **Multi-session engagements** | Elder care is dominantly multi-day / شبانه‌روزی (live-in); one-visit-per-booking can't model it. | New `booking_sessions`; EVV + payout move to the session. |
| 7 | **Partner licensed-center entity** | The recommended launch path is subcontracting to an MoH-licensed center; it may be the merchant-of-record/invoice issuer. | New `partner_centers` + `nurse_profiles.partner_center_id`. |
| 8 | **Structured credential registry** | The "verified" trust badge and renewal alerts need queryable license numbers/expiries, not just opaque PDF uploads. | New `nurse_credentials`. |
| 9 | **Cheaper search** | Nurse search needed 4+ joins from day one. | New denormalized `nurse_search_index`. |
| 10 | **Cancellation policy + tax/invoice** | "Default 100% refund" is naive; Iranian commission marketplaces owe VAT on commission. | New `cancellation_policies`, `invoices`; VAT **10%** (configurable). |
| 11 | **Integrity hardening** | Drift, double-pay, and tenancy-leak gaps the critiques found. | Drop duplicate `verification_status` & `payout_released`; add uniqueness/CHECK/tenancy invariants. |
---
## Design Principles
1. **Money is `BIGINT` in Iranian Rials (IRR).** Toman is a display concern only; conversion happens **only at a provider's API boundary** (e.g. SnappPay quotes Toman) and never internally. No floats anywhere on the money path.
2. **The platform never legally holds buyer cash.** Funds settle through a licensed PSP/پرداخت‌یار to **registered IBANs** (the platform's commission IBAN and the nurse's IBAN, via تسهیم settlement-sharing, or to one merchant-of-record account). "Escrow" and "nurse balance" are **derived ledger states** over money custodied at the provider/partner bank — represented in `ledger_entries`, never as a Balinyaar-owned cash balance.
3. **`ledger_entries` is the financial source of truth.** Every capture, commission, payout, refund, and clawback posts **balanced** double-entry rows. Per-table money fields (e.g. `bookings.gross_price_irr`) remain the operational/pricing record; the ledger is the reconciliation truth that answers "how much do we owe nurses right now" and "how much is held but unreleased."
4. **Fee split is captured per booking and never derived from live config**, so historical reporting survives commission-schedule changes. The booking stores three distinct amounts: `gross_price_irr`, `balinyaar_commission_irr`, `nurse_payout_amount`.
5. **PII fields** (national ID, IBAN, phone, addresses, clinical data) are marked **(encrypted)** — column- or application-level. Clinical data has stricter access than financial data.
6. **Two-stage clinical disclosure is a hard rule, not a convention.** At the request stage the nurse sees only `booking_requests.customer_notes`. The full encrypted `booking_care_instructions` are exposed **only after** the booking is confirmed. Enforced at the authorization layer.
7. **Soft deletes** on `users`/`nurse_profiles` via `deleted_at`. Audit, payment, ledger, and payout records are **never** deleted.
8. **Audit trail is append-only.** All state transitions on bookings, payments, refunds, payouts, verifications, reviews, and `platform_configs` produce an `audit_logs` row.
9. **Catalog/config tables are rows, not enums** (service categories, verification step types, cancellation policies, Iranian holidays) so the business evolves without migrations. They carry `name_fa`/`name_en`.
10. **Idempotency is mandatory on the money path.** Every PSP/BNPL callback is stored raw in `payment_webhook_events` and deduplicated on `external_event_id` **before** any money-state mutation.
11. **All timestamps are `DATETIME2(7)` UTC.** Persian-calendar display is a UI concern — **except** that bank-closure scheduling uses the `iranian_holidays` table, because PAYA/SATNA transfers fail on holidays.
12. **Derived flags must not drift.** `nurse_profiles.is_verified`, denormalized rating aggregates, and the search index are written **only** by the code path that owns their source of truth, inside the same transaction.
13. **Invariants are enforced, not just documented:** CHECK constraints (`gross = commission + payout`, `rating BETWEEN 1 AND 5`, amounts ≥ 0, `end_time > start_time`), filtered-UNIQUE for "one primary"/"one active", and tenancy checks (a booking's patient/address must belong to the same customer; its variant to the same nurse).
---
## The two questions this revision answers
These were the two hardest open questions (from `whatsInYourMind.txt`). Both are resolved against **verified** research that all mainstream Iranian provider-financed BNPLs use **full-upfront settlement** — the provider pays the merchant the whole amount minus commission and owns the customer's installments and default risk.
### Q1 — A booking paid by installments (BNPL) is cancelled or refunded mid-plan. What happens?
Money **always** flows `customer ↔ BNPL provider ↔ Balinyaar`**never** nurse→customer, and **never** Balinyaar→customer directly for a BNPL order.
1. Balinyaar initiates the reversal through the provider's API (SnappPay `revert` for full / `cancel`/`update` for partial, using the stored `external_payment_token`).
2. The provider then **cancels the customer's unpaid installments**, restores their credit, and **refunds any already-paid installment to the customer's bank account in ~710 business days** (asynchronous, owned by the provider).
3. Balinyaar records a `refunds` row with `refund_channel = 'bnpl_revert'`, carrying `external_revert_reference` and `expected_customer_refund_eta`; `refund_status` stays `processing` until a reconciliation job confirms.
4. The refund **decomposes** across the two fee legs — `platform_fee_refunded_irr` and `nurse_payout_refunded_irr` — and posts **balanced ledger entries**.
5. **If the nurse has not yet been paid** (still inside the dispute window / not in a processed batch): the `nurse_payable` accrual is simply reversed; nothing leaves Balinyaar. Clean.
6. **If the nurse has already been paid:** this is the **clawback** path — a `nurse_clawbacks` receivable + negative ledger entry; recovered from the next payout batch or written off.
A shortened/partial visit maps to the provider's `update` endpoint with a reduced amount; record `refund_delta_irr` and reduce `bnpl_transactions.settled_amount_irr`.
### Q2 — Under BNPL, who pays the nurse and when?
**Balinyaar pays the nurse**, on its **own normal weekly payout schedule, after EVV completion and after the dispute window closes***exactly the same path as a card-funded booking*. The BNPL provider never pays the nurse and is indifferent to the internal split.
The nurse's payout is computed from the booking's **`gross_price_irr` minus `balinyaar_commission_irr`** — **never** from the BNPL provider's net `settled_amount_irr`. The provider's commission (`bnpl_commission_irr`) is a **platform cost of accepting BNPL**, borne by Balinyaar, and must never touch the nurse's payout. Hence three separately stored amounts:
| Amount | Meaning | Drives |
|---|---|---|
| `gross_price_irr` | What the customer is charged (the booking price) | The invoice, the refund base |
| `balinyaar_commission_irr` | Platform's own cut | Platform revenue |
| `bnpl_commission_irr` | The BNPL provider's merchant discount (on `bnpl_transactions`) | Platform **expense** (never the nurse's) |
`nurse_payout_amount = gross_price_irr balinyaar_commission_irr`. The nurse receives the identical amount and on the identical schedule whether the family paid by card or by SnappPay.
---
## Diagrams
### 1. Domain map — how the clusters relate
```mermaid
flowchart LR
PARTNER["🏥 Partner Centers (launch)<br/>partner_centers"]
IDENTITY["🧑 Identity & Access<br/>users · nurse_profiles · customer_profiles<br/>patients · customer_addresses · nurse_bank_accounts"]
GEO["📍 Geography<br/>provinces · cities · districts · nurse_service_areas"]
VERIFY["✅ Verification<br/>nurse_verifications · step_types · steps<br/>documents · nurse_credentials"]
SERVICES["🩺 Services & Pricing<br/>service_categories · option_groups · option_values<br/>variants · variant_options · search_index · availability"]
BOOKING["📅 Booking & Scheduling<br/>booking_requests · bookings · booking_sessions<br/>care_instructions · visit_verifications · cancellation_policies"]
PAY["💳 Payments & Ledger<br/>payment_gateways · payment_transactions · webhook_events<br/>refunds · ledger_entries · nurse_clawbacks · invoices"]
BNPL["🧾 BNPL<br/>bnpl_transactions"]
PAYOUT["🏦 Payouts<br/>payout_batches · payouts · booking_links"]
REVIEW["⭐ Reviews & Records<br/>reviews · review_tags · patient_care_records"]
MSG["💬 Messaging<br/>tickets · participants · messages"]
NOTIFY["🔔 Notifications<br/>notifications · support_alerts"]
AUDITCFG["📜 Audit & Config<br/>audit_logs · system_events<br/>platform_configs · iranian_holidays"]
PARTNER -. "sponsors / merchant-of-record" .-> VERIFY
IDENTITY --> VERIFY
VERIFY --> SERVICES
SERVICES --> GEO
IDENTITY --> BOOKING
SERVICES --> BOOKING
BOOKING --> PAY
PAY --> BNPL
PAY --> PAYOUT
BOOKING --> REVIEW
BOOKING --> MSG
PAY --> NOTIFY
PAY --> AUDITCFG
```
### 2. Core booking spine (who books whom)
```mermaid
erDiagram
users ||--o| nurse_profiles : "role=nurse"
users ||--o| customer_profiles : "role=customer"
partner_centers ||--o{ nurse_profiles : "sponsors"
customer_profiles ||--o{ patients : "registers"
customer_profiles ||--o{ customer_addresses : "saves"
nurse_profiles ||--o{ nurse_service_variants : "offers"
customer_profiles ||--o{ booking_requests : "submits"
nurse_profiles ||--o{ booking_requests : "receives"
patients ||--o{ booking_requests : "for patient"
nurse_service_variants ||--o{ booking_requests : "selects variant"
booking_requests ||--o| bookings : "converts on payment"
bookings ||--o{ booking_sessions : "has visits"
booking_sessions ||--o| visit_verifications : "EVV per visit"
bookings ||--o| booking_care_instructions : "clinical (encrypted)"
bookings ||--o| reviews : "one review"
booking_requests {
bigint id PK
string status
string required_caregiver_gender
datetime nurse_response_deadline_at
datetime payment_deadline_at
}
bookings {
bigint id PK
bigint gross_price_irr
bigint balinyaar_commission_irr
bigint nurse_payout_amount
smallint session_count
datetime dispute_window_ends_at
string status
}
booking_sessions {
bigint id PK
int session_index
date scheduled_date
string status
datetime payout_eligible_at
}
```
### 3. Payments, ledger & payouts
```mermaid
erDiagram
bookings ||--o{ payment_transactions : "paid by (attempts)"
payment_gateways ||--o{ payment_transactions : "via"
payment_gateways ||--o{ payment_webhook_events : "emits"
payment_transactions ||--o| bnpl_transactions : "if BNPL"
payment_transactions ||--o{ refunds : "may be refunded"
refunds ||--o| nurse_clawbacks : "if after payout"
nurse_profiles ||--o{ nurse_clawbacks : "owes"
bookings ||--o{ ledger_entries : "money postings"
bookings ||--o| invoices : "billed"
nurse_payout_batches ||--o{ nurse_payouts : "groups"
nurse_profiles ||--o{ nurse_payouts : "receives"
nurse_bank_accounts ||--o{ nurse_payouts : "to IBAN"
nurse_payouts ||--o{ nurse_payout_booking_links : "covers"
bookings ||--o| nurse_payout_booking_links : "settled in one"
ledger_entries {
bigint id PK
uuid transaction_group_id
string account_type
string direction
bigint amount_irr
}
refunds {
bigint id PK
bigint platform_fee_refunded_irr
bigint nurse_payout_refunded_irr
string refund_channel
}
bnpl_transactions {
bigint id PK
string provider_code
bigint settled_amount_irr
bigint bnpl_commission_irr
string status
}
```
### 4. Financial lifecycle — escrow → payout → clawback
```mermaid
flowchart TD
A["Family submits booking_request"] --> B{"Nurse responds in time?"}
B -->|"reject / expire"| X["request closed — no money moved"]
B -->|"accept"| C["30-min payment window"]
C --> D{"Payment method"}
D -->|"Card (IPG)"| E["payment_transactions = succeeded"]
D -->|"BNPL (SnappPay)"| F["bnpl_transactions = settled<br/>full amount minus provider commission"]
E --> G["Ledger posting:<br/>DR escrow_held / CR nurse_payable + platform_revenue"]
F --> G
G --> H["Booking confirmed (escrow held)"]
H --> I["Nurse EVV check-in / check-out per session"]
I --> J["Booking completed"]
J --> K["dispute_window_ends_at = completed_at + 72h"]
K --> L{"Window passed & no dispute?"}
L -->|"yes"| M["payout_eligible"]
M --> N["Weekly batch → PAYA to nurse IBAN<br/>payout = gross balinyaar_commission"]
K -.->|"refund BEFORE payout"| O["Clean ledger reversal<br/>PSP refund / bnpl_revert"]
N --> P{"Refund AFTER payout?"}
P -->|"yes"| Q["nurse_clawbacks receivable<br/>netted next batch or written off"]
P -->|"no"| Z["Settled and reconciled"]
```
---
# Entity Catalog
Each entity carries a **role**, a **why** (the reasoning), its **fields** (full tables for new/changed; **NEW**/**CHANGED**/**CUT** markers), and its **relations**. Scope tags: **[CORE]** launch-critical · **[MVP]** in first release · **[DEFERRED]** modeled now, inactive at launch.
---
## Domain 1 — Identity & Access
### `users` [CORE]
**Role:** The single identity record for every human actor — nurse, customer, admin. `role` decides which profile sub-table is populated. Phone is the primary login credential (OTP); national ID is filled only after KYC.
**Why:** One identity table avoids three near-duplicate user tables and lets auth, audit, and notifications treat everyone uniformly. Phone-as-primary matches Iranian OTP norms and is the key Shahkar matches against. National ID stays NULL until verified so an unverified registration can't masquerade as KYC-complete.
Fields unchanged from baseline: `id`, `email` (enc, nullable), `phone` (enc, unique), `national_id` (enc, nullable), `national_id_verified_at`, `first_name`, `last_name`, `gender` *(promoted here — see note)*, `avatar_url`, `role` (`nurse`/`customer`/`admin`), `is_active`, `email_verified_at`, `phone_verified_at`, `last_login_at`, `last_login_ip`, `preferred_language`, `created_at`, `updated_at`, `deleted_at`.
| Field | Type | Notes |
|---|---|---|
| `gender` | NVARCHAR(10) NULL | **NEW/clarified**`male`/`female`. Needed because **same-gender caregiving is a near-hard requirement** in Iranian bodily-care; nurse gender (from here) is matched against `booking_requests.required_caregiver_gender`. |
| `shahkar_verified_at` | DATETIME2 NULL | **NEW** — when the phone↔national-id binding was confirmed via Shahkar. Re-set to NULL (re-verify) on phone change. |
**Relations:** 1:1 → `nurse_profiles` / `customer_profiles` (by role); 1:N → `user_sessions`, `user_roles`, `notifications`, `ticket_participants`. Admin users are referenced across the schema as `*_by_admin_id`.
### `user_sessions` [CORE]
**Role:** Refresh-token session records. **Why:** Enables logout-everywhere and stolen-token revocation without a heavyweight session store. Unchanged: `id`, `user_id`, `refresh_token_hash`, `device_info`, `ip_address`, `is_revoked`, `revoked_at`, `expires_at`, `created_at`. **Relations:** N:1 → `users`.
### `roles` / `user_roles` [CORE]
**Role:** RBAC for admin staff only (nurses/customers use `users.role`). **Why:** A small admin team still needs separable finance/support/moderation permissions and a revocation history. `user_roles` keeps `granted_by`/`granted_at`/`revoked_at` for an audit trail. **Relations:** `users` N:N `roles` via `user_roles`.
### `nurse_profiles` [CORE]
**Role:** Extended data for nurses, plus denormalized search/quality aggregates. **Why separated from `users`:** keeps the base identity table lean and isolates the (large) nurse-only attributes and the aggregates that search reads on every query.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `user_id` | BIGINT FK → users UNIQUE | 1:1 |
| `partner_center_id` | BIGINT FK → partner_centers NULL | **NEW** — the licensed center that legally sponsors this nurse at launch (Asanism model). NULL once Balinyaar holds its own permit. |
| `bio`, `years_of_experience`, `education_level`, `education_field`, `specializations_json` | … | Unchanged. |
| `is_verified` | BIT NOT NULL DEFAULT 0 | **Guarded** — set **only** inside the transaction that confirms all required `verification_steps.status='passed'`. No direct write API (Principle 12). |
| ~~`verification_status`~~ | — | **CUT** — duplicated `nurse_verifications.status`; two copies drifted. `nurse_verifications.status` is now the single source of truth. |
| `is_accepting_bookings` | BIT NOT NULL DEFAULT 0 | Nurse can pause without losing verified status. |
| `average_rating`, `total_reviews`, `total_completed_bookings` | … | Denormalized. **Recompute rule now documented**: updated on **every** review status transition (publish → +, hide/reject/unpublish → ) and on booking completion/dispute-reversal, plus a nightly reconciliation job. Fixes the "hide a 1★ review → rating stays inflated" drift. |
| ~~`response_rate`, `avg_response_time_hours`, `profile_completion_score`~~ | — | **CUT for MVP** — analytics columns on no money/safety path, each needing a maintenance job. Compute offline later. |
| `created_at`, `updated_at`, `deleted_at` | … | |
**Relations:** 1:1 → `users`, `nurse_verifications`; 1:N → `nurse_service_variants`, `nurse_service_areas`, `nurse_bank_accounts`, `nurse_credentials`, `bookings`, `nurse_payouts`, `nurse_clawbacks`; N:1 → `partner_centers`.
### `customer_profiles` [CORE]
**Role:** Lightweight extension for customers. **Why intentionally thin:** most customer reality lives in their `patients`, `customer_addresses`, and `bookings`. KYC for customers is deferred. Unchanged: `id`, `user_id` (unique), `default_emergency_contact_name`/`_phone` (enc), `created_at`, `updated_at`. **CUT for MVP:** `national_id_verified_at` (anti-fraud customer KYC — add when actually built). **Relations:** 1:1 → `users`; 1:N → `patients`, `customer_addresses`, `booking_requests`, `bookings`.
### `patients` [CORE]
**Role:** The person receiving care, **separate from the payer**. **Why:** the payer (adult child, spouse) is usually not the patient (elderly parent, newborn, post-surgical adult); one customer registers many patients, each with its own clinical baseline and longitudinal record. Unchanged: `id`, `customer_id`, `display_name`, `first_name`, `last_name`, `birth_date`, `gender`, `blood_type`, `initial_medical_notes` (enc), `is_active`, timestamps. **Relations:** N:1 → `customer_profiles`; 1:N → `booking_requests`, `patient_care_records`. **Tenancy invariant:** a `booking_request.patient_id` must belong to the same `customer_id`.
### `customer_addresses` [CORE]
**Role:** Saved service locations; the encrypted address + coordinates for EVV distance checks. **Why coordinates:** EVV check-in compares the nurse's GPS against the booking address within tolerance. Unchanged fields, plus: **filtered `UNIQUE(customer_id) WHERE is_primary=1`** so exactly one primary exists (prevents ambiguous default). **Relations:** N:1 → `customer_profiles`, `cities`, `districts`; referenced by `booking_requests`/`bookings`.
### `nurse_bank_accounts` [CORE]
**Role:** Payout destination (IBAN/Sheba). **Why hardened:** the IBAN is the single place real money leaves the platform — the original "admin eyeballs the IBAN" check is exactly the forgeable, money-mule-risk link the research warns about.
| Field | Type | Notes |
|---|---|---|
| `id`, `nurse_id`, `bank_name`, `account_holder_name` (enc), `iban` (enc), `is_primary`, `is_verified`, `verified_by_admin_id`, `verified_at`, timestamps | … | Baseline. |
| `iban_hash` | NVARCHAR(64) | **NEW** — deterministic hash for a **UNIQUE** constraint (same IBAN must not silently serve two nurses). |
| `matched_national_id` | BIT NULL | **NEW** — result of an automated **IBAN-owner ↔ national-id inquiry (استعلام شبا)** via a KYC vendor. First payout is gated on a match, not on admin eyeballing. |
| `account_holder_from_bank` | NVARCHAR(200) NULL | **NEW** — name returned by the bank inquiry, snapshot. |
| `ownership_vendor_ref` | NVARCHAR(200) NULL | **NEW** — vendor transaction id for audit. |
Constraints: **filtered `UNIQUE(nurse_id) WHERE is_primary=1`**; `UNIQUE(iban_hash)`. **Relations:** N:1 → `nurse_profiles`; 1:N → `nurse_payouts`.
---
## Domain 2 — Geographic Data
### `provinces` / `cities` / `districts` [CORE]/[MVP]
**Role:** The geo hierarchy backing service areas, addresses, and search. **Why a table, not a static list:** new cities/districts launch without a deploy, and `sort_order`/`is_active` drive ordered, toggleable dropdowns. `districts` map to Tehran's 22 municipal districts or major neighborhoods elsewhere; they are **optional** (a nurse can cover a whole city). Fields unchanged. **Relations:** `provinces` 1:N `cities` 1:N `districts`; referenced by `customer_addresses` and `nurse_service_areas`.
### `nurse_service_areas` [CORE]
**Role:** Where a nurse will travel. A row with `district_id = NULL` means the entire city. **Why a join table (not a radius):** Iranian nurses think in named districts, not GPS radii; this also drives the geographic filter in search cheaply. Unchanged, with `UNIQUE(nurse_id, city_id, district_id)`. **Relations:** N:1 → `nurse_profiles`, `cities`, `districts`.
---
## Domain 3 — Services & Pricing
The service model keeps the original three admin layers (category → option group → option value) and two nurse layers (variant → variant option). This **EAV-style configurability is deliberately kept** — it lets admins add a new pricing dimension (e.g. "شبانه‌روزی / live-in", "number of patients") without a migration, and lets each nurse price every combination independently. The only addition is a denormalized read model for search.
### `service_categories` [CORE]
**Role:** Admin-managed top-level care types (Elderly, Post-Surgery, Infant, Chronic, Companionship). The primary search dimension. **Why admin-managed rows:** the catalog is a business lever, not a code constant. Fields unchanged. **Relations:** 1:N → `service_option_groups`, `nurse_service_variants`.
### `service_option_groups` [CORE] / `service_option_values` [CORE]
**Role:** The configurable dimensions (group, e.g. "نوع شیفت") and their concrete choices (value, e.g. "شبانه‌روزی"). A NULL `service_category_id` on a group = cross-category (e.g. shift type applies everywhere). **Why two tables:** separating dimension from choice lets a dimension be `is_required` and reused across categories. Fields unchanged. **Relations:** `service_categories` 1:N `service_option_groups` 1:N `service_option_values`.
### `nurse_service_variants` [CORE]
**Role:** The atomic **bookable unit** — a specific nurse offering a category with a chosen option combination at a price. **Why this is the bookable unit (not the nurse):** a nurse offers many priced combinations; search and booking operate on the exact thing the customer pays for. The `price_unit` (`per_hour`/`per_session`/`per_half_day`/`per_day`/`per_24h`) determines display and, with `session_count`, the engagement total. Fields unchanged. **Consider** a uniqueness strategy on `(nurse_id, category, option-set)` to prevent duplicate identical listings. **Relations:** N:1 → `nurse_profiles`, `service_categories`; 1:N → `nurse_service_variant_options`, `booking_requests`.
### `nurse_service_variant_options` [CORE]
**Role:** The option values that define a variant's configuration. **Why:** one row per dimension makes the variant's meaning explicit and queryable. `UNIQUE(variant_id, option_group_id)` — one value per dimension. **Relations:** N:1 → `nurse_service_variants`, `service_option_groups`, `service_option_values`.
### `nurse_search_index` [CORE] — **NEW**
**Role:** A denormalized, one-row-per-bookable-variant read model holding every search-relevant field flat: nurse (verified + accepting), variant (category, price, unit), areas (city/district), gender, rating, partner center. **Why:** nurse search otherwise needs 4+ joins (`nurse_profiles → variants → variant_options → service_areas`) plus a rating sort from day one — slow at modest scale. A maintained-on-write flat table is far cheaper than adding Elasticsearch at MVP stage.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `variant_id` | BIGINT FK → nurse_service_variants | |
| `nurse_id` | BIGINT FK → nurse_profiles | |
| `service_category_id` | BIGINT FK | |
| `price`, `price_unit` | … | Copied from variant |
| `city_id`, `district_id` | BIGINT | One row per covered area (fan-out) |
| `nurse_gender` | NVARCHAR(10) | For same-gender filtering |
| `average_rating`, `total_reviews`, `total_completed_bookings` | … | Copied from profile |
| `is_searchable` | BIT | True **only** when nurse `is_verified=1`, not suspended, accepting, and variant `is_active=1` |
| `updated_at` | DATETIME2 | |
**Relations (read-only projection):** maintained on writes to `nurse_profiles`, `nurse_service_variants`, `nurse_service_areas`, `reviews`. **Invariant:** a row is `is_searchable=1` only when its source nurse/variant are bookable.
### `nurse_availability_slots` [MVP] / `nurse_availability_exceptions` [MVP]
**Role:** Recurring weekly windows + date overrides. **Why soft-constraint:** these are **guidance only** — the nurse still accepts/rejects each request; they inform search but never block a request. `day_of_week` uses the Shamsi week (0=Saturday … 6=Friday). Fields unchanged, with CHECK `end_time > start_time`. **Relations:** N:1 → `nurse_profiles`.
---
## Domain 4 — Verification & Credentials
The pipeline stays **data-driven**: step types are rows, so a new regulatory requirement (e.g. professional liability insurance) is one INSERT. This revision adds a **structured credential registry** because the brand *is* "verified trust" and renewal tracking needs queryable license numbers, not opaque PDFs.
### `nurse_verifications` [CORE]
**Role:** The master per-nurse verification record; aggregates step outcomes into one status (the single source of truth for verification state). **Why a header table:** one place to drive the overall lifecycle and the `is_verified` flip. Fields unchanged: `id`, `nurse_id` (unique), `status` (`not_started`/`pending`/`in_review`/`approved`/`rejected`/`suspended`), `submitted_at`, `approved_at`, `rejected_at`, `suspended_at`, `rejection_reason`, `reviewed_by_admin_id`, `internal_notes`, timestamps. **Relations:** 1:1 → `nurse_profiles`; 1:N → `verification_steps`.
### `verification_step_types` [CORE]
**Role:** Admin catalog of pipeline steps with stable machine `code`s (`identity_kyc`, `shahkar_match`, `moh_competency_license`, `ino_membership`, `criminal_record`, `bank_account_verification`). **Why rows + `is_automated`/`automation_provider`:** the Iranian credential reality is fragmented across regulators and partly automatable (Shahkar, liveness) and partly manual (license PDF) — data-driving it absorbs that without code changes. Fields unchanged. **Relations:** 1:N → `verification_steps`.
### `verification_steps` [CORE]
**Role:** One row per step per nurse; tracks status, the raw `external_response_json` (KYC vendor audit), and `expires_at` for time-limited steps (the عدم سوء پیشینه certificate expires → step reverts to `pending` + raises a `support_alert`). **Why snapshot `is_automated`:** historical records survive later step-type edits. Fields unchanged, with `UNIQUE(nurse_verification_id, step_type_id)`. **Relations:** N:1 → `nurse_verifications`, `verification_step_types`; 1:N → `verification_documents`.
### `verification_documents` [CORE]
**Role:** Uploaded evidence metadata (object-storage key + integrity hash); files live in S3-compatible storage behind signed URLs, never public. **Why metadata-only:** keeps PII bytes out of the DB and access controlled. Fields unchanged. **Relations:** N:1 → `verification_steps`.
### `nurse_credentials` [MVP] — **NEW**
**Role:** Structured, queryable registry of the actual Iranian credentials — beyond the opaque document uploads. **Why:** no public B2B API exists for MoH/INO, so an admin manually verifies an uploaded credential against the official portal — but the old model gave them **nowhere to record the verified license number** for renewal alerts, the public trust badge, or cross-check. This makes the badge and expiry monitoring real and survives a future INO/MoH API.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `nurse_id` | BIGINT FK → nurse_profiles | |
| `credential_type` | NVARCHAR(50) | `moh_competency_license` (پروانه صلاحیت حرفه‌ای) / `ino_membership` (نظام پرستاری) / `criminal_record` (عدم سوء پیشینه) |
| `credential_number` | NVARCHAR(100) (enc) | License/membership number |
| `holder_name_snapshot` | NVARCHAR(200) | Name as printed, for ID cross-check |
| `issuing_authority` | NVARCHAR(200) | |
| `issued_at`, `expires_at` | DATE NULL | Drives renewal alerts |
| `verification_source` | NVARCHAR(300) NULL | Portal URL / method |
| `verification_method` | NVARCHAR(20) | `manual` / `portal` / `api` |
| `verified_by_admin_id` | BIGINT FK → users NULL | |
| `created_at`, `updated_at` | … | |
**Relations:** N:1 → `nurse_profiles`. Cross-referenced by the relevant `verification_steps`.
---
## Domain 5 — Booking & Scheduling
Two distinct phases: the **request phase** (pre-payment intent) and the **booking phase** (post-payment commitment). The previous model's biggest domain gap — **single-visit-only bookings** — is fixed here with `booking_sessions`, because elder care is dominantly multi-day / live-in.
### `booking_requests` [CORE]
**Role:** A customer's pre-payment intent for a nurse, service, date, and time. No money involved. **Why separate from `bookings`:** a request may be rejected, expire, or have its payment window lapse without a booking ever existing — merging would mean many nullable fields and tangled status logic. The deadlines are **computed once and stored** so they're immune to later config changes.
| Field | Type | Notes |
|---|---|---|
| `id`, `customer_id`, `nurse_id`, `patient_id`, `variant_id`, `customer_address_id` | … | Baseline FKs. **Tenancy invariant:** patient & address belong to `customer_id`; variant belongs to `nurse_id`. |
| `required_caregiver_gender` | NVARCHAR(10) NULL | **NEW**`male`/`female`/`any`. Same-gender care is decisive in Iranian bodily-care; surfaced as a first-class filter and matched against nurse gender. |
| `requested_date`, `requested_time_start`, `requested_time_end` | … | For multi-day engagements these are the engagement start; sessions carry the per-visit schedule. |
| `customer_notes` | NVARCHAR(1000) NULL | **Unencrypted, request-stage only** — the *only* clinical context the nurse sees before accepting (Principle 6). |
| `status` | NVARCHAR(50) | `pending_nurse_response``accepted_awaiting_payment``converted` / `rejected_by_nurse` / `expired_no_response` / `payment_deadline_expired` / `cancelled_by_customer` |
| `nurse_response_deadline_at` | DATETIME2 | From config at creation; auto-expire after. |
| `payment_deadline_at` | DATETIME2 NULL | Set on accept; 30-min window. |
| `nurse_rejection_reason` | NVARCHAR(500) NULL | |
| timestamps | … | |
**Relations:** N:1 → `customer_profiles`, `nurse_profiles`, `patients`, `nurse_service_variants`, `customer_addresses`; 1:1 → `bookings` (on conversion).
### `bookings` [CORE]
**Role:** The confirmed engagement — exists **only** when the nurse accepted **and** payment was captured. Source of truth for the service event and its money split. **Why snapshots:** `variant_snapshot_json` and `address_snapshot_json` freeze the service and address at booking time, so later edits/deletes can't corrupt history or disputes.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `booking_request_id` | BIGINT FK UNIQUE | 1:1 — the request that created it |
| `customer_id`, `nurse_id`, `patient_id`, `variant_id`, `customer_address_id` | … | Denormalized for query performance |
| `variant_snapshot_json` | NVARCHAR(MAX) | Variant + option labels at booking time |
| `address_snapshot_json` | NVARCHAR(MAX) (enc) | Full address at booking time |
| `partner_center_id` | BIGINT FK → partner_centers NULL | **NEW** — the licensed center legally covering this visit / merchant-of-record |
| `gross_price_irr` | BIGINT | **CHANGED (renamed)** — total charged to customer |
| `balinyaar_commission_irr` | BIGINT | **CHANGED (renamed from `platform_fee_amount`)** — platform's own cut |
| `platform_fee_rate` | DECIMAL(5,4) | Rate snapshot for audit |
| `nurse_payout_amount` | BIGINT | `= gross_price_irr balinyaar_commission_irr`. **CHECK enforced.** |
| `psp_fee_amount` | BIGINT NULL | **NEW** — gateway cost on this payment, for true margin/reconciliation |
| `session_count` | SMALLINT NOT NULL DEFAULT 1 | **NEW** — 1 = single visit; >1 = multi-session engagement |
| `scheduled_date`, `scheduled_time_start`, `scheduled_time_end` | … | Engagement-level; per-visit lives in `booking_sessions` |
| `status` | NVARCHAR(30) | `pending_payment``confirmed``in_progress``completed` → (`disputed``closed`) / `cancelled`. **Now guarded by an allowed-transition table/CHECK** so it can't contradict EVV. |
| `confirmed_at`, `cancelled_at`, `cancellation_reason`, `cancelled_by`, `completed_at` | … | |
| `dispute_window_ends_at` | DATETIME2 NULL | **NEW**`completed_at + config(dispute_window_hours, default 72)`. Payout eligible only after this passes with no open dispute. |
| ~~`payout_released`~~ | — | **CUT** — second source of truth for "paid"; now derived from a `nurse_payout_booking_links` row + ledger. |
| timestamps | … | |
CHECK: `gross_price_irr = balinyaar_commission_irr + nurse_payout_amount`; all amounts ≥ 0. **Relations:** 1:1 ← `booking_requests`; 1:N → `booking_sessions`, `payment_transactions`, `ledger_entries`; 1:1 → `booking_care_instructions`, `visit_verifications` *(see note)*, `reviews`, `invoices`; referenced by `nurse_payout_booking_links`, `refunds`, `nurse_clawbacks`.
### `booking_sessions` [MVP] — **NEW**
**Role:** One row per **visit** within a booking. A 10-day post-op package or a month of nightly شبانه‌روزی care is **one booking with N sessions**, each with its own schedule, EVV, and payout eligibility. **Why:** the single-visit model literally cannot represent the dominant elder-care engagement; and money for a long engagement must release **per completed session**, not as one whole-month escrow held for weeks. Mid-engagement cancellation then cleanly refunds only the un-started sessions.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `booking_id` | BIGINT FK → bookings | |
| `session_index` | INT | 1-based ordinal |
| `scheduled_date`, `scheduled_time_start`, `scheduled_time_end` | … | Per-visit |
| `visit_payout_amount` | BIGINT | Portion of `nurse_payout_amount` for this session |
| `status` | NVARCHAR(20) | `scheduled` / `in_progress` / `completed` / `missed` / `cancelled` |
| `payout_eligible_at` | DATETIME2 NULL | Per-session dispute-window close |
| `cancellation_event_id` | BIGINT NULL | If this session was cancelled |
| timestamps | … | |
**Relations:** N:1 → `bookings`; 1:1 → `visit_verifications`. **Note:** for a single-visit booking, exactly one session is created so the EVV/payout path is uniform.
### `booking_care_instructions` [CORE]
**Role:** Encrypted clinical/logistical context provided at booking time, visible **only post-confirmation** to the assigned nurse and admin. **Why separate + encrypted:** keeps the financial/scheduling table clean and enforces the two-stage disclosure boundary (Principle 6) with stricter access controls. Fields unchanged (current conditions, medications, allergies, special instructions, emergency contact — all enc). **Relations:** 1:1 → `bookings`.
### `visit_verifications` [CORE]
**Role:** Electronic Visit Verification — the authoritative record that a visit happened and for how long; **required for payout**. **Why:** in-home care is unobserved; GPS + timestamped check-in/out is the proof that safely releases escrow. `check_in_address_match` is advisory (a mismatch triggers admin review, not auto-cancel). **CHANGED:** the FK moves to **`booking_session_id`** so each visit in a multi-session engagement is verified independently; the mapping between `visit_verifications.status` and the parent `bookings.status` is documented so the two state machines cannot silently diverge. Fields otherwise unchanged. **Relations:** 1:1 → `booking_sessions`.
### `cancellation_policies` [MVP] — **NEW**
**Role:** Config-driven, snapshot-able cancellation/refund tiers by lead time and initiating actor. **Why:** "default 100% refund" is naive — a free cancel 24h ahead, a 50% charge inside 24h, and a nurse-no-show full refund + nurse penalty are different money flows, and the applicable rule must be **frozen onto the booking** at cancel time (the same snapshot discipline used for `platform_fee_rate`).
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `code` | NVARCHAR(50) UNIQUE | e.g. `standard_24h` |
| `applies_to` | NVARCHAR(20) | `customer` / `nurse` / `admin` |
| `hours_before_start_min`, `hours_before_start_max` | INT NULL | Tier bounds |
| `refund_percentage` | DECIMAL(5,2) | 0100 |
| `fee_amount_or_rate` | … | Cancellation fee / nurse penalty |
| `is_active`, timestamps | … | |
**Relations:** referenced (snapshot) by `refunds` and the `cancellation_event` recorded on a session/booking.
---
## Domain 6 — Payments, Ledger & Refunds
This is the most-changed domain. The previous model **inferred** money state from scattered status flags; this revision makes a **double-entry ledger** the source of truth and adds the **idempotency** and **clawback** primitives that any real-money platform needs before launch.
### `payment_gateways` [CORE]
**Role:** Config per connected PSP/BNPL provider; credentials encrypted. **Why `type`:** multiple gateways run at once (standard IPG, a BNPL provider, a failover) and `type` (`standard`/`bnpl`) selects the flow. **Why this matters for Iran:** provider cut-offs happen (Toman/Jibit were abruptly suspended in Nov 2024), so the gateway is abstracted to be swappable. BNPL provider secrets (client_id/secret, merchant number, base_url, sandbox flag) live encrypted in `config_json`. Fields unchanged. **Relations:** 1:N → `payment_transactions`, `payment_webhook_events`.
### `payment_transactions` [CORE]
**Role:** Every payment attempt against a booking; the `succeeded` row triggers confirmation. Stores the full `gateway_response_json` and the **Shaparak reference code** (definitive proof) for reconciliation and chargebacks. **Why hardened:** a retried PSP webhook could otherwise insert a second `succeeded` row and double-confirm.
| Field | Type | Notes |
|---|---|---|
| baseline fields | … | `id`, `booking_id`, `customer_id`, `gateway_id`, `amount`, `currency`, `status`, `gateway_transaction_id`, `gateway_reference_code`, `gateway_response_code`, `gateway_response_json`, `is_installment`, `ip_address`, `user_agent`, timestamps |
| **constraints** | | **NEW:** `UNIQUE(gateway_reference_code) WHERE NOT NULL`; filtered `UNIQUE(booking_id) WHERE status='succeeded'` — at most one capturing transaction per booking. |
**Relations:** N:1 → `bookings`, `payment_gateways`; 1:1 → `bnpl_transactions` (if BNPL); 1:N → `refunds`, `ledger_entries`.
### `payment_webhook_events` [CORE] — **NEW**
**Role:** Raw, deduplicated store of every PSP/BNPL callback. **Why mandatory:** callbacks are at-least-once and retried; without a unique store keyed on the provider's event id, a replayed "payment succeeded" double-confirms a booking and a replayed "settled" double-counts money. The handler **upserts here first** and no-ops on a duplicate, inside the same transaction that mutates payment state.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `provider_code` | NVARCHAR(50) | `zarinpal` / `snapppay` / … |
| `external_event_id` | NVARCHAR(200) | **UNIQUE(provider_code, external_event_id)** |
| `event_type` | NVARCHAR(80) | |
| `signature_valid` | BIT | |
| `payload_json` | NVARCHAR(MAX) | Raw callback |
| `processing_status` | NVARCHAR(20) | `received` / `processed` / `failed` / `ignored` |
| `related_payment_transaction_id` | BIGINT NULL | |
| `received_at`, `processed_at` | DATETIME2 | |
**Relations:** N:1 → `payment_gateways`; optional → `payment_transactions`.
### `refunds` [CORE]
**Role:** Admin-initiated refunds (no customer self-service), always linked to a support ticket. **Why these changes:** the previous model treated refunds as 1:1 with a transaction and as a single undecomposed amount — but partials exist (shortened visit) and a refund must say how much reverses the **platform fee** vs the **nurse payout**, and how the money actually moves (card vs BNPL revert).
| Field | Type | Notes |
|---|---|---|
| baseline | … | `id`, `payment_transaction_id`, `booking_id`, `requested_by_customer_id`, `ticket_id`, `amount`, `refund_percentage`, `reason_category`, `reason_notes`, `status`, approval/rejection fields, `gateway_refund_reference`, `processed_at`, `admin_notes`, timestamps |
| **cardinality** | | **CHANGED to 1:N** per `payment_transaction` (app invariant: Σ refunded ≤ captured). The old "1:1" relationship summary was wrong. |
| `platform_fee_refunded_irr` | BIGINT | **NEW** — fee-leg decomposition |
| `nurse_payout_refunded_irr` | BIGINT | **NEW** — payout-leg decomposition (drives clawback if nurse already paid) |
| `refund_channel` | NVARCHAR(20) | **NEW**`psp_card` / `bnpl_revert` / `manual_bank` |
| `external_revert_reference` | NVARCHAR(200) NULL | **NEW** — BNPL revert id |
| `expected_customer_refund_eta` | DATE NULL | **NEW** — the ~710 business-day BNPL window, surfaced in UI/reconciliation |
| `cancellation_policy_code` / `refund_percentage_applied` | … | **NEW** — snapshot of the policy that produced this refund |
**Relations:** N:1 → `payment_transactions`, `bookings`, `customer_profiles`, `tickets`; 1:1 → `nurse_clawbacks` (only when refunding a booking whose nurse was already paid).
### `ledger_entries` [CORE] — **NEW**
**Role:** The append-only, double-entry financial **source of truth**. Every money event posts **balanced** rows sharing a `transaction_group_id` (Σ debit = Σ credit). Per-nurse payable balance derives by filtering `account_type='nurse_payable'` + `nurse_id`. **Why:** a marketplace that holds escrow and pays out weekly minus commission, with refunds and clawbacks, is exactly the shape double-entry was invented for. The alternative (more money columns + status booleans) cannot answer "how much do we owe nurses right now" or reconcile against the bank, and makes refund/clawback second-class. Cost: one table + posting discipline.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `transaction_group_id` | UNIQUEIDENTIFIER | Groups the balanced legs of one event |
| `account_type` | NVARCHAR(40) | `escrow_held` / `platform_revenue` / `nurse_payable` / `refund_payable` / `bnpl_fee_expense` / `psp_fee_expense` / `nurse_clawback_receivable` / `bad_debt` |
| `nurse_id` | BIGINT FK NULL | Set for `nurse_payable`/`nurse_clawback_receivable` |
| `direction` | NVARCHAR(6) | `debit` / `credit` |
| `amount_irr` | BIGINT | Always positive; `direction` carries the sign |
| `booking_id` | BIGINT FK NULL | |
| `source_ref_type` | NVARCHAR(40) | `payment_transaction` / `refund` / `nurse_payout` / `bnpl_transaction` / `clawback` |
| `source_ref_id` | BIGINT | |
| `memo` | NVARCHAR(300) NULL | |
| `created_at` | DATETIME2 | Append-only; never updated |
**Canonical postings:**
| Event | Debit | Credit |
|---|---|---|
| Card capture | `escrow_held` (gross) | `platform_revenue` (commission) + `nurse_payable` (payout) |
| BNPL settle | as card, **plus** `bnpl_fee_expense` (provider commission) | `escrow_held` (provider commission) → escrow reflects net cash actually received |
| Refund (pre-payout) | `nurse_payable` + `platform_revenue` (decomposed legs) | `refund_payable`; later `refund_payable``escrow_held` on confirm |
| Clawback (post-payout) | `nurse_clawback_receivable` (+ `platform_revenue` leg) | `refund_payable` |
| Clawback recovered | `nurse_payable` (next batch) | `nurse_clawback_receivable` |
**Relations:** N:1 → `bookings`; logical links to `payment_transactions`/`refunds`/`nurse_payouts`/`bnpl_transactions` via `source_ref_*`.
### `nurse_clawbacks` [CORE] — **NEW**
**Role:** A first-class receivable when a booking is refunded/disputed **after** the nurse was already paid. **Why:** this was the model's own flagged critical gap — Iranian payouts are real, hard-to-reverse bank transfers, so paying before the dispute window closes can create uncollectable loss with nowhere to record it. Closing it = gate payout on `dispute_window_ends_at` **and** record any post-payout recovery here.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `nurse_id` | BIGINT FK → nurse_profiles | |
| `booking_id` | BIGINT FK → bookings | |
| `refund_id` | BIGINT FK → refunds | |
| `original_payout_id` | BIGINT FK → nurse_payouts NULL | |
| `amount_irr` | BIGINT | |
| `status` | NVARCHAR(30) | `pending` / `recovered` / `written_off` |
| `recovered_in_payout_id` | BIGINT FK NULL | Batch that netted it |
| `created_at`, `resolved_at` | DATETIME2 | |
**Relations:** N:1 → `nurse_profiles`, `bookings`; 1:1 → `refunds`; → `nurse_payouts` (original and recovering).
### `invoices` [MVP] — **NEW**
**Role:** Minimal official-invoice/receipt record per booking. **Why:** Iranian commission marketplaces face VAT/مودیان obligations on **their commission** (the Snapp/Tapsi precedent: the provider's earnings are the provider's own income; the platform's commission is the platform's taxable revenue). The smallest footprint that satisfies bookkeeping without a full tax engine. **VAT is 10%** (rose from 9% in 1403) and stored as a **config-driven rate** so a future exemption ruling on the nursing service itself is just a value change. Nurse-side income tax is the nurse's own responsibility.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `booking_id` | BIGINT FK → bookings | |
| `invoice_number` | NVARCHAR(40) UNIQUE | Official sequential number |
| `issuing_entity_type` | NVARCHAR(20) | `platform` / `partner_center` |
| `gross_irr` | BIGINT | |
| `platform_commission_irr` | BIGINT | The VAT-relevant line |
| `bnpl_commission_irr` | BIGINT NULL | |
| `vat_rate` | DECIMAL(5,4) | Config-driven (0.10) |
| `vat_irr` | BIGINT | |
| `moadian_reference_number` | NVARCHAR(40) NULL | سامانه مودیان 22-digit ref when issued |
| `moadian_status` | NVARCHAR(20) NULL | |
| `pdf_storage_key` | NVARCHAR(512) NULL | |
| `issued_at` | DATETIME2 | |
**Relations:** 1:1 → `bookings`; N:1 → `partner_centers` (when issuer).
---
## Domain 7 — Payouts to Nurses
### `nurse_payout_batches` [CORE]
**Role:** Weekly aggregation of amounts owed for completed, payout-eligible, unpaid bookings/sessions. **Why batched:** matches the operational rhythm and the PAYA settlement cycle; an admin (or scheduled job) initiates it. **Holiday-aware:** `period_end`/processing dates shift off bank-closed days using `iranian_holidays` (a weekly payout landing on a multi-day Nowruz closure would otherwise fail). Fields unchanged: period, `total_amount`, `payout_count`, `status`, `initiated_by_admin_id`, `processed_at`, `failure_notes`, timestamps. CHECK: `total_amount = Σ payouts`. **Relations:** 1:N → `nurse_payouts`.
### `nurse_payouts` [CORE]
**Role:** One row per nurse per batch — the exact amount transferred, the IBAN snapshot, and the bank transfer reference. **Why these additions:** a batch must be able to **net prior clawbacks** so it doesn't overpay a nurse who owes money back.
| Field | Type | Notes |
|---|---|---|
| baseline | … | `id`, `batch_id`, `nurse_id`, `bank_account_id`, `iban_snapshot` (enc), `amount`, `booking_count`, `status`, `transfer_reference`, `paid_at`, `failure_reason`, `created_at` |
| `gross_earnings_irr` | BIGINT | **NEW** — sum of eligible session/booking payouts |
| `clawback_applied_irr` | BIGINT | **NEW** — clawbacks netted this batch |
| `net_amount_irr` | BIGINT | **NEW**`gross_earnings clawback`; `amount` = actually transferred net |
**Relations:** N:1 → `nurse_payout_batches`, `nurse_profiles`, `nurse_bank_accounts`; 1:N → `nurse_payout_booking_links`; referenced by `nurse_clawbacks`.
### `nurse_payout_booking_links` [CORE]
**Role:** Join from a payout to the specific bookings it covers, with `booking_id` **UNIQUE** to guarantee a booking is paid in exactly one batch. **Why:** per-booking reconciliation and the structural anti-double-pay guard (the previous model's strongest correctness feature — kept). Fields unchanged. **Relations:** N:1 → `nurse_payouts`; 1:1 → `bookings`.
---
## Domain 8 — BNPL / Installments
**Resolved.** Because verified research shows Iranian provider-financed BNPL settles the **full amount to the merchant in one lump** (provider owns the customer's installments and default risk), a BNPL order is — in our books — a card payment that lands net-of-fee. The original `installment_plans` + `installment_entries` subsystem (which tried to track the customer's repayment schedule and default) is **deleted**: it modeled a receivable Balinyaar never owns and a risk it never bears.
### `bnpl_transactions` [MVP] — **NEW (replaces `installment_plans`)**
**Role:** One row per BNPL order, 1:1 with its `payment_transaction` — the single inbound settlement to reconcile, plus the revert path. **Why one row, not a plan+entries tree:** there is nothing to amortize on our side; we track the settlement, the provider's commission, and the reversal.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `payment_transaction_id` | BIGINT FK UNIQUE | 1:1 |
| `provider_code` | NVARCHAR(50) | `snapppay` / `digipay` / `tara` / `torobpay` |
| `merchant_of_record` | NVARCHAR(40) | Balinyaar entity or partner center |
| `external_payment_token` | NVARCHAR(200) | For verify/settle/revert |
| `external_transaction_id` | NVARCHAR(200) | |
| `eligibility_status` | NVARCHAR(30) | |
| `order_amount_irr` | BIGINT | Gross order |
| `settled_amount_irr` | BIGINT | Net of provider commission actually received |
| `bnpl_commission_irr` | BIGINT | Provider's merchant discount = platform **expense** (never the nurse's) |
| `currency` | NVARCHAR(5) | `IRR`/`TOMAN` at boundary; convert in |
| `installment_count` | TINYINT | Informational (default 4) — owned by the provider |
| `status` | NVARCHAR(30) | State machine: `eligible`/`token_issued`/`verified`/`settled`/`reverted`/`cancelled`/`failed` |
| `settled_at` | DATETIME2 NULL | **Per-transaction** — timing is contract-defined (daily/T+1-3/weekly), never assumed instant |
| `revert_transaction_id`, `reverted_amount_irr`, `reverted_at` | … | Reversal path |
| `refund_channel` | NVARCHAR(20) | |
| `callback_payload_json` | NVARCHAR(MAX) | Raw verify/settle payload |
| timestamps | … | |
**Relations:** 1:1 → `payment_transactions`. **State-machine guard** on `status` for idempotency.
### `bnpl_settlement_entries` [DEFERRED]
**Role/Why:** Only needed if a future provider uses **tranched** settlement (pays the platform over time). No mainstream Iranian provider does today, so it's modeled-but-inactive; adding it later is a purely additive migration.
---
## Domain 9 — Messaging (Ticket System)
### `tickets` / `ticket_participants` / `ticket_messages` [CORE]
**Role:** All post-booking communication, admin-readable, with no direct nurse↔customer channel. **Why intentionally constrained:** it protects vulnerable patients, creates dispute evidence, and prevents disintermediation (families and nurses pairing off-platform). `ticket_messages.is_internal` keeps admin-only notes out of user view. `reference_code` is the human-facing support id. **On-site emergencies** stay an operational playbook ("call the emergency contact from the app, then open a ticket") — surfaced prominently in the booking UI; no schema change, but documented so nurses don't seek the family's number off-platform. Fields unchanged; `UNIQUE(ticket_id, user_id)` on participants. **Relations:** `tickets` 1:N `ticket_participants`/`ticket_messages`; `tickets` optionally ↔ `bookings`, `refunds`.
---
## Domain 10 — Reviews & Patient Records
### `reviews` [CORE]
**Role:** One customer review per **completed** booking; enters `pending_moderation`, published only after admin/AI approval; a low rating raises a `support_alert`. **Why these guards:** (a) review creation is allowed **only for completed/closed bookings** (a review for a cancelled booking is nonsense); (b) **every** status transition (publish/hide/reject/unpublish) recomputes `nurse_profiles` aggregates, fixing the inflated-rating-after-hide drift. Fields unchanged (rating 15 with CHECK, body, status, moderation fields). **Relations:** 1:1 → `bookings`; N:1 → `customer_profiles`, `nurse_profiles`; 1:N → `review_tag_links`.
### `review_tags_master` [MVP] / `review_tag_links` [MVP]
**Role:** Standardized tags for quantitative aggregation of qualitative feedback (e.g. "% punctual"). **Why MVP-not-core:** free-text + rating is enough to launch; structured tags are a phase-2 analytics nicety (additive leaf tables). **Relations:** `reviews` N:N `review_tags_master`.
### `patient_care_records` [MVP]
**Role:** Nurse-authored clinical notes after a visit, accumulating into a **patient-scoped longitudinal history** (not booking-scoped). **Why patient-scoped:** when a different nurse takes over, they read the history before accepting, enabling continuity of care without the family repeating everything. Strict access: owning customer, nurses with a confirmed booking for that patient, admin. All fields encrypted. **Relations:** N:1 → `patients`, `bookings`, `nurse_profiles`.
---
## Domain 11 — Notifications
### `notifications` [CORE]
**Role:** In-app notifications (no push at launch); `data_json` carries a typed payload for front-end navigation. **Why polled, not pushed:** push is out of MVP scope; a retention job hard-deletes read notifications older than 90 days to bound growth. Fields unchanged. **Relations:** N:1 → `users`.
### `support_alerts` [CORE]
**Role:** Internal-only alerts (low ratings, EVV no-shows, expired verification steps, EVV location mismatch, payment anomalies), with an owner and resolution trail. **Why distinct from notifications:** these are staff worklist items, never shown to users. Fields unchanged. **Relations:** polymorphic (`entity_type`,`entity_id`) — validated at the application layer; consider nullable typed FKs (`booking_id`,`review_id`) for the common cases.
---
## Domain 12 — Audit, Config & Reference
### `audit_logs` [CORE]
**Role:** Immutable, append-only record of every state change on sensitive entities — now explicitly **including `platform_configs`** (so finance can prove the commission rate at any moment). **Why:** compliance and accountability; `changed_fields_json` enables fast filtering. Plan month-partitioning + 23yr cold-storage archival before launch. Fields unchanged. **Relations:** polymorphic, append-only.
### `system_events` [MVP]
**Role:** High-volume behavioral/analytics event log. **Why kept but de-emphasized:** product analytics, not compliance. It grows unbounded — at scale, pipe it to an analytics sink/warehouse rather than the transactional DB. Fields unchanged.
### `platform_configs` [CORE]
**Role:** Key-value runtime business parameters — change without a deploy. **Why typed values:** `data_type` tells the app how to parse. **New keys** this revision: `dispute_window_hours` (default 72), `vat_rate` (0.10), `bnpl_merchant_of_record`, `bnpl_provider_commission_rate`, `bnpl_settlement_timing`, cancellation-tier defaults — alongside the existing `platform_fee_rate`, `booking_payment_deadline_minutes`, `nurse_response_deadline_hours`, `nurse_payout_interval_days`, `evv_location_tolerance_meters`, `min_rating_for_support_alert`. **Relations:** referenced everywhere; changes audited.
### `iranian_holidays` [MVP] — **NEW**
**Role:** Shared official/religious holiday calendar (movable, partly lunar-Hijri), with a `is_bank_closed` flag. **Why a real table:** Iran's holidays are numerous and partly movable, and they drive **payout bank-closure scheduling** (PAYA/SATNA closed → a weekly payout shifts to the next business day), optional holiday pricing, and business-hour deadline math — none of which a purely manual per-nurse availability exception can express.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `holiday_date` | DATE | |
| `name_fa` | NVARCHAR(200) | |
| `type` | NVARCHAR(20) | `official` / `religious` / `national` |
| `is_bank_closed` | BIT | Drives payout date shifting |
**Relations:** referenced by payout scheduling and (optionally) pricing.
---
## Domain 13 — Partner Centers (launch) & Future
### `partner_centers` [MVP] — **NEW**
**Role:** A licensed home-nursing center (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل) that **sponsors** nurses and is plausibly the **merchant-of-record** and invoice issuer at launch. **Why this is the single most launch-critical addition:** the research's #1 go-to-market recommendation is to operate by subcontracting to an already-licensed center (the Asanism model) while Balinyaar's own MoH permit is pending — the center is what makes the operation legal, may be who the IPG settles to, and clears the BNPL onboarding gate (which needs a جواز کسب + eNamad the company/center holds, not each nurse). Distinct from the future `organizations` (employer) table — this is the **licensing/launch sponsor**.
| Field | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | |
| `name` | NVARCHAR(300) | |
| `legal_entity_type` | NVARCHAR(30) | |
| `moh_establishment_permit_no` | NVARCHAR(100) | پروانه تأسیس |
| `technical_director_nurse_user_id` | BIGINT FK → users NULL | مسئول فنی |
| `technical_director_license_no` | NVARCHAR(100) NULL | |
| `enamad_code` | NVARCHAR(100) NULL | |
| `settlement_iban` | NVARCHAR(34) (enc) NULL | If merchant-of-record |
| `is_merchant_of_record` | BIT | |
| `commission_rate` | DECIMAL(5,4) NULL | Center's cut, if any |
| `admin_user_id` | BIGINT FK → users | Center's dashboard account |
| `is_active`, `verified_at`, timestamps | … | |
**Relations:** 1:N → `nurse_profiles` (sponsors), `bookings` (legally covered by), `invoices` (issuer).
### `organizations` / `organization_nurses` [DEFERRED]
**Role/Why:** The future **employer** model (nursing companies adding their employed nurses). Modeled-but-inactive — no launch table references them, so adding them later is a pure additive migration. Kept distinct from `partner_centers` (launch licensing) to avoid conflating "sponsor for legality" with "employer."
### `fraud_flags` [DEFERRED]
**Role/Why:** Output of a future ML fraud service. Premature for a no-traffic MVP; `support_alerts` (`fraud_signal` type) covers rule-based signals manually. Inactive stub.
### `recurring_booking_schedules` [DEFERRED]
**Role/Why:** RFC-5545 recurrence for repeating care patterns. Note: the concrete multi-day need is now met by `booking_sessions`; this remains deferred for true open-ended recurrence. Inactive stub.
---
## Relationship Summary
| Relationship | Type | Notes |
|---|---|---|
| `users``nurse_profiles` / `customer_profiles` | 1:1 | by `role` |
| `partner_centers``nurse_profiles` | 1:N | launch sponsor (NEW) |
| `customer_profiles``patients` / `customer_addresses` | 1:N | |
| `nurse_profiles``nurse_service_variants` / `nurse_service_areas` / `nurse_bank_accounts` / `nurse_credentials` | 1:N | |
| `nurse_service_variants``nurse_service_variant_options` | 1:N | option combination |
| `nurse_profiles``nurse_verifications` | 1:1 | |
| `nurse_verifications``verification_steps``verification_documents` | 1:N → 1:N | |
| `booking_requests``bookings` | 1:1 | on nurse-accept + payment |
| `bookings``booking_sessions` | 1:N | **NEW** — multi-visit engagements |
| `booking_sessions``visit_verifications` | 1:1 | **CHANGED** — EVV per session |
| `bookings``booking_care_instructions` / `reviews` / `invoices` | 1:1 | |
| `bookings``payment_transactions` | 1:N | attempts |
| `payment_transactions``bnpl_transactions` | 1:1 | if BNPL (**replaces** installment_plans) |
| `payment_transactions``refunds` | **1:N** | **CHANGED** — partials allowed |
| `payment_gateways``payment_webhook_events` | 1:N | **NEW** — idempotency |
| `bookings` / nurses → `ledger_entries` | 1:N | **NEW** — money source of truth |
| `refunds``nurse_clawbacks` | 1:1 (opt) | **NEW** — refund-after-payout |
| `nurse_payout_batches``nurse_payouts``nurse_payout_booking_links` | 1:N → 1:N | `booking_id` UNIQUE |
| `nurse_payout_booking_links``bookings` | 1:1 | exactly one payout per booking |
| `patients``patient_care_records` | 1:N | longitudinal history |
| `tickets``ticket_participants` / `ticket_messages` | 1:N | |
| Sensitive entities → `audit_logs` | *:N | append-only |
---
## Final MVP table list
**Identity & Access:** `users` · `user_sessions` · `roles` · `user_roles` · `nurse_profiles` · `customer_profiles` · `patients` · `customer_addresses` · `nurse_bank_accounts` — all **[CORE]**
**Geography:** `provinces` · `cities` **[CORE]** · `districts` **[MVP]** · `nurse_service_areas` **[CORE]**
**Services & Pricing:** `service_categories` · `service_option_groups` · `service_option_values` · `nurse_service_variants` · `nurse_service_variant_options` · **`nurse_search_index`** *(NEW)***[CORE]**; `nurse_availability_slots` · `nurse_availability_exceptions`**[MVP]**
**Verification:** `nurse_verifications` · `verification_step_types` · `verification_steps` · `verification_documents` **[CORE]**; **`nurse_credentials`** *(NEW)* **[MVP]**
**Booking & Scheduling:** `booking_requests` · `bookings` · `booking_care_instructions` · `visit_verifications` **[CORE]**; **`booking_sessions`** *(NEW)* · **`cancellation_policies`** *(NEW)* **[MVP]**
**Payments & Ledger:** `payment_gateways` · `payment_transactions` · **`payment_webhook_events`** *(NEW)* · `refunds` · **`ledger_entries`** *(NEW)* · **`nurse_clawbacks`** *(NEW)* · `nurse_payout_batches` · `nurse_payouts` · `nurse_payout_booking_links` **[CORE]**; **`invoices`** *(NEW)* **[MVP]**
**BNPL:** **`bnpl_transactions`** *(NEW — replaces `installment_plans`)* **[MVP]**; ~~`installment_plans`~~ · ~~`installment_entries`~~ **CUT**; `bnpl_settlement_entries` **[DEFERRED]**
**Messaging:** `tickets` · `ticket_participants` · `ticket_messages` **[CORE]**
**Reviews & Records:** `reviews` **[CORE]**; `review_tags_master` · `review_tag_links` · `patient_care_records` **[MVP]**
**Notifications:** `notifications` · `support_alerts` **[CORE]**
**Audit & Config:** `audit_logs` **[CORE]** · `system_events` **[MVP]** · `platform_configs` **[CORE]** · **`iranian_holidays`** *(NEW)* **[MVP]**
**Partner / Launch:** **`partner_centers`** *(NEW)* **[MVP]**
**Future (modeled, inactive):** `organizations` · `organization_nurses` · `fraud_flags` · `recurring_booking_schedules` · `bnpl_settlement_entries` — all **[DEFERRED]**
**Net change vs the original 45:** 2 cut (`installment_plans` replaced, `installment_entries` removed), +10 added (`ledger_entries`, `nurse_clawbacks`, `payment_webhook_events`, `nurse_search_index`, `booking_sessions`, `cancellation_policies`, `invoices`, `partner_centers`, `nurse_credentials`, `iranian_holidays`), 1 replaced (`bnpl_transactions`). The financial core is now a single ledger, BNPL is one settlement row, and the clawback / dispute-window / idempotency / license / multi-session gaps are all closed.
---
## Key Design Decisions (the reasoning, in one place)
1. **Escrow as a ledger state, not platform cash** — because an Iranian پرداخت‌یار legally cannot custody buyer funds. Everything else in the money domain follows from honestly representing "we don't hold the cash; we hold a claim/obligation tracked in the ledger over funds at a licensed provider." This is also why payouts are modeled as provider-side settlement to **verified, ownership-checked** IBANs.
2. **A BNPL order is a net-of-fee inbound payment, full stop** — the verified full-upfront settlement model means there is no customer receivable, no default risk, and no installment schedule for Balinyaar to track. Deleting `installment_entries` removed an entire fragile subsystem and replaced it with one reconciliation row.
3. **Three separate money amounts** so the platform's two fee deductions (its own commission, and the BNPL provider's discount) are never conflated, and the nurse is paid identically regardless of payment method.
4. **Double-entry over status flags** — the previous model could not answer "how much do we owe nurses right now" without fragile joins, and had nowhere to record a refund-after-payout. One append-only ledger + a `nurse_clawbacks` receivable fixes both and makes bank/Shaparak reconciliation possible.
5. **Dispute window gates payout** — preferring a *holding period* over a *clawback*, because clawback against an already-paid nurse IBAN is largely unenforceable. The clawback path exists for the cases that slip through.
6. **Idempotency before money**`payment_webhook_events` keyed on the provider event id, written first, is the cheapest insurance against the most damaging payments bug (double-confirm / double-settle on callback retries).
7. **Multi-session engagements are the norm, not an edge case**`booking_sessions` makes long elder-care arrangements representable, lets escrow release per completed visit instead of holding a month of money, and makes mid-engagement cancellation accounting clean.
8. **Partner center is launch-critical** — it is the legal vehicle and likely merchant-of-record; without it the recommended go-to-market and the money flow are not representable.
9. **Verified-trust must be queryable**`nurse_credentials` turns the brand promise into renewal alerts, a real badge, and audit defensibility, surviving the future arrival of an INO/MoH API.
10. **Keep the configurable service EAV; cut the analytics scaffolding** — the category/option model earns its complexity (admin-extensible pricing dimensions without migrations); `response_rate`/`profile_completion_score`/`system_events`-in-SQL do not, at launch.
---
## Open items to confirm before building (not schema blockers)
- **BNPL provider contract:** does SnappPay/Digipay permit a multi-vendor marketplace re-disbursing to many nurses as a single merchant? (Publicly undocumented — confirm with sales.) The schema assumes **one lump to Balinyaar/the center, internal allocation to nurses**, so this is an ops confirmation, not a schema dependency.
- **Commission %** and **settlement SLA** per provider (and whether the provider returns its commission on a refund — full or pro-rata).
- **PSP/تسهیم provider** for MVP (ZarinPal Multiplexing vs Vandar vs Jibit) and whether it permits the hold-then-weekly-payout timing, or whether a bank-grade escrow (Vandar میندو) is needed.
- **VAT exemption** ruling on the nursing service itself (the commission line is taxable regardless) — `vat_rate` is config-driven so either ruling is a value change.
- **مودیان** enrollment thresholds for the platform and high-earning nurses.
> Confirm decades-old regulations, provider fee/settlement specifics, and tax thresholds against current primary sources and the provider's compliance team before building the payment integration. See `payments-and-installments.md` for the full source-cited analysis.
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>بالین‌یار — مستندات فارسی</title>
<style>
:root { --teal:#1d4a40; --terracotta:#d98c6a; --bg:#faf9f5; --surface:#fff; --border:#e4ddd2; --text:#23211c; --soft:#5d574c; }
* { box-sizing:border-box; }
body { margin:0; background:var(--bg); color:var(--text); font-family:Tahoma,"Segoe UI",sans-serif; line-height:1.8; }
.wrap { max-width:760px; margin:0 auto; padding:48px 22px 80px; }
.brand { display:flex; align-items:center; gap:10px; font-size:1.5rem; font-weight:700; color:var(--teal); }
.brand .dot { width:13px; height:13px; border-radius:50%; background:var(--terracotta); }
.lead { color:var(--soft); margin:8px 0 30px; }
.card { display:block; background:var(--surface); border:1px solid var(--border); border-radius:12px;
padding:18px 20px; margin:14px 0; text-decoration:none; color:inherit; box-shadow:0 1px 3px rgba(0,0,0,.06); }
.card:hover { border-color:var(--teal); }
.card h2 { margin:0 0 6px; font-size:1.12rem; color:var(--teal); }
.card p { margin:0; color:var(--soft); font-size:.92rem; }
.back { display:inline-block; margin-top:28px; color:var(--teal); text-decoration:none; font-size:.92rem; }
hr { border:none; border-top:1px solid var(--border); margin:28px 0; }
</style>
</head>
<body>
<div class="wrap">
<div class="brand"><span class="dot"></span> بالین‌یار</div>
<p class="lead">مستندات فارسی — بازارگاه پرستاری در منزل مبتنی بر اعتماد. نسخهٔ مرجع (انگلیسی) به‌صورت موازی نگه‌داری می‌شود.</p>
<a class="card" href="platform-report.fa.html">
<h2>گزارش پلتفرم پرستاری در منزل — ایران</h2>
<p>تحلیل بازار و رقبا، مشکلات و ریسک‌ها، احراز هویت و صلاحیت پرستار، چارچوب حقوقی، و توصیه‌های ورود به بازار.</p>
</a>
<a class="card" href="nurse-verification-flow.fa.html">
<h2>فلوی احراز هویت و صلاحیت پرستار — راهنمای پیاده‌سازی</h2>
<p>اصول طراحی، داده‌های ورودی، نقشهٔ فلو، ماتریس تطبیق متقابل ضدِ تقلب، و نکات حقوقی و حریم خصوصی.</p>
</a>
<hr>
<a class="back" href="../index.html">← بازگشت به مستندات اصلی (انگلیسی)</a>
</div>
</body>
</html>
+75
View File
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Balinyaar — Product Documentation — Balinyaar docs</title>
<link rel="stylesheet" href="assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a class="active" href="index.html">Docs home</a></li><li><a href="overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="business/index.html">Overview &amp; MVP scope</a></li><li><a href="business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="data-model/index.html">Overview &amp; decisions</a></li><li><a href="data-model/diagrams.html">Diagrams</a></li><li><a href="data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="data-model/02-geography.html">2. Geography</a></li><li><a href="data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="data-model/07-payouts.html">7. Payouts</a></li><li><a href="data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="data-model/09-messaging.html">9. Messaging</a></li><li><a href="data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="data-model/11-notifications.html">11. Notifications</a></li><li><a href="data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="payments/index.html">Overview &amp; exec summary</a></li><li><a href="payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="research/index.html">Overview &amp; exec summary</a></li><li><a href="research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="research/verification.html">Verification (research)</a></li><li><a href="research/legal-landscape.html">Legal landscape</a></li><li><a href="research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="notes/open-questions.html">Open questions</a></li><li><a href="notes/future-ideas.html">Future ideas</a></li><li><a href="wireframes/index.html">Wireframes</a></li><li><a href="fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="balinyaar-product-documentation">Balinyaar — Product Documentation</h1>
<p><strong>Balinyaar</strong> is a trust-first home-nursing marketplace in Iran: independent, individually-verified nurses list configurable services; families search, book, pay, and review; the platform holds funds in an escrow-style ledger and pays nurses out weekly after a confirmed check-out.</p>
<p>This is the product/domain knowledge base — the <strong>source of truth</strong> for business rules, the data model, payments, and the market/legal research. Start with the <strong><a href="overview/platform-summary.html">Platform Summary &amp; cross-cutting ground truths</a></strong>, then dive into the area you need.</p>
<blockquote><p>The Markdown files here are canonical. The matching <code>.html</code> files are a generated, cross-linked browsing view — see <a href="README.html#regenerating-the-html-view">README</a> to regenerate.</p>
</blockquote>
<hr>
<h2 id="sections">Sections <a class="anchor" href="#sections" aria-hidden="true">#</a></h2>
<h3 id="-overviewoverviewplatform-summarymd">🧭 <a href="overview/platform-summary.html">Overview</a> <a class="anchor" href="#-overviewoverviewplatform-summarymd" aria-hidden="true">#</a></h3>
<p>What Balinyaar is, the four cross-cutting ground truths (no cash custody, 10% VAT, full-upfront BNPL, weekly nurse payout), the IRR/Toman rule, and a glossary of the Persian terms.</p>
<h3 id="-business-requirementsbusinessindexmd">📋 <a href="business/index.html">Business Requirements</a> <a class="anchor" href="#-business-requirementsbusinessindexmd" aria-hidden="true">#</a></h3>
<p>The 14 functional areas — onboarding, verification, catalog &amp; pricing, search, booking, EVV, cancellation, payments/escrow, BNPL, payouts, reviews, messaging, tax/legal, admin — each with business rules, Iran-specific considerations, MVP-vs-deferred scope, and supporting entities.</p>
<h3 id="-database-modeldata-modelindexmd">🗄️ <a href="data-model/index.html">Database Model</a> <a class="anchor" href="#-database-modeldata-modelindexmd" aria-hidden="true">#</a></h3>
<p>The refined ~54-table SQL Server schema across 13 domains, plus <a href="data-model/diagrams.html">ER &amp; flow diagrams</a>, design principles, the two resolved BNPL questions, and the key design decisions.</p>
<h3 id="-payments-escrow-bnplpaymentsindexmd">💳 <a href="payments/index.html">Payments, Escrow &amp; BNPL</a> <a class="anchor" href="#-payments-escrow-bnplpaymentsindexmd" aria-hidden="true">#</a></h3>
<p>The fintech deep-dive (with sources): the Iranian payment reality, escrow as a double-entry ledger, the BNPL landscape &amp; full-upfront finding, cancellation/refund + who-pays-the-nurse, and SnappPay / Digipay integration notes.</p>
<h3 id="-research-strategyresearchindexmd">🔬 <a href="research/index.html">Research &amp; Strategy</a> <a class="anchor" href="#-research-strategyresearchindexmd" aria-hidden="true">#</a></h3>
<p>Market &amp; competitors, problems &amp; risks, nurse identity/credential verification, the Iranian legal landscape, and go-to-market recommendations — adversarially fact-checked, with citations.</p>
<h3 id="-notesnotesopen-questionsmd">🗒️ <a href="notes/open-questions.html">Notes</a> <a class="anchor" href="#-notesnotesopen-questionsmd" aria-hidden="true">#</a></h3>
<p>Living product notes: <a href="notes/open-questions.html">open questions</a> and <a href="notes/future-ideas.html">future ideas / backlog</a>.</p>
<h3 id="-wireframeswireframesindexhtml">🖼️ <a href="wireframes/index.html">Wireframes</a> <a class="anchor" href="#-wireframeswireframesindexhtml" aria-hidden="true">#</a></h3>
<p>The Balinyaar screen wireframes (login/onboarding, nurse verification, booking, BNPL, patient record).</p>
<h3 id="-farsi-documentsfaindexhtml">🇮🇷 <a href="fa/index.html">Farsi documents</a> <a class="anchor" href="#-farsi-documentsfaindexhtml" aria-hidden="true">#</a></h3>
<p>Persian-language versions kept in parallel: the platform research report and the nurse verification-flow implementation guide.</p>
<hr>
<h2 id="how-the-docs-relate">How the docs relate <a class="anchor" href="#how-the-docs-relate" aria-hidden="true">#</a></h2>
<pre class="mermaid">flowchart LR
OV["🧭 Overview&lt;br/&gt;ground truths + glossary"]
RES["🔬 Research&lt;br/&gt;why: market, legal, risk"]
BIZ["📋 Business Requirements&lt;br/&gt;what the platform must do"]
DM["🗄️ Database Model&lt;br/&gt;how it's stored"]
PAY["💳 Payments deep-dive&lt;br/&gt;the money mechanics"]
OV --&gt; BIZ
RES --&gt; BIZ
BIZ --&gt; DM
BIZ &lt;--&gt; PAY
PAY &lt;--&gt; DM</pre>
<ul>
<li><strong>Research</strong> explains <em>why</em> (market gap, legal track, trust risks). <strong>Business Requirements</strong></li>
</ul>
<p> states <em>what</em> must ship. <strong>Database Model</strong> is <em>how</em> it's stored. <strong>Payments</strong> is the <em>money detail</em> shared by the other three. They cross-link rather than repeat each other.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
const dark = document.documentElement.getAttribute('data-theme') === 'dark';
mermaid.initialize({ startOnLoad: true, theme: dark ? 'dark' : 'neutral' });
</script>
</body>
</html>
+75
View File
@@ -0,0 +1,75 @@
# Balinyaar — Product Documentation
**Balinyaar** is a trust-first home-nursing marketplace in Iran: independent, individually-verified
nurses list configurable services; families search, book, pay, and review; the platform holds funds
in an escrow-style ledger and pays nurses out weekly after a confirmed check-out.
This is the product/domain knowledge base — the **source of truth** for business rules, the data
model, payments, and the market/legal research. Start with the
**[Platform Summary & cross-cutting ground truths](overview/platform-summary.md)**, then dive into
the area you need.
> The Markdown files here are canonical. The matching `.html` files are a generated, cross-linked
> browsing view — see [README](README.md#regenerating-the-html-view) to regenerate.
---
## Sections
### 🧭 [Overview](overview/platform-summary.md)
What Balinyaar is, the four cross-cutting ground truths (no cash custody, 10% VAT, full-upfront
BNPL, weekly nurse payout), the IRR/Toman rule, and a glossary of the Persian terms.
### 📋 [Business Requirements](business/index.md)
The 14 functional areas — onboarding, verification, catalog & pricing, search, booking, EVV,
cancellation, payments/escrow, BNPL, payouts, reviews, messaging, tax/legal, admin — each with
business rules, Iran-specific considerations, MVP-vs-deferred scope, and supporting entities.
### 🗄️ [Database Model](data-model/index.md)
The refined ~54-table SQL Server schema across 13 domains, plus
[ER & flow diagrams](data-model/diagrams.md), design principles, the two resolved BNPL questions,
and the key design decisions.
### 💳 [Payments, Escrow & BNPL](payments/index.md)
The fintech deep-dive (with sources): the Iranian payment reality, escrow as a double-entry ledger,
the BNPL landscape & full-upfront finding, cancellation/refund + who-pays-the-nurse, and SnappPay /
Digipay integration notes.
### 🔬 [Research & Strategy](research/index.md)
Market & competitors, problems & risks, nurse identity/credential verification, the Iranian legal
landscape, and go-to-market recommendations — adversarially fact-checked, with citations.
### 🗒️ [Notes](notes/open-questions.md)
Living product notes: [open questions](notes/open-questions.md) and
[future ideas / backlog](notes/future-ideas.md).
### 🖼️ [Wireframes](wireframes/index.html)
The Balinyaar screen wireframes (login/onboarding, nurse verification, booking, BNPL, patient
record).
### 🇮🇷 [Farsi documents](fa/index.html)
Persian-language versions kept in parallel: the platform research report and the nurse
verification-flow implementation guide.
---
## How the docs relate
```mermaid
flowchart LR
OV["🧭 Overview<br/>ground truths + glossary"]
RES["🔬 Research<br/>why: market, legal, risk"]
BIZ["📋 Business Requirements<br/>what the platform must do"]
DM["🗄️ Database Model<br/>how it's stored"]
PAY["💳 Payments deep-dive<br/>the money mechanics"]
OV --> BIZ
RES --> BIZ
BIZ --> DM
BIZ <--> PAY
PAY <--> DM
```
- **Research** explains *why* (market gap, legal track, trust risks). **Business Requirements**
states *what* must ship. **Database Model** is *how* it's stored. **Payments** is the *money detail*
shared by the other three. They cross-link rather than repeat each other.
+59
View File
@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Future Ideas &amp; Backlog — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="open-questions.html">Open questions</a></li><li><a class="active" href="future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="future-ideas-backlog">Future Ideas &amp; Backlog</h1>
<p><a href="../index.html">← Product docs home</a></p>
<p>Raw product thinking captured for later — <strong>not</strong> committed MVP scope. Original notes were in Farsi (<code>additional-info.txt</code>); kept verbatim with light framing.</p>
<hr>
<h2 id="1-platform-owned-pricing-flow-آینده-future">1. Platform-owned pricing flow (آینده / future) <a class="anchor" href="#1-platform-owned-pricing-flow-آینده-future" aria-hidden="true">#</a></h2>
<p>فلوی قیمت باید سمت ما باشه:</p>
<ul>
<li>وقتی فرد می‌خواد دستمزد ساعتی و روزانه‌اش رو مشخص کنه، باید یه <strong>رنجی از بازار</strong> بهش نشون بدیم و</li>
</ul>
<p> چند تا نکته بنویسیم: اگر زیاد گذاشت یا کم، که «رنج مناسبی نذاشتی و مشتری‌هات کم میشه»؛ و نسبت به <strong>سابقه و مهارت‌ها</strong> یه <strong>عدد پیشنهادی</strong> توی بازه بهش نشون بدیم که کار رو راحت‌تر کنه.</p>
<ul>
<li>در آینده باید داستان <strong>بوست (boost)</strong> رو برای هر دو طرف مشخص کنیم — اگر مشتری بخواد زودتر کسی رو</li>
</ul>
<p> پیدا کنه، یا پرستار بخواد زودتر کار بگیره (مرحلهٔ خیلی بعد).</p>
<ul>
<li>کل پروسهٔ <strong>بید زدن (bidding)</strong> پرستارها رو بذاریم برای بعداً — چون مشتری رو ناراضی می‌کنه و الان</li>
</ul>
<p> وقتش نیست.</p>
<blockquote><p>Relates to today's MVP, where nurses set their own transparent prices per variant — see <a href="../business/03-service-catalog-and-pricing.html">Service Catalog &amp; Pricing</a>. Surge/boost/bidding are explicitly <strong>deferred</strong> there.</p>
</blockquote>
<hr>
<h2 id="2-installments-only-above-a-meaningful-threshold">2. Installments only above a meaningful threshold <a class="anchor" href="#2-installments-only-above-a-meaningful-threshold" aria-hidden="true">#</a></h2>
<p>سیستم اقساطی باید بصرفه باشه — نباید برای <strong>یک روز</strong> خدمات قسطی بدیم. برای درخواست‌های <strong>بالای سه روز</strong> (شاید حتی بالاتر) منطقی‌تره که عددش معنی‌دار بشه — کسی ۴–۵ تومن رو قسطی نمی‌کنه. (این گمان هست؛ باید دیتای بیشتری ببینیم.)</p>
<p>پس نیاز داریم بتونیم برای <strong>بازه‌های قیمتی متفاوت</strong>، گزینه‌های پرداخت (کارت / BNPL) رو <strong>فعال یا غیرفعال</strong> کنیم.</p>
<blockquote><p>Implementation hook: a config-driven rule that enables/disables BNPL by booking total / duration. See the <a href="../business/09-installments-bnpl.html">BNPL business area</a> and <code>platform_configs</code> in <a href="../data-model/12-audit-config-and-reference.html">audit, config &amp; reference</a>.</p>
</blockquote>
<hr>
<h2 id="3-blog-آینده-future">3. Blog (آینده / future) <a class="anchor" href="#3-blog-آینده-future" aria-hidden="true">#</a></h2>
<p>برای آینده، یک <strong>بلاگ</strong> در نظر داشته باشیم.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+45
View File
@@ -0,0 +1,45 @@
# Future Ideas & Backlog
[← Product docs home](../index.md)
Raw product thinking captured for later — **not** committed MVP scope. Original notes were in Farsi
(`additional-info.txt`); kept verbatim with light framing.
---
## 1. Platform-owned pricing flow (آینده / future)
فلوی قیمت باید سمت ما باشه:
- وقتی فرد می‌خواد دستمزد ساعتی و روزانه‌اش رو مشخص کنه، باید یه **رنجی از بازار** بهش نشون بدیم و
چند تا نکته بنویسیم: اگر زیاد گذاشت یا کم، که «رنج مناسبی نذاشتی و مشتری‌هات کم میشه»؛ و نسبت به
**سابقه و مهارت‌ها** یه **عدد پیشنهادی** توی بازه بهش نشون بدیم که کار رو راحت‌تر کنه.
- در آینده باید داستان **بوست (boost)** رو برای هر دو طرف مشخص کنیم — اگر مشتری بخواد زودتر کسی رو
پیدا کنه، یا پرستار بخواد زودتر کار بگیره (مرحلهٔ خیلی بعد).
- کل پروسهٔ **بید زدن (bidding)** پرستارها رو بذاریم برای بعداً — چون مشتری رو ناراضی می‌کنه و الان
وقتش نیست.
> Relates to today's MVP, where nurses set their own transparent prices per variant — see
> [Service Catalog & Pricing](../business/03-service-catalog-and-pricing.md). Surge/boost/bidding
> are explicitly **deferred** there.
---
## 2. Installments only above a meaningful threshold
سیستم اقساطی باید بصرفه باشه — نباید برای **یک روز** خدمات قسطی بدیم. برای درخواست‌های **بالای سه
روز** (شاید حتی بالاتر) منطقی‌تره که عددش معنی‌دار بشه — کسی ۴–۵ تومن رو قسطی نمی‌کنه. (این گمان
هست؛ باید دیتای بیشتری ببینیم.)
پس نیاز داریم بتونیم برای **بازه‌های قیمتی متفاوت**، گزینه‌های پرداخت (کارت / BNPL) رو **فعال یا
غیرفعال** کنیم.
> Implementation hook: a config-driven rule that enables/disables BNPL by booking
> total / duration. See the [BNPL business area](../business/09-installments-bnpl.md) and
> `platform_configs` in [audit, config & reference](../data-model/12-audit-config-and-reference.md).
---
## 3. Blog (آینده / future)
برای آینده، یک **بلاگ** در نظر داشته باشیم.
+63
View File
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Open Questions &amp; To-Do Backlog — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a class="active" href="open-questions.html">Open questions</a></li><li><a href="future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="open-questions-to-do-backlog">Open Questions &amp; To-Do Backlog</h1>
<p><a href="../index.html">← Product docs home</a></p>
<p>From <code>whatsInYourMind.txt</code> — things to build, research, or decide. Some are now resolved in the refined data model; marked below.</p>
<hr>
<h2 id="build-surface-backlog">Build / surface backlog <a class="anchor" href="#build-surface-backlog" aria-hidden="true">#</a></h2>
<ul>
<li><strong>Ticket page</strong> — the admin-readable messaging surface; modeled in</li>
</ul>
<p> <a href="../data-model/09-messaging.html">Messaging (ticket system)</a> and required by <a href="../business/12-messaging-and-emergencies.html">Messaging &amp; On-Site Emergencies</a>.</p>
<ul>
<li><strong>Backoffice / admin</strong> — see <a href="../business/14-notifications-and-admin.html">Notifications &amp; Admin / Backoffice</a>.</li>
<li><strong>Verify the registration code</strong> — OTP confirmation step in onboarding.</li>
<li><strong>Rate limiting</strong> — abuse protection on auth/OTP and API.</li>
<li><strong>Workbox for cache</strong> (maybe) — PWA/offline caching, client-side.</li>
</ul>
<h2 id="needs-research">Needs research <a class="anchor" href="#needs-research" aria-hidden="true">#</a></h2>
<ul>
<li><strong>Terms of Service page</strong><em>(needs research)</em>.</li>
<li><strong>Privacy &amp; Policy page</strong><em>(needs research)</em>.</li>
</ul>
<hr>
<h2 id="resolved-questions-kept-for-the-record">Resolved questions (kept for the record) <a class="anchor" href="#resolved-questions-kept-for-the-record" aria-hidden="true">#</a></h2>
<p>These were the two hardest open questions; both are now <strong>answered</strong> against verified payment research and built into the model.</p>
<ul>
<li><del>اگر پرداخت قسطی داشته باشیم و طرف اون وسط بخواد کنسل کنه چی میشه؟</del></li>
</ul>
<p> <strong>(BNPL booking cancelled mid-plan — what happens?)</strong> → Resolved. Money always flows <code>customer ↔ provider ↔ Balinyaar</code>; Balinyaar calls the provider's revert/cancel/update API and the provider unwinds the customer's installments. See <a href="../payments/cancellation-and-payout.html">Q1 — cancellation/refund</a> and <a href="../data-model/index.html">the two questions</a>.</p>
<ul>
<li><del>BNPL اگر باشه خب پول پرستار رو کی میده؟</del></li>
</ul>
<p> <strong>(Under BNPL, who pays the nurse?)</strong> → Resolved. <strong>Balinyaar</strong> pays the nurse, on its own weekly schedule, from <code>gross balinyaar_commission</code> — identical to a card booking; the BNPL commission is a platform expense, never the nurse's. See <a href="../payments/cancellation-and-payout.html">Q2 — who pays the nurse &amp; when</a>.</p>
<hr>
<p>See also the launch-blocking items to confirm with counsel / providers: <a href="../research/go-to-market.html">research open questions</a> and <a href="../data-model/index.html">data-model open items</a>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+47
View File
@@ -0,0 +1,47 @@
# Open Questions & To-Do Backlog
[← Product docs home](../index.md)
From `whatsInYourMind.txt` — things to build, research, or decide. Some are now resolved in the
refined data model; marked below.
---
## Build / surface backlog
- **Ticket page** — the admin-readable messaging surface; modeled in
[Messaging (ticket system)](../data-model/09-messaging.md) and required by
[Messaging & On-Site Emergencies](../business/12-messaging-and-emergencies.md).
- **Backoffice / admin** — see [Notifications & Admin / Backoffice](../business/14-notifications-and-admin.md).
- **Verify the registration code** — OTP confirmation step in onboarding.
- **Rate limiting** — abuse protection on auth/OTP and API.
- **Workbox for cache** (maybe) — PWA/offline caching, client-side.
## Needs research
- **Terms of Service page***(needs research)*.
- **Privacy & Policy page***(needs research)*.
---
## Resolved questions (kept for the record)
These were the two hardest open questions; both are now **answered** against verified payment
research and built into the model.
- ~~اگر پرداخت قسطی داشته باشیم و طرف اون وسط بخواد کنسل کنه چی میشه؟~~
**(BNPL booking cancelled mid-plan — what happens?)** → Resolved. Money always flows
`customer ↔ provider ↔ Balinyaar`; Balinyaar calls the provider's revert/cancel/update API and the
provider unwinds the customer's installments. See
[Q1 — cancellation/refund](../payments/cancellation-and-payout.md) and
[the two questions](../data-model/index.md).
- ~~BNPL اگر باشه خب پول پرستار رو کی میده؟~~
**(Under BNPL, who pays the nurse?)** → Resolved. **Balinyaar** pays the nurse, on its own weekly
schedule, from `gross balinyaar_commission` — identical to a card booking; the BNPL commission is
a platform expense, never the nurse's. See [Q2 — who pays the nurse & when](../payments/cancellation-and-payout.md).
---
See also the launch-blocking items to confirm with counsel / providers:
[research open questions](../research/go-to-market.md) and
[data-model open items](../data-model/index.md).
+82
View File
@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Platform Summary &amp; Cross-Cutting Ground Truths — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a class="active" href="platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="platform-summary-cross-cutting-ground-truths">Platform Summary &amp; Cross-Cutting Ground Truths</h1>
<p><a href="../index.html">← Product docs home</a></p>
<p><strong>Balinyaar is a trust-first home-nursing marketplace in Iran.</strong> Independent, individually-verified nurses register, list configurable services with their own pricing, and pass a multi-step verification pipeline anchored on the MoH <strong>پروانه صلاحیت حرفه‌ای</strong> (professional-competency license). Families search — filtered by city/district <strong>and same-gender caregiver preference</strong> — pick a nurse and a service variant, submit a booking request, and pay <strong>through the platform</strong> after the nurse accepts. The platform records the money as an <strong>internal escrow ledger state</strong> (not platform-held cash), the nurse performs one or more EVV-verified visits, and the platform pays the nurse <strong>weekly, after the dispute window closes</strong>, minus a platform commission. All post-booking communication runs through an admin-readable ticket system.</p>
<p>At launch the platform operates under a <strong>partner licensed home-nursing center (مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل)</strong> — the Asanism-style model — which is the legal vehicle and the likely <strong>merchant-of-record</strong> for payments while Balinyaar's own MoH permit is in process.</p>
<hr>
<h2 id="the-four-cross-cutting-ground-truths">The four cross-cutting ground truths <a class="anchor" href="#the-four-cross-cutting-ground-truths" aria-hidden="true">#</a></h2>
<p>These hold across <strong>every</strong> business area and data-model domain. They are the load-bearing decisions the rest of the docs assume.</p>
<ol>
<li><strong>Balinyaar cannot legally custody customer cash.</strong> Under Iranian rules a پرداخت‌یار (payment</li>
</ol>
<p> facilitator) is forbidden from holding deposits, running wallets, or moving money between merchants. Money always flows card → licensed PSP → Shaparak settlement → <strong>bank-registered IBANs</strong>. "Escrow" is therefore an <strong>internal ledger state</strong> over funds custodied at a licensed provider/partner bank — never a Balinyaar-owned cash balance. See <a href="../payments/escrow-ledger.html">escrow as a ledger</a> and the <a href="../data-model/06-payments-ledger-and-refunds.html"><code>ledger_entries</code></a> entity.</p>
<ol>
<li><strong>VAT is 10%</strong>, not 9% — it rose from 9% to 10% in 1403 (7% government + 3% municipal) and is</li>
</ol>
<p> treated as a <strong>configurable</strong> rate. See <a href="../payments/iranian-payment-reality.html">Iranian payment reality §2.6</a> and <a href="../business/13-tax-invoicing-and-legal.html">tax, invoicing &amp; legal</a>.</p>
<ol>
<li><strong>BNPL is full-upfront.</strong> A BNPL provider settles **one full-amount lump (net of its commission)</li>
</ol>
<p> 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. See <a href="../payments/bnpl-landscape.html">the full-upfront finding</a>.</p>
<ol>
<li><strong>The nurse is paid by Balinyaar, weekly, on Balinyaar's own schedule</strong> — gated on EVV</li>
</ol>
<p> completion and a closed dispute window — regardless of how the family paid. See <a href="../payments/cancellation-and-payout.html">who pays the nurse &amp; when</a> and <a href="../business/10-payouts.html">payouts</a>.</p>
<hr>
<h2 id="money-is-irr-rials-always">Money is IRR Rials, always <a class="anchor" href="#money-is-irr-rials-always" aria-hidden="true">#</a></h2>
<p>All monetary values are in <strong>IRR (Rials)</strong>, stored as <code>BIGINT</code>. <strong>Toman is a display concern only</strong> and is converted to/from Rials <strong>solely at an external provider's API boundary</strong> (e.g. SnappPay quotes Toman). No floats anywhere on the money path.</p>
<hr>
<h2 id="glossary-the-persian-terms-you-will-keep-meeting">Glossary — the Persian terms you will keep meeting <a class="anchor" href="#glossary-the-persian-terms-you-will-keep-meeting" aria-hidden="true">#</a></h2>
<div class="table-wrap"><table><thead><tr><th>Term</th><th>What it is</th></tr></thead><tbody>
<tr><td>پرداخت‌یار (payment facilitator)</td><td>The PSP-contracted license class an MVP marketplace rides on; <strong>barred from custodying funds</strong>.</td></tr>
<tr><td>تسهیم (settlement-sharing)</td><td>Shaparak/provider splitting one card payment across registered IBANs — the compliant marketplace primitive.</td></tr>
<tr><td>Shaparak (شاپرک)</td><td>Iran's national card-payment switch; settles to registered IBANs.</td></tr>
<tr><td>IBAN / شِبا (Sheba)</td><td>The bank account number money settles to; must be ownership-verified for nurse payouts.</td></tr>
<tr><td>پروانه صلاحیت حرفه‌ای</td><td>MoH professional-competency license — the single most important nurse credential; bundles a criminal-record screen.</td></tr>
<tr><td>نظام پرستاری (INO)</td><td>Iranian Nursing Organization; membership number used as a verification cross-check.</td></tr>
<tr><td>عدم سوء پیشینه</td><td>Criminal-record ("no record") certificate; consent-gated to the individual, no company API.</td></tr>
<tr><td>Shahkar (شاهکار)</td><td>Government service matching a SIM ↔ national ID (کد ملی).</td></tr>
<tr><td>سامانه مودیان</td><td>Iran's taxpayer / e-invoicing system (22-digit fiscal numbers).</td></tr>
<tr><td>اینماد / e-namad</td><td>Electronic trust symbol; de-facto mandatory to obtain an online payment gateway.</td></tr>
<tr><td>شبانه‌روزی</td><td>24-hour / live-in care shift — the dominant elder-care shape.</td></tr>
<tr><td>EVV</td><td>Electronic Visit Verification — GPS + timestamped nurse check-in/out per visit.</td></tr>
<tr><td>BNPL</td><td>Buy-Now-Pay-Later (خرید اقساطی).</td></tr>
<tr><td>Asanism model</td><td>Going to market by partnering with already-licensed home-nursing centers.</td></tr>
</tbody></table></div>
<hr>
<h2 id="where-to-go-next">Where to go next <a class="anchor" href="#where-to-go-next" aria-hidden="true">#</a></h2>
<ul>
<li><strong><a href="../business/index.html">Business Requirements</a></strong> — what the platform must do, area by area.</li>
<li><strong><a href="../data-model/index.html">Database Model</a></strong> — the ~54-table schema, domain by domain.</li>
<li><strong><a href="../payments/index.html">Payments deep-dive</a></strong> — escrow, settlement, BNPL, integrations.</li>
<li><strong><a href="../research/index.html">Research &amp; Strategy</a></strong> — market, risks, verification, legal, GTM.</li>
</ul>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+81
View File
@@ -0,0 +1,81 @@
# Platform Summary & Cross-Cutting Ground Truths
[← Product docs home](../index.md)
**Balinyaar is a trust-first home-nursing marketplace in Iran.** Independent,
individually-verified nurses register, list configurable services with their own pricing, and pass
a multi-step verification pipeline anchored on the MoH **پروانه صلاحیت حرفه‌ای**
(professional-competency license). Families search — filtered by city/district **and same-gender
caregiver preference** — pick a nurse and a service variant, submit a booking request, and pay
**through the platform** after the nurse accepts. The platform records the money as an **internal
escrow ledger state** (not platform-held cash), the nurse performs one or more EVV-verified visits,
and the platform pays the nurse **weekly, after the dispute window closes**, minus a platform
commission. All post-booking communication runs through an admin-readable ticket system.
At launch the platform operates under a **partner licensed home-nursing center
(مرکز مشاوره و ارائه مراقبت‌های پرستاری در منزل)** — the Asanism-style model — which is the legal
vehicle and the likely **merchant-of-record** for payments while Balinyaar's own MoH permit is in
process.
---
## The four cross-cutting ground truths
These hold across **every** business area and data-model domain. They are the load-bearing
decisions the rest of the docs assume.
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.
See [escrow as a ledger](../payments/escrow-ledger.md) and the
[`ledger_entries`](../data-model/06-payments-ledger-and-refunds.md) entity.
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. See [Iranian payment reality §2.6](../payments/iranian-payment-reality.md)
and [tax, invoicing & legal](../business/13-tax-invoicing-and-legal.md).
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. See [the full-upfront finding](../payments/bnpl-landscape.md).
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. See
[who pays the nurse & when](../payments/cancellation-and-payout.md) and [payouts](../business/10-payouts.md).
---
## Money is IRR Rials, always
All monetary values are in **IRR (Rials)**, stored as `BIGINT`. **Toman is a display concern only**
and is converted to/from Rials **solely at an external provider's API boundary** (e.g. SnappPay
quotes Toman). No floats anywhere on the money path.
---
## Glossary — the Persian terms you will keep meeting
| Term | What it is |
| --- | --- |
| پرداخت‌یار (payment facilitator) | The PSP-contracted license class an MVP marketplace rides on; **barred from custodying funds**. |
| تسهیم (settlement-sharing) | Shaparak/provider splitting one card payment across registered IBANs — the compliant marketplace primitive. |
| Shaparak (شاپرک) | Iran's national card-payment switch; settles to registered IBANs. |
| IBAN / شِبا (Sheba) | The bank account number money settles to; must be ownership-verified for nurse payouts. |
| پروانه صلاحیت حرفه‌ای | MoH professional-competency license — the single most important nurse credential; bundles a criminal-record screen. |
| نظام پرستاری (INO) | Iranian Nursing Organization; membership number used as a verification cross-check. |
| عدم سوء پیشینه | Criminal-record ("no record") certificate; consent-gated to the individual, no company API. |
| Shahkar (شاهکار) | Government service matching a SIM ↔ national ID (کد ملی). |
| سامانه مودیان | Iran's taxpayer / e-invoicing system (22-digit fiscal numbers). |
| اینماد / e-namad | Electronic trust symbol; de-facto mandatory to obtain an online payment gateway. |
| شبانه‌روزی | 24-hour / live-in care shift — the dominant elder-care shape. |
| EVV | Electronic Visit Verification — GPS + timestamped nurse check-in/out per visit. |
| BNPL | Buy-Now-Pay-Later (خرید اقساطی). |
| Asanism model | Going to market by partnering with already-licensed home-nursing centers. |
---
## Where to go next
- **[Business Requirements](../business/index.md)** — what the platform must do, area by area.
- **[Database Model](../data-model/index.md)** — the ~54-table schema, domain by domain.
- **[Payments deep-dive](../payments/index.md)** — escrow, settlement, BNPL, integrations.
- **[Research & Strategy](../research/index.md)** — market, risks, verification, legal, GTM.
-347
View File
@@ -1,347 +0,0 @@
# Balinyaar — Payments, Escrow, Settlement & Installments (BNPL)
> **Purpose.** This is the fintech deep-dive for Balinyaar, an MVP home-nursing marketplace in Iran. It pins down how the platform collects money from families, holds an *internal escrow ledger state* (not custodied cash), pays nurses weekly minus commission, and integrates Iranian Buy-Now-Pay-Later (خرید اقساطی / BNPL). It answers the two questions the team cares most about — how a BNPL booking is cancelled/refunded mid-plan, and who pays the nurse (and when) under BNPL — and it grounds every decision in verified research, separating **VERIFIED** facts from **CONFIGURABLE / UNCERTAIN** items that must be confirmed at contracting. All money is **IRR (Rials), stored as `BIGINT`**; Toman is display-only and converted only at the provider API boundary.
**Date:** 2026-06-20
---
## 1. Executive summary
- **Balinyaar legally CANNOT custody buyer funds.** In Iran money always flows card → licensed PSP → Shaparak settlement → bank-registered IBANs. A پرداخت‌یار (payment facilitator — the license class an MVP rides on) is explicitly **barred from holding deposits, running wallets, paying interest, or moving money between merchants**. "Platform holds escrow" must therefore be implemented as an **internal double-entry ledger state** over funds custodied at a licensed provider — never as cash in a Balinyaar bank account. *(VERIFIED — multiple independent sources + CBI/Shaparak directives.)*
- **The compliant marketplace primitive is تسهیم (settlement-sharing):** one incoming card payment is split by the provider/Shaparak across multiple registered IBANs (the nurse's share, the platform's commission) and deposited directly — the platform never touches the split. Shaparak has separately **banned inter-merchant / inter-facilitator transfers and wallet-style holding**, which makes a "delay-then-redistribute" pool legally grey-to-prohibited. *(VERIFIED.)*
- **The decisive BNPL finding: full-upfront settlement.** Provider-financed Iranian BNPLs (SnappPay, Digipay, Tara, Torob Pay, ZarinPlus) pay the **merchant the FULL amount in ONE lump, minus a merchant commission, and bear 100% of customer-default risk.** The customer's installments are owned entirely by the provider and are **decoupled** from Balinyaar's escrow/EVV/payout cycle. *(VERIFIED for SnappPay and Torob Pay from credible sources; consistent for Digipay and Tara.)*
- **Consequence — a BNPL order = a card payment landing net-of-fee.** Therefore Balinyaar **does NOT track customer installments** (no `installment_entries`, no per-installment webhooks, no default propagation). This deletes an entire fragile subsystem.
- **But settlement TIMING is not instant.** The "full amount" is true in *amount*, not *timing*: cadence is contract-defined (daily / T+13 / weekly / 15-day), and at least one authoritative SnappPay source gates settlement on the customer's **first installment** (پس از واریز اولین قسط). Model a per-transaction `settled_at`; never assume instant. *(VERIFIED correction to the original research.)*
- **Under BNPL the nurse is paid by Balinyaar, on Balinyaar's own weekly schedule, exactly as for a card booking** — after EVV check-out and the dispute window. The nurse's payout is computed from `gross_price_irr balinyaar_commission_irr`, **NOT** from the BNPL-net amount. The BNPL commission is a **platform expense** that must never touch the nurse's payout.
- **Avoid Lendo for the MVP.** It is bank-financed (Bank Ayandeh): the **customer** pays ~1823% interest plus a ~5% (often non-refundable) service fee over 612 months — a POS loan, a poor fit for short, cancellable nursing visits.
- **Two corrections the research forced:** VAT in Iran is **10%** (rose from 9% in 1403, = govt 7% + municipal 3%), not 9% — and make it configurable since it has moved two years running. And the Digipay "24h-pay / collect-in-525-days-from-business" sentence describes the **early-settlement/factoring** product, **not** BNPL — right conclusion, wrong evidence; the correct first-party BNPL source is `mydigipay.com/bpg/`.
- **Provider continuity is a real risk.** In **Nov 2024 the CBI abruptly cut Toman and Jibit's settlement/withdrawal services** with no stated cause, stranding businesses (including millions of Snapp drivers). Design for multi-provider failover and a reconciliation ledger that survives a provider being cut mid-cycle.
- **Recommendation:** integrate **SnappPay first**, **Digipay second**, **avoid Lendo**. Onboarding the Balinyaar entity needs **both جواز کسب AND eNamad (اینماد)**. Whether a multi-vendor marketplace re-disbursing to many independent nurses qualifies as a single merchant is **publicly UNCONFIRMED** — confirm with provider sales before relying on it.
---
## 2. The Iranian payment reality
### 2.1 The rails: card → PSP → Shaparak → registered IBANs
Every card payment in Iran is acquired by a licensed **PSP** and cleared through **Shaparak** (the national switch), which settles to **bank-registered IBANs (شِبا)** of the merchant/beneficiaries. There is **no native marketplace-escrow construct** the way a US/EU platform would hold buyer cash in trust. The platform does not — and legally may not — sit in the money path as a custodian.
### 2.2 The license class: پرداخت‌یار (payment facilitator) and the custody prohibition
An MVP marketplace like Balinyaar rides on a **پرداخت‌یار (payment facilitator / aggregator)** arrangement under a contracted PSP and the CBI/Shaparak agreement. A facilitator is **explicitly forbidden** from:
- holding customer deposits,
- operating wallets,
- paying interest,
- granting credit / guarantees,
- temporarily using merchant balances.
Settlement must go **only** to merchant-registered bank accounts, and **only Shaparak** can withdraw from the special facilitator settlement account (حساب ویژه پرداخت‌یاری). Unauthorized fund-holding draws penalties, license suspension, and AML exposure. **This is the single load-bearing constraint of the whole design: Balinyaar cannot be the custodian of buyer funds.** *(VERIFIED — way2pay, Zibal legal blog, finolaw, peivast.)*
### 2.3 تسهیم (settlement-sharing) — the compliant marketplace primitive
The legitimate way to pay many providers is **تسهیم / تسویه اشتراکی (settlement-sharing)**: a single incoming card payment is split across multiple registered IBANs (the nurse's net share + the platform's commission) and **credited directly by Shaparak/the provider** to each party. The platform never touches the actual split. ZarinPal markets this for marketplaces (بازارگاه) with split-by-ratio to each partner's registered Sheba; Zibal, Sadad, SizPay, Vandar, Jibit, Zibal, PayPing, IDPay offer variants. *(VERIFIED.)*
> **Caveat (CONFIGURABLE):** ZarinPal's تسهیم appears gated to a "golden" (طلایی) membership tier; all timing/minimum/limit numbers (e.g. ~100,000 IRR minimum, processing windows, "no beneficiary limit") came from single doc reads and must be reconfirmed at contracting.
### 2.4 The banned move: inter-merchant / inter-facilitator transfers and held pools
A tempting design — "collect into a platform pool, hold until EVV check-out, then redistribute" — is **regulatory grey-to-prohibited.** Shaparak **explicitly banned inter-facilitator and inter-merchant fund transfers and wallet-style holding.** A *delayed but pre-fixed* split to the **same registered IBANs** may be tolerable; **moving/holding funds in a platform-controlled pool to release conditionally is the banned behavior.** The only clean hold/release/refund mechanism is a **bank-grade escrow product** (e.g. Vandar میندو / معاملات امن — buyer pays into trust, released to seller on confirmation, refundable on seller failure), but even that is flagged as regulatorily fragile and its API-level EVV trigger is unverified. **Practical conclusion: model escrow as an internal ledger over whichever provider primitive you contract; do not assume you can lawfully custody cash yourself.** *(VERIFIED ban; the "delay-then-hold" pattern is the OVERSTATED part of the original research.)*
### 2.5 Provider cut-off continuity risk (Toman / Jibit, Nov 2024)
In **November 2024 the CBI abruptly cut Toman's and Jibit's settlement/withdrawal services** with no stated cause, disrupting businesses including millions of Snapp drivers who could not settle. Wallet/balance facilitator models have been blocked and re-permitted before (Vandar's gateway was blocked then unblocked by Shaparak). **Design for multi-provider failover and a reconciliation ledger that survives a provider being cut off mid-cycle.** *(VERIFIED — zoomit, way2pay, ecoiran.)*
### 2.6 Tax: سامانه مودیان and VAT = 10%
- Iran's **سامانه مودیان (taxpayer / e-invoicing system)** requires electronic invoices (صورتحساب الکترونیکی) with a **22-digit number**, a **memory tax-id (شناسه یکتای حافظه مالیاتی)**, and a digital signature. The **SELLER issues the invoice** and remits VAT; the buyer cannot. For a marketplace this maps cleanly: **each nurse is the taxable seller of the nursing service; Balinyaar's taxable supply is ONLY its commission** (the Snapp/Tapsi precedent). *(VERIFIED.)*
- **VAT is 10%**, not 9%: the standard rate **rose from 9% to 10% in 1403** (govt 7% + municipal 3%) and remains 10% in 1404. Any VAT field hardcoded at 9% is stale — **use 10% and make it a configurable parameter**, since it has changed two years running. *(VERIFIED correction.)*
- مودیان enrollment is phased in by revenue threshold (individuals with sales above ~144bn IRR through end of 1404 must issue e-invoices from Tir 1405). Whether the home-nursing **service** itself is VAT-exempt (medical exemption) is **UNCERTAIN** — do not assume; model a config-driven VAT rate that can be 0.
---
## 3. Escrow as an internal ledger, not held cash
Because Balinyaar cannot custody buyer funds (§2.2), **"escrow" must be a software construct: a double-entry ledger STATE over money that legally sits at a licensed provider/bank.** The original ~45-table model had **no ledger** — escrow was only inferable by joining `bookings.status`, `bookings.payout_released`, `payment_transactions.status`, and `refunds`, with no single answer to "how much do we owe nurses right now?" Three independent critiques rated this a **critical** gap. The fix is one append-only table.
### 3.1 `ledger_entries` — the financial source of truth
Append-only, never updated or deleted. Every money event posts **balanced** rows sharing a `transaction_group_id` (Σ debit = Σ credit). Per-nurse balances are *derived by filter*, never cached in a drifting wallet-balance column.
**Account types:**
| account_type | Meaning |
|---|---|
| `escrow_held` | Funds received and held (over provider custody) not yet released or refunded |
| `platform_revenue` | Balinyaar's own commission income |
| `nurse_payable` | What the platform owes the nurse (accrued, awaiting weekly payout) |
| `refund_payable` | Amount owed back to the customer / in-flight reversal |
| `bnpl_fee_expense` | The BNPL provider's merchant commission — a platform expense |
| `nurse_clawback_receivable` | Money a nurse owes back after a refund-after-payout |
### 3.2 The postings
Amounts are positive; `direction` carries the sign. The three-amount split (`gross_price_irr`, `balinyaar_commission_irr`, `bnpl_commission_irr`) is defined in §7.
**(a) Card payment capture (inbound):**
```
DEBIT escrow_held gross_price_irr
CREDIT platform_revenue balinyaar_commission_irr
CREDIT nurse_payable nurse_payout_amount (= gross balinyaar_commission)
```
**(b) BNPL settle (inbound) — identical to a card capture, plus the provider-fee leg:**
```
DEBIT escrow_held gross_price_irr
CREDIT platform_revenue balinyaar_commission_irr
CREDIT nurse_payable nurse_payout_amount
DEBIT bnpl_fee_expense bnpl_commission_irr
CREDIT escrow_held bnpl_commission_irr (escrow reflects NET cash actually received)
```
Posted **once**, idempotently, keyed on the settling transaction. **No installment-level postings** — the customer's repayment schedule is SnappPay's ledger, not ours.
**(c) Refund — BEFORE the nurse is paid out (clean reversal):**
```
DEBIT platform_revenue platform_fee_refunded_irr
DEBIT nurse_payable nurse_payout_refunded_irr
CREDIT refund_payable (sum)
```
Clear `refund_payable` when the PSP / SnappPay confirms the customer cash-back. Nothing leaves Balinyaar toward the nurse — the `nurse_payable` accrual is simply reversed.
**(d) Clawback — refund AFTER the nurse was already paid:**
The nurse's `nurse_payable` was already drained by a processed payout batch, so there is nothing left to reverse. Instead the platform books a receivable:
```
DEBIT nurse_clawback_receivable amount_irr (nurse_id set; nurse now owes the platform)
CREDIT refund_payable amount_irr
```
Recovered by **netting against the nurse's next `nurse_payable`** at batch time, or marked `written_off` if uncollectable. A `nurse_clawbacks` row carries the lifecycle (`pending` / `recovered` / `written_off`). This is unavoidable because **Iranian payouts are real bank transfers — hard/impossible to reverse** — so the right defense is *gating payout on the dispute window*, with clawback as the fallback.
### 3.3 Why the ledger, not more columns
A marketplace that holds escrow, pays out weekly minus commission, and handles refunds + clawbacks has exactly the shape double-entry was invented for. The MVP cost is **one table + posting discipline**. The alternative (more money columns on bookings/payouts) cannot answer "how much is held but unreleased" without fragile joins and makes bank/Shaparak reconciliation nearly impossible. Keep the per-booking fee snapshot as the *pricing* record; the ledger is the *financial-truth / reconciliation* layer posted alongside.
---
## 4. BNPL landscape — comparison
All six are Iranian. The structurally important fact (full-upfront-to-merchant, provider bears default risk) holds for every **provider-financed** option; **Lendo is the outlier (bank-financed, customer pays interest).**
| Provider | Settlement model | Who bears financing cost | Customer plan (installments / tenor / interest) | Credit ceiling | Merchant fee | Service / marketplace eligibility | Integration | Confidence |
|---|---|---|---|---|---|---|---|---|
| **SnappPay (اسنپ‌پی)** | **Full-upfront**, single lump minus commission; provider bears default risk | **Merchant** (commission) | 4 installments / 4 months (1 at purchase + 3 monthly); **interest-free** | ~20M Toman (→~50M good payers); separate bank-credit product up to 100M Toman, 1224 mo, **carries bank interest** | **Undocumented** (anecdotal ~715% + ~10% VAT; one merchant cited 15%); per-contract config | Services incl. "بعضی خدمات پزشکی" eligible; in-person/appointment OK. **Multi-vendor re-disbursement UNCONFIRMED** | API + IPG redirect (OAuth → eligible → token → verify → settle → revert/cancel/update/status) | High (model) / Medium (fee, eligibility) |
| **Digipay (دیجی‌پی)** | **Full-upfront** to contracted merchant; provider bears default risk | **Customer** bears markup; merchant pays acquiring commission | 1-month (interest-free) + 4-installment (~48% on installments 24) + 3/6/9/12-mo loan | Varies widely by product/campaign (monthly ~130M Toman; 4-inst up to ~50200M; loan up to 2bn IRR) | **توافقی (negotiable)**, settlement-speed dependent; sells *early settlement* as a paid add-on | Explicit **services** (travel, hotels, insurance, **dental**); single contracted merchant, **no sub-merchant split** | UPG: ticket → redirect → callback → verify; deliver-confirm then refund. Type codes IPG=0/Wallet=11/Credit=5/BNPL=13/Credit-Card=24 | High (model, API) / Uncertain (fee, mid-plan mechanics) |
| **Tara (تارا)** | Provider-financed, full amount to seller | Merchant (interest-free to customer) | 2 interest-free installments, starting 1 month after purchase | **Up to 20M Toman** (research's "10M / 2-month" is OUTDATED); other tiers 5M / 10M / 100M / 150M | Per-contract | Interest-free (بدون سود) standard tier | API/gateway | Medium |
| **Torob Pay** | **Full-upfront**, cash to seller | Merchant | 4 equal installments, **25% down**, interest-free | New users ~12M Toman → 35M | **Concrete: 6% + VAT = 6.6%** per order | Third-party explainers (not first-party docs) | Gateway | Medium (firm fee) |
| **ZarinPlus (ZarinPal)** | Provider-financed BNPL inside the ZarinPal gateway; standard ZarinPal merchant settlement ~T+1 | Merchant | 4 installments | ~2M Toman (ID only) → 515M with history → up to 20M with cheque/promissory note | ZarinPal gateway ~1% (cap ~4000 Toman) + per-txn; BNPL-specific terms not confirmed | Inside ZarinPal IPG | Gateway / تسهیم | Medium |
| **Lendo** | Bank-financed (Bank Ayandeh); merchant effectively gets full value | **CUSTOMER** (~1823% interest **+ ~5% upfront service fee**, often non-refundable) | 6 / 9 / 12 months — a **POS loan**, not interest-free BNPL | Bank-set | — | POS loan | — | **AVOID for MVP** |
> **Key contrast:** Torob Pay's **6.6% (6% + VAT)** is the only *published* rate; SnappPay's true rate **cannot be inferred** from it and must be treated as negotiated per-contract config. Lendo's customer-borne interest + non-refundable fee make mid-engagement cancellations leave the customer out of pocket — a poor fit for short, cancellable nursing visits.
---
## 5. The decisive finding: full-upfront settlement
**The provider pays the merchant the full amount minus commission in ONE lump and bears default risk. The customer's installments are owned by the provider and are decoupled from Balinyaar's escrow/payout.** *(VERIFIED — SnappPay CEO: "ارایه‌دهنده سرویس تمام پول پذیرنده را پرداخت کرده و هیچ ریسکی سمت پذیرنده نیست"; Digipay first-party bpg page: "مبلغ حاصل از فروش را یک‌جا دریافت کنید … نگران ریسک عدم بازپرداخت اقساط نباشید". No source described any tranched-to-merchant model among provider-financed BNPLs.)*
**Therefore, in Balinyaar's books, a BNPL order is identical to a card payment that lands net-of-fee in one inbound settlement.** We **DO NOT model customer-installment tracking** (`installment_entries`, per-installment webhooks, default propagation). This removes the fragile subsystem the original model flagged as unresolved.
### Verified caveats that must remain CONFIGURABLE / UNCERTAIN
- **Settlement TIMING is NOT instant.** Cadence is contract-defined (daily / T+13 / weekly / 15-day / occasionally longer — one merchant alleged ~4 months), and the most concrete SnappPay statement gates settlement on the customer's **first installment** ("پس از واریز اولین قسط"). Digipay even sells *early settlement* as a paid feature, implying its baseline is delayed. **Model a per-transaction `settled_at` and a per-provider settlement-lag; gate weekly nurse payouts on settlement actually received, so you never pay a nurse before you hold the cash.**
- **Commission rate is per-contract config, never hardcoded.** SnappPay publishes no public rate; read the actual deducted amount from each settlement record.
- **Marketplace re-disbursement eligibility is publicly UNCONFIRMED.** SnappPay's and Digipay's documented model is **single-merchant-receiver**. Design so the provider pays **Balinyaar (the merchant-of-record) one lump**, and Balinyaar does the internal escrow→nurse allocation itself. Confirm any per-nurse routing directly with provider sales. Even Snapp Doctor's own home-nursing page does not advertise SnappPay installments — service eligibility is *plausible, not confirmed* for an in-home individual-nurse marketplace.
- **Onboarding requires BOTH جواز کسب AND eNamad (اینماد)** for the Balinyaar entity (the original research omitted eNamad). For Digipay, an activity license is mandatory only for "sensitive trades" (صنوف حساس); home-healthcare may be treated as one — confirm.
---
## 6. Q1 — Cancellation / refund of a BNPL booking mid-plan
**Decisive rule: money ALWAYS flows `customer ↔ SnappPay ↔ Balinyaar`. Never refund the customer directly, and never route a nurse→customer refund.** Balinyaar initiates the reversal through SnappPay's API using the stored payment token/transaction id:
- **Full cancel/refund → `revert`** (full amount).
- **Partial / shortened-visit → `update`** (new amount must be strictly lower than the original settled amount) — or `cancel` per the provider's partial semantics.
SnappPay then, on its own ledger and asynchronously:
1. **cancels the customer's remaining UNPAID installments** and credits their equivalent back to the customer's **credit wallet** (reusable BNPL credit — not merely "wiped"),
2. **refunds any already-PAID installment** to the customer's **bank account in ~710 business days.**
The merchant's only role is to authorize/cancel; **SnappPay owns the unwind.** *(VERIFIED verbatim: "اقساط پرداخت‌نشده لغو و معادل آن به موجودی حساب اعتباری شما برگشت داده می‌شود"; "مبلغ قسط پرداخت‌شده به حساب بانکی شما برگشت داده خواهد شد (۷ تا ۱۰ روز کاری)".)*
### Balinyaar's internal bookkeeping
1. Record a **`refund` row** with `refund_channel = 'bnpl_revert'`, `external_revert_reference`, `expected_customer_refund_eta`, and a `refund_status` that stays `processing` until SnappPay confirms (a reconciliation job clears it). **Surface the asynchronous 710-day window in the UI and reconciliation** — never assume instant.
2. **Decompose the refund** across the two fee legs: `platform_fee_refunded_irr` and `nurse_payout_refunded_irr` (the booking gross = platform fee + nurse payout; the refund must say how much of each is reversed).
3. **Post balanced ledger entries** (§3.2c/d): debit the decomposed `platform_revenue` / `nurse_payable`, credit `refund_payable`; record the revert reference on the `bnpl_transactions` row (`reverted_amount_irr`, `reverted_at`, `refund_channel`).
4. **If the nurse has NOT been paid** (booking still inside the dispute window / not in a processed batch): reverse the `nurse_payable` accrual — clean, nothing leaves Balinyaar. *(This is the common case if you gate payout on the dispute window.)*
5. **If the nurse HAS been paid** (refund-after-payout): take the **clawback** path — a `nurse_clawbacks` row + a `nurse_clawback_receivable` ledger leg (§3.2d), recovered from the next payout batch or written off.
**Partial / shortened-visit** maps to the `update` endpoint with a reduced amount: record `refund_delta_irr`, reduce `settled_amount_irr` on the `bnpl_transactions` row, and apply the same fee-leg decomposition.
> **UNCERTAIN (confirm at contracting):** whether the provider returns *its* merchant commission on a full vs partial refund (full / pro-rata / not at all) is **undocumented** and directly affects platform P&L on cancellations. Model `provider_commission_reversed_amount` as nullable and reconcile from the provider's refund response — do not hardcode. Digipay's exact mid-installment proration mechanics are likewise undocumented and contract-dependent.
---
## 7. Q2 — Under BNPL, who pays the nurse, and when?
**Balinyaar pays the nurse, on Balinyaar's own normal weekly payout schedule, after EVV check-out and after the dispute window closes — exactly the same path as a card-funded booking.** SnappPay **never** pays the nurse and is indifferent to Balinyaar's internal split. The customer's BNPL repayment timeline is completely decoupled from the nurse payout cycle.
### The crucial accounting rule — the three-amount split
The nurse's payout is computed from the booking's **own price and Balinyaar's own commission**, **NOT** from the BNPL-net amount. SnappPay's commission is a **cost of accepting BNPL, borne by Balinyaar**, and must **never** be passed through to the nurse. Store three separate amounts so the two fee deductions are never conflated:
| Amount | Meaning | Drives |
|---|---|---|
| `gross_price_irr` | What the customer is charged (booking price) | The invoice; the inbound `escrow_held` debit |
| `balinyaar_commission_irr` | Balinyaar's own cut (was `platform_fee_amount`) | `platform_revenue`; **the nurse payout** |
| `bnpl_commission_irr` | The BNPL provider's merchant discount | `bnpl_fee_expense` (platform expense) — **never the nurse** |
```
nurse_payout_amount = gross_price_irr balinyaar_commission_irr
```
**The nurse receives the identical amount whether the family paid by card or by SnappPay, and on the identical weekly timing** (batch, gated on `dispute_window_ends_at < now()`). The only difference a BNPL order makes to the books is the extra `bnpl_fee_expense` leg that reduces *Balinyaar's* margin — not the nurse's pay.
**Worked example** (illustrative; rates are config): gross `5,000,000` IRR, Balinyaar commission 15% = `750,000`, nurse payout = `4,250,000`. If paid via SnappPay at a 10% merchant commission, `bnpl_commission_irr = 500,000` is a Balinyaar expense; SnappPay settles `4,500,000` net to Balinyaar; the **nurse still receives `4,250,000`**, and Balinyaar's net margin is `750,000 500,000 = 250,000` (before PSP/VAT). The nurse payout is invariant to the payment method.
> **Timing guard (CONFIGURABLE):** because BNPL settlement can lag, optionally key weekly-payout eligibility off `bnpl_transactions.settled_at` (settlement actually received) in addition to EVV + dispute window, so the platform never advances a nurse before it holds the cash.
---
## 8. Integration notes
### 8.1 SnappPay (اسنپ‌پی) — primary
API-based with an IPG redirect. Endpoint paths are **VERIFIED** against the open-source Laravel package and match exactly:
```
POST api/online/v1/oauth/token → OAuth bearer token
GET api/online/offer/v1/eligible → eligibility / credit check on the customer
POST api/online/payment/v1/token → payment token → redirect customer to SnappPay
POST api/online/payment/v1/verify → verify after callback
POST api/online/payment/v1/settle → settle (capture the merchant lump)
POST api/online/payment/v1/revert → full reversal
POST api/online/payment/v1/cancel → cancel
POST api/online/payment/v1/update → partial (new amount strictly lower)
GET api/online/payment/v1/status → status
```
Credentials issued only after a signed contract + business-license review: `user_name`, `password`, `client_id`, `client_secret`, merchant/customer number, security code, `base_url`. Sandbox availability is plausible (issued by sales) but **TO BE CONFIRMED** — the public package does not evidence it.
> **WARNING:** the `SnapPayInc/open-api-java-sdk` GitHub repo is the **unrelated CANADIAN SnapPay** (snappay.ca, CAD) — **do NOT use it**. Likewise, English searches for "digipay split payment" return **DigiPay.Guru**, an unrelated white-label vendor — not the Iranian Digipay.
### 8.2 Digipay (دیجی‌پی) — secondary / fallback
Unified **UPG** gateway, server-side + hosted redirect:
```
POST /digipay/api/tickets/business?type=… → ticket + redirectUrl (type MUST match product)
(callback to merchant)
POST /digipay/api/purchases/verify → verify (re-check amount + providerId before trusting)
POST /digipay/api/purchases/deliver?type=… → delivery confirmation (Credit=5 / BNPL=13) — GATE ON EVV CHECK-OUT
POST /digipay/api/refunds?type=… → refund (providerId, amount, saleTrackingCode)
GET /digipay/api/refunds/{InquiryId} → poll refund status
POST /digipay/api/reverse → manual reverse (~25 min, IPG/DPG only)
```
**Type codes (VERIFIED, first-party):** IPG=0, Wallet=11, Credit=5, BNPL=13, Credit-Card=24 — **persist the gateway type per transaction**; deliver/refund calls must carry the matching code. Each purchase supports **EITHER refund OR manual reverse, not both** — store a mutually-exclusive reversal-mode flag. For a *service*, the "delivery" is the completed visit, so **gate `deliver` on the nurse's EVV check-out.** A BNPL refund returns to the customer's Digipay credit/wallet (or bank/SHEBA), **not** the original card.
### 8.3 Cross-cutting integration rules
- **Webhook idempotency:** every PSP/BNPL callback is at-least-once and retried. Upsert into **`payment_webhook_events`** keyed `UNIQUE(external_event_id)` **first**, inside the same transaction that mutates money state, and **no-op on duplicate** — prevents double-confirm / double-settle / double-refund.
- **Never trust the callback alone** — always `verify` server-side and re-check `amount` + `providerId`/reference before treating funds as captured.
- **Amounts in IRR Rials as `BIGINT`** everywhere; SnappPay/Digipay quote in **Toman** at the API boundary — store a `currency` field on the BNPL row and **convert only at the boundary, never internally.**
- **State-machine guard** on BNPL status transitions (`eligible → token_issued → verified → settled → reverted`) so callbacks/retries cannot double-settle or double-refund.
---
## 9. Schema touchpoints
Final, aligned table/field names (these supersede `installment_plans` / `installment_entries`):
- **`bnpl_transactions`** (new, **replaces `installment_plans`**; `installment_entries` **CUT**) — 1:1 with a `payment_transaction`. Fields: `payment_transaction_id` FK UNIQUE, `provider_code`, `merchant_of_record`, `external_payment_token`, `external_transaction_id`, `eligibility_status`, `order_amount_irr`, `settled_amount_irr` (net of provider commission), `bnpl_commission_irr`, `currency` (`IRR`/`TOMAN`), `status` (`eligible`/`token_issued`/`verified`/`settled`/`reverted`/`cancelled`/`failed`), `installment_count` (default 4, informational only), `settled_at`, `revert_transaction_id`, `reverted_amount_irr`, `reverted_at`, `refund_channel`, `callback_payload_json`.
- **`payment_transactions`** — keep full gateway response + Shaparak reference; **ADD** a filtered `UNIQUE(gateway_reference_code) WHERE NOT NULL` and a filtered `UNIQUE(booking_id) WHERE status='succeeded'` (single capture per booking; idempotent retries).
- **`payment_webhook_events`** (new) — `provider_code`, `event_type`, `external_event_id UNIQUE`, `payload_json`, `signature_valid`, `processing_status` (`received`/`processed`/`failed`/`ignored`), `related_payment_transaction_id` NULL, `received_at`, `processed_at`.
- **`refunds`** — **1:N** per `payment_transaction` (the original "1:1" claim is wrong); **ADD** `platform_fee_refunded_irr`, `nurse_payout_refunded_irr` (fee-leg decomposition), `refund_channel` (`psp_card`/`bnpl_revert`/`manual_bank`), `external_revert_reference`, `expected_customer_refund_eta`; app invariant `Σ refunded ≤ captured`.
- **`ledger_entries`** (new) — `transaction_group_id`, `account_type` (`escrow_held`/`platform_revenue`/`nurse_payable`/`refund_payable`/`bnpl_fee_expense`/`nurse_clawback_receivable`), `nurse_id` NULL, `direction`, `amount_irr`, `booking_id` NULL, `source_ref_type`, `source_ref_id`, `memo`, `created_at`. Append-only; balanced per group.
- **`nurse_clawbacks`** (new) — `nurse_id`, `booking_id`, `refund_id`, `amount_irr`, `status` (`pending`/`recovered`/`written_off`), `recovered_in_payout_id` NULL, `created_at`, `resolved_at`.
- **`payment_gateways`** — encrypted provider config in `config_json` / secrets: SnappPay `client_id`, `client_secret`/`username`+`password`, merchant number, security code, `base_url`, `sandbox` flag. **Never** store credentials per-transaction.
**Supporting changes:** `bookings` gets the three-way split (`gross_price_irr`, `balinyaar_commission_irr`, `nurse_payout_amount`) and `dispute_window_ends_at`; `payout_released` BIT is **CUT** (derive from `nurse_payout_booking_links` + ledger). `nurse_payouts` gets `gross_earnings_irr`, `clawback_applied_irr`, `net_amount_irr`. An **`invoices`** table (minimal) captures the commission VAT line.
---
## 10. Recommendations & open questions to confirm at contracting
### Recommendations
1. **Integrate SnappPay first, Digipay second, avoid Lendo.** SnappPay has the largest reach, explicit service-merchant support, true full-upfront settlement, full default-risk transfer, and a coded API. Digipay is the redundancy/fallback with the broadest healthcare/service coverage. Lendo's customer-borne interest + non-refundable fee is wrong for short, cancellable visits.
2. **Treat a BNPL order as one net inbound settlement** identical to a card payment net-of-fee. **Do not** build customer-installment tracking.
3. **Make escrow an internal double-entry ledger** over funds custodied at a single licensed provider; **abstract the provider** behind config so it can be swapped if blocked (Toman/Jibit precedent).
4. **Pay the nurse from `gross balinyaar_commission`, weekly, after EVV + dispute window** — identical for card and BNPL; the BNPL commission is a platform expense only.
5. **Gate payout on the dispute window** (default 72h) rather than relying on clawback — Iranian bank transfers are effectively irreversible; keep clawback as the modeled fallback.
6. **Build webhook idempotency before touching real money**, and store all amounts in IRR `BIGINT`, converting from Toman only at the API boundary.
7. **Use 10% VAT, configurable.** Treat each nurse as the taxable seller; invoice only Balinyaar's commission.
### Open questions to confirm with provider sales / at contracting
- **Marketplace eligibility:** does the provider's merchant contract permit a multi-vendor home-services marketplace that re-disburses to many independent nurses as a **single** merchant-of-record? (Publicly undocumented; their known model is single-receiver.)
- **Commission rate (%):** the actual rate for the health/home-services category (SnappPay publishes none; ~715% is anecdotal; Torob Pay's 6.6% is not a proxy).
- **Settlement SLA / timing:** daily vs T+13 vs weekly vs 15-day, and whether it is gated on the customer's first installment. Get it in writing; do not assume same-day.
- **Commission-clawback-on-refund behavior:** on a full vs partial refund, does the provider return its merchant commission fully, pro-rata, or not at all?
- **Onboarding documents:** confirm جواز کسب **and** eNamad suffice for the Balinyaar entity, and whether home-healthcare is a "sensitive trade" needing a sectoral license.
- **Sandbox credentials:** request early; confirm availability (not evidenced publicly).
- **Settlement-provider (تسهیم/payout) choice for the card leg:** which licensed provider (ZarinPal تسهیم / Vandar / Jibit), its fee schedule, batch caps, minimums, and whether delayed settlement / a bank-grade escrow product (Vandar میندو) is permissible for the EVV-gated hold.
---
## Sources
**Iranian payment-facilitator / escrow / settlement legality**
- finolaw.net — مقررات پرداخت‌یاری (facilitator rules): `https://finolaw.net/مقررات-پرداخت-یاری/`
- way2pay.ir — CBI facilitator framework: `https://way2pay.ir/480525/`, `https://way2pay.ir/484056/`
- Zibal legal blog — internet-payment rules: `https://zibal.ir/blog/قوانین-پرداخت-اینترنتی-درگاه-پرداخت-ک/`
- peivast.com — Shaparak inter-merchant/wallet ban: `https://peivast.com/p/148655`
- ZarinPal تسهیم (split-payment): `https://zarinpal.com/split-payment.html`, `https://www.zarinpal.com/blog/درگاه-پرداخت-اشتراکی-چیست؟/`, `https://next.zarinpal.com/paymentGateway/setshare.html`
- Vandar — facilitator / میندو escrow / Bank Ayandeh custody: `https://vandar.io/blog/پرداختیاری-چیست-و-پرداختیار-کیست؟/`, `https://vandar.io/miando/`, `https://docs.vandar.io/payout_service/settlement`
- Jibit transferor / payout: `https://www.jibit.io/transferor/`
- Toman/Jibit Nov-2024 cut-off: `https://www.zoomit.ir/tech-iran/429145-banning-payment-services-on-toman-and-jibit/`, `https://way2pay.ir/389544/`
**Tax / مودیان / VAT (10%)**
- systemgroup.net — مودیان registration: `https://www.systemgroup.net/knowledge-network/registration-in-the-tax-system/`
- hesabandish.com — taxpayer rules: `https://hesabandish.com/rules-taxpayer-system/`
- sepidarsystem.com — VAT rate: `https://www.sepidarsystem.com/blog/vat-rate/`
- Tapsi/Snapp commission-tax precedent: `https://ip30.ir/tapsi-taxation-challenge/`, `https://drhesaab.ir/how-is-digital-platform-tax-calculated/`
**SnappPay**
- Merchant settlement (full-upfront, risk): `https://limoo.host/blog/snap-pay-merchant-settlement/`, `https://www.portal.ir/snappay-payment-method`, `https://way2pay.ir/278219/`
- Product / CEO revenue model: `https://see5.net/blog/what-is-snappay`, `https://ideaagency.net/snapppay-the-correct-revenue-model-landtechs/`, `https://snapppay.ir/`, `https://pay.snapp.ir/`
- Refund/cancel FAQ (710 business days): `https://allsport.ir/faq/5/8.html`, `https://sourmeh.ir/common-question-about-snapppay/`
- API (Laravel package) + eligibility: `https://github.com/backendprogramer/laravel-snapp-pay`, `https://payzito.net/docs/gateways/snapppay`, `https://snapppay.ir/merchant-acquisition/`
**Digipay**
- BNPL full-upfront (credit gateway): `https://www.mydigipay.com/bpg/`, `https://matson.online/digipay-seller/`, `https://digiato.com/tech/digipay-business-solutions-pr`
- Services / merchants: `https://www.mydigipay.com/credit/merchants/`, `https://www.mydigipay.com/credit/c-credit/`, `https://www.mydigipay.com/bnpl/c-bnpl/`
- UPG dev docs (type codes, deliver/refund/reverse): `https://www.mydigipay.com/developers/docs/upg/`
- Onboarding: `https://limoo.host/blog/signup-on-digipay/`
**Tara / Torob Pay / ZarinPlus / Lendo**
- Tara: `https://tara360.ir/bnpl/`, `https://tara360.ir/`, `https://itresan.com/384039/`
- Torob Pay (6% + VAT): `https://blupoz.com/`, `https://ranginstore.com/`
- ZarinPlus: `https://www.zarinpal.com/blog/bnpl-زرین-پلاس/`, `https://www.zarinpal.com/payment-gateway`
- Lendo (bank-financed): `https://lendo.ir/blog/`, `https://lendo.ir/`
**Internal**
- Existing research: `c:\Users\Lenovo\Desktop\balinyaar\product\Home-Nursing-Platform-Research.md`
- Database model to refine: `c:\Users\Lenovo\Desktop\balinyaar\product\database-model.md`
> **Confidence legend.** VERIFIED = survived adversarial verification against multiple/first-party sources. CONFIGURABLE = real but contract-/campaign-dependent (store as config, read actuals from provider). UNCERTAIN = plausible but unconfirmed publicly — confirm at contracting before depending on it.
+56
View File
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>BNPL Landscape &amp; the Full-Upfront Finding — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="index.html">Overview &amp; exec summary</a></li><li><a href="iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="escrow-ledger.html">Escrow as a ledger</a></li><li><a class="active" href="bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<p><a href="index.html">← Payments overview</a></p>
<h1 id="bnpl-landscape-the-full-upfront-finding">BNPL Landscape &amp; the Full-Upfront Finding</h1>
<p>See also the BNPL data model (<a href="../data-model/08-bnpl.html">../data-model/08-bnpl.md</a>) and the business view (<a href="../business/09-installments-bnpl.html">../business/09-installments-bnpl.md</a>).</p>
<h2 id="4-bnpl-landscape-comparison">4. BNPL landscape — comparison <a class="anchor" href="#4-bnpl-landscape-comparison" aria-hidden="true">#</a></h2>
<p>All six are Iranian. The structurally important fact (full-upfront-to-merchant, provider bears default risk) holds for every <strong>provider-financed</strong> option; <strong>Lendo is the outlier (bank-financed, customer pays interest).</strong></p>
<div class="table-wrap"><table><thead><tr><th>Provider</th><th>Settlement model</th><th>Who bears financing cost</th><th>Customer plan (installments / tenor / interest)</th><th>Credit ceiling</th><th>Merchant fee</th><th>Service / marketplace eligibility</th><th>Integration</th><th>Confidence</th></tr></thead><tbody>
<tr><td><strong>SnappPay (اسنپ‌پی)</strong></td><td><strong>Full-upfront</strong>, single lump minus commission; provider bears default risk</td><td><strong>Merchant</strong> (commission)</td><td>4 installments / 4 months (1 at purchase + 3 monthly); <strong>interest-free</strong></td><td>~20M Toman (→~50M good payers); separate bank-credit product up to 100M Toman, 1224 mo, <strong>carries bank interest</strong></td><td><strong>Undocumented</strong> (anecdotal ~715% + ~10% VAT; one merchant cited 15%); per-contract config</td><td>Services incl. "بعضی خدمات پزشکی" eligible; in-person/appointment OK. <strong>Multi-vendor re-disbursement UNCONFIRMED</strong></td><td>API + IPG redirect (OAuth → eligible → token → verify → settle → revert/cancel/update/status)</td><td>High (model) / Medium (fee, eligibility)</td></tr>
<tr><td><strong>Digipay (دیجی‌پی)</strong></td><td><strong>Full-upfront</strong> to contracted merchant; provider bears default risk</td><td><strong>Customer</strong> bears markup; merchant pays acquiring commission</td><td>1-month (interest-free) + 4-installment (~48% on installments 24) + 3/6/9/12-mo loan</td><td>Varies widely by product/campaign (monthly ~130M Toman; 4-inst up to ~50200M; loan up to 2bn IRR)</td><td><strong>توافقی (negotiable)</strong>, settlement-speed dependent; sells <em>early settlement</em> as a paid add-on</td><td>Explicit <strong>services</strong> (travel, hotels, insurance, <strong>dental</strong>); single contracted merchant, <strong>no sub-merchant split</strong></td><td>UPG: ticket → redirect → callback → verify; deliver-confirm then refund. Type codes IPG=0/Wallet=11/Credit=5/BNPL=13/Credit-Card=24</td><td>High (model, API) / Uncertain (fee, mid-plan mechanics)</td></tr>
<tr><td><strong>Tara (تارا)</strong></td><td>Provider-financed, full amount to seller</td><td>Merchant (interest-free to customer)</td><td>2 interest-free installments, starting 1 month after purchase</td><td><strong>Up to 20M Toman</strong> (research's "10M / 2-month" is OUTDATED); other tiers 5M / 10M / 100M / 150M</td><td>Per-contract</td><td>Interest-free (بدون سود) standard tier</td><td>API/gateway</td><td>Medium</td></tr>
<tr><td><strong>Torob Pay</strong></td><td><strong>Full-upfront</strong>, cash to seller</td><td>Merchant</td><td>4 equal installments, <strong>25% down</strong>, interest-free</td><td>New users ~12M Toman → 35M</td><td><strong>Concrete: 6% + VAT = 6.6%</strong> per order</td><td>Third-party explainers (not first-party docs)</td><td>Gateway</td><td>Medium (firm fee)</td></tr>
<tr><td><strong>ZarinPlus (ZarinPal)</strong></td><td>Provider-financed BNPL inside the ZarinPal gateway; standard ZarinPal merchant settlement ~T+1</td><td>Merchant</td><td>4 installments</td><td>~2M Toman (ID only) → 515M with history → up to 20M with cheque/promissory note</td><td>ZarinPal gateway ~1% (cap ~4000 Toman) + per-txn; BNPL-specific terms not confirmed</td><td>Inside ZarinPal IPG</td><td>Gateway / تسهیم</td><td>Medium</td></tr>
<tr><td><strong>Lendo</strong></td><td>Bank-financed (Bank Ayandeh); merchant effectively gets full value</td><td><strong>CUSTOMER</strong> (~1823% interest <strong>+ ~5% upfront service fee</strong>, often non-refundable)</td><td>6 / 9 / 12 months — a <strong>POS loan</strong>, not interest-free BNPL</td><td>Bank-set</td><td></td><td>POS loan</td><td></td><td><strong>AVOID for MVP</strong></td></tr>
</tbody></table></div>
<blockquote><p><strong>Key contrast:</strong> Torob Pay's <strong>6.6% (6% + VAT)</strong> is the only <em>published</em> rate; SnappPay's true rate <strong>cannot be inferred</strong> from it and must be treated as negotiated per-contract config. Lendo's customer-borne interest + non-refundable fee make mid-engagement cancellations leave the customer out of pocket — a poor fit for short, cancellable nursing visits.</p>
</blockquote>
<hr>
<h2 id="5-the-decisive-finding-full-upfront-settlement">5. The decisive finding: full-upfront settlement <a class="anchor" href="#5-the-decisive-finding-full-upfront-settlement" aria-hidden="true">#</a></h2>
<p><strong>The provider pays the merchant the full amount minus commission in ONE lump and bears default risk. The customer's installments are owned by the provider and are decoupled from Balinyaar's escrow/payout.</strong> <em>(VERIFIED — SnappPay CEO: "ارایه‌دهنده سرویس تمام پول پذیرنده را پرداخت کرده و هیچ ریسکی سمت پذیرنده نیست"; Digipay first-party bpg page: "مبلغ حاصل از فروش را یک‌جا دریافت کنید … نگران ریسک عدم بازپرداخت اقساط نباشید". No source described any tranched-to-merchant model among provider-financed BNPLs.)</em></p>
<p><strong>Therefore, in Balinyaar's books, a BNPL order is identical to a card payment that lands net-of-fee in one inbound settlement.</strong> We <strong>DO NOT model customer-installment tracking</strong> (<code>installment_entries</code>, per-installment webhooks, default propagation). This removes the fragile subsystem the original model flagged as unresolved.</p>
<h3 id="verified-caveats-that-must-remain-configurable-uncertain">Verified caveats that must remain CONFIGURABLE / UNCERTAIN <a class="anchor" href="#verified-caveats-that-must-remain-configurable-uncertain" aria-hidden="true">#</a></h3>
<ul>
<li><strong>Settlement TIMING is NOT instant.</strong> Cadence is contract-defined (daily / T+13 / weekly / 15-day / occasionally longer — one merchant alleged ~4 months), and the most concrete SnappPay statement gates settlement on the customer's <strong>first installment</strong> ("پس از واریز اولین قسط"). Digipay even sells <em>early settlement</em> as a paid feature, implying its baseline is delayed. <strong>Model a per-transaction <code>settled_at</code> and a per-provider settlement-lag; gate weekly nurse payouts on settlement actually received, so you never pay a nurse before you hold the cash.</strong></li>
<li><strong>Commission rate is per-contract config, never hardcoded.</strong> SnappPay publishes no public rate; read the actual deducted amount from each settlement record.</li>
<li><strong>Marketplace re-disbursement eligibility is publicly UNCONFIRMED.</strong> SnappPay's and Digipay's documented model is <strong>single-merchant-receiver</strong>. Design so the provider pays <strong>Balinyaar (the merchant-of-record) one lump</strong>, and Balinyaar does the internal escrow→nurse allocation itself. Confirm any per-nurse routing directly with provider sales. Even Snapp Doctor's own home-nursing page does not advertise SnappPay installments — service eligibility is <em>plausible, not confirmed</em> for an in-home individual-nurse marketplace.</li>
<li><strong>Onboarding requires BOTH جواز کسب AND eNamad (اینماد)</strong> for the Balinyaar entity (the original research omitted eNamad). For Digipay, an activity license is mandatory only for "sensitive trades" (صنوف حساس); home-healthcare may be treated as one — confirm.</li>
</ul>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+35
View File
@@ -0,0 +1,35 @@
[← Payments overview](index.md)
# BNPL Landscape & the Full-Upfront Finding
See also the BNPL data model ([../data-model/08-bnpl.md](../data-model/08-bnpl.md)) and the business view ([../business/09-installments-bnpl.md](../business/09-installments-bnpl.md)).
## 4. BNPL landscape — comparison
All six are Iranian. The structurally important fact (full-upfront-to-merchant, provider bears default risk) holds for every **provider-financed** option; **Lendo is the outlier (bank-financed, customer pays interest).**
| Provider | Settlement model | Who bears financing cost | Customer plan (installments / tenor / interest) | Credit ceiling | Merchant fee | Service / marketplace eligibility | Integration | Confidence |
|---|---|---|---|---|---|---|---|---|
| **SnappPay (اسنپ‌پی)** | **Full-upfront**, single lump minus commission; provider bears default risk | **Merchant** (commission) | 4 installments / 4 months (1 at purchase + 3 monthly); **interest-free** | ~20M Toman (→~50M good payers); separate bank-credit product up to 100M Toman, 1224 mo, **carries bank interest** | **Undocumented** (anecdotal ~715% + ~10% VAT; one merchant cited 15%); per-contract config | Services incl. "بعضی خدمات پزشکی" eligible; in-person/appointment OK. **Multi-vendor re-disbursement UNCONFIRMED** | API + IPG redirect (OAuth → eligible → token → verify → settle → revert/cancel/update/status) | High (model) / Medium (fee, eligibility) |
| **Digipay (دیجی‌پی)** | **Full-upfront** to contracted merchant; provider bears default risk | **Customer** bears markup; merchant pays acquiring commission | 1-month (interest-free) + 4-installment (~48% on installments 24) + 3/6/9/12-mo loan | Varies widely by product/campaign (monthly ~130M Toman; 4-inst up to ~50200M; loan up to 2bn IRR) | **توافقی (negotiable)**, settlement-speed dependent; sells *early settlement* as a paid add-on | Explicit **services** (travel, hotels, insurance, **dental**); single contracted merchant, **no sub-merchant split** | UPG: ticket → redirect → callback → verify; deliver-confirm then refund. Type codes IPG=0/Wallet=11/Credit=5/BNPL=13/Credit-Card=24 | High (model, API) / Uncertain (fee, mid-plan mechanics) |
| **Tara (تارا)** | Provider-financed, full amount to seller | Merchant (interest-free to customer) | 2 interest-free installments, starting 1 month after purchase | **Up to 20M Toman** (research's "10M / 2-month" is OUTDATED); other tiers 5M / 10M / 100M / 150M | Per-contract | Interest-free (بدون سود) standard tier | API/gateway | Medium |
| **Torob Pay** | **Full-upfront**, cash to seller | Merchant | 4 equal installments, **25% down**, interest-free | New users ~12M Toman → 35M | **Concrete: 6% + VAT = 6.6%** per order | Third-party explainers (not first-party docs) | Gateway | Medium (firm fee) |
| **ZarinPlus (ZarinPal)** | Provider-financed BNPL inside the ZarinPal gateway; standard ZarinPal merchant settlement ~T+1 | Merchant | 4 installments | ~2M Toman (ID only) → 515M with history → up to 20M with cheque/promissory note | ZarinPal gateway ~1% (cap ~4000 Toman) + per-txn; BNPL-specific terms not confirmed | Inside ZarinPal IPG | Gateway / تسهیم | Medium |
| **Lendo** | Bank-financed (Bank Ayandeh); merchant effectively gets full value | **CUSTOMER** (~1823% interest **+ ~5% upfront service fee**, often non-refundable) | 6 / 9 / 12 months — a **POS loan**, not interest-free BNPL | Bank-set | — | POS loan | — | **AVOID for MVP** |
> **Key contrast:** Torob Pay's **6.6% (6% + VAT)** is the only *published* rate; SnappPay's true rate **cannot be inferred** from it and must be treated as negotiated per-contract config. Lendo's customer-borne interest + non-refundable fee make mid-engagement cancellations leave the customer out of pocket — a poor fit for short, cancellable nursing visits.
---
## 5. The decisive finding: full-upfront settlement
**The provider pays the merchant the full amount minus commission in ONE lump and bears default risk. The customer's installments are owned by the provider and are decoupled from Balinyaar's escrow/payout.** *(VERIFIED — SnappPay CEO: "ارایه‌دهنده سرویس تمام پول پذیرنده را پرداخت کرده و هیچ ریسکی سمت پذیرنده نیست"; Digipay first-party bpg page: "مبلغ حاصل از فروش را یک‌جا دریافت کنید … نگران ریسک عدم بازپرداخت اقساط نباشید". No source described any tranched-to-merchant model among provider-financed BNPLs.)*
**Therefore, in Balinyaar's books, a BNPL order is identical to a card payment that lands net-of-fee in one inbound settlement.** We **DO NOT model customer-installment tracking** (`installment_entries`, per-installment webhooks, default propagation). This removes the fragile subsystem the original model flagged as unresolved.
### Verified caveats that must remain CONFIGURABLE / UNCERTAIN
- **Settlement TIMING is NOT instant.** Cadence is contract-defined (daily / T+13 / weekly / 15-day / occasionally longer — one merchant alleged ~4 months), and the most concrete SnappPay statement gates settlement on the customer's **first installment** ("پس از واریز اولین قسط"). Digipay even sells *early settlement* as a paid feature, implying its baseline is delayed. **Model a per-transaction `settled_at` and a per-provider settlement-lag; gate weekly nurse payouts on settlement actually received, so you never pay a nurse before you hold the cash.**
- **Commission rate is per-contract config, never hardcoded.** SnappPay publishes no public rate; read the actual deducted amount from each settlement record.
- **Marketplace re-disbursement eligibility is publicly UNCONFIRMED.** SnappPay's and Digipay's documented model is **single-merchant-receiver**. Design so the provider pays **Balinyaar (the merchant-of-record) one lump**, and Balinyaar does the internal escrow→nurse allocation itself. Confirm any per-nurse routing directly with provider sales. Even Snapp Doctor's own home-nursing page does not advertise SnappPay installments — service eligibility is *plausible, not confirmed* for an in-home individual-nurse marketplace.
- **Onboarding requires BOTH جواز کسب AND eNamad (اینماد)** for the Balinyaar entity (the original research omitted eNamad). For Digipay, an activity license is mandatory only for "sensitive trades" (صنوف حساس); home-healthcare may be treated as one — confirm.
@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>BNPL Cancellation, Refund &amp; Nurse Payout (Q1 &amp; Q2) — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="index.html">Overview &amp; exec summary</a></li><li><a href="iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="escrow-ledger.html">Escrow as a ledger</a></li><li><a href="bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a class="active" href="cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<p><a href="index.html">← Payments overview</a></p>
<h1 id="bnpl-cancellation-refund-nurse-payout-q1-q2">BNPL Cancellation, Refund &amp; Nurse Payout (Q1 &amp; Q2)</h1>
<p>See also the BNPL data model (<a href="../data-model/08-bnpl.html">../data-model/08-bnpl.md</a>) and the business view (<a href="../business/09-installments-bnpl.html">../business/09-installments-bnpl.md</a>).</p>
<h2 id="6-q1-cancellation-refund-of-a-bnpl-booking-mid-plan">6. Q1 — Cancellation / refund of a BNPL booking mid-plan <a class="anchor" href="#6-q1-cancellation-refund-of-a-bnpl-booking-mid-plan" aria-hidden="true">#</a></h2>
<p><strong>Decisive rule: money ALWAYS flows <code>customer ↔ SnappPay ↔ Balinyaar</code>. Never refund the customer directly, and never route a nurse→customer refund.</strong> Balinyaar initiates the reversal through SnappPay's API using the stored payment token/transaction id:</p>
<ul>
<li><strong>Full cancel/refund → <code>revert</code></strong> (full amount).</li>
<li><strong>Partial / shortened-visit → <code>update</code></strong> (new amount must be strictly lower than the original settled amount) — or <code>cancel</code> per the provider's partial semantics.</li>
</ul>
<p>SnappPay then, on its own ledger and asynchronously:</p>
<ol>
<li><strong>cancels the customer's remaining UNPAID installments</strong> and credits their equivalent back to the customer's <strong>credit wallet</strong> (reusable BNPL credit — not merely "wiped"),</li>
<li><strong>refunds any already-PAID installment</strong> to the customer's <strong>bank account in ~710 business days.</strong></li>
</ol>
<p>The merchant's only role is to authorize/cancel; <strong>SnappPay owns the unwind.</strong> <em>(VERIFIED verbatim: "اقساط پرداخت‌نشده لغو و معادل آن به موجودی حساب اعتباری شما برگشت داده می‌شود"; "مبلغ قسط پرداخت‌شده به حساب بانکی شما برگشت داده خواهد شد (۷ تا ۱۰ روز کاری)".)</em></p>
<h3 id="balinyaars-internal-bookkeeping">Balinyaar's internal bookkeeping <a class="anchor" href="#balinyaars-internal-bookkeeping" aria-hidden="true">#</a></h3>
<ol>
<li>Record a <strong><code>refund</code> row</strong> with <code>refund_channel = 'bnpl_revert'</code>, <code>external_revert_reference</code>, <code>expected_customer_refund_eta</code>, and a <code>refund_status</code> that stays <code>processing</code> until SnappPay confirms (a reconciliation job clears it). <strong>Surface the asynchronous 710-day window in the UI and reconciliation</strong> — never assume instant.</li>
<li><strong>Decompose the refund</strong> across the two fee legs: <code>platform_fee_refunded_irr</code> and <code>nurse_payout_refunded_irr</code> (the booking gross = platform fee + nurse payout; the refund must say how much of each is reversed).</li>
<li><strong>Post balanced ledger entries</strong> (§3.2c/d): debit the decomposed <code>platform_revenue</code> / <code>nurse_payable</code>, credit <code>refund_payable</code>; record the revert reference on the <code>bnpl_transactions</code> row (<code>reverted_amount_irr</code>, <code>reverted_at</code>, <code>refund_channel</code>).</li>
<li><strong>If the nurse has NOT been paid</strong> (booking still inside the dispute window / not in a processed batch): reverse the <code>nurse_payable</code> accrual — clean, nothing leaves Balinyaar. <em>(This is the common case if you gate payout on the dispute window.)</em></li>
<li><strong>If the nurse HAS been paid</strong> (refund-after-payout): take the <strong>clawback</strong> path — a <code>nurse_clawbacks</code> row + a <code>nurse_clawback_receivable</code> ledger leg (§3.2d), recovered from the next payout batch or written off.</li>
</ol>
<p><strong>Partial / shortened-visit</strong> maps to the <code>update</code> endpoint with a reduced amount: record <code>refund_delta_irr</code>, reduce <code>settled_amount_irr</code> on the <code>bnpl_transactions</code> row, and apply the same fee-leg decomposition.</p>
<blockquote><p><strong>UNCERTAIN (confirm at contracting):</strong> whether the provider returns <em>its</em> merchant commission on a full vs partial refund (full / pro-rata / not at all) is <strong>undocumented</strong> and directly affects platform P&amp;L on cancellations. Model <code>provider_commission_reversed_amount</code> as nullable and reconcile from the provider's refund response — do not hardcode. Digipay's exact mid-installment proration mechanics are likewise undocumented and contract-dependent.</p>
</blockquote>
<hr>
<h2 id="7-q2-under-bnpl-who-pays-the-nurse-and-when">7. Q2 — Under BNPL, who pays the nurse, and when? <a class="anchor" href="#7-q2-under-bnpl-who-pays-the-nurse-and-when" aria-hidden="true">#</a></h2>
<p><strong>Balinyaar pays the nurse, on Balinyaar's own normal weekly payout schedule, after EVV check-out and after the dispute window closes — exactly the same path as a card-funded booking.</strong> SnappPay <strong>never</strong> pays the nurse and is indifferent to Balinyaar's internal split. The customer's BNPL repayment timeline is completely decoupled from the nurse payout cycle.</p>
<h3 id="the-crucial-accounting-rule-the-three-amount-split">The crucial accounting rule — the three-amount split <a class="anchor" href="#the-crucial-accounting-rule-the-three-amount-split" aria-hidden="true">#</a></h3>
<p>The nurse's payout is computed from the booking's <strong>own price and Balinyaar's own commission</strong>, <strong>NOT</strong> from the BNPL-net amount. SnappPay's commission is a <strong>cost of accepting BNPL, borne by Balinyaar</strong>, and must <strong>never</strong> be passed through to the nurse. Store three separate amounts so the two fee deductions are never conflated:</p>
<div class="table-wrap"><table><thead><tr><th>Amount</th><th>Meaning</th><th>Drives</th></tr></thead><tbody>
<tr><td><code>gross_price_irr</code></td><td>What the customer is charged (booking price)</td><td>The invoice; the inbound <code>escrow_held</code> debit</td></tr>
<tr><td><code>balinyaar_commission_irr</code></td><td>Balinyaar's own cut (was <code>platform_fee_amount</code>)</td><td><code>platform_revenue</code>; <strong>the nurse payout</strong></td></tr>
<tr><td><code>bnpl_commission_irr</code></td><td>The BNPL provider's merchant discount</td><td><code>bnpl_fee_expense</code> (platform expense) — <strong>never the nurse</strong></td></tr>
</tbody></table></div>
<pre><code>nurse_payout_amount = gross_price_irr balinyaar_commission_irr</code></pre>
<p><strong>The nurse receives the identical amount whether the family paid by card or by SnappPay, and on the identical weekly timing</strong> (batch, gated on <code>dispute_window_ends_at &lt; now()</code>). The only difference a BNPL order makes to the books is the extra <code>bnpl_fee_expense</code> leg that reduces <em>Balinyaar's</em> margin — not the nurse's pay.</p>
<p><strong>Worked example</strong> (illustrative; rates are config): gross <code>5,000,000</code> IRR, Balinyaar commission 15% = <code>750,000</code>, nurse payout = <code>4,250,000</code>. If paid via SnappPay at a 10% merchant commission, <code>bnpl_commission_irr = 500,000</code> is a Balinyaar expense; SnappPay settles <code>4,500,000</code> net to Balinyaar; the <strong>nurse still receives <code>4,250,000</code></strong>, and Balinyaar's net margin is <code>750,000 500,000 = 250,000</code> (before PSP/VAT). The nurse payout is invariant to the payment method.</p>
<blockquote><p><strong>Timing guard (CONFIGURABLE):</strong> because BNPL settlement can lag, optionally key weekly-payout eligibility off <code>bnpl_transactions.settled_at</code> (settlement actually received) in addition to EVV + dispute window, so the platform never advances a nurse before it holds the cash.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,56 @@
[← Payments overview](index.md)
# BNPL Cancellation, Refund & Nurse Payout (Q1 & Q2)
See also the BNPL data model ([../data-model/08-bnpl.md](../data-model/08-bnpl.md)) and the business view ([../business/09-installments-bnpl.md](../business/09-installments-bnpl.md)).
## 6. Q1 — Cancellation / refund of a BNPL booking mid-plan
**Decisive rule: money ALWAYS flows `customer ↔ SnappPay ↔ Balinyaar`. Never refund the customer directly, and never route a nurse→customer refund.** Balinyaar initiates the reversal through SnappPay's API using the stored payment token/transaction id:
- **Full cancel/refund → `revert`** (full amount).
- **Partial / shortened-visit → `update`** (new amount must be strictly lower than the original settled amount) — or `cancel` per the provider's partial semantics.
SnappPay then, on its own ledger and asynchronously:
1. **cancels the customer's remaining UNPAID installments** and credits their equivalent back to the customer's **credit wallet** (reusable BNPL credit — not merely "wiped"),
2. **refunds any already-PAID installment** to the customer's **bank account in ~710 business days.**
The merchant's only role is to authorize/cancel; **SnappPay owns the unwind.** *(VERIFIED verbatim: "اقساط پرداخت‌نشده لغو و معادل آن به موجودی حساب اعتباری شما برگشت داده می‌شود"; "مبلغ قسط پرداخت‌شده به حساب بانکی شما برگشت داده خواهد شد (۷ تا ۱۰ روز کاری)".)*
### Balinyaar's internal bookkeeping
1. Record a **`refund` row** with `refund_channel = 'bnpl_revert'`, `external_revert_reference`, `expected_customer_refund_eta`, and a `refund_status` that stays `processing` until SnappPay confirms (a reconciliation job clears it). **Surface the asynchronous 710-day window in the UI and reconciliation** — never assume instant.
2. **Decompose the refund** across the two fee legs: `platform_fee_refunded_irr` and `nurse_payout_refunded_irr` (the booking gross = platform fee + nurse payout; the refund must say how much of each is reversed).
3. **Post balanced ledger entries** (§3.2c/d): debit the decomposed `platform_revenue` / `nurse_payable`, credit `refund_payable`; record the revert reference on the `bnpl_transactions` row (`reverted_amount_irr`, `reverted_at`, `refund_channel`).
4. **If the nurse has NOT been paid** (booking still inside the dispute window / not in a processed batch): reverse the `nurse_payable` accrual — clean, nothing leaves Balinyaar. *(This is the common case if you gate payout on the dispute window.)*
5. **If the nurse HAS been paid** (refund-after-payout): take the **clawback** path — a `nurse_clawbacks` row + a `nurse_clawback_receivable` ledger leg (§3.2d), recovered from the next payout batch or written off.
**Partial / shortened-visit** maps to the `update` endpoint with a reduced amount: record `refund_delta_irr`, reduce `settled_amount_irr` on the `bnpl_transactions` row, and apply the same fee-leg decomposition.
> **UNCERTAIN (confirm at contracting):** whether the provider returns *its* merchant commission on a full vs partial refund (full / pro-rata / not at all) is **undocumented** and directly affects platform P&L on cancellations. Model `provider_commission_reversed_amount` as nullable and reconcile from the provider's refund response — do not hardcode. Digipay's exact mid-installment proration mechanics are likewise undocumented and contract-dependent.
---
## 7. Q2 — Under BNPL, who pays the nurse, and when?
**Balinyaar pays the nurse, on Balinyaar's own normal weekly payout schedule, after EVV check-out and after the dispute window closes — exactly the same path as a card-funded booking.** SnappPay **never** pays the nurse and is indifferent to Balinyaar's internal split. The customer's BNPL repayment timeline is completely decoupled from the nurse payout cycle.
### The crucial accounting rule — the three-amount split
The nurse's payout is computed from the booking's **own price and Balinyaar's own commission**, **NOT** from the BNPL-net amount. SnappPay's commission is a **cost of accepting BNPL, borne by Balinyaar**, and must **never** be passed through to the nurse. Store three separate amounts so the two fee deductions are never conflated:
| Amount | Meaning | Drives |
|---|---|---|
| `gross_price_irr` | What the customer is charged (booking price) | The invoice; the inbound `escrow_held` debit |
| `balinyaar_commission_irr` | Balinyaar's own cut (was `platform_fee_amount`) | `platform_revenue`; **the nurse payout** |
| `bnpl_commission_irr` | The BNPL provider's merchant discount | `bnpl_fee_expense` (platform expense) — **never the nurse** |
```
nurse_payout_amount = gross_price_irr balinyaar_commission_irr
```
**The nurse receives the identical amount whether the family paid by card or by SnappPay, and on the identical weekly timing** (batch, gated on `dispute_window_ends_at < now()`). The only difference a BNPL order makes to the books is the extra `bnpl_fee_expense` leg that reduces *Balinyaar's* margin — not the nurse's pay.
**Worked example** (illustrative; rates are config): gross `5,000,000` IRR, Balinyaar commission 15% = `750,000`, nurse payout = `4,250,000`. If paid via SnappPay at a 10% merchant commission, `bnpl_commission_irr = 500,000` is a Balinyaar expense; SnappPay settles `4,500,000` net to Balinyaar; the **nurse still receives `4,250,000`**, and Balinyaar's net margin is `750,000 500,000 = 250,000` (before PSP/VAT). The nurse payout is invariant to the payment method.
> **Timing guard (CONFIGURABLE):** because BNPL settlement can lag, optionally key weekly-payout eligibility off `bnpl_transactions.settled_at` (settlement actually received) in addition to EVV + dispute window, so the platform never advances a nurse before it holds the cash.
+69
View File
@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Escrow as an Internal Ledger, Not Held Cash — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="index.html">Overview &amp; exec summary</a></li><li><a href="iranian-payment-reality.html">Iranian payment reality</a></li><li><a class="active" href="escrow-ledger.html">Escrow as a ledger</a></li><li><a href="bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<p><a href="index.html">← Payments overview</a></p>
<h1 id="escrow-as-an-internal-ledger-not-held-cash">Escrow as an Internal Ledger, Not Held Cash</h1>
<p>Because Balinyaar cannot custody buyer funds (§2.2), <strong>"escrow" must be a software construct: a double-entry ledger STATE over money that legally sits at a licensed provider/bank.</strong> The original ~45-table model had <strong>no ledger</strong> — escrow was only inferable by joining <code>bookings.status</code>, <code>bookings.payout_released</code>, <code>payment_transactions.status</code>, and <code>refunds</code>, with no single answer to "how much do we owe nurses right now?" Three independent critiques rated this a <strong>critical</strong> gap. The fix is one append-only table.</p>
<p>The ledger entity is detailed in the data model: see <a href="../data-model/06-payments-ledger-and-refunds.html">payments, ledger &amp; refunds</a>.</p>
<h2 id="31-ledger_entries-the-financial-source-of-truth">3.1 <code>ledger_entries</code> — the financial source of truth <a class="anchor" href="#31-ledger_entries-the-financial-source-of-truth" aria-hidden="true">#</a></h2>
<p>Append-only, never updated or deleted. Every money event posts <strong>balanced</strong> rows sharing a <code>transaction_group_id</code> (Σ debit = Σ credit). Per-nurse balances are <em>derived by filter</em>, never cached in a drifting wallet-balance column.</p>
<p><strong>Account types:</strong></p>
<div class="table-wrap"><table><thead><tr><th>account_type</th><th>Meaning</th></tr></thead><tbody>
<tr><td><code>escrow_held</code></td><td>Funds received and held (over provider custody) not yet released or refunded</td></tr>
<tr><td><code>platform_revenue</code></td><td>Balinyaar's own commission income</td></tr>
<tr><td><code>nurse_payable</code></td><td>What the platform owes the nurse (accrued, awaiting weekly payout)</td></tr>
<tr><td><code>refund_payable</code></td><td>Amount owed back to the customer / in-flight reversal</td></tr>
<tr><td><code>bnpl_fee_expense</code></td><td>The BNPL provider's merchant commission — a platform expense</td></tr>
<tr><td><code>nurse_clawback_receivable</code></td><td>Money a nurse owes back after a refund-after-payout</td></tr>
</tbody></table></div>
<h2 id="32-the-postings">3.2 The postings <a class="anchor" href="#32-the-postings" aria-hidden="true">#</a></h2>
<p>Amounts are positive; <code>direction</code> carries the sign. The three-amount split (<code>gross_price_irr</code>, <code>balinyaar_commission_irr</code>, <code>bnpl_commission_irr</code>) is defined in §7.</p>
<p><strong>(a) Card payment capture (inbound):</strong></p>
<pre><code>DEBIT escrow_held gross_price_irr
CREDIT platform_revenue balinyaar_commission_irr
CREDIT nurse_payable nurse_payout_amount (= gross balinyaar_commission)</code></pre>
<p><strong>(b) BNPL settle (inbound) — identical to a card capture, plus the provider-fee leg:</strong></p>
<pre><code>DEBIT escrow_held gross_price_irr
CREDIT platform_revenue balinyaar_commission_irr
CREDIT nurse_payable nurse_payout_amount
DEBIT bnpl_fee_expense bnpl_commission_irr
CREDIT escrow_held bnpl_commission_irr (escrow reflects NET cash actually received)</code></pre>
<p>Posted <strong>once</strong>, idempotently, keyed on the settling transaction. <strong>No installment-level postings</strong> — the customer's repayment schedule is SnappPay's ledger, not ours.</p>
<p><strong>(c) Refund — BEFORE the nurse is paid out (clean reversal):</strong></p>
<pre><code>DEBIT platform_revenue platform_fee_refunded_irr
DEBIT nurse_payable nurse_payout_refunded_irr
CREDIT refund_payable (sum)</code></pre>
<p>Clear <code>refund_payable</code> when the PSP / SnappPay confirms the customer cash-back. Nothing leaves Balinyaar toward the nurse — the <code>nurse_payable</code> accrual is simply reversed.</p>
<p><strong>(d) Clawback — refund AFTER the nurse was already paid:</strong> The nurse's <code>nurse_payable</code> was already drained by a processed payout batch, so there is nothing left to reverse. Instead the platform books a receivable:</p>
<pre><code>DEBIT nurse_clawback_receivable amount_irr (nurse_id set; nurse now owes the platform)
CREDIT refund_payable amount_irr</code></pre>
<p>Recovered by <strong>netting against the nurse's next <code>nurse_payable</code></strong> at batch time, or marked <code>written_off</code> if uncollectable. A <code>nurse_clawbacks</code> row carries the lifecycle (<code>pending</code> / <code>recovered</code> / <code>written_off</code>). This is unavoidable because <strong>Iranian payouts are real bank transfers — hard/impossible to reverse</strong> — so the right defense is <em>gating payout on the dispute window</em>, with clawback as the fallback.</p>
<h2 id="33-why-the-ledger-not-more-columns">3.3 Why the ledger, not more columns <a class="anchor" href="#33-why-the-ledger-not-more-columns" aria-hidden="true">#</a></h2>
<p>A marketplace that holds escrow, pays out weekly minus commission, and handles refunds + clawbacks has exactly the shape double-entry was invented for. The MVP cost is <strong>one table + posting discipline</strong>. The alternative (more money columns on bookings/payouts) cannot answer "how much is held but unreleased" without fragile joins and makes bank/Shaparak reconciliation nearly impossible. Keep the per-booking fee snapshot as the <em>pricing</em> record; the ledger is the <em>financial-truth / reconciliation</em> layer posted alongside.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+63
View File
@@ -0,0 +1,63 @@
[← Payments overview](index.md)
# Escrow as an Internal Ledger, Not Held Cash
Because Balinyaar cannot custody buyer funds (§2.2), **"escrow" must be a software construct: a double-entry ledger STATE over money that legally sits at a licensed provider/bank.** The original ~45-table model had **no ledger** — escrow was only inferable by joining `bookings.status`, `bookings.payout_released`, `payment_transactions.status`, and `refunds`, with no single answer to "how much do we owe nurses right now?" Three independent critiques rated this a **critical** gap. The fix is one append-only table.
The ledger entity is detailed in the data model: see [payments, ledger & refunds](../data-model/06-payments-ledger-and-refunds.md).
## 3.1 `ledger_entries` — the financial source of truth
Append-only, never updated or deleted. Every money event posts **balanced** rows sharing a `transaction_group_id` (Σ debit = Σ credit). Per-nurse balances are *derived by filter*, never cached in a drifting wallet-balance column.
**Account types:**
| account_type | Meaning |
|---|---|
| `escrow_held` | Funds received and held (over provider custody) not yet released or refunded |
| `platform_revenue` | Balinyaar's own commission income |
| `nurse_payable` | What the platform owes the nurse (accrued, awaiting weekly payout) |
| `refund_payable` | Amount owed back to the customer / in-flight reversal |
| `bnpl_fee_expense` | The BNPL provider's merchant commission — a platform expense |
| `nurse_clawback_receivable` | Money a nurse owes back after a refund-after-payout |
## 3.2 The postings
Amounts are positive; `direction` carries the sign. The three-amount split (`gross_price_irr`, `balinyaar_commission_irr`, `bnpl_commission_irr`) is defined in §7.
**(a) Card payment capture (inbound):**
```
DEBIT escrow_held gross_price_irr
CREDIT platform_revenue balinyaar_commission_irr
CREDIT nurse_payable nurse_payout_amount (= gross balinyaar_commission)
```
**(b) BNPL settle (inbound) — identical to a card capture, plus the provider-fee leg:**
```
DEBIT escrow_held gross_price_irr
CREDIT platform_revenue balinyaar_commission_irr
CREDIT nurse_payable nurse_payout_amount
DEBIT bnpl_fee_expense bnpl_commission_irr
CREDIT escrow_held bnpl_commission_irr (escrow reflects NET cash actually received)
```
Posted **once**, idempotently, keyed on the settling transaction. **No installment-level postings** — the customer's repayment schedule is SnappPay's ledger, not ours.
**(c) Refund — BEFORE the nurse is paid out (clean reversal):**
```
DEBIT platform_revenue platform_fee_refunded_irr
DEBIT nurse_payable nurse_payout_refunded_irr
CREDIT refund_payable (sum)
```
Clear `refund_payable` when the PSP / SnappPay confirms the customer cash-back. Nothing leaves Balinyaar toward the nurse — the `nurse_payable` accrual is simply reversed.
**(d) Clawback — refund AFTER the nurse was already paid:**
The nurse's `nurse_payable` was already drained by a processed payout batch, so there is nothing left to reverse. Instead the platform books a receivable:
```
DEBIT nurse_clawback_receivable amount_irr (nurse_id set; nurse now owes the platform)
CREDIT refund_payable amount_irr
```
Recovered by **netting against the nurse's next `nurse_payable`** at batch time, or marked `written_off` if uncollectable. A `nurse_clawbacks` row carries the lifecycle (`pending` / `recovered` / `written_off`). This is unavoidable because **Iranian payouts are real bank transfers — hard/impossible to reverse** — so the right defense is *gating payout on the dispute window*, with clawback as the fallback.
## 3.3 Why the ledger, not more columns
A marketplace that holds escrow, pays out weekly minus commission, and handles refunds + clawbacks has exactly the shape double-entry was invented for. The MVP cost is **one table + posting discipline**. The alternative (more money columns on bookings/payouts) cannot answer "how much is held but unreleased" without fragile joins and makes bank/Shaparak reconciliation nearly impossible. Keep the per-booking fee snapshot as the *pricing* record; the ledger is the *financial-truth / reconciliation* layer posted alongside.
+77
View File
@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Payments, Escrow, Settlement &amp; Installments (BNPL) — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a class="active" href="index.html">Overview &amp; exec summary</a></li><li><a href="iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="escrow-ledger.html">Escrow as a ledger</a></li><li><a href="bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="payments-escrow-settlement-installments-bnpl">Payments, Escrow, Settlement &amp; Installments (BNPL)</h1>
<blockquote><p><strong>Purpose.</strong> This is the fintech deep-dive for Balinyaar, an MVP home-nursing marketplace in Iran. It pins down how the platform collects money from families, holds an <em>internal escrow ledger state</em> (not custodied cash), pays nurses weekly minus commission, and integrates Iranian Buy-Now-Pay-Later (خرید اقساطی / BNPL). It answers the two questions the team cares most about — how a BNPL booking is cancelled/refunded mid-plan, and who pays the nurse (and when) under BNPL — and it grounds every decision in verified research, separating <strong>VERIFIED</strong> facts from <strong>CONFIGURABLE / UNCERTAIN</strong> items that must be confirmed at contracting. All money is <strong>IRR (Rials), stored as <code>BIGINT</code></strong>; Toman is display-only and converted only at the provider API boundary.</p>
</blockquote>
<p><strong>Date:</strong> 2026-06-20</p>
<hr>
<h2 id="1-executive-summary">1. Executive summary <a class="anchor" href="#1-executive-summary" aria-hidden="true">#</a></h2>
<ul>
<li><strong>Balinyaar legally CANNOT custody buyer funds.</strong> In Iran money always flows card → licensed PSP → Shaparak settlement → bank-registered IBANs. A پرداخت‌یار (payment facilitator — the license class an MVP rides on) is explicitly <strong>barred from holding deposits, running wallets, paying interest, or moving money between merchants</strong>. "Platform holds escrow" must therefore be implemented as an <strong>internal double-entry ledger state</strong> over funds custodied at a licensed provider — never as cash in a Balinyaar bank account. <em>(VERIFIED — multiple independent sources + CBI/Shaparak directives.)</em></li>
</ul>
<ul>
<li><strong>The compliant marketplace primitive is تسهیم (settlement-sharing):</strong> one incoming card payment is split by the provider/Shaparak across multiple registered IBANs (the nurse's share, the platform's commission) and deposited directly — the platform never touches the split. Shaparak has separately <strong>banned inter-merchant / inter-facilitator transfers and wallet-style holding</strong>, which makes a "delay-then-redistribute" pool legally grey-to-prohibited. <em>(VERIFIED.)</em></li>
</ul>
<ul>
<li><strong>The decisive BNPL finding: full-upfront settlement.</strong> Provider-financed Iranian BNPLs (SnappPay, Digipay, Tara, Torob Pay, ZarinPlus) pay the <strong>merchant the FULL amount in ONE lump, minus a merchant commission, and bear 100% of customer-default risk.</strong> The customer's installments are owned entirely by the provider and are <strong>decoupled</strong> from Balinyaar's escrow/EVV/payout cycle. <em>(VERIFIED for SnappPay and Torob Pay from credible sources; consistent for Digipay and Tara.)</em></li>
</ul>
<ul>
<li><strong>Consequence — a BNPL order = a card payment landing net-of-fee.</strong> Therefore Balinyaar <strong>does NOT track customer installments</strong> (no <code>installment_entries</code>, no per-installment webhooks, no default propagation). This deletes an entire fragile subsystem.</li>
</ul>
<ul>
<li><strong>But settlement TIMING is not instant.</strong> The "full amount" is true in <em>amount</em>, not <em>timing</em>: cadence is contract-defined (daily / T+13 / weekly / 15-day), and at least one authoritative SnappPay source gates settlement on the customer's <strong>first installment</strong> (پس از واریز اولین قسط). Model a per-transaction <code>settled_at</code>; never assume instant. <em>(VERIFIED correction to the original research.)</em></li>
</ul>
<ul>
<li><strong>Under BNPL the nurse is paid by Balinyaar, on Balinyaar's own weekly schedule, exactly as for a card booking</strong> — after EVV check-out and the dispute window. The nurse's payout is computed from <code>gross_price_irr balinyaar_commission_irr</code>, <strong>NOT</strong> from the BNPL-net amount. The BNPL commission is a <strong>platform expense</strong> that must never touch the nurse's payout.</li>
</ul>
<ul>
<li><strong>Avoid Lendo for the MVP.</strong> It is bank-financed (Bank Ayandeh): the <strong>customer</strong> pays ~1823% interest plus a ~5% (often non-refundable) service fee over 612 months — a POS loan, a poor fit for short, cancellable nursing visits.</li>
</ul>
<ul>
<li><strong>Two corrections the research forced:</strong> VAT in Iran is <strong>10%</strong> (rose from 9% in 1403, = govt 7% + municipal 3%), not 9% — and make it configurable since it has moved two years running (see <a href="../research/legal-landscape.html">legal landscape</a>). And the Digipay "24h-pay / collect-in-525-days-from-business" sentence describes the <strong>early-settlement/factoring</strong> product, <strong>not</strong> BNPL — right conclusion, wrong evidence; the correct first-party BNPL source is <code>mydigipay.com/bpg/</code>.</li>
</ul>
<ul>
<li><strong>Provider continuity is a real risk.</strong> In <strong>Nov 2024 the CBI abruptly cut Toman and Jibit's settlement/withdrawal services</strong> with no stated cause, stranding businesses (including millions of Snapp drivers). Design for multi-provider failover and a reconciliation ledger that survives a provider being cut mid-cycle.</li>
</ul>
<ul>
<li><strong>Recommendation:</strong> integrate <strong>SnappPay first</strong>, <strong>Digipay second</strong>, <strong>avoid Lendo</strong>. Onboarding the Balinyaar entity needs <strong>both جواز کسب AND eNamad (اینماد)</strong> (see <a href="../research/legal-landscape.html">legal landscape</a>). Whether a multi-vendor marketplace re-disbursing to many independent nurses qualifies as a single merchant is <strong>publicly UNCONFIRMED</strong> — confirm with provider sales before relying on it.</li>
</ul>
<hr>
<h2 id="sub-pages">Sub-pages <a class="anchor" href="#sub-pages" aria-hidden="true">#</a></h2>
<ul>
<li><a href="iranian-payment-reality.html">The Iranian payment reality</a> — the card → PSP → Shaparak → IBAN rails, the پرداخت‌یار custody prohibition, تسهیم settlement-sharing, banned held pools, provider cut-off risk, and VAT/مودیان.</li>
<li><a href="escrow-ledger.html">Escrow as an internal ledger</a> — why escrow is a double-entry ledger state, the <code>ledger_entries</code> account types, and all the balanced posting blocks.</li>
<li><a href="bnpl-landscape.html">BNPL Landscape &amp; the Full-Upfront Finding</a> — the six-provider comparison table and the decisive full-upfront settlement finding plus its verified caveats.</li>
<li><a href="cancellation-and-payout.html">BNPL Cancellation, Refund &amp; Nurse Payout (Q1 &amp; Q2)</a> — how a BNPL booking is unwound mid-plan, and who pays the nurse (and when) including the three-amount split and a worked example.</li>
<li><a href="integration-notes.html">Integration Notes &amp; Schema Touchpoints</a> — SnappPay and Digipay endpoints, cross-cutting integration rules, and the final table/field names.</li>
<li><a href="sources.html">Recommendations, Open Questions &amp; Sources</a> — contracting recommendations, the open-questions checklist, the full source list, and the confidence legend.</li>
</ul>
<p>See also: the <a href="../data-model/index.html">data model</a> and the <a href="../research/index.html">market research</a>.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+42
View File
@@ -0,0 +1,42 @@
# Payments, Escrow, Settlement & Installments (BNPL)
> **Purpose.** This is the fintech deep-dive for Balinyaar, an MVP home-nursing marketplace in Iran. It pins down how the platform collects money from families, holds an *internal escrow ledger state* (not custodied cash), pays nurses weekly minus commission, and integrates Iranian Buy-Now-Pay-Later (خرید اقساطی / BNPL). It answers the two questions the team cares most about — how a BNPL booking is cancelled/refunded mid-plan, and who pays the nurse (and when) under BNPL — and it grounds every decision in verified research, separating **VERIFIED** facts from **CONFIGURABLE / UNCERTAIN** items that must be confirmed at contracting. All money is **IRR (Rials), stored as `BIGINT`**; Toman is display-only and converted only at the provider API boundary.
**Date:** 2026-06-20
---
## 1. Executive summary
- **Balinyaar legally CANNOT custody buyer funds.** In Iran money always flows card → licensed PSP → Shaparak settlement → bank-registered IBANs. A پرداخت‌یار (payment facilitator — the license class an MVP rides on) is explicitly **barred from holding deposits, running wallets, paying interest, or moving money between merchants**. "Platform holds escrow" must therefore be implemented as an **internal double-entry ledger state** over funds custodied at a licensed provider — never as cash in a Balinyaar bank account. *(VERIFIED — multiple independent sources + CBI/Shaparak directives.)*
- **The compliant marketplace primitive is تسهیم (settlement-sharing):** one incoming card payment is split by the provider/Shaparak across multiple registered IBANs (the nurse's share, the platform's commission) and deposited directly — the platform never touches the split. Shaparak has separately **banned inter-merchant / inter-facilitator transfers and wallet-style holding**, which makes a "delay-then-redistribute" pool legally grey-to-prohibited. *(VERIFIED.)*
- **The decisive BNPL finding: full-upfront settlement.** Provider-financed Iranian BNPLs (SnappPay, Digipay, Tara, Torob Pay, ZarinPlus) pay the **merchant the FULL amount in ONE lump, minus a merchant commission, and bear 100% of customer-default risk.** The customer's installments are owned entirely by the provider and are **decoupled** from Balinyaar's escrow/EVV/payout cycle. *(VERIFIED for SnappPay and Torob Pay from credible sources; consistent for Digipay and Tara.)*
- **Consequence — a BNPL order = a card payment landing net-of-fee.** Therefore Balinyaar **does NOT track customer installments** (no `installment_entries`, no per-installment webhooks, no default propagation). This deletes an entire fragile subsystem.
- **But settlement TIMING is not instant.** The "full amount" is true in *amount*, not *timing*: cadence is contract-defined (daily / T+13 / weekly / 15-day), and at least one authoritative SnappPay source gates settlement on the customer's **first installment** (پس از واریز اولین قسط). Model a per-transaction `settled_at`; never assume instant. *(VERIFIED correction to the original research.)*
- **Under BNPL the nurse is paid by Balinyaar, on Balinyaar's own weekly schedule, exactly as for a card booking** — after EVV check-out and the dispute window. The nurse's payout is computed from `gross_price_irr balinyaar_commission_irr`, **NOT** from the BNPL-net amount. The BNPL commission is a **platform expense** that must never touch the nurse's payout.
- **Avoid Lendo for the MVP.** It is bank-financed (Bank Ayandeh): the **customer** pays ~1823% interest plus a ~5% (often non-refundable) service fee over 612 months — a POS loan, a poor fit for short, cancellable nursing visits.
- **Two corrections the research forced:** VAT in Iran is **10%** (rose from 9% in 1403, = govt 7% + municipal 3%), not 9% — and make it configurable since it has moved two years running (see [legal landscape](../research/legal-landscape.md)). And the Digipay "24h-pay / collect-in-525-days-from-business" sentence describes the **early-settlement/factoring** product, **not** BNPL — right conclusion, wrong evidence; the correct first-party BNPL source is `mydigipay.com/bpg/`.
- **Provider continuity is a real risk.** In **Nov 2024 the CBI abruptly cut Toman and Jibit's settlement/withdrawal services** with no stated cause, stranding businesses (including millions of Snapp drivers). Design for multi-provider failover and a reconciliation ledger that survives a provider being cut mid-cycle.
- **Recommendation:** integrate **SnappPay first**, **Digipay second**, **avoid Lendo**. Onboarding the Balinyaar entity needs **both جواز کسب AND eNamad (اینماد)** (see [legal landscape](../research/legal-landscape.md)). Whether a multi-vendor marketplace re-disbursing to many independent nurses qualifies as a single merchant is **publicly UNCONFIRMED** — confirm with provider sales before relying on it.
---
## Sub-pages
- [The Iranian payment reality](iranian-payment-reality.md) — the card → PSP → Shaparak → IBAN rails, the پرداخت‌یار custody prohibition, تسهیم settlement-sharing, banned held pools, provider cut-off risk, and VAT/مودیان.
- [Escrow as an internal ledger](escrow-ledger.md) — why escrow is a double-entry ledger state, the `ledger_entries` account types, and all the balanced posting blocks.
- [BNPL Landscape & the Full-Upfront Finding](bnpl-landscape.md) — the six-provider comparison table and the decisive full-upfront settlement finding plus its verified caveats.
- [BNPL Cancellation, Refund & Nurse Payout (Q1 & Q2)](cancellation-and-payout.md) — how a BNPL booking is unwound mid-plan, and who pays the nurse (and when) including the three-amount split and a worked example.
- [Integration Notes & Schema Touchpoints](integration-notes.md) — SnappPay and Digipay endpoints, cross-cutting integration rules, and the final table/field names.
- [Recommendations, Open Questions & Sources](sources.md) — contracting recommendations, the open-questions checklist, the full source list, and the confidence legend.
See also: the [data model](../data-model/index.md) and the [market research](../research/index.md).
+77
View File
@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Integration Notes &amp; Schema Touchpoints — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="index.html">Overview &amp; exec summary</a></li><li><a href="iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="escrow-ledger.html">Escrow as a ledger</a></li><li><a href="bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a class="active" href="integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<p><a href="index.html">← Payments overview</a></p>
<h1 id="integration-notes-schema-touchpoints">Integration Notes &amp; Schema Touchpoints</h1>
<h2 id="8-integration-notes">8. Integration notes <a class="anchor" href="#8-integration-notes" aria-hidden="true">#</a></h2>
<h3 id="81-snapppay-اسنپپی-primary">8.1 SnappPay (اسنپ‌پی) — primary <a class="anchor" href="#81-snapppay-اسنپپی-primary" aria-hidden="true">#</a></h3>
<p>API-based with an IPG redirect. Endpoint paths are <strong>VERIFIED</strong> against the open-source Laravel package and match exactly:</p>
<pre><code>POST api/online/v1/oauth/token → OAuth bearer token
GET api/online/offer/v1/eligible → eligibility / credit check on the customer
POST api/online/payment/v1/token → payment token → redirect customer to SnappPay
POST api/online/payment/v1/verify → verify after callback
POST api/online/payment/v1/settle → settle (capture the merchant lump)
POST api/online/payment/v1/revert → full reversal
POST api/online/payment/v1/cancel → cancel
POST api/online/payment/v1/update → partial (new amount strictly lower)
GET api/online/payment/v1/status → status</code></pre>
<p>Credentials issued only after a signed contract + business-license review: <code>user_name</code>, <code>password</code>, <code>client_id</code>, <code>client_secret</code>, merchant/customer number, security code, <code>base_url</code>. Sandbox availability is plausible (issued by sales) but <strong>TO BE CONFIRMED</strong> — the public package does not evidence it.</p>
<blockquote><p><strong>WARNING:</strong> the <code>SnapPayInc/open-api-java-sdk</code> GitHub repo is the <strong>unrelated CANADIAN SnapPay</strong> (snappay.ca, CAD) — <strong>do NOT use it</strong>. Likewise, English searches for "digipay split payment" return <strong>DigiPay.Guru</strong>, an unrelated white-label vendor — not the Iranian Digipay.</p>
</blockquote>
<h3 id="82-digipay-دیجیپی-secondary-fallback">8.2 Digipay (دیجی‌پی) — secondary / fallback <a class="anchor" href="#82-digipay-دیجیپی-secondary-fallback" aria-hidden="true">#</a></h3>
<p>Unified <strong>UPG</strong> gateway, server-side + hosted redirect:</p>
<pre><code>POST /digipay/api/tickets/business?type=… → ticket + redirectUrl (type MUST match product)
(callback to merchant)
POST /digipay/api/purchases/verify → verify (re-check amount + providerId before trusting)
POST /digipay/api/purchases/deliver?type=… → delivery confirmation (Credit=5 / BNPL=13) — GATE ON EVV CHECK-OUT
POST /digipay/api/refunds?type=… → refund (providerId, amount, saleTrackingCode)
GET /digipay/api/refunds/{InquiryId} → poll refund status
POST /digipay/api/reverse → manual reverse (~25 min, IPG/DPG only)</code></pre>
<p><strong>Type codes (VERIFIED, first-party):</strong> IPG=0, Wallet=11, Credit=5, BNPL=13, Credit-Card=24 — <strong>persist the gateway type per transaction</strong>; deliver/refund calls must carry the matching code. Each purchase supports <strong>EITHER refund OR manual reverse, not both</strong> — store a mutually-exclusive reversal-mode flag. For a <em>service</em>, the "delivery" is the completed visit, so <strong>gate <code>deliver</code> on the nurse's EVV check-out.</strong> A BNPL refund returns to the customer's Digipay credit/wallet (or bank/SHEBA), <strong>not</strong> the original card.</p>
<h3 id="83-cross-cutting-integration-rules">8.3 Cross-cutting integration rules <a class="anchor" href="#83-cross-cutting-integration-rules" aria-hidden="true">#</a></h3>
<ul>
<li><strong>Webhook idempotency:</strong> every PSP/BNPL callback is at-least-once and retried. Upsert into <strong><code>payment_webhook_events</code></strong> keyed <code>UNIQUE(external_event_id)</code> <strong>first</strong>, inside the same transaction that mutates money state, and <strong>no-op on duplicate</strong> — prevents double-confirm / double-settle / double-refund.</li>
<li><strong>Never trust the callback alone</strong> — always <code>verify</code> server-side and re-check <code>amount</code> + <code>providerId</code>/reference before treating funds as captured.</li>
<li><strong>Amounts in IRR Rials as <code>BIGINT</code></strong> everywhere; SnappPay/Digipay quote in <strong>Toman</strong> at the API boundary — store a <code>currency</code> field on the BNPL row and <strong>convert only at the boundary, never internally.</strong></li>
<li><strong>State-machine guard</strong> on BNPL status transitions (<code>eligible → token_issued → verified → settled → reverted</code>) so callbacks/retries cannot double-settle or double-refund.</li>
</ul>
<hr>
<h2 id="9-schema-touchpoints">9. Schema touchpoints <a class="anchor" href="#9-schema-touchpoints" aria-hidden="true">#</a></h2>
<p>Final, aligned table/field names (these supersede <code>installment_plans</code> / <code>installment_entries</code>). The canonical entity definitions live in the data model: <a href="../data-model/06-payments-ledger-and-refunds.html">payments, ledger &amp; refunds</a> and <a href="../data-model/08-bnpl.html">BNPL</a>.</p>
<ul>
<li><strong><code>bnpl_transactions</code></strong> (new, <strong>replaces <code>installment_plans</code></strong>; <code>installment_entries</code> <strong>CUT</strong>) — 1:1 with a <code>payment_transaction</code>. Fields: <code>payment_transaction_id</code> FK UNIQUE, <code>provider_code</code>, <code>merchant_of_record</code>, <code>external_payment_token</code>, <code>external_transaction_id</code>, <code>eligibility_status</code>, <code>order_amount_irr</code>, <code>settled_amount_irr</code> (net of provider commission), <code>bnpl_commission_irr</code>, <code>currency</code> (<code>IRR</code>/<code>TOMAN</code>), <code>status</code> (<code>eligible</code>/<code>token_issued</code>/<code>verified</code>/<code>settled</code>/<code>reverted</code>/<code>cancelled</code>/<code>failed</code>), <code>installment_count</code> (default 4, informational only), <code>settled_at</code>, <code>revert_transaction_id</code>, <code>reverted_amount_irr</code>, <code>reverted_at</code>, <code>refund_channel</code>, <code>callback_payload_json</code>.</li>
<li><strong><code>payment_transactions</code></strong> — keep full gateway response + Shaparak reference; <strong>ADD</strong> a filtered <code>UNIQUE(gateway_reference_code) WHERE NOT NULL</code> and a filtered <code>UNIQUE(booking_id) WHERE status='succeeded'</code> (single capture per booking; idempotent retries).</li>
<li><strong><code>payment_webhook_events</code></strong> (new) — <code>provider_code</code>, <code>event_type</code>, <code>external_event_id UNIQUE</code>, <code>payload_json</code>, <code>signature_valid</code>, <code>processing_status</code> (<code>received</code>/<code>processed</code>/<code>failed</code>/<code>ignored</code>), <code>related_payment_transaction_id</code> NULL, <code>received_at</code>, <code>processed_at</code>.</li>
<li><strong><code>refunds</code></strong><strong>1:N</strong> per <code>payment_transaction</code> (the original "1:1" claim is wrong); <strong>ADD</strong> <code>platform_fee_refunded_irr</code>, <code>nurse_payout_refunded_irr</code> (fee-leg decomposition), <code>refund_channel</code> (<code>psp_card</code>/<code>bnpl_revert</code>/<code>manual_bank</code>), <code>external_revert_reference</code>, <code>expected_customer_refund_eta</code>; app invariant <code>Σ refunded ≤ captured</code>.</li>
<li><strong><code>ledger_entries</code></strong> (new) — <code>transaction_group_id</code>, <code>account_type</code> (<code>escrow_held</code>/<code>platform_revenue</code>/<code>nurse_payable</code>/<code>refund_payable</code>/<code>bnpl_fee_expense</code>/<code>nurse_clawback_receivable</code>), <code>nurse_id</code> NULL, <code>direction</code>, <code>amount_irr</code>, <code>booking_id</code> NULL, <code>source_ref_type</code>, <code>source_ref_id</code>, <code>memo</code>, <code>created_at</code>. Append-only; balanced per group.</li>
<li><strong><code>nurse_clawbacks</code></strong> (new) — <code>nurse_id</code>, <code>booking_id</code>, <code>refund_id</code>, <code>amount_irr</code>, <code>status</code> (<code>pending</code>/<code>recovered</code>/<code>written_off</code>), <code>recovered_in_payout_id</code> NULL, <code>created_at</code>, <code>resolved_at</code>.</li>
<li><strong><code>payment_gateways</code></strong> — encrypted provider config in <code>config_json</code> / secrets: SnappPay <code>client_id</code>, <code>client_secret</code>/<code>username</code>+<code>password</code>, merchant number, security code, <code>base_url</code>, <code>sandbox</code> flag. <strong>Never</strong> store credentials per-transaction.</li>
</ul>
<p><strong>Supporting changes:</strong> <code>bookings</code> gets the three-way split (<code>gross_price_irr</code>, <code>balinyaar_commission_irr</code>, <code>nurse_payout_amount</code>) and <code>dispute_window_ends_at</code>; <code>payout_released</code> BIT is <strong>CUT</strong> (derive from <code>nurse_payout_booking_links</code> + ledger). <code>nurse_payouts</code> gets <code>gross_earnings_irr</code>, <code>clawback_applied_irr</code>, <code>net_amount_irr</code>. An <strong><code>invoices</code></strong> table (minimal) captures the commission VAT line.</p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+64
View File
@@ -0,0 +1,64 @@
[← Payments overview](index.md)
# Integration Notes & Schema Touchpoints
## 8. Integration notes
### 8.1 SnappPay (اسنپ‌پی) — primary
API-based with an IPG redirect. Endpoint paths are **VERIFIED** against the open-source Laravel package and match exactly:
```
POST api/online/v1/oauth/token → OAuth bearer token
GET api/online/offer/v1/eligible → eligibility / credit check on the customer
POST api/online/payment/v1/token → payment token → redirect customer to SnappPay
POST api/online/payment/v1/verify → verify after callback
POST api/online/payment/v1/settle → settle (capture the merchant lump)
POST api/online/payment/v1/revert → full reversal
POST api/online/payment/v1/cancel → cancel
POST api/online/payment/v1/update → partial (new amount strictly lower)
GET api/online/payment/v1/status → status
```
Credentials issued only after a signed contract + business-license review: `user_name`, `password`, `client_id`, `client_secret`, merchant/customer number, security code, `base_url`. Sandbox availability is plausible (issued by sales) but **TO BE CONFIRMED** — the public package does not evidence it.
> **WARNING:** the `SnapPayInc/open-api-java-sdk` GitHub repo is the **unrelated CANADIAN SnapPay** (snappay.ca, CAD) — **do NOT use it**. Likewise, English searches for "digipay split payment" return **DigiPay.Guru**, an unrelated white-label vendor — not the Iranian Digipay.
### 8.2 Digipay (دیجی‌پی) — secondary / fallback
Unified **UPG** gateway, server-side + hosted redirect:
```
POST /digipay/api/tickets/business?type=… → ticket + redirectUrl (type MUST match product)
(callback to merchant)
POST /digipay/api/purchases/verify → verify (re-check amount + providerId before trusting)
POST /digipay/api/purchases/deliver?type=… → delivery confirmation (Credit=5 / BNPL=13) — GATE ON EVV CHECK-OUT
POST /digipay/api/refunds?type=… → refund (providerId, amount, saleTrackingCode)
GET /digipay/api/refunds/{InquiryId} → poll refund status
POST /digipay/api/reverse → manual reverse (~25 min, IPG/DPG only)
```
**Type codes (VERIFIED, first-party):** IPG=0, Wallet=11, Credit=5, BNPL=13, Credit-Card=24 — **persist the gateway type per transaction**; deliver/refund calls must carry the matching code. Each purchase supports **EITHER refund OR manual reverse, not both** — store a mutually-exclusive reversal-mode flag. For a *service*, the "delivery" is the completed visit, so **gate `deliver` on the nurse's EVV check-out.** A BNPL refund returns to the customer's Digipay credit/wallet (or bank/SHEBA), **not** the original card.
### 8.3 Cross-cutting integration rules
- **Webhook idempotency:** every PSP/BNPL callback is at-least-once and retried. Upsert into **`payment_webhook_events`** keyed `UNIQUE(external_event_id)` **first**, inside the same transaction that mutates money state, and **no-op on duplicate** — prevents double-confirm / double-settle / double-refund.
- **Never trust the callback alone** — always `verify` server-side and re-check `amount` + `providerId`/reference before treating funds as captured.
- **Amounts in IRR Rials as `BIGINT`** everywhere; SnappPay/Digipay quote in **Toman** at the API boundary — store a `currency` field on the BNPL row and **convert only at the boundary, never internally.**
- **State-machine guard** on BNPL status transitions (`eligible → token_issued → verified → settled → reverted`) so callbacks/retries cannot double-settle or double-refund.
---
## 9. Schema touchpoints
Final, aligned table/field names (these supersede `installment_plans` / `installment_entries`). The canonical entity definitions live in the data model: [payments, ledger & refunds](../data-model/06-payments-ledger-and-refunds.md) and [BNPL](../data-model/08-bnpl.md).
- **`bnpl_transactions`** (new, **replaces `installment_plans`**; `installment_entries` **CUT**) — 1:1 with a `payment_transaction`. Fields: `payment_transaction_id` FK UNIQUE, `provider_code`, `merchant_of_record`, `external_payment_token`, `external_transaction_id`, `eligibility_status`, `order_amount_irr`, `settled_amount_irr` (net of provider commission), `bnpl_commission_irr`, `currency` (`IRR`/`TOMAN`), `status` (`eligible`/`token_issued`/`verified`/`settled`/`reverted`/`cancelled`/`failed`), `installment_count` (default 4, informational only), `settled_at`, `revert_transaction_id`, `reverted_amount_irr`, `reverted_at`, `refund_channel`, `callback_payload_json`.
- **`payment_transactions`** — keep full gateway response + Shaparak reference; **ADD** a filtered `UNIQUE(gateway_reference_code) WHERE NOT NULL` and a filtered `UNIQUE(booking_id) WHERE status='succeeded'` (single capture per booking; idempotent retries).
- **`payment_webhook_events`** (new) — `provider_code`, `event_type`, `external_event_id UNIQUE`, `payload_json`, `signature_valid`, `processing_status` (`received`/`processed`/`failed`/`ignored`), `related_payment_transaction_id` NULL, `received_at`, `processed_at`.
- **`refunds`** — **1:N** per `payment_transaction` (the original "1:1" claim is wrong); **ADD** `platform_fee_refunded_irr`, `nurse_payout_refunded_irr` (fee-leg decomposition), `refund_channel` (`psp_card`/`bnpl_revert`/`manual_bank`), `external_revert_reference`, `expected_customer_refund_eta`; app invariant `Σ refunded ≤ captured`.
- **`ledger_entries`** (new) — `transaction_group_id`, `account_type` (`escrow_held`/`platform_revenue`/`nurse_payable`/`refund_payable`/`bnpl_fee_expense`/`nurse_clawback_receivable`), `nurse_id` NULL, `direction`, `amount_irr`, `booking_id` NULL, `source_ref_type`, `source_ref_id`, `memo`, `created_at`. Append-only; balanced per group.
- **`nurse_clawbacks`** (new) — `nurse_id`, `booking_id`, `refund_id`, `amount_irr`, `status` (`pending`/`recovered`/`written_off`), `recovered_in_payout_id` NULL, `created_at`, `resolved_at`.
- **`payment_gateways`** — encrypted provider config in `config_json` / secrets: SnappPay `client_id`, `client_secret`/`username`+`password`, merchant number, security code, `base_url`, `sandbox` flag. **Never** store credentials per-transaction.
**Supporting changes:** `bookings` gets the three-way split (`gross_price_irr`, `balinyaar_commission_irr`, `nurse_payout_amount`) and `dispute_window_ends_at`; `payout_released` BIT is **CUT** (derive from `nurse_payout_booking_links` + ledger). `nurse_payouts` gets `gross_earnings_irr`, `clawback_applied_irr`, `net_amount_irr`. An **`invoices`** table (minimal) captures the commission VAT line.
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The Iranian Payment Reality — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="index.html">Overview &amp; exec summary</a></li><li><a class="active" href="iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="escrow-ledger.html">Escrow as a ledger</a></li><li><a href="bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<p><a href="index.html">← Payments overview</a></p>
<h1 id="the-iranian-payment-reality">The Iranian Payment Reality</h1>
<h2 id="21-the-rails-card-psp-shaparak-registered-ibans">2.1 The rails: card → PSP → Shaparak → registered IBANs <a class="anchor" href="#21-the-rails-card-psp-shaparak-registered-ibans" aria-hidden="true">#</a></h2>
<p>Every card payment in Iran is acquired by a licensed <strong>PSP</strong> and cleared through <strong>Shaparak</strong> (the national switch), which settles to <strong>bank-registered IBANs (شِبا)</strong> of the merchant/beneficiaries. There is <strong>no native marketplace-escrow construct</strong> the way a US/EU platform would hold buyer cash in trust. The platform does not — and legally may not — sit in the money path as a custodian.</p>
<h2 id="22-the-license-class-پرداختیار-payment-facilitator-and-the-custody-prohibition">2.2 The license class: پرداخت‌یار (payment facilitator) and the custody prohibition <a class="anchor" href="#22-the-license-class-پرداختیار-payment-facilitator-and-the-custody-prohibition" aria-hidden="true">#</a></h2>
<p>An MVP marketplace like Balinyaar rides on a <strong>پرداخت‌یار (payment facilitator / aggregator)</strong> arrangement under a contracted PSP and the CBI/Shaparak agreement. A facilitator is <strong>explicitly forbidden</strong> from:</p>
<ul>
<li>holding customer deposits,</li>
<li>operating wallets,</li>
<li>paying interest,</li>
<li>granting credit / guarantees,</li>
<li>temporarily using merchant balances.</li>
</ul>
<p>Settlement must go <strong>only</strong> to merchant-registered bank accounts, and <strong>only Shaparak</strong> can withdraw from the special facilitator settlement account (حساب ویژه پرداخت‌یاری). Unauthorized fund-holding draws penalties, license suspension, and AML exposure. <strong>This is the single load-bearing constraint of the whole design: Balinyaar cannot be the custodian of buyer funds.</strong> <em>(VERIFIED — way2pay, Zibal legal blog, finolaw, peivast.)</em></p>
<h2 id="23-تسهیم-settlement-sharing-the-compliant-marketplace-primitive">2.3 تسهیم (settlement-sharing) — the compliant marketplace primitive <a class="anchor" href="#23-تسهیم-settlement-sharing-the-compliant-marketplace-primitive" aria-hidden="true">#</a></h2>
<p>The legitimate way to pay many providers is <strong>تسهیم / تسویه اشتراکی (settlement-sharing)</strong>: a single incoming card payment is split across multiple registered IBANs (the nurse's net share + the platform's commission) and <strong>credited directly by Shaparak/the provider</strong> to each party. The platform never touches the actual split. ZarinPal markets this for marketplaces (بازارگاه) with split-by-ratio to each partner's registered Sheba; Zibal, Sadad, SizPay, Vandar, Jibit, Zibal, PayPing, IDPay offer variants. <em>(VERIFIED.)</em></p>
<blockquote><p><strong>Caveat (CONFIGURABLE):</strong> ZarinPal's تسهیم appears gated to a "golden" (طلایی) membership tier; all timing/minimum/limit numbers (e.g. ~100,000 IRR minimum, processing windows, "no beneficiary limit") came from single doc reads and must be reconfirmed at contracting.</p>
</blockquote>
<h2 id="24-the-banned-move-inter-merchant-inter-facilitator-transfers-and-held-pools">2.4 The banned move: inter-merchant / inter-facilitator transfers and held pools <a class="anchor" href="#24-the-banned-move-inter-merchant-inter-facilitator-transfers-and-held-pools" aria-hidden="true">#</a></h2>
<p>A tempting design — "collect into a platform pool, hold until EVV check-out, then redistribute" — is <strong>regulatory grey-to-prohibited.</strong> Shaparak <strong>explicitly banned inter-facilitator and inter-merchant fund transfers and wallet-style holding.</strong> A <em>delayed but pre-fixed</em> split to the <strong>same registered IBANs</strong> may be tolerable; <strong>moving/holding funds in a platform-controlled pool to release conditionally is the banned behavior.</strong> The only clean hold/release/refund mechanism is a <strong>bank-grade escrow product</strong> (e.g. Vandar میندو / معاملات امن — buyer pays into trust, released to seller on confirmation, refundable on seller failure), but even that is flagged as regulatorily fragile and its API-level EVV trigger is unverified. <strong>Practical conclusion: model escrow as an internal ledger over whichever provider primitive you contract; do not assume you can lawfully custody cash yourself.</strong> <em>(VERIFIED ban; the "delay-then-hold" pattern is the OVERSTATED part of the original research.)</em></p>
<h2 id="25-provider-cut-off-continuity-risk-toman-jibit-nov-2024">2.5 Provider cut-off continuity risk (Toman / Jibit, Nov 2024) <a class="anchor" href="#25-provider-cut-off-continuity-risk-toman-jibit-nov-2024" aria-hidden="true">#</a></h2>
<p>In <strong>November 2024 the CBI abruptly cut Toman's and Jibit's settlement/withdrawal services</strong> with no stated cause, disrupting businesses including millions of Snapp drivers who could not settle. Wallet/balance facilitator models have been blocked and re-permitted before (Vandar's gateway was blocked then unblocked by Shaparak). <strong>Design for multi-provider failover and a reconciliation ledger that survives a provider being cut off mid-cycle.</strong> <em>(VERIFIED — zoomit, way2pay, ecoiran.)</em></p>
<h2 id="26-tax-سامانه-مودیان-and-vat-10">2.6 Tax: سامانه مودیان and VAT = 10% <a class="anchor" href="#26-tax-سامانه-مودیان-and-vat-10" aria-hidden="true">#</a></h2>
<ul>
<li>Iran's <strong>سامانه مودیان (taxpayer / e-invoicing system)</strong> requires electronic invoices (صورتحساب الکترونیکی) with a <strong>22-digit number</strong>, a <strong>memory tax-id (شناسه یکتای حافظه مالیاتی)</strong>, and a digital signature. The <strong>SELLER issues the invoice</strong> and remits VAT; the buyer cannot. For a marketplace this maps cleanly: <strong>each nurse is the taxable seller of the nursing service; Balinyaar's taxable supply is ONLY its commission</strong> (the Snapp/Tapsi precedent). <em>(VERIFIED.)</em></li>
<li><strong>VAT is 10%</strong>, not 9%: the standard rate <strong>rose from 9% to 10% in 1403</strong> (govt 7% + municipal 3%) and remains 10% in 1404. Any VAT field hardcoded at 9% is stale — <strong>use 10% and make it a configurable parameter</strong>, since it has changed two years running. <em>(VERIFIED correction.)</em></li>
<li>مودیان enrollment is phased in by revenue threshold (individuals with sales above ~144bn IRR through end of 1404 must issue e-invoices from Tir 1405). Whether the home-nursing <strong>service</strong> itself is VAT-exempt (medical exemption) is <strong>UNCERTAIN</strong> — do not assume; model a config-driven VAT rate that can be 0.</li>
</ul>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
@@ -0,0 +1,39 @@
[← Payments overview](index.md)
# The Iranian Payment Reality
## 2.1 The rails: card → PSP → Shaparak → registered IBANs
Every card payment in Iran is acquired by a licensed **PSP** and cleared through **Shaparak** (the national switch), which settles to **bank-registered IBANs (شِبا)** of the merchant/beneficiaries. There is **no native marketplace-escrow construct** the way a US/EU platform would hold buyer cash in trust. The platform does not — and legally may not — sit in the money path as a custodian.
## 2.2 The license class: پرداخت‌یار (payment facilitator) and the custody prohibition
An MVP marketplace like Balinyaar rides on a **پرداخت‌یار (payment facilitator / aggregator)** arrangement under a contracted PSP and the CBI/Shaparak agreement. A facilitator is **explicitly forbidden** from:
- holding customer deposits,
- operating wallets,
- paying interest,
- granting credit / guarantees,
- temporarily using merchant balances.
Settlement must go **only** to merchant-registered bank accounts, and **only Shaparak** can withdraw from the special facilitator settlement account (حساب ویژه پرداخت‌یاری). Unauthorized fund-holding draws penalties, license suspension, and AML exposure. **This is the single load-bearing constraint of the whole design: Balinyaar cannot be the custodian of buyer funds.** *(VERIFIED — way2pay, Zibal legal blog, finolaw, peivast.)*
## 2.3 تسهیم (settlement-sharing) — the compliant marketplace primitive
The legitimate way to pay many providers is **تسهیم / تسویه اشتراکی (settlement-sharing)**: a single incoming card payment is split across multiple registered IBANs (the nurse's net share + the platform's commission) and **credited directly by Shaparak/the provider** to each party. The platform never touches the actual split. ZarinPal markets this for marketplaces (بازارگاه) with split-by-ratio to each partner's registered Sheba; Zibal, Sadad, SizPay, Vandar, Jibit, Zibal, PayPing, IDPay offer variants. *(VERIFIED.)*
> **Caveat (CONFIGURABLE):** ZarinPal's تسهیم appears gated to a "golden" (طلایی) membership tier; all timing/minimum/limit numbers (e.g. ~100,000 IRR minimum, processing windows, "no beneficiary limit") came from single doc reads and must be reconfirmed at contracting.
## 2.4 The banned move: inter-merchant / inter-facilitator transfers and held pools
A tempting design — "collect into a platform pool, hold until EVV check-out, then redistribute" — is **regulatory grey-to-prohibited.** Shaparak **explicitly banned inter-facilitator and inter-merchant fund transfers and wallet-style holding.** A *delayed but pre-fixed* split to the **same registered IBANs** may be tolerable; **moving/holding funds in a platform-controlled pool to release conditionally is the banned behavior.** The only clean hold/release/refund mechanism is a **bank-grade escrow product** (e.g. Vandar میندو / معاملات امن — buyer pays into trust, released to seller on confirmation, refundable on seller failure), but even that is flagged as regulatorily fragile and its API-level EVV trigger is unverified. **Practical conclusion: model escrow as an internal ledger over whichever provider primitive you contract; do not assume you can lawfully custody cash yourself.** *(VERIFIED ban; the "delay-then-hold" pattern is the OVERSTATED part of the original research.)*
## 2.5 Provider cut-off continuity risk (Toman / Jibit, Nov 2024)
In **November 2024 the CBI abruptly cut Toman's and Jibit's settlement/withdrawal services** with no stated cause, disrupting businesses including millions of Snapp drivers who could not settle. Wallet/balance facilitator models have been blocked and re-permitted before (Vandar's gateway was blocked then unblocked by Shaparak). **Design for multi-provider failover and a reconciliation ledger that survives a provider being cut off mid-cycle.** *(VERIFIED — zoomit, way2pay, ecoiran.)*
## 2.6 Tax: سامانه مودیان and VAT = 10%
- Iran's **سامانه مودیان (taxpayer / e-invoicing system)** requires electronic invoices (صورتحساب الکترونیکی) with a **22-digit number**, a **memory tax-id (شناسه یکتای حافظه مالیاتی)**, and a digital signature. The **SELLER issues the invoice** and remits VAT; the buyer cannot. For a marketplace this maps cleanly: **each nurse is the taxable seller of the nursing service; Balinyaar's taxable supply is ONLY its commission** (the Snapp/Tapsi precedent). *(VERIFIED.)*
- **VAT is 10%**, not 9%: the standard rate **rose from 9% to 10% in 1403** (govt 7% + municipal 3%) and remains 10% in 1404. Any VAT field hardcoded at 9% is stale — **use 10% and make it a configurable parameter**, since it has changed two years running. *(VERIFIED correction.)*
- مودیان enrollment is phased in by revenue threshold (individuals with sales above ~144bn IRR through end of 1404 must issue e-invoices from Tir 1405). Whether the home-nursing **service** itself is VAT-exempt (medical exemption) is **UNCERTAIN** — do not assume; model a config-driven VAT rate that can be 0.
+101
View File
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Recommendations, Open Questions &amp; Sources — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="index.html">Overview &amp; exec summary</a></li><li><a href="iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="escrow-ledger.html">Escrow as a ledger</a></li><li><a href="bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a class="active" href="sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="../research/index.html">Overview &amp; exec summary</a></li><li><a href="../research/market-and-competitors.html">Market &amp; competitors</a></li><li><a href="../research/problems-and-risks.html">Problems &amp; risks</a></li><li><a href="../research/verification.html">Verification (research)</a></li><li><a href="../research/legal-landscape.html">Legal landscape</a></li><li><a href="../research/go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<p><a href="index.html">← Payments overview</a></p>
<h1 id="recommendations-open-questions-sources">Recommendations, Open Questions &amp; Sources</h1>
<h2 id="10-recommendations-open-questions-to-confirm-at-contracting">10. Recommendations &amp; open questions to confirm at contracting <a class="anchor" href="#10-recommendations-open-questions-to-confirm-at-contracting" aria-hidden="true">#</a></h2>
<h3 id="recommendations">Recommendations <a class="anchor" href="#recommendations" aria-hidden="true">#</a></h3>
<ol>
<li><strong>Integrate SnappPay first, Digipay second, avoid Lendo.</strong> SnappPay has the largest reach, explicit service-merchant support, true full-upfront settlement, full default-risk transfer, and a coded API. Digipay is the redundancy/fallback with the broadest healthcare/service coverage. Lendo's customer-borne interest + non-refundable fee is wrong for short, cancellable visits.</li>
<li><strong>Treat a BNPL order as one net inbound settlement</strong> identical to a card payment net-of-fee. <strong>Do not</strong> build customer-installment tracking.</li>
<li><strong>Make escrow an internal double-entry ledger</strong> over funds custodied at a single licensed provider; <strong>abstract the provider</strong> behind config so it can be swapped if blocked (Toman/Jibit precedent).</li>
<li><strong>Pay the nurse from <code>gross balinyaar_commission</code>, weekly, after EVV + dispute window</strong> — identical for card and BNPL; the BNPL commission is a platform expense only.</li>
<li><strong>Gate payout on the dispute window</strong> (default 72h) rather than relying on clawback — Iranian bank transfers are effectively irreversible; keep clawback as the modeled fallback.</li>
<li><strong>Build webhook idempotency before touching real money</strong>, and store all amounts in IRR <code>BIGINT</code>, converting from Toman only at the API boundary.</li>
<li><strong>Use 10% VAT, configurable.</strong> Treat each nurse as the taxable seller; invoice only Balinyaar's commission.</li>
</ol>
<h3 id="open-questions-to-confirm-with-provider-sales-at-contracting">Open questions to confirm with provider sales / at contracting <a class="anchor" href="#open-questions-to-confirm-with-provider-sales-at-contracting" aria-hidden="true">#</a></h3>
<ul>
<li><strong>Marketplace eligibility:</strong> does the provider's merchant contract permit a multi-vendor home-services marketplace that re-disburses to many independent nurses as a <strong>single</strong> merchant-of-record? (Publicly undocumented; their known model is single-receiver.)</li>
<li><strong>Commission rate (%):</strong> the actual rate for the health/home-services category (SnappPay publishes none; ~715% is anecdotal; Torob Pay's 6.6% is not a proxy).</li>
<li><strong>Settlement SLA / timing:</strong> daily vs T+13 vs weekly vs 15-day, and whether it is gated on the customer's first installment. Get it in writing; do not assume same-day.</li>
<li><strong>Commission-clawback-on-refund behavior:</strong> on a full vs partial refund, does the provider return its merchant commission fully, pro-rata, or not at all?</li>
<li><strong>Onboarding documents:</strong> confirm جواز کسب <strong>and</strong> eNamad suffice for the Balinyaar entity, and whether home-healthcare is a "sensitive trade" needing a sectoral license.</li>
<li><strong>Sandbox credentials:</strong> request early; confirm availability (not evidenced publicly).</li>
<li><strong>Settlement-provider (تسهیم/payout) choice for the card leg:</strong> which licensed provider (ZarinPal تسهیم / Vandar / Jibit), its fee schedule, batch caps, minimums, and whether delayed settlement / a bank-grade escrow product (Vandar میندو) is permissible for the EVV-gated hold.</li>
</ul>
<hr>
<h2 id="sources">Sources <a class="anchor" href="#sources" aria-hidden="true">#</a></h2>
<p><strong>Iranian payment-facilitator / escrow / settlement legality</strong></p>
<ul>
<li>finolaw.net — مقررات پرداخت‌یاری (facilitator rules): <code>https://finolaw.net/مقررات-پرداخت-یاری/</code></li>
<li>way2pay.ir — CBI facilitator framework: <code>https://way2pay.ir/480525/</code>, <code>https://way2pay.ir/484056/</code></li>
<li>Zibal legal blog — internet-payment rules: <code>https://zibal.ir/blog/قوانین-پرداخت-اینترنتی-درگاه-پرداخت-ک/</code></li>
<li>peivast.com — Shaparak inter-merchant/wallet ban: <code>https://peivast.com/p/148655</code></li>
<li>ZarinPal تسهیم (split-payment): <code>https://zarinpal.com/split-payment.html</code>, <code>https://www.zarinpal.com/blog/درگاه-پرداخت-اشتراکی-چیست؟/</code>, <code>https://next.zarinpal.com/paymentGateway/setshare.html</code></li>
<li>Vandar — facilitator / میندو escrow / Bank Ayandeh custody: <code>https://vandar.io/blog/پرداختیاری-چیست-و-پرداختیار-کیست؟/</code>, <code>https://vandar.io/miando/</code>, <code>https://docs.vandar.io/payout_service/settlement</code></li>
<li>Jibit transferor / payout: <code>https://www.jibit.io/transferor/</code></li>
<li>Toman/Jibit Nov-2024 cut-off: <code>https://www.zoomit.ir/tech-iran/429145-banning-payment-services-on-toman-and-jibit/</code>, <code>https://way2pay.ir/389544/</code></li>
</ul>
<p><strong>Tax / مودیان / VAT (10%)</strong></p>
<ul>
<li>systemgroup.net — مودیان registration: <code>https://www.systemgroup.net/knowledge-network/registration-in-the-tax-system/</code></li>
<li>hesabandish.com — taxpayer rules: <code>https://hesabandish.com/rules-taxpayer-system/</code></li>
<li>sepidarsystem.com — VAT rate: <code>https://www.sepidarsystem.com/blog/vat-rate/</code></li>
<li>Tapsi/Snapp commission-tax precedent: <code>https://ip30.ir/tapsi-taxation-challenge/</code>, <code>https://drhesaab.ir/how-is-digital-platform-tax-calculated/</code></li>
</ul>
<p><strong>SnappPay</strong></p>
<ul>
<li>Merchant settlement (full-upfront, risk): <code>https://limoo.host/blog/snap-pay-merchant-settlement/</code>, <code>https://www.portal.ir/snappay-payment-method</code>, <code>https://way2pay.ir/278219/</code></li>
<li>Product / CEO revenue model: <code>https://see5.net/blog/what-is-snappay</code>, <code>https://ideaagency.net/snapppay-the-correct-revenue-model-landtechs/</code>, <code>https://snapppay.ir/</code>, <code>https://pay.snapp.ir/</code></li>
<li>Refund/cancel FAQ (710 business days): <code>https://allsport.ir/faq/5/8.html</code>, <code>https://sourmeh.ir/common-question-about-snapppay/</code></li>
<li>API (Laravel package) + eligibility: <code>https://github.com/backendprogramer/laravel-snapp-pay</code>, <code>https://payzito.net/docs/gateways/snapppay</code>, <code>https://snapppay.ir/merchant-acquisition/</code></li>
</ul>
<p><strong>Digipay</strong></p>
<ul>
<li>BNPL full-upfront (credit gateway): <code>https://www.mydigipay.com/bpg/</code>, <code>https://matson.online/digipay-seller/</code>, <code>https://digiato.com/tech/digipay-business-solutions-pr</code></li>
<li>Services / merchants: <code>https://www.mydigipay.com/credit/merchants/</code>, <code>https://www.mydigipay.com/credit/c-credit/</code>, <code>https://www.mydigipay.com/bnpl/c-bnpl/</code></li>
<li>UPG dev docs (type codes, deliver/refund/reverse): <code>https://www.mydigipay.com/developers/docs/upg/</code></li>
<li>Onboarding: <code>https://limoo.host/blog/signup-on-digipay/</code></li>
</ul>
<p><strong>Tara / Torob Pay / ZarinPlus / Lendo</strong></p>
<ul>
<li>Tara: <code>https://tara360.ir/bnpl/</code>, <code>https://tara360.ir/</code>, <code>https://itresan.com/384039/</code></li>
<li>Torob Pay (6% + VAT): <code>https://blupoz.com/</code>, <code>https://ranginstore.com/</code></li>
<li>ZarinPlus: <code>https://www.zarinpal.com/blog/bnpl-زرین-پلاس/</code>, <code>https://www.zarinpal.com/payment-gateway</code></li>
<li>Lendo (bank-financed): <code>https://lendo.ir/blog/</code>, <code>https://lendo.ir/</code></li>
</ul>
<p><strong>Internal</strong></p>
<ul>
<li>Existing research: <code>c:\Users\Lenovo\Desktop\balinyaar\product\Home-Nursing-Platform-Research.md</code></li>
<li>Database model to refine: <code>c:\Users\Lenovo\Desktop\balinyaar\product\database-model.md</code></li>
</ul>
<blockquote><p><strong>Confidence legend.</strong> VERIFIED = survived adversarial verification against multiple/first-party sources. CONFIGURABLE = real but contract-/campaign-dependent (store as config, read actuals from provider). UNCERTAIN = plausible but unconfirmed publicly — confirm at contracting before depending on it.</p>
</blockquote>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+69
View File
@@ -0,0 +1,69 @@
[← Payments overview](index.md)
# Recommendations, Open Questions & Sources
## 10. Recommendations & open questions to confirm at contracting
### Recommendations
1. **Integrate SnappPay first, Digipay second, avoid Lendo.** SnappPay has the largest reach, explicit service-merchant support, true full-upfront settlement, full default-risk transfer, and a coded API. Digipay is the redundancy/fallback with the broadest healthcare/service coverage. Lendo's customer-borne interest + non-refundable fee is wrong for short, cancellable visits.
2. **Treat a BNPL order as one net inbound settlement** identical to a card payment net-of-fee. **Do not** build customer-installment tracking.
3. **Make escrow an internal double-entry ledger** over funds custodied at a single licensed provider; **abstract the provider** behind config so it can be swapped if blocked (Toman/Jibit precedent).
4. **Pay the nurse from `gross balinyaar_commission`, weekly, after EVV + dispute window** — identical for card and BNPL; the BNPL commission is a platform expense only.
5. **Gate payout on the dispute window** (default 72h) rather than relying on clawback — Iranian bank transfers are effectively irreversible; keep clawback as the modeled fallback.
6. **Build webhook idempotency before touching real money**, and store all amounts in IRR `BIGINT`, converting from Toman only at the API boundary.
7. **Use 10% VAT, configurable.** Treat each nurse as the taxable seller; invoice only Balinyaar's commission.
### Open questions to confirm with provider sales / at contracting
- **Marketplace eligibility:** does the provider's merchant contract permit a multi-vendor home-services marketplace that re-disburses to many independent nurses as a **single** merchant-of-record? (Publicly undocumented; their known model is single-receiver.)
- **Commission rate (%):** the actual rate for the health/home-services category (SnappPay publishes none; ~715% is anecdotal; Torob Pay's 6.6% is not a proxy).
- **Settlement SLA / timing:** daily vs T+13 vs weekly vs 15-day, and whether it is gated on the customer's first installment. Get it in writing; do not assume same-day.
- **Commission-clawback-on-refund behavior:** on a full vs partial refund, does the provider return its merchant commission fully, pro-rata, or not at all?
- **Onboarding documents:** confirm جواز کسب **and** eNamad suffice for the Balinyaar entity, and whether home-healthcare is a "sensitive trade" needing a sectoral license.
- **Sandbox credentials:** request early; confirm availability (not evidenced publicly).
- **Settlement-provider (تسهیم/payout) choice for the card leg:** which licensed provider (ZarinPal تسهیم / Vandar / Jibit), its fee schedule, batch caps, minimums, and whether delayed settlement / a bank-grade escrow product (Vandar میندو) is permissible for the EVV-gated hold.
---
## Sources
**Iranian payment-facilitator / escrow / settlement legality**
- finolaw.net — مقررات پرداخت‌یاری (facilitator rules): `https://finolaw.net/مقررات-پرداخت-یاری/`
- way2pay.ir — CBI facilitator framework: `https://way2pay.ir/480525/`, `https://way2pay.ir/484056/`
- Zibal legal blog — internet-payment rules: `https://zibal.ir/blog/قوانین-پرداخت-اینترنتی-درگاه-پرداخت-ک/`
- peivast.com — Shaparak inter-merchant/wallet ban: `https://peivast.com/p/148655`
- ZarinPal تسهیم (split-payment): `https://zarinpal.com/split-payment.html`, `https://www.zarinpal.com/blog/درگاه-پرداخت-اشتراکی-چیست؟/`, `https://next.zarinpal.com/paymentGateway/setshare.html`
- Vandar — facilitator / میندو escrow / Bank Ayandeh custody: `https://vandar.io/blog/پرداختیاری-چیست-و-پرداختیار-کیست؟/`, `https://vandar.io/miando/`, `https://docs.vandar.io/payout_service/settlement`
- Jibit transferor / payout: `https://www.jibit.io/transferor/`
- Toman/Jibit Nov-2024 cut-off: `https://www.zoomit.ir/tech-iran/429145-banning-payment-services-on-toman-and-jibit/`, `https://way2pay.ir/389544/`
**Tax / مودیان / VAT (10%)**
- systemgroup.net — مودیان registration: `https://www.systemgroup.net/knowledge-network/registration-in-the-tax-system/`
- hesabandish.com — taxpayer rules: `https://hesabandish.com/rules-taxpayer-system/`
- sepidarsystem.com — VAT rate: `https://www.sepidarsystem.com/blog/vat-rate/`
- Tapsi/Snapp commission-tax precedent: `https://ip30.ir/tapsi-taxation-challenge/`, `https://drhesaab.ir/how-is-digital-platform-tax-calculated/`
**SnappPay**
- Merchant settlement (full-upfront, risk): `https://limoo.host/blog/snap-pay-merchant-settlement/`, `https://www.portal.ir/snappay-payment-method`, `https://way2pay.ir/278219/`
- Product / CEO revenue model: `https://see5.net/blog/what-is-snappay`, `https://ideaagency.net/snapppay-the-correct-revenue-model-landtechs/`, `https://snapppay.ir/`, `https://pay.snapp.ir/`
- Refund/cancel FAQ (710 business days): `https://allsport.ir/faq/5/8.html`, `https://sourmeh.ir/common-question-about-snapppay/`
- API (Laravel package) + eligibility: `https://github.com/backendprogramer/laravel-snapp-pay`, `https://payzito.net/docs/gateways/snapppay`, `https://snapppay.ir/merchant-acquisition/`
**Digipay**
- BNPL full-upfront (credit gateway): `https://www.mydigipay.com/bpg/`, `https://matson.online/digipay-seller/`, `https://digiato.com/tech/digipay-business-solutions-pr`
- Services / merchants: `https://www.mydigipay.com/credit/merchants/`, `https://www.mydigipay.com/credit/c-credit/`, `https://www.mydigipay.com/bnpl/c-bnpl/`
- UPG dev docs (type codes, deliver/refund/reverse): `https://www.mydigipay.com/developers/docs/upg/`
- Onboarding: `https://limoo.host/blog/signup-on-digipay/`
**Tara / Torob Pay / ZarinPlus / Lendo**
- Tara: `https://tara360.ir/bnpl/`, `https://tara360.ir/`, `https://itresan.com/384039/`
- Torob Pay (6% + VAT): `https://blupoz.com/`, `https://ranginstore.com/`
- ZarinPlus: `https://www.zarinpal.com/blog/bnpl-زرین-پلاس/`, `https://www.zarinpal.com/payment-gateway`
- Lendo (bank-financed): `https://lendo.ir/blog/`, `https://lendo.ir/`
**Internal**
- Existing research: `c:\Users\Lenovo\Desktop\balinyaar\product\Home-Nursing-Platform-Research.md`
- Database model to refine: `c:\Users\Lenovo\Desktop\balinyaar\product\database-model.md`
> **Confidence legend.** VERIFIED = survived adversarial verification against multiple/first-party sources. CONFIGURABLE = real but contract-/campaign-dependent (store as config, read actuals from provider). UNCERTAIN = plausible but unconfirmed publicly — confirm at contracting before depending on it.
+58
View File
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Recommendations, Go-To-Market &amp; Sources — Balinyaar docs</title>
<link rel="stylesheet" href="../assets/doc.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<a class="brand" href="../index.html"><span class="dot"></span> Balinyaar docs</a>
<p class="tagline">Trust-first home-nursing marketplace · Iran</p>
<nav><div class="group"><div class="label">Start here</div><ul><li><a href="../index.html">Docs home</a></li><li><a href="../overview/platform-summary.html">Platform summary &amp; ground truths</a></li></ul></div><div class="group"><div class="label">Business requirements</div><ul><li><a href="../business/index.html">Overview &amp; MVP scope</a></li><li><a href="../business/01-actors-and-onboarding.html">1. Actors &amp; onboarding</a></li><li><a href="../business/02-nurse-verification.html">2. Nurse verification</a></li><li><a href="../business/03-service-catalog-and-pricing.html">3. Service catalog &amp; pricing</a></li><li><a href="../business/04-search-and-matching.html">4. Search &amp; matching</a></li><li><a href="../business/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../business/06-evv-and-service-delivery.html">6. EVV / service delivery</a></li><li><a href="../business/07-cancellation-and-refunds.html">7. Cancellation &amp; refunds</a></li><li><a href="../business/08-payments-and-escrow.html">8. Payments &amp; escrow</a></li><li><a href="../business/09-installments-bnpl.html">9. Installments / BNPL</a></li><li><a href="../business/10-payouts.html">10. Payouts to nurses</a></li><li><a href="../business/11-reviews-trust-and-safety.html">11. Reviews, trust &amp; safety</a></li><li><a href="../business/12-messaging-and-emergencies.html">12. Messaging &amp; emergencies</a></li><li><a href="../business/13-tax-invoicing-and-legal.html">13. Tax, invoicing &amp; legal</a></li><li><a href="../business/14-notifications-and-admin.html">14. Notifications &amp; admin</a></li></ul></div><div class="group"><div class="label">Database model</div><ul><li><a href="../data-model/index.html">Overview &amp; decisions</a></li><li><a href="../data-model/diagrams.html">Diagrams</a></li><li><a href="../data-model/01-identity-and-access.html">1. Identity &amp; access</a></li><li><a href="../data-model/02-geography.html">2. Geography</a></li><li><a href="../data-model/03-services-and-pricing.html">3. Services &amp; pricing</a></li><li><a href="../data-model/04-verification-and-credentials.html">4. Verification &amp; credentials</a></li><li><a href="../data-model/05-booking-and-scheduling.html">5. Booking &amp; scheduling</a></li><li><a href="../data-model/06-payments-ledger-and-refunds.html">6. Payments, ledger &amp; refunds</a></li><li><a href="../data-model/07-payouts.html">7. Payouts</a></li><li><a href="../data-model/08-bnpl.html">8. BNPL / installments</a></li><li><a href="../data-model/09-messaging.html">9. Messaging</a></li><li><a href="../data-model/10-reviews-and-records.html">10. Reviews &amp; records</a></li><li><a href="../data-model/11-notifications.html">11. Notifications</a></li><li><a href="../data-model/12-audit-config-and-reference.html">12. Audit, config &amp; reference</a></li><li><a href="../data-model/13-partner-centers-and-future.html">13. Partner centers &amp; future</a></li></ul></div><div class="group"><div class="label">Payments deep-dive</div><ul><li><a href="../payments/index.html">Overview &amp; exec summary</a></li><li><a href="../payments/iranian-payment-reality.html">Iranian payment reality</a></li><li><a href="../payments/escrow-ledger.html">Escrow as a ledger</a></li><li><a href="../payments/bnpl-landscape.html">BNPL landscape &amp; finding</a></li><li><a href="../payments/cancellation-and-payout.html">Cancellation &amp; nurse payout</a></li><li><a href="../payments/integration-notes.html">Integration &amp; schema touchpoints</a></li><li><a href="../payments/sources.html">Recommendations &amp; sources</a></li></ul></div><div class="group"><div class="label">Research &amp; strategy</div><ul><li><a href="index.html">Overview &amp; exec summary</a></li><li><a href="market-and-competitors.html">Market &amp; competitors</a></li><li><a href="problems-and-risks.html">Problems &amp; risks</a></li><li><a href="verification.html">Verification (research)</a></li><li><a href="legal-landscape.html">Legal landscape</a></li><li><a class="active" href="go-to-market.html">Go-to-market &amp; sources</a></li></ul></div><div class="group"><div class="label">Notes &amp; more</div><ul><li><a href="../notes/open-questions.html">Open questions</a></li><li><a href="../notes/future-ideas.html">Future ideas</a></li><li><a href="../wireframes/index.html">Wireframes</a></li><li><a href="../fa/index.html">Farsi documents</a></li></ul></div></nav>
</aside>
<main class="main"><div class="content">
<div class="topbar"><button class="theme-toggle" type="button" onclick="__t()">theme</button></div>
<h1 id="recommendations-go-to-market-sources">Recommendations, Go-To-Market &amp; Sources</h1>
<p><a href="index.html">← Research overview</a></p>
<h2 id="actionable-recommendations-go-to-market">Actionable Recommendations &amp; Go-To-Market <a class="anchor" href="#actionable-recommendations-go-to-market" aria-hidden="true">#</a></h2>
<p>**1. Choose the legal vehicle now: register a <em>Home Nursing Services Center</em>.** Either you (if a nurse with BSc + 5 yrs experience) or a nurse co-founder serves as founder/technical director. If you want to offer physician-supervised clinical services later, add a physician partner and the clinical-care track separately.</p>
<p><strong>2. Go to market fast via the Asanism model — partner with already-licensed centers</strong> while your own permit is in process. This lets you launch the tech/brand/marketplace layer legally and quickly, then bring supply in-house over time.</p>
<p><strong>3. Make verified trust your entire brand.</strong> Bundle (not upsell) a visible vetting badge: ✓ identity verified (Shahkar + face match), ✓ MoH پروانه صلاحیت حرفه‌ای confirmed, ✓ نظام پرستاری number, ✓ عدم سوء پیشینه on file, ✓ trial period + security guarantee. Display your own license number like Salamat Aval does.</p>
<p><strong>4. Win the geography others ignore.</strong> Tehran/Karaj are saturated and concentrated; <strong>target second-tier cities</strong> (Mashhad, Isfahan, Shiraz, Tabriz, Ahvaz, Qom) where incumbents are thin.</p>
<p><strong>5. Buy verification, don't build it.</strong> Integrate one KYC vendor (Finnotech or U-ID) for Shahkar + national-ID + liveness; require the MoH competency license + INO number for the license layer; require nurse-uploaded عدم سوء پیشینه.</p>
<p><strong>6. Decide the employment model with counsel before scaling</strong> — neutral marketplace vs. employer/agency. Avoid the "control-for-quality + contractor-for-cost" trap that triggers misclassification liability. Carry platform liability insurance regardless.</p>
<p><strong>7. Engineer against disintermediation from day one:</strong> in-platform escrow payment + dispute resolution, a backup-nurse coverage guarantee, EVV check-in/out, and protections that only apply on-platform.</p>
<p><strong>8. Build the institutional flywheel early:</strong> hospital post-discharge referral partnerships (post-surgery, post-stroke), and pilot B2B contracts with insurers (Salamat / تأمین اجتماعی), charities, or employers to subsidize visits.</p>
<p><strong>9. Add a lighter "companionship / daily-living" tier</strong> (the Papa model) — lower supply constraint, broader market, and a feeder into skilled-nursing as needs escalate. Court the <strong>diaspora</strong> ("pay for your parent's care back home").</p>
<p><strong>10. Never over-market safety.</strong> Every Care.com penalty traces to claiming a check it didn't perform or a dark-pattern cancellation. Under-promise, over-verify, make cancellation easy.</p>
<hr>
<h2 id="key-open-questions-to-verify-before-launch">Key Open Questions / To Verify Before Launch <a class="anchor" href="#key-open-questions-to-verify-before-launch" aria-hidden="true">#</a></h2>
<ol>
<li><strong>Current (14041405) registered-company count</strong> and the present status of the سخت و زیان‌آور labor-law gap — has any legislation closed it?</li>
<li><strong>Full capital, facility, staffing, and insurance requirements</strong> for the nursing-services-center track specifically, and whether a <strong>tech-first marketplace</strong> can operate by subcontracting <em>only</em> to already-licensed partner centers (the Asanism model) without holding its own permit initially.</li>
<li>Whether the <strong>INO / MoH offer any B2B verification API</strong> behind a portal (only "not found" via public search so far).</li>
<li><strong>Tax, VAT, and company-structure specifics</strong> with a local accountant; <strong>employment classification</strong> with a labor lawyer.</li>
</ol>
<hr>
<h2 id="sources-selected">Sources (selected) <a class="anchor" href="#sources-selected" aria-hidden="true">#</a></h2>
<p><strong>Iran — legal &amp; local market (verified):</strong> arakmu.ac.ir/vct/fa/regulation/1063/ · mcls.gov.ir/fa/law/61 · qavanin.ir/Law/TreeText/83385 · irannurse.ir · vct.iums.ac.ir · ilna.ir/بخش-کارگری-9/797233 · ecommerce.gov.ir · netafraz.com/blog/getting-enamad-complete-guide/ · asanism.com · snapp.doctor/home-nursing/ · salamateaval.com · myket.ir/app/hirad.sc.com</p>
<p><strong>Foreign platforms:</strong> techcrunch.com (Honor, Cera, Vivian, Birdie, Portea) · ftc.gov &amp; cnbc.com (Care.com FTC) · mobihealthnews.com (Papa) · florence.co.uk · techcrunch.com/technode.global (Homage) · tvmcapitalhealthcare.com (Manzil) · quartr.com (Veteranpoolen)</p>
<p><strong>Risks &amp; failures:</strong> thedailybeast.com &amp; backgroundchecks.com (Care.com/WSJ) · engadget.com (listing purge) · nurse.org &amp; washingtonpost.com (Womack imposter nurse) · hrmorning.com &amp; ogletree.com (misclassification) · shiftcare.com &amp; axiscare.com (turnover) · sharetribe.com (disintermediation) · aarp.org (financial elder abuse) · pymnts.com (Care.com $1M Marin)</p>
<p><strong>Verification tooling:</strong> ncsbn.org &amp; nursys.com (Nursys) · nmc.org.uk (NMC) · checkr.com &amp; sterlingcheck.app (background vendors) · behdasht.gov.ir &amp; heyvagroup.com (MoH/INO licensing) · fa.wikipedia.org/سامانه_شاهکار (Shahkar) · finnotech.ir (KYC) · asretarakonesh.ir (8 Iranian KYC firms) · heyvalaw.com (عدم سوء پیشینه via ثنا)</p>
<p><em>Report compiled from an adversarially-verified research pass (Iranian legal framework + local competitors) plus three targeted research agents (foreign competitors, risk/failure cases, verification tooling). Verify decades-old regulations, self-reported competitor stats, and funding figures against current primary sources before making decisions or publishing.</em></p>
<a class="back-to-top" href="#">↑ Back to top</a>
</div></main>
</div>
<script>
(function(){var k='balinyaar-docs-theme';var s=localStorage.getItem(k);
if(s)document.documentElement.setAttribute('data-theme',s);
else if(matchMedia('(prefers-color-scheme: dark)').matches)document.documentElement.setAttribute('data-theme','dark');})();
function __t(){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'light':'dark';
d.setAttribute('data-theme',n);localStorage.setItem('balinyaar-docs-theme',n);}
</script>
</body>
</html>
+47
View File
@@ -0,0 +1,47 @@
# Recommendations, Go-To-Market & Sources
[← Research overview](index.md)
## Actionable Recommendations & Go-To-Market
**1. Choose the legal vehicle now: register a *Home Nursing Services Center*.** Either you (if a nurse with BSc + 5 yrs experience) or a nurse co-founder serves as founder/technical director. If you want to offer physician-supervised clinical services later, add a physician partner and the clinical-care track separately.
**2. Go to market fast via the Asanism model — partner with already-licensed centers** while your own permit is in process. This lets you launch the tech/brand/marketplace layer legally and quickly, then bring supply in-house over time.
**3. Make verified trust your entire brand.** Bundle (not upsell) a visible vetting badge: ✓ identity verified (Shahkar + face match), ✓ MoH پروانه صلاحیت حرفه‌ای confirmed, ✓ نظام پرستاری number, ✓ عدم سوء پیشینه on file, ✓ trial period + security guarantee. Display your own license number like Salamat Aval does.
**4. Win the geography others ignore.** Tehran/Karaj are saturated and concentrated; **target second-tier cities** (Mashhad, Isfahan, Shiraz, Tabriz, Ahvaz, Qom) where incumbents are thin.
**5. Buy verification, don't build it.** Integrate one KYC vendor (Finnotech or U-ID) for Shahkar + national-ID + liveness; require the MoH competency license + INO number for the license layer; require nurse-uploaded عدم سوء پیشینه.
**6. Decide the employment model with counsel before scaling** — neutral marketplace vs. employer/agency. Avoid the "control-for-quality + contractor-for-cost" trap that triggers misclassification liability. Carry platform liability insurance regardless.
**7. Engineer against disintermediation from day one:** in-platform escrow payment + dispute resolution, a backup-nurse coverage guarantee, EVV check-in/out, and protections that only apply on-platform.
**8. Build the institutional flywheel early:** hospital post-discharge referral partnerships (post-surgery, post-stroke), and pilot B2B contracts with insurers (Salamat / تأمین اجتماعی), charities, or employers to subsidize visits.
**9. Add a lighter "companionship / daily-living" tier** (the Papa model) — lower supply constraint, broader market, and a feeder into skilled-nursing as needs escalate. Court the **diaspora** ("pay for your parent's care back home").
**10. Never over-market safety.** Every Care.com penalty traces to claiming a check it didn't perform or a dark-pattern cancellation. Under-promise, over-verify, make cancellation easy.
---
## Key Open Questions / To Verify Before Launch
1. **Current (14041405) registered-company count** and the present status of the سخت و زیان‌آور labor-law gap — has any legislation closed it?
2. **Full capital, facility, staffing, and insurance requirements** for the nursing-services-center track specifically, and whether a **tech-first marketplace** can operate by subcontracting *only* to already-licensed partner centers (the Asanism model) without holding its own permit initially.
3. Whether the **INO / MoH offer any B2B verification API** behind a portal (only "not found" via public search so far).
4. **Tax, VAT, and company-structure specifics** with a local accountant; **employment classification** with a labor lawyer.
---
## Sources (selected)
**Iran — legal & local market (verified):** arakmu.ac.ir/vct/fa/regulation/1063/ · mcls.gov.ir/fa/law/61 · qavanin.ir/Law/TreeText/83385 · irannurse.ir · vct.iums.ac.ir · ilna.ir/بخش-کارگری-9/797233 · ecommerce.gov.ir · netafraz.com/blog/getting-enamad-complete-guide/ · asanism.com · snapp.doctor/home-nursing/ · salamateaval.com · myket.ir/app/hirad.sc.com
**Foreign platforms:** techcrunch.com (Honor, Cera, Vivian, Birdie, Portea) · ftc.gov & cnbc.com (Care.com FTC) · mobihealthnews.com (Papa) · florence.co.uk · techcrunch.com/technode.global (Homage) · tvmcapitalhealthcare.com (Manzil) · quartr.com (Veteranpoolen)
**Risks & failures:** thedailybeast.com & backgroundchecks.com (Care.com/WSJ) · engadget.com (listing purge) · nurse.org & washingtonpost.com (Womack imposter nurse) · hrmorning.com & ogletree.com (misclassification) · shiftcare.com & axiscare.com (turnover) · sharetribe.com (disintermediation) · aarp.org (financial elder abuse) · pymnts.com (Care.com $1M Marin)
**Verification tooling:** ncsbn.org & nursys.com (Nursys) · nmc.org.uk (NMC) · checkr.com & sterlingcheck.app (background vendors) · behdasht.gov.ir & heyvagroup.com (MoH/INO licensing) · fa.wikipedia.org/سامانه_شاهکار (Shahkar) · finnotech.ir (KYC) · asretarakonesh.ir (8 Iranian KYC firms) · heyvalaw.com (عدم سوء پیشینه via ثنا)
*Report compiled from an adversarially-verified research pass (Iranian legal framework + local competitors) plus three targeted research agents (foreign competitors, risk/failure cases, verification tooling). Verify decades-old regulations, self-reported competitor stats, and funding figures against current primary sources before making decisions or publishing.*

Some files were not shown because too many files have changed in this diff Show More