2026-06-03 01:43:55 +03:30
|
|
|
# همکادر — 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}` | بررسی خودکار (پارسر) و انتشار آگهی بهصورت شیفت یا استخدام |
|
2026-06-03 06:31:15 +03:30
|
|
|
| `/Admin/Facilities` | تأیید/لغو تأیید مراکز درمانی (نشان «تأیید شده») |
|
2026-06-03 06:26:54 +03:30
|
|
|
| `/Employer` | **پنل کارفرما**: مراکز من + شمار شیفت/استخدام/متقاضی |
|
|
|
|
|
| `/Employer/RegisterFacility` | ثبت مرکز درمانی (خودسرویس → نقش FacilityAdmin) |
|
|
|
|
|
| `/Employer/PostShift`، `/PostJob` | انتشار شیفت یا موقعیت استخدامی |
|
|
|
|
|
| `/Employer/Listings` | مدیریت آگهیها (بستن/بازگشایی/حذف) + لیست متقاضیان با تماس |
|
2026-06-03 01:43:55 +03:30
|
|
|
|
|
|
|
|
## 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 →
|
2026-06-03 06:26:54 +03:30
|
|
|
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.
|
2026-06-03 01:43:55 +03:30
|
|
|
|
2026-06-03 08:18:19 +03:30
|
|
|
### Scrape / ingestion engine
|
|
|
|
|
Pluggable `IListingSource`s (working `SampleListingSource`; credential-ready `Telegram`/`Divar`
|
|
|
|
|
stubs) → `IngestionService` **dedupes by content hash → parses → validates → enqueues** as
|
|
|
|
|
`RawListing` (status New / Flagged / Discarded-spam) with a confidence score. `ListingValidator`
|
|
|
|
|
scores completeness (role, location, pay, phone, length) and screens spam. `IngestionWorker`
|
|
|
|
|
(hosted, config-gated `Ingestion:Enabled`) runs it on a timer; admins can also run it on demand
|
|
|
|
|
from `/Admin`. `IListingParser` / `HeuristicListingParser` does the field extraction (kind, role,
|
|
|
|
|
shift type, employment, pay, **profit-share %**, city/district, phone) — **no AI dependency** (LLM
|
|
|
|
|
APIs are blocked from Iran). Admin reviews the prefilled form and publishes. Swap an
|
|
|
|
|
`LlmListingParser`/real sources behind the same interfaces later.
|
|
|
|
|
|
|
|
|
|
### Hour-range visualization
|
|
|
|
|
Every shift card, recommendation card, and detail page shows a **24-hour timeline bar**
|
|
|
|
|
(`_HourBar`) with the shift's hours filled and colored by type; overnight shifts wrap past
|
|
|
|
|
midnight into two segments.
|
2026-06-03 01:43:55 +03:30
|
|
|
|
|
|
|
|
### 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
|