Files
hamkadr/PLAN.md
T
soroush.asadi 2fb86a435e Initial commit — Hamkadr (همکادر) healthcare-staffing marketplace
ASP.NET Core 10 Razor Pages + PostgreSQL/EF Core. RTL Persian, Jalali dates, self-hosted Vazirmatn, teal/coral brand.

Features:
- Shift listings: browse/filter (city, district, role, type, pay), weekly Jalali calendar, detail + interest handoff, near-me distance sort
- Hiring (استخدام) listings with employment type + salary range
- Pattern-engine recommendations + anonymous interest tracking (visitor cookie)
- Heuristic Persian listing-parser + admin queue (raw channel post → shift/job)
- Phone-OTP cookie auth + visitor-history linking + profile

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 01:44:24 +03:30

7.3 KiB

JobsMedical — Medical Shift Marketplace (Iran)

A niche platform connecting GP doctors with hospitals & clinics that have open shifts. Replaces the chaotic hunt across Bale / Telegram channels / Divar with one structured, filterable view organized by hospital, location, and weekly shift calendar.

Date: 2026-06-02 · Market: Iran (Persian/Farsi, RTL) · Revenue: TBD


1. The problem & the bet

Today: A GP doctor wanting locum/extra shifts scrolls dozens of Telegram/Bale channels and Divar posts. Listings are unstructured text, no filters, no calendar, no trust signals, expire silently. Hospitals broadcast to the same noisy channels and get random DMs.

Our bet: The value isn't more listings — it's structure + filtering + trust. "Show me open GP shifts, in Tehran, this week, paid X" should be one screen, not 40 channels.

Why a marketplace is hard (and our answer):

  • Cold-start problem — empty marketplace helps no one. We solve supply first via the mixed strategy: (1) admin posts manually + (2) auto-aggregate from channels → so the site looks full from day one, then (3) convert hospitals to self-serve posting over time.

2. The two sides

Doctors (supply of labor) Hospitals / Clinics (demand)
Who GPs (پزشک عمومی) seeking shifts Hospitals, clinics, درمانگاه‌ها
Want Find shifts fast: by city, date, pay Fill open shifts with vetted doctors
Onboard via Phone OTP signup, build profile Phase 2 self-serve; phase 1 we post for them
Trust signal نظام پزشکی (medical license) number Verified facility badge

3. MVP scope (Phase 1 — "the structured board")

Goal: a doctor can find and express interest in a relevant shift in under 60 seconds.

Must have:

  1. Shift browse + filter — by city, hospital, date range, specialty, shift type (day/night), pay.
  2. Weekly calendar view per hospital — the signature feature. Jalali (Shamsi) week grid showing open shifts per day.
  3. Shift detail page — hospital, location (map pin), date, hours, pay, requirements, how to apply.
  4. Doctor signup/login — phone OTP (standard in Iran), basic profile (name, license, city, specialty).
  5. Express interest / apply — doctor taps "interested" → handoff to facility contact (call/Bale/ in-app message). Track applications.
  6. Admin panel — we add/edit shifts manually, and review/normalize aggregated listings before they go live.
  7. Aggregation ingest (basic) — pull text from selected Telegram/Bale channels into a "raw listings" queue for admin to normalize. (Start semi-manual; full automation later.)

Explicitly NOT in MVP (Phase 2+):

  • Hospital self-serve posting & dashboards
  • Payments / monetization
  • Ratings & reviews
  • Automated matching/recommendations, push alerts
  • Full unattended scraping pipeline

4. Data model (core entities)

User            id, phone, full_name, role(doctor|facility_admin|admin), created_at
DoctorProfile   user_id, license_no(نظام پزشکی), specialty, city, years_exp, bio, verified
Facility        id, name, type(hospital|clinic|درمانگاه), city, address, lat,lng,
                phone, bale_id, verified, owner_user_id(nullable, phase 2)
