fix(portal): 토큰 DEFAULT·UNIQUE 인덱스 보장 + 메일 제목 이스케이프 제거
- contact_requests.public_token: 인라인 UNIQUE 제거, 백필 UPDATE 직후 SET DEFAULT + CREATE UNIQUE INDEX IF NOT EXISTS 패턴으로 교체 (라이브 DB 멱등성 보장) - quotes.public_token: ADD COLUMN IF NOT EXISTS + SET DEFAULT + 백필 UPDATE + CREATE UNIQUE INDEX IF NOT EXISTS 4줄 구조로 교체 (인라인 UNIQUE NO-OP 문제 해소) - sendQuoteSentEmail / sendQuoteDecisionEmail subject에서 escapeHtml() 제거 — 메일 제목은 평문, HTML 본문 이스케이프는 유지 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ export async function sendQuoteSentEmail(opts: {
|
|||||||
await resend().emails.send({
|
await resend().emails.send({
|
||||||
from: FROM,
|
from: FROM,
|
||||||
to: [clientEmail],
|
to: [clientEmail],
|
||||||
subject: `[쟁승메이드] 견적서가 도착했습니다 — ${escapeHtml(quoteTitle)}`,
|
subject: `[쟁승메이드] 견적서가 도착했습니다 — ${quoteTitle}`,
|
||||||
html: `
|
html: `
|
||||||
<h2>견적서를 보내드립니다</h2>
|
<h2>견적서를 보내드립니다</h2>
|
||||||
<p>${escapeHtml(clientName)}님, 요청하신 건의 견적서가 준비되었습니다.</p>
|
<p>${escapeHtml(clientName)}님, 요청하신 건의 견적서가 준비되었습니다.</p>
|
||||||
@@ -57,7 +57,7 @@ export async function sendQuoteDecisionEmail(opts: {
|
|||||||
await resend().emails.send({
|
await resend().emails.send({
|
||||||
from: FROM,
|
from: FROM,
|
||||||
to: [ADMIN_EMAIL],
|
to: [ADMIN_EMAIL],
|
||||||
subject: `[쟁승메이드] 견적 ${label} — ${escapeHtml(quoteTitle)}`,
|
subject: `[쟁승메이드] 견적 ${label} — ${quoteTitle}`,
|
||||||
html: `
|
html: `
|
||||||
<h2>고객이 견적을 ${label}했습니다</h2>
|
<h2>고객이 견적을 ${label}했습니다</h2>
|
||||||
<p>견적: ${escapeHtml(quoteTitle)} / 고객: ${escapeHtml(clientName)}</p>
|
<p>견적: ${escapeHtml(quoteTitle)} / 고객: ${escapeHtml(clientName)}</p>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- 2026-06-12 Phase 3: 외주 고객 포털
|
-- 2026-06-12 Phase 3: 외주 고객 포털
|
||||||
-- (1) contact_requests 확장
|
-- (1) contact_requests 확장
|
||||||
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS public_token text UNIQUE;
|
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS public_token text;
|
||||||
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS project_type text;
|
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS project_type text;
|
||||||
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS budget text;
|
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS budget text;
|
||||||
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS timeline text;
|
ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS timeline text;
|
||||||
@@ -9,6 +9,9 @@ ALTER TABLE contact_requests ADD COLUMN IF NOT EXISTS updated_at timestamptz DEF
|
|||||||
-- 기존 행 토큰 백필 (멱등 — NULL만)
|
-- 기존 행 토큰 백필 (멱등 — NULL만)
|
||||||
UPDATE contact_requests SET public_token = gen_random_uuid()::text WHERE public_token IS NULL;
|
UPDATE contact_requests SET public_token = gen_random_uuid()::text WHERE public_token IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE contact_requests ALTER COLUMN public_token SET DEFAULT gen_random_uuid()::text;
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_contact_requests_public_token_unique ON contact_requests (public_token);
|
||||||
|
|
||||||
-- 상태 머신 CHECK (레거시 3종 포함 8종)
|
-- 상태 머신 CHECK (레거시 3종 포함 8종)
|
||||||
ALTER TABLE contact_requests DROP CONSTRAINT IF EXISTS contact_requests_status_check;
|
ALTER TABLE contact_requests DROP CONSTRAINT IF EXISTS contact_requests_status_check;
|
||||||
ALTER TABLE contact_requests ADD CONSTRAINT contact_requests_status_check
|
ALTER TABLE contact_requests ADD CONSTRAINT contact_requests_status_check
|
||||||
@@ -19,8 +22,7 @@ ALTER TABLE quotes ADD COLUMN IF NOT EXISTS contact_request_id uuid REFERENCES c
|
|||||||
CREATE INDEX IF NOT EXISTS idx_quotes_contact_request ON quotes (contact_request_id);
|
CREATE INDEX IF NOT EXISTS idx_quotes_contact_request ON quotes (contact_request_id);
|
||||||
|
|
||||||
-- (3) quotes.public_token 컬럼 보장 (live DB에 직접 생성된 경우 대비)
|
-- (3) quotes.public_token 컬럼 보장 (live DB에 직접 생성된 경우 대비)
|
||||||
ALTER TABLE quotes ADD COLUMN IF NOT EXISTS public_token text UNIQUE;
|
ALTER TABLE quotes ADD COLUMN IF NOT EXISTS public_token text;
|
||||||
|
|
||||||
-- quotes.public_token 기본값 보장
|
|
||||||
ALTER TABLE quotes ALTER COLUMN public_token SET DEFAULT gen_random_uuid()::text;
|
ALTER TABLE quotes ALTER COLUMN public_token SET DEFAULT gen_random_uuid()::text;
|
||||||
UPDATE quotes SET public_token = gen_random_uuid()::text WHERE public_token IS NULL;
|
UPDATE quotes SET public_token = gen_random_uuid()::text WHERE public_token IS NULL;
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_quotes_public_token_unique ON quotes (public_token);
|
||||||
|
|||||||
Reference in New Issue
Block a user