diff --git a/CLAUDE.md b/CLAUDE.md
index 35f6a25..056ca56 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,5 +1,8 @@
# CLAUDE.md
+> ๐ง **๊ฐ๋ฐ์์ฉ ๋ฌธ์**: ๊ธฐ์ ์์ธ, ์ฝ๋ ํจํด, ํธ๋ฌ๋ธ์ํ
+> ๐ **[README.md](./README.md)**: ๊ธฐ๋ฅ ์๊ฐ, ๋ฐฐํฌ ๊ฐ์ด๋, ์ฌ์ฉ๋ฒ
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Auto-Read on Start
@@ -69,8 +72,8 @@ npm run chat # CLI ํ
์คํธ ํด๋ผ์ด์ธํธ
**CLI ํ
์คํธ ํด๋ผ์ด์ธํธ:**
```bash
-# ํ๊ฒฝ๋ณ์ ์ค์
-export WEBHOOK_SECRET="..." # Vault: secret/data/telegram-bot
+# .env ํ์ผ ์์ฑ (์ต์ด 1ํ)
+echo 'WEBHOOK_SECRET=...' > .env # Vault: secret/data/telegram-bot
# ๋ํํ ๋ชจ๋
npm run chat
@@ -84,6 +87,7 @@ npm run chat "๋ ์จ ์๋ ค์ค"
wrangler secret put BOT_TOKEN # Telegram Bot Token
wrangler secret put WEBHOOK_SECRET # Webhook ๊ฒ์ฆ์ฉ
wrangler secret put OPENAI_API_KEY # OpenAI API ํค
+wrangler secret put NAMECHEAP_API_KEY # namecheap-api ๋ํผ ์ธ์ฆ ํค
```
**Webhook ์ค์ :**
@@ -223,7 +227,7 @@ Telegram Webhook โ Security Validation โ Command/Message Router
| ๋ฌธ์ | `lookup_docs` | Context7 | ๋ฌธ์, ์ฌ์ฉ๋ฒ, API |
| ๋๋ฉ์ธ | `manage_domain` | ์ฝ๋ ์ง์ ์ฒ๋ฆฌ โ Namecheap | ๋๋ฉ์ธ, ๋ค์์๋ฒ, WHOIS |
| ๋๋ฉ์ธ ์ถ์ฒ | `suggest_domains` | GPT + Namecheap | **๋๋ฉ์ธ ์ถ์ฒ, ๋๋ฉ์ธ ์ ์, ๋๋ฉ์ธ ์์ด๋์ด** |
-| ์์น๊ธ | `manage_deposit` | ์ฝ๋ ์ง์ ์ฒ๋ฆฌ โ D1 | **์
๊ธ, ์ถฉ์ , ์์ก, ๊ณ์ข, ์ก๊ธ** |
+| ์์น๊ธ | `manage_deposit` | ์ฝ๋ ์ง์ ์ฒ๋ฆฌ | **์
๊ธ, ์ถฉ์ , ์์ก, ๊ณ์ข, ์ก๊ธ** |
**Data Layer (D1 SQLite):**
| ํ
์ด๋ธ | ์ฉ๋ | ์ฃผ์ ์ปฌ๋ผ |
@@ -351,18 +355,6 @@ case 'new_tool':
**๋ก๊ทธ:** `[search_web] ๋ฒ์ญ: "ํ๊ณจ๋ฆฐ VPN" โ "Pangolin VPN"`
-### Deposit Agent ํ๋กฌํํธ ์์ ๋ฐฉ๋ฒ
-```bash
-# Vault์์ API ํค ์กฐํ
-curl -s -H "X-Vault-Token: hvs.xxx" https://vault.anvil.it.com/v1/secret/data/openai
-
-# Assistant ํ๋กฌํํธ ์
๋ฐ์ดํธ
-curl -X POST 'https://api.openai.com/v1/assistants/asst_XMoVGU7ZwRpUPI6PHGvRNm8E' \
- -H 'Authorization: Bearer sk-xxx' \
- -H 'OpenAI-Beta: assistants=v2' \
- -d @update-agent.json
-```
-
---
## Configuration
@@ -375,7 +367,6 @@ curl -X POST 'https://api.openai.com/v1/assistants/asst_XMoVGU7ZwRpUPI6PHGvRNm8E
| `DOMAIN_OWNER_ID` | - | ๋๋ฉ์ธ ๊ด๋ฆฌ ๊ถํ Telegram ID |
| `DEPOSIT_ADMIN_ID` | - | ์์น๊ธ ๊ด๋ฆฌ ๊ถํ Telegram ID |
| `WEBHOOK_SECRET` | - | Telegram Webhook ์ธ์ฆ (wrangler secret, Vault: telegram-bot) |
-| `BANK_API_SECRET` | - | ์
๊ธ ์๋ฆผ API ์ธ์ฆ ํค (wrangler secret) |
| `BRAVE_API_KEY` | - | Brave Search API ํค (wrangler secret) |
| `DEPOSIT_API_SECRET` | - | Deposit API ์ธ์ฆ ํค (namecheap-api์ฉ, wrangler secret) |
@@ -392,8 +383,7 @@ curl -X POST 'https://api.openai.com/v1/assistants/asst_XMoVGU7ZwRpUPI6PHGvRNm8E
| wttr.in | ๋ ์จ | wttr.in | - |
| Brave Search | ๊ฒ์ | api.search.brave.com | Free AI ํ๋ (2,000/์) |
| Vault | API ํค ๊ด๋ฆฌ | vault.anvil.it.com | - |
-| Gmail | ์
๊ธ SMS ์์ | deposit.anvil@gmail.com | Apps Script ์ฐ๋ |
-| Apps Script | Gmail โ Worker ์ฐ๋ | script.google.com | 1๋ถ๋ง๋ค ์คํ, message_id ์ค๋ณต ๋ฐฉ์ง |
+| Email Routing | ์
๊ธ SMS ์์ | Cloudflare Email Routing | Worker email handler๋ก ์ง์ ์ฒ๋ฆฌ |
### Cloudflare AI Gateway
@@ -423,10 +413,8 @@ URL: gateway.ai.cloudflare.com/v1/{account_id}/telegram-bot/openai/...
โ
๋งค์นญ O โ confirmed + ์์กโ | ๋งค์นญ X โ pending
-[์๋๋ฆฌ์ค 2: SMS ๋จผ์ - Gmail โ Apps Script โ Worker]
-์ํ SMS โ Gmail(deposit.anvil@gmail.com) โ Apps Script (1๋ถ๋ง๋ค)
- โ
- POST /api/bank-notification
+[์๋๋ฆฌ์ค 2: SMS ๋จผ์ - Email Routing]
+์ํ SMS โ ๋ฉ์ผ ์ ๋ฌ โ Cloudflare Email Routing โ Worker (email handler)
โ
ํ์ฑ โ bank_notifications ์ ์ฅ
โ
@@ -442,22 +430,9 @@ URL: gateway.ai.cloudflare.com/v1/{account_id}/telegram-bot/openai/...
| ์๋ ๋งค์นญ ์ฑ๊ณต | โ
์
๊ธ์ก + ํ์ฌ ์์ก | โ
์
๊ธ ์ ๋ณด + ๋งค์นญ ์๋ฃ |
| ๋งค์นญ ๋๊ธฐ (SMS๋ง) | - | โ
์
๊ธ ์ ๋ณด + ๋๊ธฐ ์ํ |
-**Gmail โ Worker ์ฐ๋:**
-- Gmail ๊ณ์ : `deposit.anvil@gmail.com`
-- Apps Script: 1๋ถ๋ง๋ค `is:unread ์
๊ธ` ๊ฒ์ โ Worker API ํธ์ถ
-- ์ค๋ณต ๋ฐฉ์ง: Gmail message_id ๊ธฐ๋ฐ
-
-**API ์๋ํฌ์ธํธ:**
-```
-POST /api/bank-notification
-Content-Type: application/json
-
-{
- "content": "[Web๋ฐ์ ]\nํ๋,01/16, 23:30\n427******27104\n์
๊ธ5์\nํฉ๋ณํ",
- "messageId": "19bc737b3415596a",
- "secret": "BANK_API_SECRET ๊ฐ"
-}
-```
+**Email Routing ์ค์ :**
+- Cloudflare Dashboard โ Email โ Email Routing โ Routes
+- ์์ ์ฃผ์ โ Worker: `telegram-summary-bot` ๋ผ์ฐํ
**์
๊ธ ๊ณ์ข:** ํ๋์ํ 427-910018-27104 (์ฃผ์ํ์ฌ ์์ด์ธํด๋๋)
- Vault ๊ฒฝ๋ก: `secret/companies/ironclad-corp`
diff --git a/README.md b/README.md
index 4af20bf..1a2d408 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,9 @@
> Cloudflare Workers + D1 + OpenAI๋ฅผ ํ์ฉํ ์ฌ์ฉ์ ํ๋กํ ๊ธฐ๋ฐ ํ
๋ ๊ทธ๋จ ๋ด
+**๐ ์ด ๋ฌธ์**: ๊ธฐ๋ฅ ์๊ฐ, ๋ฐฐํฌ ๊ฐ์ด๋, ์ฌ์ฉ๋ฒ (์ฌ์ฉ์/์ด์์์ฉ)
+**๐ง [CLAUDE.md](./CLAUDE.md)**: ๊ธฐ์ ์์ธ, ์ฝ๋ ํจํด, ํธ๋ฌ๋ธ์ํ
(๊ฐ๋ฐ์์ฉ)
+
## ๋ชฉ์ฐจ
1. [๊ฐ์](#๊ฐ์)
@@ -26,8 +29,7 @@
- **Context7 ์ฐ๋**: ํ๋ก๊ทธ๋๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณต์ ๋ฌธ์ ์ค์๊ฐ ์กฐํ
- **๋์ ๋๊ตฌ ๋ก๋ฉ**: ๋ฉ์์ง ํค์๋ ๊ธฐ๋ฐ์ผ๋ก ํ์ํ ๋๊ตฌ๋ง ์ ํํ์ฌ ํ ํฐ ์ ์ฝ
- **๋๋ฉ์ธ ์ถ์ฒ**: GPT๊ฐ ์ฐฝ์์ ๋๋ฉ์ธ ์์ฑ โ ๊ฐ์ฉ์ฑ ์๋ ํ์ธ โ ๊ฐ๊ฒฉ๊ณผ ํจ๊ป ์ ์
-- **Deposit Agent**: OpenAI Assistants API ๊ธฐ๋ฐ ์์น๊ธ ๊ด๋ฆฌ ์์ด์ ํธ ์ฐ๋
-- **์์น๊ธ ์์คํ
**: ์ํ ์
๊ธ ์๋ ๊ฐ์ง + ์ฌ์ฉ์ ์ ๊ณ ๋งค์นญ์ผ๋ก ์๋ ์ถฉ์
+- **์์น๊ธ ์์คํ
**: ์ฝ๋ ์ง์ ์ฒ๋ฆฌ, ์ํ ์
๊ธ ์๋ ๊ฐ์ง + ์ฌ์ฉ์ ์ ๊ณ ๋งค์นญ์ผ๋ก ์๋ ์ถฉ์
- **Email Worker**: SMS โ ๋ฉ์ผ โ ์๋ ํ์ฑ์ผ๋ก ์
๊ธ ์๋ฆผ ์ฒ๋ฆฌ
- **๋ฌดํ ์ปจํ
์คํธ**: ์ฌ๋ผ์ด๋ฉ ์๋์ฐ(3๊ฐ)๋ก ํ๋กํ ์ ์ง, ๋ฌด์ ํ ๋ํ ๊ธฐ์ต
- **๊ฐ์ธํ ์๋ต**: ํ๋กํ ๊ธฐ๋ฐ์ผ๋ก ๋ง์ถคํ AI ์๋ต ์ ๊ณต
@@ -43,7 +45,7 @@
| **Context7** | ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฌธ์ ์กฐํ API |
| **๋๋ฉ์ธ ๊ด๋ฆฌ** | ์ฝ๋ ์ง์ ์ฒ๋ฆฌ โ Namecheap API |
| **๋๋ฉ์ธ ์ถ์ฒ** | GPT + Namecheap API (์ฝ๋ ๋ ๋ฒจ) |
-| **Deposit Agent** | ์์น๊ธ ๊ด๋ฆฌ (OpenAI Assistants) |
+| **์์น๊ธ ๊ด๋ฆฌ** | ์ฝ๋ ์ง์ ์ฒ๋ฆฌ โ D1 |
| **Namecheap API** | ๋๋ฉ์ธ ์กฐํ/๊ฐ์ฉ์ฑ/๊ฐ๊ฒฉ ๋ฐฑ์๋ |
| **Email Workers** | SMS โ ๋ฉ์ผ ํ์ฑ (์
๊ธ ์๋ฆผ) |
| **Workers AI** | ํด๋ฐฑ์ฉ (Llama 3.1 8B) |
@@ -148,7 +150,7 @@ OpenAI Function Calling์ ํตํด AI๊ฐ ์๋์ผ๋ก ํ์ํ ๋๊ตฌ๋ฅผ ํธ์ถ
| **๋ฌธ์** | "React hooks ์ฌ์ฉ๋ฒ", "OpenAI API ์์ " | Context7 |
| **๋๋ฉ์ธ** | "๋๋ฉ์ธ ๋ชฉ๋ก", "anvil.it.com ๋ค์์๋ฒ", ".com ๊ฐ๊ฒฉ", "google.com whois" | ์ฝ๋ ์ง์ ์ฒ๋ฆฌ + WHOIS API |
| **๋๋ฉ์ธ ์ถ์ฒ** | "์ปคํผ์ ๋๋ฉ์ธ ์ถ์ฒํด์ค", "์คํํธ์
๋๋ฉ์ธ ์์ด๋์ด" | GPT + Namecheap |
-| **์์น๊ธ** | "์์ก ํ์ธ", "์ถฉ์ ํ๊ณ ์ถ์ด", "10000์ ์
๊ธํ์ด" | D1 + Email Worker |
+| **์์น๊ธ** | "์์ก ํ์ธ", "์ถฉ์ ํ๊ณ ์ถ์ด", "10000์ ์
๊ธํ์ด" | ์ฝ๋ ์ง์ ์ฒ๋ฆฌ |
### ๋์ ๋ฐฉ์
@@ -168,6 +170,31 @@ OpenAI: ๋ ์จ ๋ฐ์ดํฐ๋ฅผ ์์ฐ์ด๋ก ์๋ต ์์ฑ
์๋ต: "๐ค ์์ธ ๋ ์จ\n์จ๋: 5ยฐC\n์ต๋: 45%..."
```
+### ๋์ ๋๊ตฌ ๋ก๋ฉ
+
+๋ฉ์์ง ํค์๋๋ฅผ ๋ถ์ํ์ฌ ํ์ํ ๋๊ตฌ๋ง ์ ํ์ ์ผ๋ก ๋ก๋ฉํฉ๋๋ค. (ํ ํฐ 40% ์ ์ฝ)
+
+| ์นดํ
๊ณ ๋ฆฌ | ๋๊ตฌ | ๊ฐ์ง ํจํด |
+|----------|------|-----------|
+| domain | manage_domain, suggest_domains | ๋๋ฉ์ธ, ๋ค์์๋ฒ, whois, .com |
+| deposit | manage_deposit | ์
๊ธ, ์ถฉ์ , ์์ก, ๊ณ์ข |
+| weather | get_weather | ๋ ์จ, ๊ธฐ์จ, ๋น, ๋ |
+| search | search_web, lookup_docs | ๊ฒ์, ์ฐพ์, ๋ญ์ผ, ๊ฐ๊ฒฉ |
+| utility | get_current_time, calculate | (ํญ์ ํฌํจ) |
+
+ํจํด ๋งค์นญ ์์ผ๋ฉด ์ ์ฒด ๋๊ตฌ ์ฌ์ฉ (ํด๋ฐฑ)
+
+### AI Gateway
+
+OpenAI API ํธ์ถ์ Cloudflare AI Gateway๋ฅผ ํตํด ํ๋ก์ํ์ฌ ์ง์ญ ์ ํ์ ์ฐํํฉ๋๋ค.
+
+```
+Gateway ID: telegram-bot
+URL: gateway.ai.cloudflare.com/v1/{account_id}/telegram-bot/openai/...
+```
+
+**๋์๋ณด๋**: Cloudflare Dashboard โ AI โ AI Gateway โ telegram-bot
+
---
## ์์น๊ธ ์์คํ
@@ -202,7 +229,7 @@ OpenAI: ๋ ์จ ๋ฐ์ดํฐ๋ฅผ ์์ฐ์ด๋ก ์๋ต ์์ฑ
```
[์๋๋ฆฌ์ค 2: ์ํ SMS๊ฐ ๋จผ์ ๋์ฐฉ]
-์ํ SMS โ Gmail โ Apps Script
+์ํ SMS โ ๋ฉ์ผ ์ ๋ฌ โ Cloudflare Email Routing โ Worker (email handler)
โ
โผ
โโโโโโโโโโโโโโโโโโโโ
@@ -280,57 +307,23 @@ OpenAI: ๋ ์จ ๋ฐ์ดํฐ๋ฅผ ์์ฐ์ด๋ก ์๋ต ์์ฑ
๊ฐ์ฌํฉ๋๋ค! ๐
```
-### Gmail โ Apps Script โ Worker ์ฐ๋
+### Cloudflare Email Routing
-SMS๋ฅผ Gmail๋ก ์ ๋ฌ๋ฐ์ Apps Script์์ Worker API๋ฅผ ํธ์ถํฉ๋๋ค.
+SMS๋ฅผ ๋ฉ์ผ๋ก ์ ๋ฌ๋ฐ์ Worker์์ ์ง์ ์ฒ๋ฆฌํฉ๋๋ค.
**ํ๋ฆ:**
```
-์ํ SMS โ Gmail(deposit.anvil@gmail.com) โ Apps Script (1๋ถ๋ง๋ค)
- โ
- POST /api/bank-notification โ DB ์ ์ฅ โ ์๋ ๋งค์นญ
- โ
- ๋งค์นญ ์ฑ๊ณต โ ์ฌ์ฉ์/๊ด๋ฆฌ์ Telegram ์๋ฆผ
+์ํ SMS โ ๋ฉ์ผ ์ ๋ฌ โ Cloudflare Email Routing โ Worker (email handler)
+ โ
+ SMS ํ์ฑ โ DB ์ ์ฅ โ ์๋ ๋งค์นญ
+ โ
+ ๋งค์นญ ์ฑ๊ณต โ ์ฌ์ฉ์/๊ด๋ฆฌ์ Telegram ์๋ฆผ
```
-**Apps Script ์ฝ๋:**
-```javascript
-function checkBankEmails() {
- var threads = GmailApp.search('is:unread ์
๊ธ', 0, 10);
-
- for (var i = 0; i < threads.length; i++) {
- var messages = threads[i].getMessages();
-
- for (var j = 0; j < messages.length; j++) {
- var message = messages[j];
- if (!message.isUnread()) continue;
-
- var messageId = message.getId();
- var body = message.getPlainBody();
-
- try {
- UrlFetchApp.fetch(
- 'https://telegram-summary-bot.kappa-d8e.workers.dev/api/bank-notification',
- {
- method: 'POST',
- contentType: 'application/json',
- payload: JSON.stringify({
- content: body,
- messageId: messageId,
- secret: 'BANK_API_SECRET ๊ฐ'
- })
- }
- );
- } catch (e) {
- console.log('Error: ' + e);
- }
- }
- threads[i].markRead();
- }
-}
-```
-
-**ํธ๋ฆฌ๊ฑฐ ์ค์ :** ์๊ฐ ๊ธฐ๋ฐ โ ๋ถ ํ์ด๋จธ โ 1๋ถ๋ง๋ค
+**์ค์ ๋ฐฉ๋ฒ:**
+1. Cloudflare Dashboard โ Email โ Email Routing โ Routes
+2. ์์ ์ฃผ์ ์ค์ (์: `deposit@your-domain.com`)
+3. Worker๋ก ๋ผ์ฐํ
: `telegram-summary-bot`
**์ง์ ์ํ SMS ํจํด:**
- ํ๋์ํ (Web๋ฐ์ ): `[Web๋ฐ์ ] ํ๋,01/16, 23:30 427******27104 ์
๊ธ5์ ํฉ๋ณํ`
@@ -540,14 +533,14 @@ wrangler secret put WEBHOOK_SECRET
# OpenAI API Key (ํ์)
wrangler secret put OPENAI_API_KEY
-# ์
๊ธ ์๋ฆผ API Secret (Apps Script ์ฐ๋์ฉ)
-wrangler secret put BANK_API_SECRET
-
# Brave Search API Key
wrangler secret put BRAVE_API_KEY
# Deposit API Secret (namecheap-api ์ฐ๋์ฉ)
wrangler secret put DEPOSIT_API_SECRET
+
+# namecheap-api ๋ํผ ์ธ์ฆ ํค (๋๋ฉ์ธ ์ถ์ฒ์ฉ)
+wrangler secret put NAMECHEAP_API_KEY
```
### Vault ์ฐ๋ (์ ํ)
@@ -582,6 +575,19 @@ curl https://telegram-summary-bot.kappa-d8e.workers.dev/setup-webhook
curl https://telegram-summary-bot.kappa-d8e.workers.dev/webhook-info
```
+### 6. CLI ํ
์คํธ (์ ํ)
+
+```bash
+# .env ํ์ผ ์์ฑ (์ต์ด 1ํ)
+echo 'WEBHOOK_SECRET=...' > .env # Vault: secret/telegram-bot
+
+# ๋ํํ ๋ชจ๋
+npm run chat
+
+# ๋จ์ผ ๋ฉ์์ง ๋ชจ๋
+npm run chat "์๋
"
+```
+
---
## ๋ณด์ ์ค์
@@ -680,7 +686,7 @@ database_id = "c285bb5b-888b-405d-b36f-475ae5aed20e"
| `/webhook-info` | GET | Webhook ์ํ |
| `/setup-webhook` | GET | Webhook ์ค์ |
| `/webhook` | POST | Telegram Webhook |
-| `/api/bank-notification` | POST | ์
๊ธ ์๋ฆผ API (Apps Script ์ฐ๋) |
+| `/api/bank-notification` | POST | ์
๊ธ ์๋ฆผ API (๋ ๊ฑฐ์, Email Routing์ผ๋ก ๋์ฒด) |
| `/api/deposit/balance` | GET | ์์น๊ธ ์์ก ์กฐํ (namecheap-api์ฉ) |
| `/api/deposit/deduct` | POST | ์์น๊ธ ์ฐจ๊ฐ (namecheap-api์ฉ) |
diff --git a/scripts/chat.ts b/scripts/chat.ts
index d9051f4..bfba813 100644
--- a/scripts/chat.ts
+++ b/scripts/chat.ts
@@ -2,11 +2,25 @@
/**
* Telegram Bot CLI Chat Client
* - Worker์ /api/test ์๋ํฌ์ธํธ๋ฅผ ํตํด ์ง์ ๋ํ
- * - ์ฌ์ฉ๋ฒ: npx tsx scripts/chat.ts
- * ๋๋: npx tsx scripts/chat.ts "๋ฉ์์ง"
+ * - ์ฌ์ฉ๋ฒ: npm run chat
+ * ๋๋: npm run chat "๋ฉ์์ง"
*/
import * as readline from 'readline';
+import * as fs from 'fs';
+import * as path from 'path';
+
+// .env ํ์ผ ๋ก๋
+const envPath = path.join(process.cwd(), '.env');
+if (fs.existsSync(envPath)) {
+ const envContent = fs.readFileSync(envPath, 'utf-8');
+ for (const line of envContent.split('\n')) {
+ const [key, ...valueParts] = line.split('=');
+ if (key && valueParts.length > 0) {
+ process.env[key.trim()] = valueParts.join('=').trim();
+ }
+ }
+}
const WORKER_URL = process.env.WORKER_URL || 'https://telegram-summary-bot.kappa-d8e.workers.dev';
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
diff --git a/src/deposit-agent.ts b/src/deposit-agent.ts
index f92594d..07e6adf 100644
--- a/src/deposit-agent.ts
+++ b/src/deposit-agent.ts
@@ -1,5 +1,8 @@
/**
- * Deposit Agent - ์์น๊ธ ๊ด๋ฆฌ ์์ด์ ํธ (OpenAI Assistants API)
+ * Deposit Agent - ์์น๊ธ ๊ด๋ฆฌ (์ฝ๋ ์ง์ ์ฒ๋ฆฌ)
+ *
+ * ๋ณ๊ฒฝ ์ด๋ ฅ:
+ * - 2026-01: Assistants API โ ์ฝ๋ ์ง์ ์ฒ๋ฆฌ๋ก ๋ณ๊ฒฝ (์ง์ญ ์ ํ ์ฐํ, ์๋ต ์ผ๊ด์ฑ)
*
* ๊ธฐ๋ฅ:
* - ์์ก ์กฐํ
diff --git a/src/index.ts b/src/index.ts
index 62a3365..cc442ce 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -169,112 +169,6 @@ export default {
}
}
- // Bank Notification API (Gmail โ Apps Script โ Worker)
- if (url.pathname === '/api/bank-notification' && request.method === 'POST') {
- try {
- const body = await request.json() as { content: string; secret?: string; messageId?: string };
-
- // ๊ฐ๋จํ ์ธ์ฆ (BANK_API_SECRET ๋๋ WEBHOOK_SECRET ์ฌ์ฉ)
- const apiSecret = (env as any).BANK_API_SECRET || env.WEBHOOK_SECRET;
- if (apiSecret && body.secret !== apiSecret) {
- return Response.json({ error: 'Unauthorized' }, { status: 401 });
- }
-
- console.log('[API] Bank notification received:', body.content?.slice(0, 100));
-
- // ๋ฉ์ผ ID๋ก ์ค๋ณต ์ฒดํฌ
- if (body.messageId) {
- const existing = await env.DB.prepare(
- 'SELECT id FROM bank_notifications WHERE message_id = ?'
- ).bind(body.messageId).first();
-
- if (existing) {
- console.log('[API] ์ค๋ณต ๋ฉ์ผ ๋ฌด์:', body.messageId);
- return Response.json({ success: true, duplicate: true, messageId: body.messageId });
- }
- }
-
- // SMS ํ์ฑ
- const notification = parseBankSMS(body.content || '');
- if (!notification) {
- console.log('[API] ํ์ฑ ์คํจ:', body.content);
- return Response.json({ error: 'Parse failed', content: body.content }, { status: 400 });
- }
-
- console.log('[API] ํ์ฑ ๊ฒฐ๊ณผ:', notification);
-
- // DB์ ์ ์ฅ
- const insertResult = await env.DB.prepare(
- `INSERT INTO bank_notifications (bank_name, depositor_name, amount, balance_after, transaction_time, raw_message, message_id)
- VALUES (?, ?, ?, ?, ?, ?, ?)`
- ).bind(
- notification.bankName,
- notification.depositorName,
- notification.amount,
- notification.balanceAfter || null,
- notification.transactionTime?.toISOString() || null,
- notification.rawMessage,
- body.messageId || null
- ).run();
-
- const notificationId = insertResult.meta.last_row_id;
- console.log('[API] ์๋ฆผ ์ ์ฅ ์๋ฃ, ID:', notificationId);
-
- // ์๋ ๋งค์นญ ์๋
- const matched = await tryAutoMatch(env.DB, notificationId as number, notification);
-
- // ๋งค์นญ ์ฑ๊ณต ์ ์ฌ์ฉ์์๊ฒ ์๋ฆผ
- if (matched && env.BOT_TOKEN) {
- const user = await env.DB.prepare(
- 'SELECT telegram_id FROM users WHERE id = ?'
- ).bind(matched.userId).first<{ telegram_id: string }>();
-
- if (user) {
- // ์
๋ฐ์ดํธ๋ ์์ก ์กฐํ
- const deposit = await env.DB.prepare(
- 'SELECT balance FROM user_deposits WHERE user_id = ?'
- ).bind(matched.userId).first<{ balance: number }>();
-
- await sendMessage(
- env.BOT_TOKEN,
- parseInt(user.telegram_id),
- `โ
์
๊ธ ํ์ธ ์๋ฃ!\n\n` +
- `์
๊ธ์ก: ${matched.amount.toLocaleString()}์\n` +
- `ํ์ฌ ์์ก: ${(deposit?.balance || 0).toLocaleString()}์\n\n` +
- `๊ฐ์ฌํฉ๋๋ค! ๐`
- );
- }
- }
-
- // ๊ด๋ฆฌ์์๊ฒ ์๋ฆผ
- if (env.BOT_TOKEN && env.DEPOSIT_ADMIN_ID) {
- const statusMsg = matched
- ? `โ
์๋ ๋งค์นญ ์๋ฃ! (๊ฑฐ๋ #${matched.transactionId})`
- : 'โณ ๋งค์นญ ๋๊ธฐ ์ค (์ฌ์ฉ์ ์
๊ธ ์ ๊ณ ํ์)';
-
- await sendMessage(
- env.BOT_TOKEN,
- parseInt(env.DEPOSIT_ADMIN_ID),
- `๐ฆ ์
๊ธ ์๋ฆผ\n\n` +
- `์ํ: ${notification.bankName}\n` +
- `์
๊ธ์: ${notification.depositorName}\n` +
- `๊ธ์ก: ${notification.amount.toLocaleString()}์\n` +
- `${notification.balanceAfter ? `์์ก: ${notification.balanceAfter.toLocaleString()}์\n` : ''}` +
- `\n${statusMsg}`
- );
- }
-
- return Response.json({
- success: true,
- notification,
- matched: !!matched
- });
- } catch (error) {
- console.error('[API] Bank notification error:', error);
- return Response.json({ error: String(error) }, { status: 500 });
- }
- }
-
// Deposit API - ์์ก ์กฐํ (namecheap-api ์ ์ฉ)
if (url.pathname === '/api/deposit/balance' && request.method === 'GET') {
try {
@@ -497,7 +391,7 @@ Documentation: https://github.com/your-repo
// SMS ๋ด์ฉ ํ์ฑ
const notification = parseBankSMS(rawEmail);
if (!notification) {
- console.log('[Email] ์ํ SMS ํ์ฑ ์คํจ:', rawEmail.slice(0, 200));
+ console.log('[Email] ์ํ SMS ํ์ฑ ์คํจ');
return;
}
@@ -568,10 +462,55 @@ Documentation: https://github.com/your-repo
},
};
+// Quoted-Printable UTF-8 ๋์ฝ๋ฉ
+function decodeQuotedPrintableUTF8(str: string): string {
+ // ์ค ์ฐ์ ๋ฌธ์ ์ ๊ฑฐ
+ str = str.replace(/=\r?\n/g, '');
+
+ // =XX ํจํด์ ๋ฐ์ดํธ๋ก ๋ณํ
+ const bytes: number[] = [];
+ let i = 0;
+ while (i < str.length) {
+ if (str[i] === '=' && i + 2 < str.length) {
+ const hex = str.slice(i + 1, i + 3);
+ if (/^[0-9A-Fa-f]{2}$/.test(hex)) {
+ bytes.push(parseInt(hex, 16));
+ i += 3;
+ continue;
+ }
+ }
+ bytes.push(str.charCodeAt(i));
+ i++;
+ }
+
+ // UTF-8 ๋ฐ์ดํธ๋ฅผ ๋ฌธ์์ด๋ก ๋ณํ
+ try {
+ return new TextDecoder('utf-8').decode(new Uint8Array(bytes));
+ } catch {
+ return str;
+ }
+}
+
// ์ํ SMS ํ์ฑ ํจ์
function parseBankSMS(content: string): BankNotification | null {
- // ์ด๋ฉ์ผ์์ SMS ๋ณธ๋ฌธ ์ถ์ถ (์ฌ๋ฌ ์ค์ ๊ฑธ์ณ ์์ ์ ์์)
- const text = content.replace(/\r\n/g, '\n').replace(/=\n/g, '');
+ // MIME ์ด๋ฉ์ผ ์ ์ฒ๋ฆฌ
+ let text = content;
+
+ // Quoted-Printable UTF-8 ๋์ฝ๋ฉ
+ text = decodeQuotedPrintableUTF8(text);
+
+ // HTML
ํ๊ทธ๋ฅผ ์ค๋ฐ๊ฟ์ผ๋ก ๋ณํ
+ text = text.replace(/
/gi, '\n');
+
+ // ์ค๋ฐ๊ฟ ์ ๊ทํ
+ text = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
+
+ // [Web๋ฐ์ ] ๋๋ ์ํ ํค์๋๊ฐ ์๋ ๋ถ๋ถ๋ง ์ถ์ถ
+ const smsStartMatch = text.match(/\[Web๋ฐ์ \]|\[ํ๋์ํ\]|\[KB\]|\[์ ํ\]|\[์ฐ๋ฆฌ\]|\[๋ํ\]/);
+ if (smsStartMatch && smsStartMatch.index !== undefined) {
+ // SMS ์์์ ๋ถํฐ 500์ ์ถ์ถ
+ text = text.slice(smsStartMatch.index, smsStartMatch.index + 500);
+ }
// ํ๋์ํ Web๋ฐ์ ํจํด (์ฌ๋ฌ ์ค):
// [Web๋ฐ์ ]
diff --git a/src/openai-service.ts b/src/openai-service.ts
index 804229a..457befd 100644
--- a/src/openai-service.ts
+++ b/src/openai-service.ts
@@ -253,8 +253,7 @@ function selectToolsForMessage(message: string): typeof tools {
}
// ๋๋ฉ์ธ ์ถ์ฒ ํจ์
-async function suggestDomains(keywords: string, apiKey: string): Promise {
- const namecheapApiKey = '05426957210b42e752950f565ea82a3f48df9cccfdce9d82cd9817011968076e';
+async function suggestDomains(keywords: string, apiKey: string, namecheapApiKey: string): Promise {
const namecheapApiUrl = 'https://namecheap-api.anvil.it.com';
const TARGET_COUNT = 10;
const MAX_RETRIES = 3;
@@ -1123,11 +1122,15 @@ async function executeTool(name: string, args: Record, env?: Env
console.log('[suggest_domains] ์์:', { keywords });
if (!env?.OPENAI_API_KEY) {
- return '๐ซ ๋๋ฉ์ธ ์ถ์ฒ ๊ธฐ๋ฅ์ด ์ค์ ๋์ง ์์์ต๋๋ค.';
+ return '๐ซ ๋๋ฉ์ธ ์ถ์ฒ ๊ธฐ๋ฅ์ด ์ค์ ๋์ง ์์์ต๋๋ค. (OPENAI_API_KEY ๋ฏธ์ค์ )';
+ }
+
+ if (!env?.NAMECHEAP_API_KEY) {
+ return '๐ซ ๋๋ฉ์ธ ์ถ์ฒ ๊ธฐ๋ฅ์ด ์ค์ ๋์ง ์์์ต๋๋ค. (NAMECHEAP_API_KEY ๋ฏธ์ค์ )';
}
try {
- const result = await suggestDomains(keywords, env.OPENAI_API_KEY);
+ const result = await suggestDomains(keywords, env.OPENAI_API_KEY, env.NAMECHEAP_API_KEY);
console.log('[suggest_domains] ์๋ฃ:', result?.slice(0, 100));
return result;
} catch (error) {
diff --git a/src/types.ts b/src/types.ts
index d7cdd6f..dd5aac6 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -9,7 +9,6 @@ export interface Env {
OPENAI_API_KEY?: string;
NAMECHEAP_API_KEY?: string;
DOMAIN_OWNER_ID?: string;
- DEPOSIT_AGENT_ID?: string;
DEPOSIT_ADMIN_ID?: string;
BRAVE_API_KEY?: string;
DEPOSIT_API_SECRET?: string;
diff --git a/wrangler.toml b/wrangler.toml
index caaa418..c5b1988 100644
--- a/wrangler.toml
+++ b/wrangler.toml
@@ -6,12 +6,11 @@ compatibility_date = "2024-01-01"
binding = "AI"
[vars]
-SUMMARY_THRESHOLD = "20"
-MAX_SUMMARIES_PER_USER = "3"
-N8N_WEBHOOK_URL = "https://n8n.anvil.it.com"
-DOMAIN_OWNER_ID = "821596605"
-DEPOSIT_AGENT_ID = "asst_XMoVGU7ZwRpUPI6PHGvRNm8E"
-DEPOSIT_ADMIN_ID = "821596605"
+SUMMARY_THRESHOLD = "20" # ํ๋กํ ์
๋ฐ์ดํธ ์ฃผ๊ธฐ (๋ฉ์์ง ์)
+MAX_SUMMARIES_PER_USER = "3" # ์ ์งํ ํ๋กํ ๋ฒ์ ์ (์ฌ๋ผ์ด๋ฉ ์๋์ฐ)
+N8N_WEBHOOK_URL = "https://n8n.anvil.it.com" # n8n ์ฐ๋ (์ ํ)
+DOMAIN_OWNER_ID = "821596605" # ๋๋ฉ์ธ ๊ด๋ฆฌ ๊ถํ Telegram ID
+DEPOSIT_ADMIN_ID = "821596605" # ์์น๊ธ ๊ด๋ฆฌ ๊ถํ Telegram ID
[[d1_databases]]
binding = "DB"
@@ -27,3 +26,6 @@ database_id = "c285bb5b-888b-405d-b36f-475ae5aed20e"
# - BOT_TOKEN: Telegram Bot Token
# - WEBHOOK_SECRET: Webhook ๊ฒ์ฆ์ฉ ์ํฌ๋ฆฟ
# - OPENAI_API_KEY: OpenAI API ํค
+# - NAMECHEAP_API_KEY: namecheap-api ๋ํผ ์ธ์ฆ ํค (๋๋ฉ์ธ ์ถ์ฒ์ฉ)
+# - BRAVE_API_KEY: Brave Search API ํค
+# - DEPOSIT_API_SECRET: Deposit API ์ธ์ฆ ํค (namecheap-api ์ฐ๋)