# GT4IT clinic systems on server1.royalgt4.com: yahab (alielhaddad) and glory center (glorygt4it). Health check and IVF inventory

> **Source:** read-only examination on 2026-10-24 (server clock 22:43 GMT) of `root@51.89.20.165` (cPanel, MariaDB 10.11.16).
> **Method:** I read the code with `ls`, `grep`, `md5sum` and `sed`. On the DBs I ran only `SELECT`, `information_schema` and `COUNT`, in `SET SESSION TRANSACTION READ ONLY` sessions. HTTP checks were `curl` GET/HEAD requests to entry pages only. **Nothing was written on the remote, no service was touched, I did not log in to any web UI, and no credential was read out or copied.** From config files I printed only the DB *name*.
> **Privacy:** this file holds schema, lookup values, counts, date ranges and aggregates only. Staff names and patient data are left out. Arabic labels were stored as latin1 mojibake and are decoded here.
> Related: [`legacy-ivf.md`](legacy-ivf.md) (Amr's obgy), [`moon-current.md`](moon-current.md) §3 (gap list), [`global-benchmark.md`](global-benchmark.md).

## TL;DR (ملخص)
- **yahab (`yahabcenter.com/yahab`, DB `alielhad_center`) is live and busy.** In 2026 so far it has 22,096 visits, ~1,830 visits and 418 new patients in the last 30 days, and 19 staff users logged in over the last 30 days. Its own nightly dump ran tonight. The IVF part in actual use is **one small "ICSI" tab inside the gyna sheet**: 1,423 fresh and 738 frozen attempt rows, 53 fresh rows in the last 30 days, last row today. Billing (last 365 d): OPU 163 × ~31.5k EGP; ET 185 × ~3.3k EGP.
- **glory center (`glory2.gt4it.com/center`, DB `glorygt4it_center`) is live, but it is not an IVF clinic.** 95% of last year's visits went to the **cardiology clinic** and to operations. The 41 IVF files are only the shared product code. Their IVF tables hold **0 rows**, and their lookups are developer junk ("1111", "qqqq").
- **Same product line.** The "aw" framework (RedBean + Smarty, PHP 5.5) is shared by Amr's obgy, then yahab (2017–2024 code), then glory/royal (a 2023–2025 fork with deeper IVF). yahab still carries Amr's empty `ivfsheet`/`ovst`/`eprep` tables.
- **The deep IVF lab suite was never used in production on this server.** It covers embryology per embryo D1–D6, OPU/ET sheets, embryo and sperm freezing, a tank→canister→row→col→cell cryo map, thawing and andrology reports. Only trial rows exist: 1 in yahab (2023), 6–7 in an old `alielhad_royal` copy (2022), and a cryo map used for 4 months in 2023 in `erpgt4it_royalnew`. **Treat it as a design reference, not a proven data model.**
- **Urgent security and ops flags** (§1.4): patient-upload and DB-dump archives can be downloaded publicly; open directory listings; generic "write any table/column" endpoints, one family with auth commented out; PHP 5.5; a 13.9 GB `error_log`.

---

## 1. «شغال ولا لأ؟»: health

### 1.1 Verdicts
| System | URL / path | DB | Verdict | Evidence |
|---|---|---|---|---|
| **yahab clinic** | `yahabcenter.com/yahab/` → 302 → `core/controllers/login.php` (200, title "Yahab Infertility Center") | `alielhad_center` (565 tables, 97 MB) | ✅ **actively used, heavily** | visits/yr: 2021 8,774 · 2022 11,985 · 2023 14,244 · 2024 15,164 · 2025 19,888 · **2026 22,096**; last 6 months 1,976–2,548 visits/month; last 7 d 515; `MAX(create_date)` today 20:26; patients 18,243 (+418 in 30 d); gyna sheets 1,563 and antenatal visits 748 in 30 d; receipts 1,062 in 30 d; 19 distinct users logged in over 30 d |
| yahab patient portal | `yahabcenter.com/yahab_patients/` → login (200) | same `alielhad_center` | ✅ used | `pat_login_tacking` 935 logins in 30 d, last tonight; 3,005 `short_urls` (SMS links) in 30 d |
| yahab `api` (mobile booking: OTP, booking, packages, medical-analysis) | `/yahab/api/` → **500** | same | ⚠️ half-broken / idle | last mobile-app booking (`visits.mobileappvisit=1`) **2022-09-22** (4,951 total); api `error_log` shows fatal *table `slider` doesn't exist* tonight |
| `app/` ("دكتور على الحداد" site) | `yahabcenter.com/app/` 200 | `alielhad_app` (+`alielhad_obgy`) | 💤 brochure site only | notifications stop 2022-09; `contact` form last 2026-10-18 (46 rows) |
| `alielhad_obgy` (Amr-lineage obgy for this doctor) | no live dir | `alielhad_obgy` | 💤 retired | 25,323 visits, last **2023-07-12**; `ivfsheet`/`ovst`/`eprep` = 0 rows |
| yahab `pharmacy` / `board` | 403 | — | 💤 dead | newest controller 2018 / 2015 |
| yahab `screen` (queue display, title "مركز رويال للخصوبة") / `vote` (kiosk survey) | 200 | — | ❓ display pages, last code change 2022 | — |
| `erp/` (alielhaddad) | 302 → login | `alielhaddad_erp` | 💤 idle | last stock movement 2023-11-09. yahab's `hosturl_ERP` points at `/royalerp`, **which doesn't exist on this account**, so the clinic→ERP link is broken or unused |
| `nona/` (a different business's ERP) | `Index of /nona` 200 | `alielhaddad_nona2025` | 💤 stopped 2026-04 | last movement 2026-04-08; 171k movements |
| **glory center** | `glory2.gt4it.com/center/` → **200 with a 2-byte body** (fatal: `public/aw_config.php` not found, from `center/index.php`, logged tonight 22:49); `center/core/controllers/login.php` 200 | `glorygt4it_center` (615 tables, 25 MB) | ✅ **actively used (cardiology + operations); IVF unused** | visits 2025 8,788 · 2026 9,148; 812–1,217/month; 213 in 7 d; last `create_date` 2026-10-25 00:18 Cairo; patients 6,960 (+355 in 30 d); 17 users in 30 d. Departments over 365 d: **30 = عيادة أمراض قلب 8,695**, 13 = العمليات 1,976, others <60 |
| glory `erp/` | 200 | `glorygt4it_erp` | ✅ active | `dailyentry` last 2026-10-24 22:00 (50,875 rows); nightly dump `glorygt4it_erp_2026-10-25.sql`; the center posts to it over `curl` (`erp_common.php` → `/erp/controllers/api_web.php`) |
| glory `royal/` (same code as center) | login 200 | `glorygt4it_royal` | 💤 idle copy | 177 patients / 275 visits; last write 2025-12-31 |
| glory `centertest/` | login 200 | `glorygt4it_centertest` | test copy | 6,343 patients / 16,288 visits (a copy of live, so it holds real patient data), last write 2026-09-22 |
| glory `center_old/` | login 200 | ⚠️ **`glorygt4it_center` (the LIVE DB)** | stale code wired to production | its `aw_config.php` uses `$db_name = 'glorygt4it_center'` |
| glory `royalerp/` | `Index of /royalerp` 200 | `glorygt4it_royalerp` | 💤 stopped 2025-02 | last movement 2025-02-09 |

### 1.2 Runtime
- Both vhosts run **`ea-php55`** (handler `application/x-httpd-ea-php55`, not FPM). PHP 5.5 has been EOL since 2016. DB is MariaDB 10.11.16. Disk `/` is at 63% (668 GB free). Home dirs: `alielhaddad` 27 GB, `glorygt4it` 14 GB. No quotas.
- Text is stored as **latin1 mojibake** (`R::exec('SET NAMES latin1')` on UTF-8 text). Arabic reads correctly only through `CONVERT(CAST(CONVERT(x USING latin1) AS BINARY) USING utf8mb4)`. This matters for any data migration.

### 1.3 Error logs (summarised)
| Log | Size / last write | Content |
|---|---|---|
| `yahab/core/controllers/error_log` | **13.9 GB**, written tonight | the same warning on every hit: `readdir() expects parameter 1 to be resource` in `patients.php:351`. Harmless, but filling the disk |
| `glory center/core/controllers/error_log` | **4.8 GB**, today 18:49 | RedBean uncaught exceptions from `visits.php:3142` (a `SELECT DISTINCT…`) and `heart_reports.php` → `Controllers->update()` |
| `glory center/error_log` | 57 KB, tonight | fatal `require_once(public/aw_config.php)` from `center/index.php` (the blank `/center/` page) |
| `yahab/api/controllers/error_log` | tonight | fatal: table `alielhad_center.slider` doesn't exist |
| `alielhaddad/public_html/error_log` | last 2024-03 | old mysqli socket warnings from the root `index.php` |

### 1.4 Backups and exposure (⚠️ for the owner, not for Moon)
- **App-level nightly dumps** go to the same disk: `yahab/core/db_backups/opgy_YYYY-MM-DD.sql` (~124 MB, last 2026-10-24 21:00 UTC). The filenames say `opgy`, but the header says `Database: alielhad_center`, so the script is mislabelled and the content is the live DB. glory: `center/core/db_backups` (~24.7 MB, last 2026-10-24) and `erp/db_backups`. Both folders are `.htaccess`-protected (403). WHM: `/backup/weekly/2026-10-13` and `/backup/monthly/2026-10-01` exist, but their `accounts/` folders are empty, so I could not confirm an off-disk copy of these accounts (root runs a `check_hbox_backup.sh` cron).
- **Publicly downloadable (HTTP 200, HEAD only):** `yahabcenter.com/yahab/upload.zip` (5.3 MB, 2022: a zip of the uploads folder, i.e. patient files), `/nona/__db.tar.gz` (36.9 MB DB dump, 2022), `/yahab/_library.zip`, `/yahab/api.zip` (2026-03), `/app.zip` (189 MB). Directory listing is on at `glory2.gt4it.com/` (it lists center, center_old, centertest, erp, erp0, "erp old by fatma", erptest, royal, royalerp), at `/nona/`, at `/royalerp/` and at `center/__db/` (the `.sql` files inside return 403). **Recommend: delete or move these archives and turn off `Indexes`.**
- **Code-level vulnerability classes, described only (no exploit detail):**
  - Generic AJAX endpoints take the **table and column name from the request**: 40 of 106 controllers in yahab, 47 of 128 in glory.
  - 29 (yahab) / 34 (glory) controllers contain at least one **commented-out auth check**. I confirmed one case by reading it: `ivf_reports.php::update()`, which writes any table/column from POST with no login check.
  - `del()` / `complete_one()` build SQL by concatenating request values.
  - Report filters concatenate `patientId` into SQL.
  - Changing the embryo count in `embryoslab` wipes and re-creates all `embryoscoring` rows.
- `center_old` and `centertest` are reachable logins on the same host; `center_old` writes to the live DB and `centertest` holds a copy of live patient data.

---

## 2. IVF inventory

There are **two tiers**. Tier A is what yahab actually uses. Tier B is the full lab suite, which ships in both codebases and is deeper in glory, but has never been used in production.

### 2.1 Tier A: the yahab "ICSI" tab inside the gyna sheet (live since Jan 2024)
- `gyna.php` gets an ICSI tab with two repeating grids, `views/obgy/gyna/icsi*.html` (mtime 2024-01). Each row is added with `append` (the table name comes from POST `type`), and each cell is written with the generic `update`.
- **Fresh grid `icsi_fresh`** columns: Date (`try_date`), LMP, Protocol+TTT (`icsi_protocol` → lookup), Trigger name/day (lookups), Follicles last size, Ovums **MI / MII / GV**, Semen, **Embryos**, **Groups**, Preg. (checkbox), Notes. All columns are `varchar` except the dates.
- **Frozen grid `icsi_frozen`** columns: Date, LMP, **TTT** (E2 prep regimen), Endometrium size / shape / trigger day, Transfer difficulty / location / catheter (lookup) / **No.** (lookup), Preg., Delivery, Notes. It has **no link to the fresh cycle or to any frozen embryos.**
- Volume:

| Table | Rows | Rows per year | Date range | Patients |
|---|---|---|---|---|
| `icsi_fresh` | 1,423 live (+35 deleted) | 2024 403 · 2025 437 · **2026 573** | 2022-11 → **2026-10-24** | 1,237 |
| `icsi_frozen` | 738 live (+40 deleted) | 2024 358 · 2025 260 · 2026 118 | 2023-10 → **2026-10-24** | 591 |

**Fill rates show that doctors route around the structure:**

| Field | Filled | What is actually typed |
|---|---|---|
| Protocol / trigger name / trigger day (lookups) | **30 / 23 / 22 of 1,423 (≈2%)** | lookups are tiny and dosage-like: protocol = "duphaston 300", "gonapure 150 + epigonal 150"…; trigger = choriomon / deca; trig day = d8–d13 |
| LMP / last follicle size | 32 / 29 | — |
| MII / MI / GV | 1,205 / 1,066 / 1,084 | numeric strings; mean MII 14.8, MI 2.3, GV 4.4 (n=1,205) |
| Semen | 763 | "n" 575, "frozen" 84, "TA"/"frozen TA" 18, counts "80M"… |
| **Embryos** | 1,360 | free text holding count + grades + **sex**: "6(5a..1b)", "2XY(A..B)", "4(3A+1B) d5", "no males", "cancelled". 984 rows follow the `N(…)` shape; **255 (18%) mention XY/XX/male = sex selection** |
| **Groups** (embryos transferred + day) | 1,327 | "1", "2", "2(day 5)", "1(day 4)"; day-5 in 286 rows, day 3–4 in 147 |
| **Pregnancy** checkbox | **11 of 1,423** | outcome is effectively not recorded for fresh cycles |
| Frozen: TTT / endometrium shape / trigger day / transfer No. | 430 / 550 / 490 / 491 of 738 | TTT "2*2", "estravod 2*2", "cyclo 2*2"; shape "tri ++"/"tri +++"; trans No. 2 = 269, 1 = 136, 4 = 48 |
| Frozen: pregnancy / delivery | 181 / 194 | preg=1 in 178; "delivery" holds "failed" (108) and **doctor names typed into the outcome field** |

- **Report:** `gyna.php::icsiReport/icsiSearch` gives a date-range **register** (one row per attempt, fresh or frozen). It computes nothing, so no KPI.
- **Billing:** separate services in `detections`: «سحب بويضات» (OPU; 163 visits in 365 d, avg 31,489 EGP, ~5.13 M EGP total) and «نقل اجنه» (ET; 185 visits, avg 3,285 EGP), plus «متابعه حقن» (inactive). Prices are typed per visit (catalog value 0). The ICSI row is **not linked** to the billed visit.
- Around it in yahab: andrology visits (`andvisits` 2 rows), `semen` (32 rows, last 2026-08), `gynainfertility` (101 rows, last 2026-10-22: type, duration, FSH/LH/TSH/PRL/AMH, HSG as text), and Amr's abandoned `mointoringsheet` v2 (24 sheets, 14 visits, 2020-02 → 2022-08).

### 2.2 Tier B: the IVF lab suite (yahab 2017–2022 code; glory 2023-12 → 2025-01, ~2× larger)
| Stage | Controller → table(s) | Shape / key columns | Production rows |
|---|---|---|---|
| Stim / monitoring | glory `ivf_reports.php::ivf_*` → `ivf_report` (protocol, trial_no, BMI, AMH, FSH, **`trig_date` DATE + `trig_time` TIME**, doctor, completed) → `ivf_records` per scan (record_date, cycle_day, E2, R no/size, L no/size, endo) → `ivf_records_drugs` per scan and `ivf_drugs` per cycle (`drugid` → `drugs` catalog + dose) | typed dates; sizes are text | 0 everywhere |
| OPU | `ovumpickupembryotrans.php` → `ovumpickup` (consultant, anaesthetist, nurse, embryologist, no_of_ova, quality, UT/CX, AVF/RVF, easy/difficult, post-op, complications) + `followup_operation` (pre/post notes, instructions, drugs, surgeon/assistant/anaesthetist, anesthesia type; can send follow-up/prescription) | all varchar | 0 |
| Andrology | glory `ivf_reports.php` → `semen_analysis` (vol, pH, liquefaction, viscosity, count, motility A/B/AB/C/D, morphology, agglutination, pus, diagnosis, cryopreservation, frozen_samples), `semen_processing` (swim-up / mini-swim / gradient / wash flags), `semen_cryopreservation`, `sperm_extract` (TESE/PESA/micro-TESE; varicocele, aspiration and biopsy per side, histopathology, frozen samples). LIS-style `investigationresults_semen` (WHO-style fields, each with a `*_rangeid` → `lab_devices_ranges` = reference-range flags) | per test | yahab 0; `alielhad_royal` 19 analyses (2022-08/09, trial) |
| **Embryology lab** | `embryoslab.php` → `embryoslab` (one row per OPU/ICSI case, opened from a `visit_id`): sperm source + processing + count/motility/morphology; clinician, **embryologist, ICSI-by, freeze-embryologist**; no_oocyte, follicular volume, blood; **MII/MI/GV/atretic counts**; oocyte quality/zona/cytoplasm/PVS/other (lookups, cohort level); fertilized / division / unfertilized / degenerated; media/oil/incubator/CO₂; straws/embryos frozen, day of freezing, freezing incubator/CO₂/O₂/temp; **lot/kit no + expiry** (media traceability); catheter, device, glue, tank; `oocyte_activation`, `cancelled` + `cancel_reason` (with cancel/reverse user) | wide, varchar | yahab 1 (2023-07); glory 0 |
| **Per-embryo D1–D6** | `embryoscoring`: **one row per embryo** (`itr` = embryo index, created N-at-once by `embryoScoringRows`), and for each day 1–6: stage, grade, media, oil, incubator, embryologist. `embryoselection` = **fate per embryo** (`result_id` → `embryo_result`) | wide by day | 0 |
| ET | `embryotransfer`: et_day, clinician, embryologist, nurse, stage/grade for embryos 1–4, catheter type, difficulty, blood, duration, jet place, LAH (assisted hatching), type, fresh/thaw flag | — | 0 (`alielhad_royal` 1) |
| Embryo freezing | `embryofreezing.php` → `embryofreezingreport` (date, embryologist, straws, embryos, day, kit, lot, device, location) + `embryo` (per straw/embryo: stage1–6/grade1–6) | — | 0 (`alielhad_royal` 1) |
| **Cryo map** | `tanks.php` + `tankLocation*()` in the freezing controllers → `tanks_general` (tank **A/B**, 21 "btn" = canisters each, colour for each of **9 rows**) → `embryoslab_tank_cells` (location, btn_no, row_no, col_no, **cell_no 1–10**, embryoslab_id, soft delete + edit user/date); older `tank_cells`/`tankcells` (tank → level → cell → part → patient, colour) + **`tankcellhistory`** (Add/Remove patient, by user, datetime) | positional and colour-coded | glory: config only (42 canisters). `erpgt4it_royalnew`: **740 placements for 268 (tank A) + 205 (tank B) lab-case ids, 2023-03 → 2023-07** (the table `embryoslab` there now has 0 rows), then abandoned |
| Thaw / FET | `embryothawing`: no_of_embryos, thawing_date, **recovered / lost** (survival), ET date, embryos, grades, embryologist, clinician, catheter → `embryofreezing_id`. Consumes a *freezing report*, not specific straws/positions | — | 0 (`alielhad_royal` 7, 2022-09) |
| Sperm freezing | `spermfreezingreport`: source, count, motility, A+B, abnormal morph, samples_no, media, protocol, **purpose of freezing**, location, **colour of pen**, **embryologist1 + embryologist2** (a de-facto witness) | — | 0 |
| Outcome | ET result = `visits.result` on the linked visit (1 = pregnant according to the report code; I did not confirm the other codes). Glory `fet_no` lookup lives in the antenatal file (pregnancies after FET) | — | — |
| Reports / KPIs | glory `ivf_reports.php::icsi_cases_report` / `icsi_casesSearch2`: **total egg collections, ETs, cancelled, pregnant, blastocyst transfers**, split by **oocyte band (<5 / 5–15 / >15)** and **age (<35 / 35–39 / ≥40)**, plus cancel-reason counts. Also `freezing_report`, `ivf_cases`. yahab only has the register (§2.1) | counts only, no rates | — |

**Lookups** (glory, values as found):
- Real-looking: oocyte quality (good / moderate / poor / very poor); zona (Z1, splitted, thick, thick&dark); cytoplasm (dark, granulated, dark&granulated, irregular, severe extracellular debris); oocyte "other" (14: fragile, vacuolated, fragmented / multiple PB, SER…); embryotype (partial / complete); LAH (yes / no); difficulty (easy); catheter (labotect); freezing media (b1, b2, ferticult).
- **Junk / placeholder:** `grade` (20 rows: "vvvvd", "2", "4", "grade 1"… no Gardner/ASEBIR scheme), `stage` (19: "blastocyst", "122ww", "ffffffff"…), `treatprotocol` / `cancel_reason` / `embryo_result` ("1111", "2222"), media/oil/incubator/CO₂ ("qqqq", "eeeee"), device, lot, kit.
- yahab's copies of these lab lookups are **empty**.

**Links:**
- Pharmacy: IVF drugs reference the `drugs` prescription catalog; **no stock issue** (the old `pharmacy/` sub-app is dead).
- Billing: `embryoslab.visit_id` ties the lab case to a paid visit; `detections.for_embryo` flag exists in glory (0 of 157 services flagged); **no storage fees, renewals or expiry anywhere.**
- Portal: yahab_patients shows visits only, with no IVF content.
- Consents: only generic `decleration` / `patientdecleration` templates (0 rows); no IVF / freezing / disposal consents.

---

## 3. Comparison

### 3.1 Lineage
| | Amr obgy (`amrtechogate`) | yahab (`alielhad_center`) | glory center / royal (`glorygt4it_*`) |
|---|---|---|---|
| Framework | aw* + RedBean + Smarty | same | same |
| Code age | — | controllers 2017–2024 (gyna 2024-02, invsdept 2024-09) | 2023-12 → 2025-01 (royal copy 2025-02) |
| IVF lab files vs yahab | — | baseline | `embryology`, `infertility`, `followup`, `showreports` **identical (md5)**; `embryoslab` 985 → 1,876 lines, `ivf_reports` 675 → 2,570, `embryofreezing` 936 → 1,273, `tanks` 528 → 754, `spermfreezing` 561 → 887 |
| Schema | `ivfsheet` (75 varchar cols) + `ovst`/`eprep`/`sefo` | **still has Amr's `ivfsheet`/`ovst`/`eprep`/`infertilitysheet`/`mointoringsheet*` (empty or abandoned)** + lab suite + `icsi_fresh/frozen` | dropped Amr's tables; added `ivf_report/records/drugs`, `embryologist`, `tank_cells`, `tanks_general`, `embryoslab_tank_cells`, `cancel_reason`, `treatprotocol`, `fet_no`, semen lookups, hospital and cardiology tables (25 extra controllers: colonoscopy, endoscopy, heart_reports, approvals, today_list…) |
| IVF actually used | `ivfsheet` (615 fresh cycles) | `icsi_fresh` 1,423 / `icsi_frozen` 738 | none |

Conclusion: one product, three generations. Each time, the clinic in real use (Amr, then yahab) ended up on a **flat one-row-per-attempt grid**, and the deep lab suite stayed unused.

### 3.2 Against Moon's gap list (`moon-current.md` §3)
| Gap item | Tier A (yahab live) | Tier B (glory suite) | Take-away for Moon |
|---|---|---|---|
| Embryology sheet: per oocyte | no (counts) | **no**: MII/MI/GV/atretic counts + cohort-level quality lookups | per-oocyte stays a Moon design decision |
| Per embryo D1–D6, grading, fate | free text "6(5a..1b)" | **partial**: a row per embryo with stage+grade per day (wide), fate via `embryoselection`; grading lookup is junk | adopt "row per embryo" but make it day rows; ship a seeded Gardner/Istanbul scheme |
| Incubator / media / dish | — | **yes (weak)**: media/oil/incubator/CO₂ per embryo per day + lot/kit no & expiry | adopt **lot/expiry traceability** of culture media (link to Inventory lots) |
| Witnessing | — | **no** (only embryologist ids; sperm freezing has 2 embryologists) | double sign-off still needed |
| Cryobank: tank → canister → cane → straw | — | **partial, the strongest idea here**: tank A/B → 21 canisters → 9 colour-coded rows → col → cell 1–10, visual picker, add/remove history | reuse the **visual, colour-coded position grid + move history**; add straw/device ids, LN₂ log, contracts |
| Storage contracts / fees / renewal / discard consent | — | **no** | Moon gap stands, and it is also the commercial differentiator |
| Thaw / FET consuming specific straws | not linked | **partial**: thaw → freezing report with recovered/lost (survival), not a straw | link the thaw to the straw/position; record survival per embryo |
| Sperm bank (frozen / TESE vials) | text | **partial**: `spermfreezingreport` (purpose, pen colour, location, 2 embryologists) + `sperm_extract` (TESE/PESA/micro-TESE per side) | good field list for Moon's andrology cryo |
| Donor | — | no | — |
| Couple consents with expiry | — | no (generic declarations only) | gap stands |
| OPU/ET/IUI board, trigger → OPU 36 h | — | **partial**: typed `trig_date`+`trig_time`; OPU/ET staff + difficulty/blood/LAH/jet place; generic operations calendar | adopt typed trigger time and the ET/OPU field set |
| Nurse protocol / drug calendar, gonadotropin stock | dosage-like protocol names | **partial**: drugs per monitoring day from the catalog; no stock | Moon should go further (Inventory issue) |
| LIS link (E2/P4/LH/β-hCG, semen) | — | **partial**: semen in the lab module with reference-range ids; E2 typed by hand | Moon already has a stronger LIS |
| Stage-based IVF package | separate OPU / ET services | separate services; `for_embryo` flag unused | gap stands |
| KPIs / registry | register only | **partial**: counts of EC/ET/cancel/pregnant/blast with **oocyte-band and age-band** splits | adopt the band splits as default breakdowns; add the rates (fert, blast, CPR, LBR, cumulative) |
| Embryologist / andrologist roles | — | **yes**: `embryologist` lookup + role-based user lists | Moon needs the role |
| Typed trigger datetime, fresh → FET link | no / no | yes / partial | — |

### 3.3 What Moon should adopt (and avoid)
**Adopt:**
1. The **two-speed UX**: a one-line attempt summary grid on the gyna/couple file (what doctors actually fill in), *computed* from a structured lab record underneath. Don't force lab detail on the clinician.
2. **Sex-selection / PGT tagging per embryo.** 18% of yahab fresh rows carry XY data in free text, so it must be a coded field (owner/legal decision for Egypt).
3. **Cryo position picker** (tank → canister → colour row → col → cell) with add/remove history.
4. **Media/kit lot + expiry per case.**
5. **Typed trigger datetime.**
6. **Thaw survival** (recovered/lost).
7. KPI splits by **oocyte band (<5 / 5–15 / >15)** and **age (<35 / 35–39 / ≥40)**.
8. **Cancel reason with cancel/reverse audit.**
9. Rich andrology field lists (`sperm_extract`, `spermfreezingreport` purpose/pen colour, two-person sign-off).

**Avoid:**
- Request-driven table/column writes and unauthenticated update endpoints.
- latin1 mojibake storage.
- varchar for numbers and dates.
- Lookups with no seed (junk values went into production).
- Wide `stage1..6/grade1..6` columns.
- Wipe-and-recreate child rows.
- Outcome coded on a generic `visits.result`.
- The free-text "Embryos/Groups/Delivery" pattern.
- Test/old copies wired to the live DB.

**Migration note:** if yahab ever moves to Moon, the importable IVF data is `icsi_fresh`/`icsi_frozen` (2,161 rows). MI/MII/GV import as numbers. Embryos/Groups need a parser for the "N(grades) dX / XY" grammar. Outcome is mostly missing. Text needs latin1→utf8 repair.
