High-Performance PCR Primer Design & Visualization Platform
๋์ฉ๋ ์ ์ ์ ์์ด(10,000bp+)์ ์น ๋ธ๋ผ์ฐ์ ์์ ์ง์ฐ ์์ด ๋ถ์ํ๊ณ ์๊ฐํํ๋ ํ๋ก ํธ์๋ ์์ง ๋ฆฌํฌ์งํ ๋ฆฌ์ ๋๋ค.
PrimeFlow๋ ์๋ช ๊ณผํ ์ฐ๊ตฌ์๋ค์ด PCR ํ๋ผ์ด๋จธ๋ฅผ ์ค๊ณํ ๋ ๊ฒช๋ ๋นํจ์จ์ ํด๊ฒฐํ๊ธฐ ์ํ ์น ์๋ฃจ์ ์ ๋๋ค. ๋ณธ ๋ฆฌํฌ์งํ ๋ฆฌ(Frontend)๋ ๋ฐฑ์๋์์ ๋ถ์๋ ์ ์ ์ ๋ฐ์ดํฐ์ ํ๋ผ์ด๋จธ ํ๋ณด๊ตฐ์ HTML5 Canvas๋ฅผ ํ์ฉํด ์๊ฐ์ ์ผ๋ก ํํํ๋ ๋ฐ ์ง์คํฉ๋๋ค.
- Custom Rendering Engine: DOM ์กฐ์ ๋ฐฉ์์ด ์๋, Canvas API ๊ธฐ๋ฐ์ ์์ฒด ๋ ๋๋ง ์์ง์ ๊ตฌํํ์ฌ 10,000bp ์ด์์ ๋ฐ์ดํฐ๋ฅผ 60fps๋ก ๋ถ๋๋ฝ๊ฒ ๋ ๋๋งํฉ๋๋ค.
- Optimization Algorithms:
- View Culling: ์ด๋ถ ํ์(Binary Search)์ ํ์ฉํ์ฌ ํ๋ฉด ๋ฐ์ ๋ฐ์ดํฐ ๋ ๋๋ง์ ์๋ตํฉ๋๋ค.
- Auto Layout: ๊ทธ๋ฆฌ๋(Greedy) ์๊ณ ๋ฆฌ์ฆ์ ์์ฉํ์ฌ ๊ฒน์น๋ ํ๋ผ์ด๋จธ ๊ตฌ๊ฐ์ ์๋์ผ๋ก ๋ฐฐ์นํฉ๋๋ค.
- Interactive UX: ํ๋ ฌ ๋ณํ(Matrix Transformation)์ ์ ์ฉํ ์ ๋ฐํ Zoom-In/Out ๋ฐ Panning ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- Core: Next.js 16 (App Router), TypeScript
- Graphics: HTML5 Canvas API (2D Context)
- Styling: Tailwind CSS
- State Management: Zustand
- Data Fetching: SWR / TanStack Query
- Deployment: Vercel
PrimerFlow-FE/
โโโ app/ # ๐ [Main] ํ์ด์ง ๋ฐ ๋ผ์ฐํ
(Next.js App Router)
โ โโโ page.tsx # ๋ฉ์ธ ๋์๋ณด๋ ํ๋ฉด
โ โโโ layout.tsx # ์ ์ญ ๋ ์ด์์ (Header, Font ๋ฑ)
โ
โโโ components/ # ๐งฉ UI ์ปดํฌ๋ํธ ๋ชจ์
โ โโโ canvas/ # โจ [Core] ์๊ฐํ ์์ง (GenomeCanvas, Controls ๋ฑ)
โ โโโ ui/ # ๊ณตํต UI (Button, Input, Card ๋ฑ)
โ
โโโ lib/ # ๐งฎ ์์ ํจ์ ๋ฐ ์๊ณ ๋ฆฌ์ฆ
โ โโโ algorithms/ # [Optimization] ์ด๋ถ ํ์, ๋ ์ด์์ ์๊ณ ๋ฆฌ์ฆ
โ โโโ math/ # [Math] ์ขํ ๋ณํ(World <-> Screen), ํ๋ ฌ ์ฐ์ฐ
โ โโโ parsers/ # [Data] FASTA ํ์ฑ ๋ฐ API ๋ฐ์ดํฐ ๋ณํ
โ
โโโ store/ # ๐พ ์ ์ญ ์ํ ๊ด๋ฆฌ (Zustand)
โ โโโ useViewStore.ts # ์ค ๋ ๋ฒจ, ๋ทฐํฌํธ ์์น ๋ฑ ๊ด๋ฆฌ
โ
โโโ docs/ # ๐ ๋ฌธ์ ๋ฐ ํ๋กฌํํธ ์์นด์ด๋ธ
โ โโโ prompts/ # AI ๊ฐ๋ฐ์ ์ํ ๊ธฐ๋ฅ ๋ช
์ธ์(Spec) ๋ชจ์
โ
โโโ public/ # ๐ผ๏ธ ์ ์ ํ์ผ (์ด๋ฏธ์ง, ์์ด์ฝ)
- Node.js 20.9.0 ์ด์
- npm ๋๋ yarn
# 1. ์ ์ฅ์ ํด๋ก
git clone [https://github.com/Seq-Lab/PrimerFlow-FE.git](https://github.com/Seq-Lab/PrimerFlow-FE.git)
# 2. ํ๋ก์ ํธ ํด๋๋ก ์ด๋
cd PrimerFlow-FE
# 3. ํจํค์ง ์ค์น
npm ci
# 4. ํ๊ฒฝ ๋ณ์ ์ค์ (.env.local ์์ฑ)
- `.env.example` ํ์ผ์ ๋ณต์ฌํ์ฌ `.env.local`์ ์์ฑํ์ธ์.
- Next.js `rewrites`์์ ๋ฐฑ์๋ ๋ชฉ์ ์ง๋ `BACKEND_URL`์ด ์ค์ ๋๋ฉด ํด๋น ๊ฐ์, ์์ผ๋ฉด `http://127.0.0.1:8000`(๋ก์ปฌ)๋ก ์ฌ์ฉํฉ๋๋ค.
- ๋ก์ปฌ ๊ธฐ๋ณธ๊ฐ(127.0.0.1:8000)์ ์ฌ์ฉํ๋ ค๋ฉด `.env.local`์ ๋น์ ๋์ด๋ ๋ฌด๋ฐฉํฉ๋๋ค.
- ๋ค๋ฅธ ๋ฐฑ์๋๋ก ํ๋ก์ํด์ผ ํ๋ค๋ฉด `.env.local`์ ์๋์ฒ๋ผ ์ค์ ํ์ธ์:
```env
BACKEND_URL=[https://api.example.com](https://api.example.com)- Vercel ๋ฑ ๋ฐฐํฌ ํ๊ฒฝ์์๋ ๋์ผํ ํ๊ฒฝ ๋ณ์๋ฅผ ํ๋ก์ ํธ ํ๊ฒฝ ๋ณ์๋ก ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
npm run dev
- ์์
๋ด์ญ:
- ๊ธฐ์ ์คํ ์ ์
- Next.js: ๋ฉ์ธ ํ์ด์ง(app/page.tsx)์ ์ ์ญ ๋ ์ด์์์ ๊ตฌ์ฑ, ์ ์ ๋ฆฌ์์ค ๊ด๋ฆฌยทํค๋ ์ค์
- Typescript: ์ปดํฌ๋ํธยท์ ์ญ ์คํ ์ดยท์ ํธ ํ์ ์ ๋ช ์
- Canvas API: ์บ๋ฒ์ค ์ปจํ ์คํธ๋ฅผ ์ง์ ์ฒ๋ฆฌ; ๋์ฉ๋ ์์ด ๋๋๋ง, ์ค/ํจ๋ ๋ณํ, ํ ์คํธ/๋ฐ ๋ํ ๊ทธ๋ฆฌ๊ธฐ
- Zustand: ์บ๋ฒ์ค ๋ทฐ ์ํ, ๋ฆฌ์ /์ ๋ฐ์ดํธ ์ก์ ์ ์ ์ญ ๊ด๋ฆฌ
- Vercel: Next.js์ฑ ๋ฐฐํฌ
- ํ๋ก์ ํธ ๊ธฐ๋ณธ ์ํคํ ์ฒ ๋ฐ ์ค์ผ๋ ํค ์ฝ๋ ๊ตฌ์ฑ
- ๊ธฐ์ ์คํ ์ ์
- AI ํ์ฉ: Gemini๋ก ์์ธํ ๋ด์ฉ ํ๋กฌํํธ๋ก ์์ฑ, codex๋ก ํ๋ก์ ํธ ์ํคํ ์ฒ ๋ฐ ์ค์ผ๋ ํค ์ฝ๋ ์์ฑ.
- ๋ค์ ์ฃผ ๊ณํ: page.tsx, layout.tsx ๊ตฌํ, ๋ชฉ ๋ฐ์ดํฐ ์ถ๋ ฅ ํด๋ณด๊ธฐ
- ์์
๋ด์ญ:
- ๋๋ฏธ ๋ฐ์ดํฐ๋ก ํ์ด์ง์ ์ฐ๊ฒฐ
- ๋ทฐ ์ํ(Zustand)์ ์คยทํจ๋ ๋์์ ์ ๋
- AI ํ์ฉ:
- codex ํ์ฉํ์ฌ layout.tsx, page.tsx ์ธ๋ถ ๊ตฌํ ๋ฐ ๋๋ฒ๊น
- ์๋ฃ ๊ธฐ๋ฅ:
- ๋ชฉ ๋ฐ์ดํฐ์ ์ถ๋ ฅ ์ํ ํ์ธ
- ํ ์คํธ ๊ฒฐ๊ณผ:
- ๋ค์ ์ฃผ ๊ณํ: ์คํ ๊ธฐ๋ฐ ์ด๊ธฐ ์ ๋ ฅ ํผ๊ณผ ๊ฒ์ฆ ๋ก์ง ์ฐฉ์.
- ์์
๋ด์ญ:
- PCR ํ๋ผ์ด๋จธ ๋์์ธ ์คํ์ ์์ฑํด 1-based ๊ท์นยทIUPAC ์ ํยท์ฑ๋ฅ ๋ชฉํ๋ฅผ ํฌํจํ ์๊ตฌ์ฌํญ๊ณผ ์๋๋ฆฌ์ค๋ฅผ ์ ๋ฆฌ
- ๋ฉ์ธ UI ๋์์ธ ๊ฒฐ์ ; ๋คํฌ ํค 4๋จ๊ณ ์คํ ํ๋ก์ฐ๋ก ๋ฆฌ์ํฌ
- Genome ํ์ ๋ถ๋ฆฌ
- AI ํ์ฉ:
- stitch, figma์ ๊ฐ์ ํ๋กฌํํธ๋ฅผ ๋ฃ๊ณ ๋์์ธ์ ๋น๊ต, ์ฑํ.
- ์๋ฃ ๊ธฐ๋ฅ:
- ๋จ๊ณ๋ณ UI ๊ตฌํ ์๋ฃ
- 1๋จ๊ณ: ์ํ์ค ์ ๋ ฅ(FASTA/raw textarea)
- 2๋จ๊ณ: Primer Properties: GC% ๋ฒ์, ์ต๋ Tm ์ฐจ์ด, GC Clamp ์จ/์คํ, Poly-X ์ ํ, ๋๋/์ผ ์กฐ๊ฑด ์ ๋ ฅ
- 3๋จ๊ณ: Binding Location: Search range ์์/๋, Exon junction ๊ณ ๋ ค ์ฌ๋ถ, Intron ํฌํจ ์ฌ๋ถ์ Intron size ๋ฒ์, Restriction enzyme ๋ชฉ๋ก/์ ํ.
- 4๋จ๊ณ: ๊ฒฐ๊ณผ๋ฌผ ์ถ๋ ฅ
- ๋จ๊ณ๋ณ UI ๊ตฌํ ์๋ฃ
- ํ ์คํธ ๊ฒฐ๊ณผ:
- ๋ค์ ์ฃผ ๊ณํ: ์ค์ ๋ฐ์ดํฐ ์ฐ๋, GenomeCanvas ๋ฏธ๋ฆฌ๋ณด๊ธฐยท์ปจํธ๋กค ๋ง๋ฌด๋ฆฌ.
-
์์ ๋ด์ญ:
- ๋ฐฑ์๋ ๋ชจํน ์๋น์ค ๊ตฌํ ๋ฐ ๊ฒฐ๊ณผ ์๊ฐํ
- Step 1 ์ํ์ค ์ ๋ ฅ ํธ์์ฑ ๊ฐ์
- ์ปดํฌ๋ํธ ์ํคํ ์ฒ ๊ฐ์ ๋ฐ UI ์ ๋ฐ์ดํธ
-
AI ํ์ฉ:
- codex๋ก ์บ๋ฒ์ค๊ฐ ํ์๋๋ ๋ชจ๋ฌ ๊ตฌํ
- paste๋ฑ ๋ฒํผ ๊ธฐ๋ฅ ๊ตฌํ
-
์๋ฃ ๊ธฐ๋ฅ:
- ๋ชฉ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ฌ์ ์ด์ฉํ์ฌ ํ์
- Step1์์ DNA์์ด ์ ๋ ฅ ์, fastaํ์ผ ์ ๋ก๋, ํด๋ฆฝ๋ณด๋์์ ๋ถ์ฌ๋ฃ๊ธฐ ์ง์
-
ํ ์คํธ ๊ฒฐ๊ณผ:
-
๋ค์ ์ฃผ ๊ณํ: ์์ฑ๋ ๋ฐฑ์๋์ ์ฐ๋ํ์ฌ ๊ฒฐ๊ณผ ํ์ ๋ฐ ๋๋ฒ๊น
- ์์ ๋ด์ญ: ํ๋ก ํธ์๋-๋ฐฑ์๋ ๊ฐ API ํต์ ๊ท๊ฒฉ(Spec) ์ ์ ๋ฐ ์ฐ๋ ๊ตฌํ
- AI ํ์ฉ: codex ์ด์ฉํ์ฌ ๋ณต์กํ Nested Object์ UI ์ ์ฉ ์ํ(Flat Object)๋ก ๋ณํํ๋ ์ด๋ํฐ ํจํด ์ฝ๋ ์๋ ์์ฑ
- ์๋ฃ ๊ธฐ๋ฅ:
- ํ๋ผ์ด๋จธ ์ค๊ณ ์์ฒญ(Request) ํ๋ก์ธ์ค ๊ตฌํ: ์ ๋ ฅ๊ฐ โ ์ด๋ํฐ โ API ํธ์ถ ํ๋ฆ ์์ฑ
- ๊ฒฐ๊ณผ ๋ชจ๋ฌ(Result Modal) ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ: Mock ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ์ฌ ์บ๋ฒ์ค ๋ฐ ๋ฆฌ์คํธ์ ๋ถ์ ๊ฒฐ๊ณผ ๋ ๋๋ง
- ๋ค์ ์ฃผ ๊ณํ: ์ฌ์ฉ์ ์ ๋ ฅ ๋ฐ์ดํฐ(DNA ์์ด)์ ๋ํ ์ ์ฒ๋ฆฌ(Sanitization) ๋ฐ ์ ํจ์ฑ ๊ฒ์ฆ ๋ก์ง ๊ตฌํ
- ์์
๋ด์ญ:
- ๋์ฉ๋ ๋ฐ์ดํฐ(10,000bp ์ด์) ๋ ๋๋ง ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ๋ทฐํฌํธ ํ์ ๋ก์ง ๊ฐ์
- ์บ๋ฒ์ค UI ์คํฌ๋กค ์กฐ์ ์ ๋ฐฐ๊ฒฝ์ด ํจ๊ป ๋ฐ๋ฆฌ๋ ๋ฒ๊ทธ(Jittering) ์์ ๋ฐ ๋ ์ด์ด ๊ณ ์ ์ฒ๋ฆฌ
- AI ํ์ฉ:
- codex๋ฅผ ์ด์ฉํ์ฌ binary search ์๊ณ ๋ฆฌ์ฆ ๋ก์ง ๊ฒ์ฆ ๋ฐ ์ต์ ํ
- gemini๋ก ํ์ฌ ๋ฐ์ํ๊ณ ์๋ ์ํฉ์ ์ ํํ๊ฒ ์ค๋ช ํ์ฌ ํด๊ฒฐ์ ์๊ตฌํ๋ ํ๋กฌํํธ ์์ฑ ๋ฐ codex๋ฅผ ์ด์ฉํ ์์
- ์๋ฃ ๊ธฐ๋ฅ:
- Binary Search ๋ ๋๋ง ์ต์ ํ:
$O(N)$ ํ์์$O(\log N)$ ์ผ๋ก ๊ฐ์ ํ์ฌ High BP ๊ตฌ๊ฐ ํ๋ ์ ๋๋ ํด๊ฒฐ - Canvas Background Fix: ์คํฌ๋กค ์ด๋ฒคํธ ์ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง๊ฐ ๊ณ ์ ๋๋๋ก ๋ ๋๋ง ๋ก์ง ์์
- Binary Search ๋ ๋๋ง ์ต์ ํ:
- ๋ค์ ์ฃผ ๊ณํ:
- ์ ๋ ฅ ๋ฐ์ดํฐ validator ๊ตฌํ
-
Step1 ์ํ์ค ์ ๋ ฅ ์ ๊ทํ ๋ฐ ๊ฒ์ฆ UX ๊ฐ์
- ATGC ๋์๋ฌธ์ ์ฒ๋ฆฌ ๋ฐ ๋น์ ์ ๋ฌธ์(N, ์ซ์, ํน์๋ฌธ์) ํํฐ๋ง ๋ก์ง ์ ๋ฆฝ
- ๋ถ์ฌ๋ฃ๊ธฐ ๋ฐ ํ์ผ ์ ๋ก๋ ์ ์ฌ์ฉ์ ๋์ UX ์ผ๊ด์ฑ ํ๋ณด
-
AI ํ์ฉ:
- 4๋จ๊ณ ํ๋กฌํํธ(Phase 1~4)๋ฅผ ๊ตฌ์ฑํ์ฌ AI์ ๋จ๊ณ๋ณ ๋ก์ง ๊ณ ๋ํ ๋ฐ ํธ๋ฌ๋ธ์ํ ์งํ
- Next.js Turbopack ๋น๋ ์๋ฌ(Import ๊ฒฝ๋ก ์ด์) ๋ถ์ ๋ฐ ํด๊ฒฐ
- ๋๋ ๋ฌธ์์ด ๋ถ์ฌ๋ฃ๊ธฐ ์ ๋ฐ์ํ๋ ๋ฐ์ดํฐ ์์ค(๊ณผ๋ํ ์ญ์ ) ๋ฌธ์ ์ ๋ํ ์ต์ ํ๋ Sanitize ์ ๊ทผ ๋ฐฉ์ ์ ์ ๋ฐ ์ ์ฉ
-
์๋ฃ ๊ธฐ๋ฅ:
- ์ค์๊ฐ ์ ๊ทํ: ์ ๋ ฅ ์ฆ์ ๋์๋ฌธ์ ๊ตฌ๋ถ ์์ด ๋๋ฌธ์ ATGC๋ก ์๋ ๋ณํ ๋ฐ ์ค์๊ฐ ํํฐ๋ง ์ ์ฉ (์๋ด ์บก์ ์ถ๊ฐ)
- ์ฌ์ฉ์ ๋์ ๊ธฐ๋ฐ ์์ธ ์ฒ๋ฆฌ: FASTA ํ์ผ ์ ๋ก๋, Paste ๋ฒํผ, Ctrl+V ์ ๋ ฅ ์ ๋น์ ์ ๋ฌธ์๊ฐ ๊ฐ์ง๋๋ฉด ์ฆ์ ์ญ์ ํ์ง ์๊ณ window.confirm์ ํตํ ์ฌ์ฉ์ ์ ๊ฑฐ ๋์ ๋ก์ง ๊ตฌํ
- ๋ก์ง ์ต์ ํ: ์กฐ๊ฐ(chunk) ๋จ์ ์ฐ๋ํ์ด์ฆ(Sanitize) ๋ฐฉ์์ผ๋ก ์ ํํ์ฌ ์ฑ๋ฅ ๊ฐ์ ๋ฐ Generate ๋จ๊ณ์ ๋ถํ์ํ ์ค๋ณต ๊ฒ์ฆ ๋ก์ง ์ ๊ฑฐ
-
๋ค์ ์ฃผ ๊ณํ:
- ๋ชฉ๋ฐ์ดํฐ ์ ๊ฑฐ ๋ฐ ๋ฐฐํฌ๋ ๋ฐฑ์๋์ ์ฐ๊ฒฐ
- ์์
๋ด์ญ:
- ๋ชฉ๋ฐ์ดํฐ(Mock Data) ๊ธฐ๋ฐ ์๋ต ์ ๊ฑฐ ๋ฐ ์ค์๋ฒ ์๋ต ๊ตฌ์กฐ ๊ธฐ์ค์ผ๋ก ํ๋ก ํธ ๋ก์ง ์ ํ
- ํ๋ผ์ด๋จธ ๋ถ์ ์์ฒญ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐฑ์๋ ์คํ์ ๋ง๊ฒ ์ ๋ฆฌํ๊ณ ์์ฒญ/์๋ต ๋งคํ ํ๋ฆ ์ ๊ฒ
- API ํธ์ถ ์คํจ ์ํฉ(๋คํธ์ํฌ/์๋ฒ ์ค๋ฅ)์ ๋ํ ์ฌ์ฉ์ ๋ฉ์์ง ๋ ธ์ถ ๋ฐ ์ํ ์ฒ๋ฆฌ ๋ณด๊ฐ
- AI ํ์ฉ:
- Codex๋ฅผ ํ์ฉํด API ํด๋ผ์ด์ธํธ ๊ฒฝ๋ก(
/api/design)์ ์๋น์ค ๋ ์ด์ด ๋งคํ ๋ก์ง ๊ฒ์ฆ - ์๋ต ๋ฐ์ดํฐ ๋ณํ(UI ์ ์ฉ ํธ๋/ํ๋ผ์ด๋จธ ํ๋ณด ๋งคํ) ๊ณผ์ ์ ํ์ ์์ ์ฑ ์ ๊ฒ ๋ฐ ๊ฐ์
- Codex๋ฅผ ํ์ฉํด API ํด๋ผ์ด์ธํธ ๊ฒฝ๋ก(
- ์๋ฃ ๊ธฐ๋ฅ:
- ํ๋ผ์ด๋จธ ์ค๊ณ ์์ฒญ์ด ๋ฐฐํฌ๋ ๋ฐฑ์๋ API๋ก ์ ์ก๋๋๋ก ์ฐ๋ ์๋ฃ
- ๋ฐฑ์๋ ์๋ต์ Result Modal/Canvas์ ๋ ๋๋ง ๊ฐ๋ฅํ ํํ๋ก ๋ณํํ์ฌ ํ์
- Mock ์์กด ํ๋ฆ์ ์ ๊ฑฐํ๊ณ ์ค๋ฐ์ดํฐ ๊ธฐ๋ฐ ๋์์ผ๋ก ์ ํ
- ๋ค์ ์ฃผ ๊ณํ:
- Vercel ํ๊ฒฝ์ ํ๋ก ํธ์๋ ๋ฐฐํฌ ๋ฐ ๋ฐฐํฌ ํ๊ฒฝ ๋ณ์(API Base URL) ์ ๊ฒ
- ์์ ๋ด์ญ:
- AI ํ์ฉ:
- ์๋ฃ ๊ธฐ๋ฅ:
- ๋ค์ ์ฃผ ๊ณํ:
- ์์ ๋ด์ญ:





