82c94c89a6
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
94 lines
6.2 KiB
Markdown
94 lines
6.2 KiB
Markdown
# همکادر — Hamkadr
|
|
|
|
سامانهی واسط میان **کادر درمان** (پزشک، پرستار، ماما، تکنسین) و **بیمارستانها و کلینیکها**
|
|
برای یافتن **شیفت و موقعیت استخدامی**. بهجای گشتن در کانالهای تلگرام/بله و دیوار،
|
|
همهی فرصتها یکجا — بر اساس مرکز درمانی، محل و تقویم هفتگی شمسی، با **پیشنهاد هوشمند**
|
|
متناسب با علاقهمندی و فعالیت هر فرد.
|
|
|
|
A two-sided healthcare-staffing marketplace (shifts **and** permanent hiring) connecting all
|
|
clinical staff with hospitals/clinics. See [PLAN.md](PLAN.md) and [FEATURES.md](FEATURES.md).
|
|
|
|
## Stack
|
|
- **ASP.NET Core (Razor Pages), .NET 10** — server-rendered for SEO
|
|
- **PostgreSQL + EF Core (Npgsql)**
|
|
- RTL Persian UI, Jalali (Shamsi) dates via `System.Globalization.PersianCalendar`
|
|
- **Pattern-engine recommendations** + anonymous interest tracking (cookie-based visitor id)
|
|
- **Self-hosted Vazirmatn font** (`wwwroot/fonts`, no CDN), teal + coral brand palette
|
|
- **Location filters:** city → district/neighborhood, plus **"near me"** (browser geolocation → Haversine distance sort)
|
|
|
|
## Run locally
|
|
|
|
```bash
|
|
# 1. Start PostgreSQL (host port 5433)
|
|
docker compose up -d
|
|
|
|
# 2. Run the web app (applies migrations + seeds Tehran sample data on startup)
|
|
dotnet run --project src/JobsMedical.Web
|
|
```
|
|
|
|
Then open the URL printed in the console (e.g. http://localhost:5020).
|
|
|
|
### Pages
|
|
| Route | Page |
|
|
|---|---|
|
|
| `/` | خانه — hero, role/city search, **پیشنهادهای ویژه شما**, latest shifts |
|
|
| `/Shifts` | فهرست با فیلتر (شهر، **محله/منطقه**، نقش، مرکز، نوع شیفت، حقوق) + **«نزدیک من»** |
|
|
| `/Shifts/Details/{id}` | جزئیات + اعلام تمایل / ذخیره / رد (همه رویدادها ثبت میشوند) |
|
|
| `/Jobs` | موقعیتهای **استخدامی** با فیلتر (شهر، محله، نقش، نوع همکاری) + «نزدیک من» |
|
|
| `/Jobs/Details/{id}` | جزئیات موقعیت استخدامی + اعلام تمایل / ذخیره / رد |
|
|
| `/Calendar` | تقویم هفتگی شمسی شیفتها |
|
|
| `/Facilities` | فهرست مراکز درمانی |
|
|
| `/Preferences` | تنظیم علاقهمندیها (نقش، شهر، نوع شیفت، حقوق) |
|
|
| `/Account/Login` | ورود/ثبتنام با **کد یکبارمصرف موبایل (OTP)** |
|
|
| `/Account/Profile` | پروفایل: شیفتها/موقعیتهای ذخیرهشده و اعلام تمایلها |
|
|
| `/Admin` | پنل مدیریت (نقش Admin): صف آگهیهای خام |
|
|
| `/Admin/Review/{id}` | بررسی خودکار (پارسر) و انتشار آگهی بهصورت شیفت یا استخدام |
|
|
| `/Admin/Facilities` | تأیید/لغو تأیید مراکز درمانی (نشان «تأیید شده») |
|
|
| `/Employer` | **پنل کارفرما**: مراکز من + شمار شیفت/استخدام/متقاضی |
|
|
| `/Employer/RegisterFacility` | ثبت مرکز درمانی (خودسرویس → نقش FacilityAdmin) |
|
|
| `/Employer/PostShift`، `/PostJob` | انتشار شیفت یا موقعیت استخدامی |
|
|
| `/Employer/Listings` | مدیریت آگهیها (بستن/بازگشایی/حذف) + لیست متقاضیان با تماس |
|
|
|
|
## How recommendations work (Stage 1 — pattern engine)
|
|
`RecommendationService` scores open shifts against (a) explicit `UserPreferences` and (b) recent
|
|
`InterestEvent`s (view/save/apply/dismiss), and returns the top matches **each with a Persian
|
|
reason** ("متناسب با نقش مورد علاقه شما"، "چون به فرصتهای پرستار علاقه نشان دادی"). Fully
|
|
explainable, no AI infra, works from the first visit. The behavioral log is the fuel for the
|
|
later collaborative + ML/embedding stages (see [FEATURES.md](FEATURES.md) Part A).
|
|
|
|
## Project status
|
|
Done: multi-role domain model, Postgres + migrations, RTL shell, browse/filter (incl. role,
|
|
district, near-me), weekly Jalali calendar, shift detail + interest handoff, interest tracking +
|
|
pattern-engine recommendation feed + preferences, self-hosted Vazirmatn + teal/coral palette,
|
|
**hiring (استخدام) listings**, **admin queue + heuristic listing-parser** (raw channel post →
|
|
structured shift/job), **phone-OTP auth + visitor-history linking + profile**, **employer side** (self-serve facility
|
|
registration → FacilityAdmin role, post/manage shifts & jobs, applicants list with contact),
|
|
Tehran seed data.
|
|
|
|
Both sides of the marketplace now work end-to-end: an employer self-registers a facility, posts a
|
|
shift, it appears publicly, a logged-in user applies, and the employer sees that applicant's
|
|
phone in their dashboard.
|
|
|
|
### Compensation models
|
|
Shifts support fixed (مقطوع), hourly (ساعتی), **profit-share (درصدی / سهم درآمد)**, توافقی, or a
|
|
**choice** between a fixed amount and a share % ("… یا … به انتخاب شما"). `JalaliDate.PayLabel`
|
|
centralizes the display; `Shift.SharePercent` holds the percentage; the listing-parser detects
|
|
"۵۰٪ / درصد / سهم" from raw posts; and `/Shifts` has a "سهم درآمد" filter.
|
|
|
|
### Listing parser (Stage 1)
|
|
`IListingParser` / `HeuristicListingParser` extracts kind (shift vs hire), role, shift type,
|
|
employment type, pay, city/district, and phone from a raw Persian post via keyword + regex
|
|
heuristics — **no AI dependency** (LLM APIs are blocked from Iran). Admin reviews the prefilled
|
|
form and publishes. Swap in an `LlmListingParser` later behind the same interface.
|
|
|
|
### Auth
|
|
Phone OTP via `OtpService` (in-memory codes; dev shows the code on screen — wire Kavenegar/SMS.ir
|
|
for prod). Cookie auth; the configured `Auth:AdminPhone` gets the `Admin` role. On login the
|
|
anonymous `hk_vid` visitor (and its interest history) is linked to the user account.
|
|
|
|
Next:
|
|
- Unified recommendations across shifts **and** jobs (currently shift-focused)
|
|
- Self-serve facility posting + dashboards; verification badges
|
|
- Real SMS gateway + Neshan/Balad interactive maps
|
|
- LLM-backed listing parser; automated channel aggregation worker
|