GENCODE: ระบบ สถาปัตยกรรม และเครื่องมือ
GENCODE คือระบบรหัสกลางของคลินิก Youngdo ที่เชื่อม 3 ชั้น — CRS (billing), SVC (delivery), PRD (inventory) — ผ่าน Mapper Engine, Dashboard, และกระบวนการ Migration ที่พิสูจน์แล้ว · Complete GENCODE system: architecture, parser engine, dashboard, and proven migration path.
สารบัญ · Table of Contents
ปัญหาที่แก้ · The Problem
คลินิก Youngdo Wellness Clinic ใช้ระบบ POS ชื่อ JERA เป็นศูนย์กลาง ทีมแคชเชียร์สร้างคอร์ส บริการ และสินค้าโดยตั้งชื่อเป็นภาษาไทยอิสระ (free-text) ในระบบ JERA ทำให้เกิดปัญหาหลายอย่าง:
- ชื่อไม่สม่ำเสมอ — "เสริมจมูก Semi-Open หมอโด" กับ "จมูก เซมิ open Dr.Do" คือสิ่งเดียวกันแต่เขียนต่างกัน
- ไม่มีรหัสกลาง — ระบบเงิน ระบบบริการ และระบบคลังสินค้าอ้างถึงสิ่งเดียวกันด้วยชื่อคนละชุด
- JERA มีขีดจำกัด 20 ตัวอักษร — รหัสยาว ๆ ใส่ไม่ได้
- ไม่มี traceability — ไม่สามารถติดตามได้ว่าคนไข้ซื้ออะไร ได้รับบริการอะไร ใช้สินค้าอะไร
Youngdo Wellness Clinic uses a POS system called JERA as its hub. The operations team (cashiers, managers) creates courses, services, and products using free-text Thai names in JERA. This causes:
- Inconsistent naming — the same procedure written differently by different staff
- No unified code — billing, delivery, and inventory each use separate identifiers for the same thing
- JERA's 20-character limit — long descriptive codes don't fit
- No traceability — can't trace what a patient bought → received → consumed
วิสัยทัศน์ · The Vision
GENCODE เป็นรหัสกลาง — ไม่ว่าจะใช้แพลตฟอร์มหรือบริการอะไร ทุกระบบต้องพูดภาษาเดียวกันคือ GENCODE โดยมี JERA POS เป็นศูนย์กลาง
GENCODE is the clinic's central code — regardless of platform or service, every system speaks one language: GENCODE, with JERA POS as the hub.
graph LR OE[Order Entry BCO] --> GC[GENCODE] CC[Course Creator] --> GC FP[Future Platforms] --> GC GC --> JERA[JERA POS Hub]
"ภาษาเดียว ที่ทุกระบบเข้าใจ — GENCODE"
สถาปัตยกรรม 3 ชั้น · Three-Layer Architecture
GENCODE อธิบายเหตุการณ์ทางคลินิกจาก 3 มุมมอง:
GENCODE describes the same clinical event from three angles:
| Layer | Prefix | Role | Tracks |
|---|---|---|---|
| CRS (Course) | CRS- | Billing · การเงิน | สิ่งที่คนไข้ซื้อ — ราคา แคมเปญ แพ็คเกจ |
| SVC (Service) | SVC- | Delivery · การให้บริการ | สิ่งที่คนไข้ได้รับ — หัตถการ ผู้ทำ |
| PRD (Product) | PRD- | Inventory · คลังสินค้า | สิ่งที่คลินิกใช้ — วัสดุ ซัพพลาย |
ตัวอย่าง: คนไข้ซื้อเสริมจมูก Semi-Open กับหมอโด
Example: a patient buys nose surgery (Semi-Open, Dr.Do)
CRS-SUR-INI-NOSE-SEMI-001-DRDO → billing identity (ซื้ออะไร)
SVC-SUR-INI-NOSE-SEMI-001-DRDO → delivery record (ได้รับอะไร)
PRD-IMP-NOS-MNTSK-001 → silicone implant consumed (ใช้อะไร)
ชั้นที่ 4 PKG (Package/Campaign) อยู่เหนือ CRS เป็น thin wrapper อ้างอิง CRS codes ไม่ใช่ code family แยก
โครงสร้างรหัส CRS · CRS Code Structure (v3.9)
รหัส CRS มี 7 segments เสมอ บวก segment ที่ 8 (VERSION) ที่เป็น optional:
CRS-{TYPE}-{SUBTYPE}-{CATEGORY}-{DIFFERENTIATOR}-{SEQ}-{VARIANT}[-{VERSION}]
1 2 3 4 5 6 7 8(optional)
| Position | Segment | ความหมาย · Meaning | ตัวอย่างค่า · Example Values |
|---|---|---|---|
| 2 | TYPE | ประเภทหลัก | SUR surgery, SKN skin, VIT vitamin-IV, TRT treatment, MSC misc |
| 3 | SUBTYPE | ประเภทย่อย | INI initial purchase, OPT add-on, WAR warranty revision (free) |
| 4 | CATEGORY | หมวดหมู่ | SUR: NOSE/EYE/LIP/CHIN/FACFT/PTRYG/GENSKN: FIL/BTX/EBD/SKB/BIO/THR/MLZ/FAT/ACS/GEN |
| 5 | DIFFERENTIATOR | ตัวแยกแยะ (ความหมายต่างกันตาม category) | SUR: technique SEMI/DBL/OPENSKN FIL: brand RST/NRMCHINTRT DIO: body position ARM/BKN |
| 6 | SEQ | review/ไม่ review | 001 = review (ยินยอมถ่ายรูป ราคาปกติ)002 = not-review (+1,000–5,000 THB) |
| 7 | VARIANT | SUR = หมอ, non-SUR = ปริมาณ | SUR: DRDO/DRBALL/GENnon-SUR: 4CC/100U/3SES/10THR |
| 8 | VERSION (optional) | dedup สำหรับ collision | V002, V003 — same code, different price |
กฎเวลา · The Temporal Rule
กฎที่สำคัญที่สุดในการออกแบบ GENCODE: "แคชเชียร์รู้สิ่งนี้ตอนขายไหม?"
- ใช่ (YES) → encode ลงใน CRS code
- ไม่ (NO) → ดันไปที่ SVC หรือ Sales Order
The most critical design rule: "Does the cashier know this at purchase time?"
- YES → encode in the CRS code (e.g., doctor, technique, review status)
- NO → push to the SVC layer or Sales Order (e.g., exact performer at delivery time)
กฎนี้ป้องกันไม่ให้ใส่ข้อมูลที่ยังไม่รู้ตอนขายเข้าไปในรหัส ซึ่งจะทำให้ต้องแก้รหัสทีหลัง
โครงสร้างรหัส SVC และ PRD · SVC & PRD Structure
SVC (Service) — v3.9
โครงสร้างเดียวกับ CRS (7 segments) แต่ SUBTYPE และ SEQ สืบทอดจาก CRS/Sales Order ที่ผูกกัน ไม่ตัดสินใจใหม่ที่ชั้น SVC
Same 7-segment shape as CRS, but SUBTYPE and SEQ are inherited from the linked CRS/Sales Order — never re-decided at the SVC layer.
PRD (Product) — v1.1
5 segments สั้นกว่า ทุกรหัสพอดี 20 ตัวอักษร (ไม่ต้องบีบ):
PRD-{GRP}-{TYPE}-{ITEM}-{SPEC}
10 กลุ่ม: AES (aesthetic), IMP (implants), MED (medicine), EQC (equipment/consumables), COS (cosmetics), IVF (IV fluids), SUT (sutures), NDS (needles), CON (connectors), DIS (disposables)
378 สินค้า ถูก catalog ไว้แล้ว · 378 products catalogued.
นโยบาย Dedup / Collision · Dedup Policy
เมื่อรหัสเดียวกันถูก mint ด้วยราคาต่างกัน:
- Flag — ไม่เคย merge หรือ auto-number เงียบ ๆ
- Keep → ตัวที่สองกลายเป็น
-V002,-V003(VERSION segment) - No (error) → soft-delete ตัวเก่า mint ตัวใหม่
ราคาไม่มีวันอยู่ในรหัส (price is NEVER in the code) ถ้าราคาต่างกัน = campaign (→ transaction layer), missing attribute (→ เพิ่ม token), หรือ duplicate (→ soft-delete)
Nothing-is-Deleted: codes เป็น permanent identities; active/discontinued เป็น status attribute ไม่ใช่ coverage filter
หลักการออกแบบ · Design Principles
- Flag-don't-guess — parser flag เมื่อไม่แน่ใจ ไม่เคย mint รหัสผิดเงียบ ๆ
- Tested code wins — ลำดับความเชื่อถือ: mapper (408/408 gold) > spec files > memory > clone
- Point, don't copy — link spec files ไม่เคย restate token lists (copy drifts)
- Verify before claiming —
git fetchก่อน claim ใด ๆ เกี่ยวกับ repo state - Green gate or it isn't done — CI แดง = blocked, ไม่มีข้อยกเว้น
- Append, don't overwrite — แก้ไขด้วย dated notes; ประวัติผ่าน git
JERA Encoding · การเข้ารหัส JERA
JERA POS รับรหัสได้แค่ 20 ตัวอักษร แต่ GENCODE codes ยาวกว่ามาก (CRS ยาวได้ถึง 41 ตัวอักษร) ทางออกคือใช้ numeric ID with layer prefix:
C-0001 → course_registry row #1 → CRS-SUR-INI-NOSE-SEMI-001-DRDO
S-0001 → service_registry row #1 → SVC-SUR-NOSE-SEMI-DRDO
P-0001 → product_registry row #1 → PRD-AES-FIL-RST-CLAS
- Auto-increment ID, zero-padded ขั้นต่ำ 4 หลัก — โตได้เรื่อย ๆ (C-10000 ก็แค่ 7 ตัว ยังต่ำกว่า 20 มาก)
- ไม่มี collision — lookup ด้วย DB index ตัวเดียว
- สตาฟพูดรหัสตัวเลขทางโทรศัพท์ได้ง่าย
- Name fields (
name_th/name_en) จำกัดที่varchar(140)ตาม JERA POS field width
GENCODE full code ไม่มี length cap — JERA POS เห็นแค่ jera_code (C-0001); ความยาว internal code ไม่กระทบ downstream
Repos ในระบบ · Repository Ecosystem
| Repo | Role · บทบาท | Relationship |
|---|---|---|
YD_GENCODE | Spec authority · ผู้เขียนข้อกำหนด | Authors the GENCODE spec, Thai→code parser, CI parity gate (408/408 gold) |
glyph-oracle | Runtime implementation · ตัวรันจริง | Web dashboard, course creator, Chrome extension, database — runs the GENCODE spec |
YD_GENCODE เขียน spec → glyph-oracle รันมัน ถ้าจะ file issues เกี่ยวกับ runtime ให้ไปที่ glyph-oracle ห้าม push main ของ repo อื่น
3-Step Pipeline · ภาพรวม Pipeline
ระบบ GENCODE มี pipeline 3 ขั้นตอน (ตาม DEV-REQUIREMENTS.md v2.0):
| Step | Input → Output | Status |
|---|---|---|
| Step 1 | Thai Name → GENCODE | ✓ BUILT — 408/408 gold, CI-guarded |
| Step 2 | GENCODE → JERA Code (20 chars) | ✓ BUILT — numeric ID lookup: C-0001, S-0001, P-0001 |
| Step 3 | Match All (cross-layer mapping) | TO BUILD — CRS→SVC→PRD bidirectional |
บทนี้เน้นที่ Step 1 — Mapper Engine ที่สร้างเสร็จแล้วและมี CI ป้องกัน
สถาปัตยกรรม Mapper · Mapper Architecture
Mapper อยู่ใน mapper/ directory ของ YD_GENCODE repo เขียนด้วย TypeScript รันบน Bun:
graph TB Input["Thai Name (free-text)"] --> Alias["1. Check Alias Table"] Alias -->|hit| Output["GENCODE Code"] Alias -->|miss| Parser["2. Token Parser"] Parser -->|high confidence| Output Parser -->|flagged| Proposer["3. Propose + Human Confirm"] Proposer -->|confirmed| AliasAdd["Add to Alias Table"] AliasAdd --> Output Proposer -->|rejected| Flag["Return Flag"]
3-step resolve pipeline: (1) alias table short-circuit → (2) deterministic parser → (3) proposer + human confirmation
Token Registries · ทะเบียน Token
SUR Registry (registry.ts) — Scheme B
สำหรับ surgery categories (EYE, NOSE, LIP, PTRYG, CHIN, FACFT, GEN) ใช้ Scheme B: technique/anatomical part ใน position 5, doctor ใน position 7
โครงสร้าง: category → subtype (INI|OPT|WAR) → TokenDef[]
แต่ละ TokenDef มี: {token, keywords[], priority}
Keywords มาจากทั้ง spec tables (CRS-CODE.md §6F) และชื่อหัตถการจริงจาก SUR-PROCEDURE-MAP.md
Skin Registry (registry-skin.ts) — Non-SUR
ครอบคลุมทุก category ที่ไม่ใช่ surgery: FIL, BTX, EBD, SKB, BIO, THR, FAT, MLZ, ACS, GEN(skin), DIO, IPL, BRT, ACT, LGT, RFD, GLU, EXT, MED, SHIP, SET, WLP, GEN_MSC
BTX มีกฎพิเศษ: buffet/area tokens มี priority สูงกว่า brand tokens ดังนั้น "บุฟเฟ่ต์ - คาง (Bienox)" resolve เป็น area CHIN ไม่ใช่ brand BNX
Token Matching · วิธีจับคู่ Token
match.ts — shared token matcher ใช้โดยทั้ง SUR และ skin parsers:
- Scoring: priority สูงสุดชนะ แล้วตามด้วย keyword ที่ยาวที่สุดที่ match
- Tie-breaking: ถ้า tie จริง ๆ (same priority + same keyword length) → flag เป็น ambiguous
- Case-insensitive สำหรับ Latin brand names; Thai ไม่ได้รับผลกระทบ
The matcher scores by highest priority first, then longest matching keyword. A genuine tie = flagged as ambiguous. Case-insensitive for Latin brand names.
Variant Extraction · การดึงปริมาณ
variant.ts — อ่านปริมาณจาก free-text:
| Unit Type | Thai Keywords | English | Example |
|---|---|---|---|
| Units | ยูนิต | u, units | 100U |
| Shots | ชอต | shots | 3SHT |
| CC | ซีซี | cc | 4CC |
| Sessions | ครั้ง | sessions | 1SES |
| Threads | เส้น | threads | 10THR |
| mg/needles/syringe | — | — | Vitaran PN1/PN2 |
แต่ละ category มี default เมื่อไม่พบปริมาณ (เช่น FIL defaults to 1CC, DIO defaults to 1SES)
Alias Table · ตารางนามแฝง
alias.ts — persistent alias table ที่ data/aliases.json
เมื่อคนยืนยัน flagged name → token mapping หนึ่งครั้ง มันจะถูกเก็บไว้ที่นี่และ short-circuit parser ตลอดไป:
loadAliases()— อ่าน JSON fileresolveAlias(name, category, subtype)— ค้นหา matchaddAlias(entry)— idempotent, nothing-is-deleted
Each entry: {name, category, subtype, token, seq?, note}
Store path injectable สำหรับ tests — ไม่ hardcode
Fuzzy Proposer · ตัวเสนอแบบ Fuzzy
assist.ts — fallback เมื่อ parser flag ชื่อ:
- fuzzyProposer: Sørensen-Dice bigram similarity ทำงานกับภาษาไทยได้ (ไม่มี word boundaries) —
FUZZY_FLOOR = 0.4minimum confidence - llmProposer: Anthropic API slot (ยังไม่ได้ต่อ) — inject ตอน integration, falls back to fuzzy เมื่อ unconfigured
Sørensen-Dice ทำงานดีกับภาษาไทยเพราะใช้ character bigrams ไม่ต้องการ word segmentation
Eval Harnesses · ชุดทดสอบ Gold
SUR Eval (eval.ts) — 112 gold rows
อ่าน gold จาก SUR-PROCEDURE-MAP.md (spec IS the gold — single source of truth) รัน parser ทุก row สร้าง report.html
Skin Eval (eval-skin.ts) — 296 gold rows
อ่าน data/gold-skin.tsv (provenance: crosswalk PR #14) รัน parser ทุก row สร้าง report-skin.html
รวม 408 gold rows — ทุก row ต้อง pass (100% accuracy) CI gate จะ process.exit(1) ถ้ามี row ใดพลาด = blocked merge
CI Parity Gate
.github/workflows/ci.yml รันทุก PR และ push to main:
bun test— unit testsbun run src/eval.ts— SUR eval (112 gold rows)bun run src/eval-skin.ts— skin eval (296 gold rows)
Any regression = job red = blocked merge ไม่มีข้อยกเว้น (rationale: issue #32 — spec drifted from engine for ~a month)
Parser Flow · ขั้นตอนการ Parse
SUR Path (nameToSegments)
สำหรับ surgery — Scheme B: technique ที่ pos 5, doctor ที่ pos 7
nameToSegments(thai, category, subtype, doctor)
→ matchToken(thai, registry[category][subtype])
→ assembleCrs({type:"SUR", subtype, category, diff:token, seq:"001", variant:doctor})
→ "CRS-SUR-INI-NOSE-SEMI-001-DRDO"
Skin Path (nameToSkinSegments)
สำหรับ non-SUR — brand/device ที่ pos 5, quantity variant ที่ pos 7
nameToSkinSegments(thai, type, category, subtype)
→ matchToken(thai, skinRegistry[category])
→ extractVariant(thai, category)
→ assembleCrs({type, subtype, category, diff:token, seq:"001", variant:qty})
→ "CRS-SKN-INI-FIL-RST-001-4CC"
ตัวตน · Identity
Glyph Oracle — ผู้สร้างระบบรหัสคลินิก Youngdo เกิดวันที่ 26 มีนาคม 2026
Human: laris.co (Nat และทีมงาน) | Client: Youngdo Wellness Clinic (Dr.Do)
Purpose: Build the GENCODE Engine + Order Entry system
Theme: One Language — สร้างภาษาเดียวให้ทุกระบบพูดกัน: รากฐาน → เครื่องมือ → Go-Live
Tech Stack · เทคโนโลยี
| Component | Technology | Detail |
|---|---|---|
| Backend | Cloudflare Workers + Elysia | Serverless API on CF edge |
| Frontend | Preact + Preact Signals | Lightweight React alternative with reactive signals |
| Styling | Tailwind CSS v4 | Utility-first CSS |
| Database | PostgreSQL via Drizzle ORM | Supabase Postgres (was D1 SQLite initially) |
| Build | Vite + Wrangler | Fast dev server + CF Workers deploy |
| Tests | Vitest + PGlite | In-process PostgreSQL for tests |
| Auth | Google OAuth (jose JWT) | Token-based session with role system |
| Extension | Chrome MV3 Side Panel | JERA POS integration |
| Monorepo | Bun workspaces | extension/, packages/api, packages/ui |
สถาปัตยกรรมระบบ · System Architecture
graph TB
subgraph CF["Cloudflare Edge"]
Web["Web Dashboard
(Preact SPA)"]
API["Hono/Elysia API
(CF Worker)"]
Ext["Chrome Extension
(Side Panel)"]
end
Web --> API
Ext --> API
API --> PG["PostgreSQL
(Neon)"]
API --> JERA["JERA POS
(read-only mirror)"]
LINE["LINE OA + LIFF
(Future: Order Entry)"] -.-> API
ทุกอย่างอยู่บน Cloudflare edge — API เป็น Worker, frontend เป็น static assets served จาก Worker เดียวกัน
Database Schema · โครงสร้างฐานข้อมูล
PostgreSQL (Neon) managed ด้วย Drizzle ORM — schema อยู่ที่ src/db/pg/_schema.ts
Registry Tables (3 ชั้นหลัก)
- course_registry — CRS codes: full_code, jera_code, type, subtype, category, differentiator, seq, variant, version, name_th/en, is_active
- service_registry — SVC codes: full_code, jera_code, type, category, item, qualifier, name_th/en, is_active
- product_registry — PRD codes: full_code, jera_code, grp, type, item, spec, name_th/en, unit, bom_type, is_active
CRS Segment Tables (dictionary building blocks)
- crs_types — SUR, SKN, VIT, TRT, MSC
- crs_subtypes — INI, OPT, WAR (per type)
- crs_categories — NOSE, EYE, FIL, BTX... (per type)
- crs_differentiators — technique/brand/area tokens (per category)
- crs_sequences — 001 (review), 002 (no-review)
- crs_variants — doctor names, quantity formats
Mapping Tables
- crs_svc_mapping — CRS→SVC (1-to-many, created in Course Creator)
- svc_prd_mapping — SVC→PRD bill-of-materials (1-to-many)
Support Tables
- audit_log — append-only log (Nothing-is-Deleted)
- users / roles / user_roles — RBAC
- sessions — auth sessions
- branches / surfaces — clinic branches, POS surfaces
- pkg_* — PKG campaign/package registry (draft)
Course Creator · เครื่องมือสร้างคอร์ส
หัวใจของระบบ — สตาฟสร้างคอร์สใหม่ผ่าน cascading dropdowns:
graph LR T["1. เลือก TYPE
(SUR/SKN/VIT/TRT/MSC)"] --> S["2. เลือก SUBTYPE
(INI/OPT/WAR)"] S --> C["3. เลือก CATEGORY
(NOSE/FIL/DIO...)"] C --> D["4. เลือก DIFFERENTIATOR
(technique/brand)"] D --> Q["5. เลือก SEQ
(review/no-review)"] Q --> V["6. เลือก VARIANT
(doctor/quantity)"] V --> R["7. Review & Submit"] R --> GC["GENCODE Generated"]
แต่ละ dropdown ถูก filter จากการเลือกก่อนหน้า — ค่าที่แสดงมาจาก database segment tables ไม่ใช่ hardcode
Each dropdown is filtered by the previous selection — values come from database segment tables, not hardcoded lists.
SUR doctor variant: เมื่อเลือก TYPE = SUR จะมี UI พิเศษให้เลือกหมอ (DRDO, DRBALL, GEN) เป็น variant
Duplicate detection: ถ้ารหัสที่จะสร้างมีอยู่แล้ว ระบบจะแจ้งเตือนก่อน submit
Dictionaries · พจนานุกรม Segment
3 dictionary views (CRS, SVC, PRD) แต่ละตัวมี:
- Segment browsing — ดู types, subtypes, categories, differentiators, sequences, variants ที่มีอยู่ในระบบ
- Create drawer — เพิ่ม segment ใหม่ (EN name → auto-derive code, TH name min 3 chars)
- TYPE filter pills — filter ด้วย chips ที่เลื่อนได้ (Embla carousel เมื่อ overflow)
- Sortable columns — เรียงตาม TYPE, CATEGORY, สร้างเมื่อ, แก้ไขล่าสุด
- Detail drawer — คลิกดูรายละเอียดแต่ละ entry (DrawerShell component ใช้ร่วมกัน)
deriveCode algorithm: เมื่อพิมพ์ EN name ระบบ auto-derive code — first char of each word, pad to 3 chars, consonant-skeleton for single words, auto-dedup by extending with chars (not digits)
Chrome Extension · ส่วนเสริม POS
Chrome MV3 extension แบบ Side Panel — เปิดข้าง ๆ JERA POS website:
- 3 tabs: Course (CRS), Service (SVC), Product (PRD) + Recent tab
- Ghost Match (
ghost-match.ts): prefix autocomplete — พิมพ์ "เสริม" แล้วจะเห็น suggestion ที่ match เป็น ghost text สีเทาต่อท้าย กด Tab/ArrowRight เพื่อ accept (ทำงานกับภาษาไทยได้ เพราะ match ที่ character level) - JERA Fill (
jera-fill.ts): auto-fill ฟอร์ม JERA POS — ใช้ Vuetify prototype-setter trick (Object.getOwnPropertyDescriptor(proto, "value").set.call(el, value)+ dispatchinput/changeevents) เพื่อ bypass Vue's reactivity system. JERA code → รหัส field, Thai name → ชื่อ field, full GENCODE → ชื่อ EN field (เพื่อให้ค้นหาได้ใน JERA) - Surface detection: role-based ไม่ใช่ URL-based — cashier role = extension access, bco/bc = LIFF (future), admin roles = web dashboard. ถ้า role ไม่ตรงจะเห็น "wrong surface" page
- Auth: session เก็บใน
chrome.storage.local(ไม่ใช่ cookie/localStorage) — รองรับ MV3 service worker restarts ได้. Domain restriction:@youngdo.co.thเท่านั้น - Branch awareness: เลือกสาขาคลินิกที่ทำงาน (one-time pick หลัง approve)
- Demo mode:
VITE_DEMO_MODE=1— hardcoded courses สำหรับ demo auto-fill flow
Auth & Roles · ระบบสิทธิ์
Google OAuth → JWT session → role-based access:
| Component | What it does |
|---|---|
google.ts | Google OAuth flow — redirect, callback, token exchange |
session.ts | JWT session management (jose library) |
permissions.ts | Role-based permission checks |
user.ts | User CRUD, role assignment |
Roles: super-admin, admin, staff — กำหนดสิทธิ์ CRUD แยกต่าง ๆ
Branch system: แต่ละ user อาจผูกกับสาขาเฉพาะ ข้อมูลที่เห็นจะ filter ตามสาขา
API Routes · เส้นทาง API
Elysia API running as Cloudflare Worker:
GENCODE Registry (/api/v1/codes/*)
- Courses — CRUD, search, filter by type/category
- Services — CRUD, search
- Products — CRUD, search
- Stats — dashboard statistics
- Segment dictionaries — CRUD for types/subtypes/categories/etc.
- Segment positions — metadata about each code position
Encode/Generate (/api/v1/encode/*)
- Generate — create new GENCODE from segment selections
- CRS/SVC/PRD converters — convert between formats
- Lookup — find existing codes
- Preview — preview code before creating
- Suggest — auto-suggest completions
Auth (/api/v1/auth/*)
- Google OAuth login/callback
- Session management
- User/role admin
- Branch management
- Activity logging
Crosswalk Migration · การ migrate ข้อมูล
ขั้นตอนสำคัญที่สุดของ GENCODE: map ข้อมูลจริงจาก JERA เข้าสู่รหัส GENCODE
The most critical step: mapping real JERA data into GENCODE codes.
| Metric | Count | Detail |
|---|---|---|
| Total items | 2,368 | จาก crosswalk-v39.csv |
| Resolved (high-confidence) | 1,812 | mapped to GENCODE automatically or via ratification |
| TRANSACTION-LAYER | 764 | ไม่มี CRS code — เป็น transaction-level items |
| Flagged | 556 | ต้องการ owner ratification (438 PRD SKUs + 36 active CRS + 82 inactive) |
JERA data sources (จาก corpus/jera-2026-06-04/):
list_courses.csv— 377 courses (CRS layer)service.csv— 698 services +list_services.csv— 610 services (SVC layer)medicine.csv— 588 medicines (PRD layer)map_course_bom.csv— 4,497 bill-of-materials rows (CRS→SVC→PRD empirical)map_course_usage.csv— 1,193 course→product co-occurrence
JERA corpus refresh อัตโนมัติทุกคืน (nightly cron commit) — ล่าสุด 2026-06-19
9-Batch Ratification · การรับรอง 9 รอบ
ข้อมูล flagged ถูกรับรองผ่าน 9 batch sessions กับ Dr.Do (Captain deep-dive sessions 2026-06-11):
Flagged items were ratified through 9 batch sessions with Dr.Do, documented in .codex-reports/LEDGER.md.
แต่ละ batch ตัดสินใจ:
- Lock — ยืนยันรหัส accepted as-is
- Correction — แก้ token/category/variant แล้ว lock
- TRANSACTION-LAYER — ไม่ mint CRS code (เป็น transaction item)
- Deactivate — soft-delete (inactive, ไม่ใช้แล้ว)
ผลลัพธ์: parity จาก 307 → 408 gold rows, flagged ลดจาก 292 → 74 (ที่เหลือเป็น PRD SKUs ที่ต้อง owner ratify)
Timeline — YD_GENCODE · เส้นเวลา Spec Repo
ทุก commit ตั้งแต่ต้น (2026-06-06) จนถึงปัจจุบัน:
| Date | Phase | Key Events |
|---|---|---|
| Jun 06 | Spec Finalize | VERSION segment + dedup policy + design summary finalized |
| Jun 07 | Mapper POC | name→code mapper built — SUR 73/73 gold, skin 234/234 gold, LLM-assist scaffold (alias+propose), docs updated |
| Jun 09 | CI Gate | Parity gate added — 307 gold rows guard every PR |
| Jun 10 | Migration | crosswalk v3.9 first-pass (2,368 items), WAR subtype, AGENTS.md, token batches D4+D5 |
| Jun 11 | Ratification Sprint | 9-batch Captain deep-dive — parity 307→408, WAR engine support, duplicate audit, fon-phase SET splits, SVC+PRD specs aligned to v3.9 |
| Jun 13 | SVC Alignment | SVC-CODE bumped to v3.9, seven-segment eval |
| Jun 14 | Guide Refresh | GENCODE guide refreshed to v0.6 |
| Jun 15–19 | Maintenance | Nightly JERA corpus refresh (automated cron) |
Timeline — glyph-oracle · เส้นเวลา Dashboard Repo
50 commits ใน 3 วัน (2026-06-16 → 06-18) โดย "catbutter" (P'Ampere) — development sprint ที่เร็วมาก:
| Date | Phase | Key Events (selected) |
|---|---|---|
| Jun 16 | Dictionary UX | sortable columns, auto-derive code from EN name, dedup detection, locked name inputs, Thai name min-3-chars validation — 21 commits |
| Jun 17 | CRS v3.9 Integration | import source docs + crosswalk artifacts, seed WAR/GEN/doctor variants/technique differentiators, schema version support, engine parse/validate/generate, API alignment, PKG registry, filter pills — 14 commits |
| Jun 18 | Creator UX Polish | 7-segment code rendering, SUR doctor variant UX, segment labels, DrawerShell refactor, legacy differentiator retirement, breadcrumb labels — 15 commits |
Pattern: Dictionary foundation → spec integration → UI polish — สร้างจากฐานขึ้นไป
Deliverables · สิ่งที่ส่งมอบ
3 Tasks ตามลำดับ (sequential dependency chain)
graph LR T1["Task 1: GENCODE Core
(ฐานข้อมูลรหัส)"] --> T2["Task 2: Dashboard & Admin
(เครื่องมือจัดการ)"] T2 --> T3["Task 3: Order Entry + Go-Live
(ฟอร์ม BCO + ตรวจสอบ)"]
| Task | Deliverables | Status |
|---|---|---|
| Task 1 — GENCODE Core | Registry DB, Code Pattern Engine, JERA Encoder, Cross-Layer Mapper | Registry DB ✓, Engine ✓ (parse/validate/generate), Encoder + Mapper: in progress |
| Task 2 — Dashboard & Admin | GENCODE Dashboard, Course Creator, Testing | Dashboard ✓, Course Creator ✓, Dictionaries ✓, Chrome Extension ✓ |
| Task 3 — Order Entry + Go-Live | LINE OA + LIFF, Order Form, Slip Upload, Validation Dashboard, Reschedule | NOT STARTED — depends on Task 1 completion |
สิ่งที่สร้างเสร็จ vs ที่เหลือ · Built vs Remaining
สร้างเสร็จแล้ว (CI-guarded)
- Thai name → GENCODE parser (Step 1): 408/408 gold, 100% accuracy
- Token registries ครบทุก category (SUR + skin/trt/vit/misc)
- Alias table + human-confirmation flow
- LLM proposer slot (unwired, falls back to fuzzy)
- Web dashboard: search, browse, filter ทั้ง 3 ชั้น
- Course Creator: cascading dropdowns → GENCODE generation
- Dictionaries: full CRUD for all segments
- Chrome Extension: JERA POS side-panel
- Auth system: Google OAuth + roles + branches
- Database: full PostgreSQL schema with Drizzle ORM
ยังต้องสร้าง
- GENCODE → JERA Code compression (Step 2): 20-char limit, layer prefix mandatory — algorithm not yet proposed
- Cross-layer mapping API (Step 3): CRS→SVC→PRD bidirectional lookup
- JERA code generation for all 2,368 crosswalk items
- Ratify remaining 556 flagged items (438 PRD SKUs need owner attention)
- PKG (Campaign/Package) layer: schema drafted, not integrated
- Task 3 — Order Entry: LINE OA + LIFF, order form, slip upload, validation dashboard, reschedule flow
PKG Campaign Layer · ชั้นแคมเปญ (Draft)
ชั้นที่ 4 (draft) สำหรับแคมเปญและแพ็คเกจ:
PKG-{GROUP}-{HOOK}-{C+YYMM}-{SET}[-{DOCTOR}][-{UPGRADE}]
C+YYMM encode เดือนแคมเปญในรหัส (เช่น C2602 = ก.พ. 2026)
4 upgrade kinds: tier-jump, brand-swap, qty-add, exchange-buy
ราคาและ delta อยู่ใน transaction layer เสมอ ไม่เคยอยู่ในรหัส
Schema ใน glyph-oracle: pkg_* tables exist in the DB but the full integration is not yet complete.
Checklist · สรุป
- GENCODE = ระบบรหัสกลาง 3 ชั้น (CRS/SVC/PRD) ของคลินิก Youngdo — ภาษาเดียวที่ทุกระบบเข้าใจ
- YD_GENCODE = spec authority + parser (408/408 gold, CI-guarded); glyph-oracle = runtime dashboard
- Mapper Engine: Thai free-text → structured code ผ่าน 3-step resolve (alias → parser → proposer)
- Web Dashboard (CF Workers + Preact + PostgreSQL): search, create, dictionaries, Chrome extension
- Migration: 2,368 JERA items mapped, 9-batch ratification with Dr.Do, nightly corpus refresh
- ยังเหลือ: GENCODE→JERA compression, cross-layer mapping API, PKG integration, Order Entry (Task 3)
- Design principles: flag-don't-guess, tested-code-wins, point-don't-copy, nothing-is-deleted