generated from ttipo/project-base
feat(backend): 본문 길이 초과 코드 MAIL_007·본문 잘림 표시·보이지 않는 서식 제거
- 본문이 너무 길면 일반 VAL_001 대신 MAIL_007 을 돌려준다 — 텍스트 100,000자·서식 본문 500,000자 초과(클라이언트와 같은 JS 길이), 서식 본문의 정화 전 비용 초과, 정화 뒤 2,000,000바이트 초과. 모두 엔진·중복 방지 잠금 전이라 메일은 나가지 않는다. 클라이언트 에러 사전(frontend·flutter)도 다시 생성했다 - 메일 상세에 isHtmlBodyOmitted(정화 한도를 넘어 HTML 을 비움)와 isBodyTruncated(보여 줄 본문이 읽기 한도에서 잘림)를 더했다 — 보여 줄 본문은 htmlBody, 그것이 null 이거나 공백뿐이면 textBody 다 - 보내는 서식 본문은 8px 미만 글자 크기와 알파 0.3 미만 글자 색을 지운다 — 붙여 넣거나 인용한 글에 숨긴 글이 그대로 나가지 않게. 받은 메일 정화는 그대로다 계약: docs/mail/api-contract.md 2절 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,11 @@ import { DataSource } from 'typeorm';
|
||||
import { AppModule } from '@/app.module';
|
||||
import { configureApp } from '@/app.setup';
|
||||
import { AUTH_SETTINGS, type AuthSettings } from '@/modules/auth/auth.settings';
|
||||
import {
|
||||
MAX_BODY_HTML_LENGTH,
|
||||
MAX_BODY_LENGTH,
|
||||
MAX_SUBJECT_LENGTH,
|
||||
} from '@/modules/mail/mail.constants';
|
||||
import { MAIL_PROVIDER } from '@/modules/mail/mail.provider';
|
||||
import { MAIL_SETTINGS, type MailSettings } from '@/modules/mail/mail.settings';
|
||||
import { UPLOAD_DIR } from '@/modules/upload/upload.config';
|
||||
@@ -537,6 +542,39 @@ describe('응답 계약 (e2e)', () => {
|
||||
const stored = join(UPLOAD_DIR, basename(saved?.fileName ?? ''));
|
||||
if (saved?.fileName && existsSync(stored)) unlinkSync(stored);
|
||||
});
|
||||
|
||||
it('발송 본문이 너무 길면 400 MAIL_007 — 형식 검증이 아니라 서비스가 JS 문자열 길이(UTF-16)로 센다, 제목은 그대로 VAL_001', async () => {
|
||||
const accessToken = sign(
|
||||
{ sub: EMPLOYEE.email, typ: 'access', name: EMPLOYEE.name },
|
||||
600,
|
||||
);
|
||||
// 대역 엔진에는 발송이 없다 — 엔진에 닿으면 500 이 된다 (한도는 엔진에 묻기 전에 본다)
|
||||
const send = (overrides: object) =>
|
||||
request(server)
|
||||
.post('/api/messages')
|
||||
.set('Cookie', `access_token=${accessToken}`)
|
||||
.send({
|
||||
to: [{ name: null, email: 'doyun.lee@e2e.arasystem.test' }],
|
||||
subject: '제목',
|
||||
body: '본문',
|
||||
...overrides,
|
||||
});
|
||||
|
||||
for (const overrides of [
|
||||
// 이모지 50,001개 = 100,002자 — 예전 형식 검증(MaxLength)은 50,001자로 세어 통과시켰다
|
||||
{ body: '😀'.repeat(MAX_BODY_LENGTH / 2 + 1) },
|
||||
{ bodyHtml: 'x'.repeat(MAX_BODY_HTML_LENGTH + 1) },
|
||||
]) {
|
||||
const res = await send(overrides).expect(400);
|
||||
expect(body(res).error?.code).toBe('MAIL_007');
|
||||
expect(body(res).error?.traceId).toBe(res.headers['x-request-id']);
|
||||
}
|
||||
|
||||
const longSubject = await send({
|
||||
subject: '가'.repeat(MAX_SUBJECT_LENGTH + 1),
|
||||
}).expect(400);
|
||||
expect(body(longSubject).error?.code).toBe('VAL_001');
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user