Shift           id, facility_id, date(jalali stored as ISO), start_time, end_time,
                specialty_required, shift_type(day|night|on_call), pay_amount, pay_type,
                description, status(open|filled|expired|cancelled),
                source(direct|admin|aggregated), source_url, created_at
Application     id, shift_id, doctor_id, status(interested|accepted|rejected|withdrawn),
                message, created_at
RawListing      id, source_channel, raw_text, parsed_json, status(new|normalized|discarded),
                linked_shift_id, fetched_at      ← aggregation staging area
City            id, name, province              ← canonical city list for filters

Key decisions:

  • Dates stored as ISO (UTC) in DB, displayed as Jalali in the UI. Never store Jalali strings.
  • A Shift can originate from a RawListing (aggregation) or be created directly (admin/facility).
  • Phone is the unique identity; OTP login, no passwords.

5. Tech architecture

Constraints that drive choices: Iran hosting (many global SaaS block Iranian IPs/payments → prefer self-hostable, open-source), SEO matters (doctors will find shifts via Google → need server-rendered pages), RTL + Jalali, phone OTP via Iranian SMS providers.

Recommended stack:

  • Frontend + backend: Next.js (App Router) + TypeScript — SSR for SEO, one codebase, great RTL support.
  • UI: Tailwind CSS (RTL mode) + a Persian font (Vazirmatn). Jalali via dayjs-jalali or jalaali-js.
  • DB: PostgreSQL + Prisma ORM.
  • Auth: Phone OTP. SMS via Kavenegar or SMS.ir (Iranian providers). Sessions via JWT/cookies.
  • Maps: Neshan or Balad map tiles (Iranian, work without VPN) instead of Google Maps.
  • Aggregation: A small worker (Node) using Telegram Bot API / Telethon-style reader for Bale, writing into RawListing. Runs as a separate scheduled job.
  • Hosting / CI: Self-hosted on an Iranian VPS, deployed via your Gitea + Nexus pipeline (soroush ci/cd method). Docker Compose: web + postgres + worker.

If you'd rather build in .NET (you have the Nexus/.NET pipeline set up), the equivalent is ASP.NET Core + Blazor/Razor + EF Core + Postgres. Same architecture, different language. ← confirm.

Why not Google Maps / Vercel / Firebase / Stripe: all routinely blocked or unusable from Iran. Everything above is self-hostable or has an Iranian equivalent.


6. Key screens

  1. Home — hero + search (city, specialty, date) + "shifts this week" + featured hospitals. SEO landing.
  2. Shift listing — filter sidebar + result cards + map toggle.
  3. Weekly calendar (per hospital or per city) — Shamsi week grid, open shifts as chips.
  4. Shift detail — all info + map + "I'm interested" CTA.
  5. Doctor onboarding — phone OTP → profile form.
  6. Doctor dashboard — my applications, saved shifts.
  7. Admin — shift CRUD, raw-listing normalization queue, facility management.

7. Phased roadmap

  • Phase 0 — Foundation: repo, Docker, Postgres+Prisma schema, RTL+Jalali shell, OTP auth.
  • Phase 1 — MVP board: browse/filter, calendar, shift detail, doctor signup, apply, admin CRUD, basic raw-listing ingest. → launch to a few hospitals + a doctor Telegram group.
  • Phase 2 — Self-serve + trust: hospital posting dashboards, facility/doctor verification, in-app messaging, saved searches + alerts (via Bale bot).
  • Phase 3 — Monetization: pick model (likely hospitals pay to post or commission per filled shift — decide after we see what converts), Iranian payment gateway (Zarinpal/IDPay).
  • Phase 4 — Scale: full automated aggregation, recommendations, expand beyond GPs to specialists.

8. Open questions to revisit

  • Monetization model (deferred — validate demand first).
  • Which specific Telegram/Bale channels to aggregate first?
  • Start single-city (Tehran?) to concentrate liquidity, or national from day one?
  • Build language: TypeScript/Next.js (recommended) vs .NET (your existing pipeline)?