sanjae-apply
by seojaehong
README.md
<div align="center">
# ๐ฉน sanjae-apply
**์ฐ์ฌ ์ ์ฒญ ๋์ฐ๋ฏธ ยท MCP ์๋ฒ + CLI**
๊ธ์ฌ ์ข
๋ฅ์ ์ฌํด ์ํฉ์ ๋งํ๋ฉด **ํ์ํ ์์ยท์ฒจ๋ถยท๊ทผ๊ฑฐ ์กฐ๋ฌธ**์ ์๋ ค ์ค๋๋ค.
๊ทผ๋ก๋ณต์ง๊ณต๋จ **์ ๋ณธ PDF 12์ข
**๋ ๊ทธ ์๋ฆฌ์์ ์ฑ์ ์ค๋๋ค.
[](https://github.com/seojaehong/sanjae-apply/releases)
[](LICENSE)
[](https://nodejs.org)
[](https://modelcontextprotocol.io)
[](test/)
<img src="docs/img/demo_yoyang.jpg" alt="ํฉ์ฑ ๊ฐ์ผ๋ก ์ฑ์ด ์์๊ธ์ฌ์ ์ฒญ์. ์ผ์ชฝ PDF ์ถ๋ ฅ, ์ค๋ฅธ์ชฝ ํ๊ธ(hwpx) ์ถ๋ ฅ" width="100%">
<sub>ํฉ์ฑ ๊ฐ์ผ๋ก ์ฑ์ด ์์๊ธ์ฌ์ ์ฒญ์. ์ผ์ชฝ์ด PDF ์ถ๋ ฅ, ์ค๋ฅธ์ชฝ์ด ํ๊ธ(.hwpx) ์ถ๋ ฅ์ ํ๊ธ์์ ์ฐ ๋ชจ์ต์
๋๋ค.</sub>
</div>
---
## โจ ๋ฌด์์ ํด ์ฃผ๋์
์ฐ์ฌ๋ณดํ์ **์ฒญ๊ตฌ์ฃผ์**์
๋๋ค. ์ฌํด์๋ ๋๋ฆฌ์ธ์ด ๊ธ์ฌ ์ข
๋ฅ๋ง๋ค ๋ค๋ฅธ ์์๊ณผ ์ฒจ๋ถ๋ฅผ ์ง์ ์ฑ๊ฒจ์ผ ํฉ๋๋ค.
์ด ๋๊ตฌ๋ ๊ทธ ใ์ฑ๊ธฐ๋ ์ผใ์ ๋์ต๋๋ค.
| ํ๋ ์ผ | ์ค๋ช
|
|---|---|
| ๐ **ํ์ ์์ ํ์ธ** | ๊ธ์ฌ 9์ข
(์์ยทํด์
ยท์ฅํดยท์ ์กฑยท๊ฐ๋ณ๋ฃ ๋ฑ) ร ์ฌ๊ณ /์ถํด๊ทผ/์ง๋ณ ร ์ 3์ ์ ๋ฌด๋ฅผ ๋ฐ์ `REQUIRED` / `CONDITIONAL` / `NOT_APPLICABLE` ๋ก ๋๋ ค์ค๋๋ค |
| ๐ **์ฒจ๋ถ ์ ๊ฒ** | ์ด๋ฏธ ๊ฐ์ง ๊ฒ์ `PROVIDED`, ์๋ ๊ฒ์ `MISSING`, ๋ค๋ฅธ ์๋ฅ๋ก ๊ฐ์๋๋ ๊ฒ์ `SUBSTITUTABLE` |
| โ๏ธ **๊ทผ๊ฑฐ ์กฐ๋ฌธ** | ์ฐ์ฌ๋ณดํ๋ฒยท์ํ๋ นยท์ํ๊ท์น ์กฐ๋ฌธ ๋ฒํธ์ ์ ๋ชฉ์ ํจ๊ป ๋ถ์
๋๋ค(๋ฒ์ ์ฒ ๊ตญ๊ฐ๋ฒ๋ น์ ๋ณด Open API) |
| โ **๋จ์ ์ง๋ฌธ** | ์์ง ๋ต์ด ์๋ ๋ถ๊ธฐ๋ `open_confirmations` ๋ก ๋๋๋ ค ์ค๋๋ค. ๋ชจ๋ฅด๋ ๊ฒ์ ์ง์ด๋ด์ง ์์ต๋๋ค |
| ๐จ๏ธ **PDF ์ฑ์ฐ๊ธฐ** | ๊ณต๋จ ์์์๋ฃ์ค ์ ๋ณธ PDF ์์ ๊ฐ์ ์น์ด ๋๋ ค์ค๋๋ค. ์ ์ฒญ์ธ ์นธ๋ง ์ฑ์ฐ๊ณ ์์ฌยท์ฌ์
์ฃผยท๊ณต๋จ ์นธ์ ๋น์๋๋ค |
> [!IMPORTANT]
> **์น์ธ ์ฌ๋ถ๋ ๋ค๋ฃจ์ง ์์ต๋๋ค.** ๊ฒฐ๊ณผ์ `READY_TO_SUBMIT` ์ ใ์ ์ถํ ์ ์๋ ์ํใ์ด์ง ์น์ธ์ด ์๋๋๋ค.
> ๊ฒฐ๊ณผ๋ฅผ ์ ์น๋ ํํ์ ์ฝ๋ ํํฐ๊ฐ ์ถ๋ ฅ ๋จ๊ณ์์ ๋ง์ต๋๋ค.
> [!NOTE]
> **์
๋ ฅ๊ฐ์ ์ ์ฅํ์ง ์์ต๋๋ค.** ๋ก์ปฌ ์ค์น๋ PC ๋ฐ์ผ๋ก ์๋ฌด๊ฒ๋ ๋ณด๋ด์ง ์์ต๋๋ค. ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ ๊ฐ์ ์นธ์ ๋น์ ๋๊ณ ์ถ๋ ฅํ ๋ค ์์ผ๋ก ์ ์ด๋ ๋ฉ๋๋ค.
---
## ๐ 30์ด ์ค์น (๋ด PC, ํ ํฐ ์์)
Node.js 20 ์ด์๋ง ์์ผ๋ฉด ๋ฉ๋๋ค. ๋จ๊ณ๋ณ ๋ฐ๋ผ ํ๊ธฐ์ ๋ฌธ์ ํด๊ฒฐ์ [์ฌ์ฉ ๋งค๋ด์ผ](docs/์ฌ์ฉ_๋งค๋ด์ผ.md)์ ์์ต๋๋ค.
### Claude Code
```bash
claude mcp add --scope user sanjae-apply -- npx -y sanjae-apply mcp
```
### Claude Desktop
`claude_desktop_config.json` ์ ์ถ๊ฐํฉ๋๋ค.
```json
{
"mcpServers": {
"sanjae-apply": { "command": "npx", "args": ["-y", "sanjae-apply", "mcp"] }
}
}
```
<details>
<summary>๐ช Windows ์์ Claude Desktop ์ด npx ๋ฅผ ๋ชป ์ฐพ์ ๋</summary>
`cmd /c` ๋ก ๊ฐ์๋๋ค.
```json
{
"mcpServers": {
"sanjae-apply": { "command": "cmd", "args": ["/c", "npx", "-y", "sanjae-apply", "mcp"] }
}
}
```
</details>
<details>
<summary>๐งฉ Cursor ยท Windsurf ยท ๊ทธ ๋ฐ์ MCP ํธ์คํธ</summary>
๊ฐ์ `command` / `args` ๋ฅผ ๊ฐ ๋๊ตฌ์ MCP ์ค์ ์ ๋ฃ์ต๋๋ค. stdio ์ ์ก์ด๋ฉด ์ ๋ถ ๋ฉ๋๋ค.
</details>
๋ถ์ด๊ณ ๋์ AI ์๊ฒ ์ด๋ ๊ฒ ๋งํด ๋ณด์ธ์.
> ใ์ถํด๊ทผ ์ค ๊ตํต์ฌ๊ณ ์ธ๋ฐ ์๋ ์ด์ ์๊ฐ ์์ด์. ์์๊ธ์ฌ ์ ์ฒญํ๋ ค๋ฉด ๋ญ๊ฐ ํ์ํด์?ใ
> ใ์์๊ธ์ฌ์ ์ฒญ์์ ์ด ๊ฐ์ผ๋ก ์ฑ์์ PDF ๋ก ์ค.ใ
---
## ๐ป ๋ช
๋ น์ค๋ก ์ฐ๊ธฐ
```bash
# ํ์ ์์ยท์ฒจ๋ถยท๊ทผ๊ฑฐ ์กฐ๋ฌธ
npx -y sanjae-apply check YOYANG --accident COMMUTE --third-party yes
npx -y sanjae-apply check JANGHAE --tags NOISE_HEARING_LOSS --json
# ์์ ์ ๋ณธ ๋์ฅ๊ณผ ์ฑ์ธ ์ ์๋ ์นธ ์ด๋ฆ
npx -y sanjae-apply catalog F_YOYANG_APPLY
# ๊ณต๋จ ์ ๋ณธ PDF ์์ ์ฑ์ฐ๊ธฐ
npx -y sanjae-apply fill F_YOYANG_APPLY values.json --out ์ ์ฒญ์.pdf
# ๊ฐ์ ๊ฐ์ ํ๊ธ ๋ฌธ์(.hwpx)๋ก. ํ์ฅ์๋ง ๋ฐ๊พธ๋ฉด ๋ฉ๋๋ค
npx -y sanjae-apply fill F_YOYANG_APPLY values.json --out ์ ์ฒญ์.hwpx
# PDF ์ ๋์ฅ๊น์ง. ์ด๋ฆ๋ง ์ฃผ๋ฉด ์ฑ๋ช
์ธ์ ๋ง๋ค์ด ์ ์ฒญ์ธ ์๋ช
๋ ์ ๋ถ์ ์ฐ์ต๋๋ค
npx -y sanjae-apply fill F_YOYANG_APPLY values.json --out ์ ์ฒญ์.pdf --stamp ํ๊ธธ๋
npx -y sanjae-apply fill F_YOYANG_APPLY values.json --out ์ ์ฒญ์.pdf --stamp-png ๋ด๋์ฅ.png --stamp-spot applicant
# ๋์ฅ PNG ๋ง ๋ฐ๋ก (์ฑ๋ช
์ธ ยท ์ฌ๊ฐ ยท ํ์ ยท ๋ฒ์ธํ)
npx -y sanjae-apply seal --out ๋์ฅ.png --name ํ๊ธธ๋
npx -y sanjae-apply seal --out ์ง์ธ.png --shape ellipse --arc "์ฃผ์ํ์ฌ ๊ฐ๋๋ค" --center ๋ํ์ด์ฌ --bottom 123-45-67890
```
`values.json` ์ ์นธ ์ด๋ฆ์ `catalog <FORM_ID>` ๊ฒฐ๊ณผ์ `slots` ์ ๋์ต๋๋ค. PDF ์ ํ๊ธ์ ์นธ ์ด๋ฆ์ด ๊ฐ์ต๋๋ค. ์์์ด ๊ฐฑ์ ๋๋ฉด `npx -y sanjae-apply@latest` ๋ก ๋ฐ์ต๋๋ค.
### ๐ ๋์ฅ(๋ ์ธ)์ ์ด๋ป๊ฒ ๋๋
- `--stamp ์ด๋ฆ` ์ด๋ฉด ์ฑ๋ช
์ธ(์ํ ๊ธฐ๋ณธ, `--stamp-shape square|ellipse`)์ ๋ง๋ค์ด ์ฐ๊ณ `--stamp-png` ๋ฉด ๊ฐ์ง ๋์ฅ PNG(ํฌ๋ช
๋ฐฐ๊ฒฝ, 4096px ์ดํ)๋ฅผ ๊ฒ์ฌํ ๋ค ๊ทธ๋๋ก ์ฐ์ต๋๋ค. ์ธ์ฃผ์ ์ ์, ์ง๋ฆ 42pt(์ฝ 1.5cm). ๋๋ด ๊ธ๊ผด(๋๋๊ณ ๋)์ ์๋ ๊ธ์(ํ์ ๋ฑ)๋ ๋น ๋์ฅ์ด ๋์ง ์๋๋ก ์ค๋ฅ๋ก ๋ฉ์ถฅ๋๋ค. ๊ทธ๋ฐ ์ด๋ฆ์ `--stamp-png` ๋ก ๊ฐ์ง ๋์ฅ์ ๋ฃ์ด ์ฃผ์ธ์.
- ์๋ฆฌ๋ ์์๋ง๋ค ์ง๋์ ์ ํด์ ธ ์๊ณ `catalog <FORM_ID>` ์ `stamps` ์ ์ด๋ฆ์ด ๋์ต๋๋ค. ๋น์ฐ๋ฉด **์ ์ฒญ์ธ ๋ณธ์ธ ์๋ฆฌ ์ ๋ถ**(`applicant` ๋ณธ๋ฌธ ยท `delegation` ์์์ฅ ยท `consent` ๊ฐ์ธ์ ๋ณด ๋์)์ ์ฐ๊ณ `--stamp-spot a,b` ๋ก ๊ณ ๋ฆ
๋๋ค. ํ์ธ ์๋ช
๋(`confirm` ํ์ธ์ ยท `commute_reporter` ์ ๊ณ ์ธ ยท `choice_confirmer` ๋ฑ)์ ์ด๋ฆ์ ์ ์ด ์ค ๋๋ง ์ฐ์ต๋๋ค. ์ง๋์ ์๋ ์๋ฆฌ๋ ๊ฑด๋๋ฐ๊ณ ๊ฒฐ๊ณผ์ `stamps_skipped` ์ ์ ์ต๋๋ค.
- PDF ์ ํ๊ธ(hwpx) ์ถ๋ ฅ **๋ ๋ค** ์ฐํ๋๋ค. ํ๊ธ์์๋ ์๋ช
๋ ๋ฌธ๋จ์ ใ๊ธ ์์ผ๋กใ ๋ ์๋ ๊ทธ๋ฆผ์ผ๋ก ๋ค์ด๊ฐ ๊ธ์๋ฅผ ๋ฐ์ง ์์ต๋๋ค(์ชฝ ๋ฐ๋ฆผ 0, 11์ข
์ค์ธก). ํ๊ธ์์ ์ด์ด ์ฎ๊ธฐ๊ฑฐ๋ ์ง์ธ ์ ์์ต๋๋ค.
- ๋์ฅ์ ๋ช
์์์ ์ธ๊ฒฉ ํ์ง์
๋๋ค. **๋ณธ์ธ ๋๋ ๋ช
์์ ๋์๊ฐ ์๋ ์ด๋ฆ๋ง** ๋ฃ์ด ์ฃผ์ธ์. ๋ฑ๋ก ์ธ๊ฐ์ ํ๋ด ๋ด๋ ์ฉ๋๊ฐ ์๋๋๋ค(์ฌ์ฉ์ธ๊ฐ ์ฑ๊ฒฉ).
### ๐จ๏ธ ํ๊ธ(hwpx) ์ถ๋ ฅ์ ์ด๋ป๊ฒ ๋๋
- ๊ณต๋จ์ด ๋ฐฐํฌํ **HWP ์๋ณธ**์ ํ๊ธ์์ hwpx ๋ก ํ ๋ฒ ๋ณํํด ๋๋ดํ์ต๋๋ค(`forms/hwpx/`). ์ฑ์ธ ๋๋ ํ๊ธ์ด ํ์ ์์ต๋๋ค. zip ์ XML ์ ํ ์นธ์ ๊ฐ์ ๋ฃ๋ ์์ TypeScript ์
๋๋ค. ์๋์ฐยท๋งฅยท๋ฆฌ๋
์ค ์ด๋์๋ ๋๋๋ค.
- ๊ฒฐ๊ณผ๋ **.hwpx** ์
๋๋ค. ํ๊ธ 2014 ์ด์์์ ์ด์ด ๊ณ ์น๊ณ ์ธ์ํ ์ ์์ต๋๋ค. ์์์ ๊ธ๊ผดยทํยท์ชฝ ๊ตฌ์ฑ์ ๊ณต๋จ ์๋ณธ ๊ทธ๋๋ก์
๋๋ค.
- ๋น ์์์ ์จ์ด ์๋ ์๋ฆฌํ์์ ๊ธ์์(ํ์ยทํ๋)๊ณผ 1pt ์์ ๊ธ์๋ ๊ฒ์ ์ ์ฒด๋ก ๋ฐ๊ฟ ๋ฃ์ต๋๋ค. ๊ฐ์ด ์นธ๋ณด๋ค ๊ธธ๋ฉด ๊ธ์๋ฅผ ์ค์
๋๋ค(PDF ์ ๊ฐ์ ๊ท์น).
- ์ฌํ๋ณด์กฐ๊ธฐ๊ตฌ ์ฒ๋ฐฉ์ ์ ๊ณต๋จ์ด PDF ๋ง ๋ฐฐํฌํด ํ๊ธ ์ถ๋ ฅ์ด ์์ต๋๋ค.
- ์ ์์์ ํ๊ธ๋ก ์ฑ์ฐ๊ฒ ๋ง๋๋ ๋ฒ์ [`docs/ํ๊ธ์ง๋_์์ฑ๋ฒ.md`](docs/ํ๊ธ์ง๋_์์ฑ๋ฒ.md) ์ ์์ต๋๋ค.
<details>
<summary>๐ง MCP ๋๊ตฌ 5๊ฐ</summary>
| ๋๊ตฌ | ํ๋ ์ผ |
|---|---|
| `list_required_forms` | ๊ธ์ฌยท์ฌํด ๋ถ๊ธฐ โ ์์ยท์ฒจ๋ถยท์กฐ๋ฌธยท์ ์ฐจยท๋จ์ ์ง๋ฌธ |
| `get_form_catalog` | ๊ณต๋จ ์ ๋ณธ ๋์ฅ(ํ์ผ๋ช
ยท๊ฐ์ ์ผยทsha256ยท๊ฒ์๊ธ URL)๊ณผ ์ฑ์ธ ์ ์๋ ์์(`fillable` PDF ยท `fillable_hwpx` ํ๊ธ)ยท์นธ ์ด๋ฆยท๋์ฅ ์๋ฆฌ ์ด๋ฆ(`stamps`) |
| `fill_form` | `form_id` + ๊ฐ (+ `format: "pdf" | "hwpx"`, + `stamp: { name }` ๋๋ `{ png_base64 }`, `spot`) โ ์ฑ์ด ํ์ผ(base64). ๋ก์ปฌ ์ค์น๋ฉด `save_to`(์ ๋ ๊ฒฝ๋ก)๋ก ํ์ผ์ ๋ฐ๋ก ์ ์ฅ |
| `make_seal` | ์ด๋ฆ โ ์ฑ๋ช
์ธ(์ยท์ฌ๊ฐยทํ์) ๋๋ ๋ฒ์ธํ(์์ฃผ ๋ฒ์ธ๋ช
+ ์ค์ฌ ๋ฌธ์ + ํ๋จ ๋ถ๋ฌธ์) ๋์ฅ PNG(base64). ๋ก์ปฌ ์ค์น๋ฉด `save_to` ๋ก ๋ฐ๋ก ์ ์ฅ |
| `fill_yoyang_apply` | v0.1 ํธํ. `fill_form(form_id="F_YOYANG_APPLY")` ๊ณผ ๊ฐ์ต๋๋ค |
</details>
---
## ๐ ์ฑ์ธ ์ ์๋ ์์ 12์ข
| ์์ | ์นธ ์ | PDF | ํ๊ธ | ๋์ฅ ์๋ฆฌ |
|---|---:|:-:|:-:|:-:|
| ์์๊ธ์ฌ์ ์ฒญ์ (๋ณ์ง ์ 2ํธ, 2026.7.7 ๊ฐ์ ) | 74 | โ
| โ
| 3 |
| ์ถํด๊ทผ ์ฌํด ํฉ๋ณธ (์ ์ฒญ์ + ๋ฐ์์ ๊ณ ์) | 118 | โ
| โ
| 4 |
| ์ 3์ ์ฌํด ์ ๊ณ ์ + ํ์ธ์ | 62 | โ
| โ
| 2 |
| ์ ์กฑ๊ธ์ฌ ์ฒญ๊ตฌ์ | 79 | โ
| โ
| 2 |
| ๋ณธ์ธ๋ถ๋ด ์น๋ฃ๋น ์ฒญ๊ตฌ์ | 75 | โ
| โ
| 4 |
| ํด์
๊ธ์ฌ ์ฒญ๊ตฌ์ | 40 | โ
| โ
| 2 |
| ๊ฐ๋ณ๋ฃยท์ด์ก๋นยท๋ณด์กฐ๊ธฐ ์ฒญ๊ตฌ์ | 60 | โ
| โ
| 3 |
| ์ฌํ๋ณด์กฐ๊ธฐ๊ตฌ ์ฒ๋ฐฉ์ (๊ธฐํ) | 12 | โ
| ๊ณต๋จ์ด PDF ๋ง ๋ฐฐํฌ | ์๋ฃ๊ธฐ๊ด ์์ฑ |
| ๋ฏธ์ง๊ธ ๋ณดํ๊ธ์ฌ ์ฒญ๊ตฌ์ | 63 | โ
| โ
| 1 |
| ์ฅํด๊ธ์ฌ ๋ฌถ์ (์ฒญ๊ตฌ์ + ์์์์
ํ์ธ์ + ์ ํ ํ์ธ์) | 159 | โ
| โ
| 5 |
| ์ถ๊ฐ์๋ณ ์ ์ฒญ์ | 40 | โ
| โ
| 3 |
| ์ฌ์์ ์ ์ฒญ์ | 54 | โ
| โ
| 3 |
- ์ ๋ณธ์ **๊ทผ๋ก๋ณต์ง๊ณต๋จ ์์์๋ฃ์ค** ํ์ผ๋ง ์๋๋ค. ์ขํ ์ง๋๋ ์ ๋ณธ์ `sha256` ์ ๋ฌถ์ฌ ์์ด ๊ณต๋จ์ด ์์์ ๋ฐ๊พธ๋ฉด ์ํ์ด ๋จผ์ ๊นจ์ง๋๋ค.
- ๊ณต๋จ์ด HWP ๋ง ์ฃผ๋ ์์์ ํ๊ธ์์ PDF ๋ก ๋ฐ๊ฟ ๋๋ดํ์ต๋๋ค.
- ์ด ๋๊ตฌ์ ๋ฒ์๋ ์ฑ์ด ์ถ๋ ฅ๋ฌผ์ ๋ง๋๋ ๊ฒ๊น์ง์
๋๋ค. ์จ๋ผ์ธ ์ ์(ํ ํ์๋น์ค)๋ ๋ฒ์ ๋ฐ์
๋๋ค.
---
## ๐ ์๊ฒฉ MCP (์ด์์๊ฐ ํ ํฐ์ ์ฃผ๋ ๊ฒฝ์ฐ)
```bash
claude mcp add --transport http --scope user sanjae-apply https://sanjae-apply.vercel.app/api/mcp/mcp \
--header "Authorization: Bearer <๋ฐ๊ธ๋ฐ์ ํ ํฐ>"
```
๊ฐ์ ๋๊ตฌ 5๊ฐ๊ฐ ์๊ฒฉ์ผ๋ก ๋๋๋ค. ์
๋ ฅ์ ์๋ฒ์ ์ ์ฅ๋์ง ์์ง๋ง ๋คํธ์ํฌ๋ฅผ ๊ฑฐ์นฉ๋๋ค.
<details>
<summary>๐ ์ง์ ํธ์คํ
ํ๊ธฐ(Vercel)</summary>
์ด ๋ ํฌ๋ฅผ Vercel ์ ์ฌ๋ฆฌ๊ณ ํ๊ฒฝ๋ณ์๋ฅผ ๋ฃ์ผ๋ฉด `/api/mcp/mcp` ๊ฐ ์ด๋ฆฝ๋๋ค.
| ๋ณ์ | ๋ป |
|---|---|
| `SANJAE_MCP_TOKENS` | ํ์ฉํ Bearer ํ ํฐ. ์ผํ๋ก ์ฌ๋ฌ ๊ฐ |
| `LAW_GO_KR_OC` | ๋ฒ์ ์ฒ Open API ์ธ์ฆํค. ์กฐ๋ฌธ ์ค์๊ฐ ์กฐํ๋ฅผ ์ธ ๋๋ง |
</details>
---
## ๐งช ๊ฒ์ฆ ์์ค
| ์ธต | ๋ด์ฉ | ์ |
|---|---|---:|
| ๊ท์น | ๊ธ์ฌ 9์ข
ร ๋ถ๊ธฐ, ๊ธ์ง์ด ํํฐ ์๊ธฐ์ํ | vitest |
| ์กฐ๋ฌธ ๋์กฐ | ์ฝ๋์ ๊ทผ๊ฑฐ ์กฐ๋ฌธ โ ๋ฒ์ ์ฒ์์ ๋ฐ์ ์กฐ๋ฌธ XML ์ ๋ชฉ | 18๊ฑด |
| ์์ ๋์ฅ | ์ฝ๋์ ์์ โ `forms/catalog.json` sha256 | 15์ข
|
| PDF ์ฑ์ฐ๊ธฐ | 12์ข
์ ๋ถ ๊ธ์ ์์น + **ํฝ์
๋น๊ต**(๋ฐฑ์ง ์ถ๋ ฅ ์ฌ๊ณ ๋ฐฉ์ง) + ์ก์ | ์ฝ 590์นธ |
| ํ๊ธ ์ฑ์ฐ๊ธฐ | 11์ข
์ ๋ถ zip ์ ๊ธ์ยท์ฒดํฌ ์ยท๊ธ์์ + **ํ๊ธ์ด ์ค์ ๋ก ์ด์ด PDF ๋ก ๊ทธ๋ฆฌ๋์ง**(COM) + ์ชฝ์๊ฐ ์๋ณธ๊ณผ ๊ฐ์์ง + ์ก์ | ์ฝ 650์นธ |
| MCP | http ยท stdio ์์ชฝ initialize / tools/list / tools/call | SDK ํด๋ผ์ด์ธํธ |
| ์ด์ ๋๋ผ์ด๋ฐ | Vercel ์ด์ ๋์ ์ ๊ณต์ SDK ๋ก 31๊ฑด | ์ ๋ถ ํต๊ณผ |
์ ๋ถ **ํฉ์ฑ ๊ฐ**์ผ๋ก๋ง ๋๋ ธ์ต๋๋ค. ์ค์ ์ฌ๊ฑด์ผ๋ก๋ ๊ฒ์ฆํ์ง ์์์ต๋๋ค.
```bash
git clone https://github.com/seojaehong/sanjae-apply && cd sanjae-apply
npm ci && npm test
# ์ฑ์ด PDF ๋ฅผ ๊ธ์ ์์น + ํฝ์
๋ก ๊ฒ์ฌ
python scripts/verify_fill.py out.pdf forms/maps/F_YOYANG_APPLY.json test/samples/F_YOYANG_APPLY.json out.jpg forms/bundled/F_YOYANG_APPLY.pdf
# ์ฑ์ด ํ๊ธ ํ์ผ์ ๊ฒ์ฌ (ํ๊ธ์ด ์๋ ์๋์ฐ๋ฉด ์ค์ ๋ ๋๊น์ง, ์์ผ๋ฉด --no-render)
python scripts/verify_hwpx_fill.py out.hwpx test/samples/F_YOYANG_APPLY.json forms/hwpx_maps/F_YOYANG_APPLY.json out.jpg
```
์ค์น๋ถํฐ ํ์ฉ๊น์ง ๋ฐ๋ผ ํ๋ ์ฌ์ฉ ๋งค๋ด์ผ๊ณผ ์ค์ธก ๊ธฐ๋ก์ [`docs/์ฌ์ฉ_๋งค๋ด์ผ.md`](docs/์ฌ์ฉ_๋งค๋ด์ผ.md) ์ ์์ต๋๋ค.
์ ์์์ ์ขํ ์ง๋๋ [`docs/์ขํ์ง๋_์์ฑ๋ฒ.md`](docs/์ขํ์ง๋_์์ฑ๋ฒ.md), ํ๊ธ ์ง๋๋ [`docs/ํ๊ธ์ง๋_์์ฑ๋ฒ.md`](docs/ํ๊ธ์ง๋_์์ฑ๋ฒ.md), ๋ฐฐํฌยท์ฐ๊ฒฐ ์ ์ฒด๋ [`docs/ํจํค์ง_๋ฐฐํฌ_์ฐ๊ฒฐ_๊ฐ์ด๋.md`](docs/ํจํค์ง_๋ฐฐํฌ_์ฐ๊ฒฐ_๊ฐ์ด๋.md).
---
## ๐๏ธ ๊ตฌ์กฐ
```
src/core ๊ท์น S-01~S-13 ยท ์์/์ฒจ๋ถ ์นดํ๋ก๊ทธ ยท ๊ธ์ง์ด ํํฐ(์์ TS, IO ์์)
src/fill overlay.ts pdf-lib ์ค๋ฒ๋ ์ด(text / boxes / check / multiline)
hwpx.ts ํ๊ธ hwpx ์ฑ์ฐ๊ธฐ(cell / after / check / digits / boxes / group, ๊ธ์์ยทํฌ๊ธฐ ๊ต์ )
src/stamp seal.ts ๋์ฅ PNG ์์ฑ(๊ธ๋ฆฌํ ์ค๊ณฝ ๋์คํฐ) ยท resolve.ts ์๋ฆฌ ์ ํ. PDFยทhwpx ๋ ์ธ์ overlay.tsยทhwpx.ts ์ stamps
src/mcp ๋๊ตฌ 5๊ฐ ยท ์๊ฒฉ(mcp-handler, Bearer) ยท ๋ก์ปฌ(stdio)
src/laws ๋ฒ์ ์ฒ Open API ํด๋ผ์ด์ธํธ
api/mcp Vercel ํจ์
web/ ์๋ด ํ์ด์ง ์คํฌ๋ฆฝํธ(engine.ts = src/core ๋ธ๋ผ์ฐ์ ๋ฒ๋ค ยท main.ts = ํ๋ฉด). npm run build:web โ public/app ยท public/data
forms/ catalog.json(์ ๋ณธ ๋์ฅ) ยท maps/(PDF ์ขํ ์ง๋ 12) ยท bundled/(๋๋ด PDF 12) ยท hwpx/(๋ณํ hwpx 11) ยท hwpx_maps/(ํ๊ธ ์ง๋ 11)
scripts/ comwel_forms.py(์์์๋ฃ์ค ์์ง) ยท verify_fill.py ยท probe_form.py ยท hwp_to_hwpx.py ยท probe_hwpx.py ยท verify_hwpx_fill.py ยท hwpx_stamp_anchors.py(๋์ฅ ์ต์ปค) ยท verify_hwpx_stamps.py(ํ๊ธ ๋ ์ธ ์ค์ธก) ยท mcp_dryrun.mjs
test/ vitest 227 (formal_rules.test.ts ์ ์ 10,368๊ฑด ํฌํจ)
docs/ ์ขํ์ง๋ ์์ฑ๋ฒ ยท ํ๊ธ์ง๋ ์์ฑ๋ฒ ยท ํจํค์งยท๋ฐฐํฌยท์ฐ๊ฒฐ ๊ฐ์ด๋
```
---
## โ๏ธ ๊ฒฝ๊ณ
- ๊ณต์ธ๋
ธ๋ฌด์ฌ๋ฒ ์ 27์กฐ์ ๋ฐ๋ผ ์ฒญ๊ตฌ์ ๋ํยท๋๋ฆฌ์ ์๋ฅ์ ์์ฑยทํ์ธ์ ๊ณต์ธ๋
ธ๋ฌด์ฌ์ ์ง๋ฌด์
๋๋ค. ์ด ๋๊ตฌ๋ **๊ทธ ์ผ์ ๋๋ ๋๊ตฌ**์ด์ง ๋์ ํ์ง ์์ต๋๋ค.
- ๊ท์น์ ์ฐ์ฌ ์ค๋ฌด ๋ฉ๋ชจ(์ฐ์ฌ์ฐฝ๊ณ ๋ธ๋ก๊ทธ, 2025.1.14 ๊ธฐ์ค)๋ฅผ ์ฎ๊ธฐ๊ณ ๋ฒ ์กฐ๋ฌธ์ผ๋ก ๊ทผ๊ฑฐ๋ฅผ ๋ถ์ธ ๊ฒ์
๋๋ค. ๊ณต๋จ ๋ด๋ถ ๊ท์ ๊ณผ๋ ๋์กฐํ์ง ์์์ต๋๋ค. **์ถ๋ ฅ๋ฌผ์ ๋ด๋น ๋
ธ๋ฌด์ฌ๊ฐ ํ์ธํ ๋ค ์ฐ์ญ์์ค.**
- ์์ ๊ฐ์ ์ ๊ณต๋จ์ด ์๊ณ ์์ด ํฉ๋๋ค. `catalog` ๋ก ๊ฐ์ ์ผ์ ํ ๋ฒ์ฉ ํ์ธํ์ธ์.
---
## ๐ค ๊ธฐ์ฌ
- ์ ์์ ์ขํ ์ง๋๋ [`docs/์ขํ์ง๋_์์ฑ๋ฒ.md`](docs/์ขํ์ง๋_์์ฑ๋ฒ.md), ํ๊ธ ์ง๋๋ [`docs/ํ๊ธ์ง๋_์์ฑ๋ฒ.md`](docs/ํ๊ธ์ง๋_์์ฑ๋ฒ.md) ๋ฅผ ๋ฐ๋ผ ๋ง๋ค๊ณ `test/samples/` ์ ํฉ์ฑ ๊ฐ์ ํจ๊ป ๋ฃ์ด ์ฃผ์ธ์.
- ๊ท์น(S-xx)์ ๊ณ ์น ๋๋ ์คํจํ๋ ์ํ์ ๋จผ์ ์ถ๊ฐํฉ๋๋ค.
- ์ค์ ์ฌ๊ฑด์ ๊ฐยท์ค๋ช
ยท์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ๋ ์ด์ยทPR ์ด๋์๋ ์ฌ๋ฆฌ์ง ๋ง์ธ์.
## ๐ ๋ผ์ด์ ์ค
MIT. ๋๋ด ๊ธ๊ผด ๋๋๊ณ ๋์ SIL OFL 1.1([`fonts/OFL.txt`](fonts/OFL.txt)). ๊ณต๋จ ์์ PDF ๋ ๊ทผ๋ก๋ณต์ง๊ณต๋จ ๊ณต๊ฐ ์๋ฃ์
๋๋ค.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues